Bug 365336 text-decoration width should be rounded to the device pixels r+sr=roc
authormasayuki@d-toybox.com
Mon, 06 Aug 2007 01:15:00 -0700
changeset 4302 6ea6e9f29942f16ae651f3014c3c04a99a2346c3
parent 4301 a7a8c7d444261a0c08b24ee1c9b283204f19a4cc
child 4303 b03016c98bb6dcf46fa48b19871bf4e2187fdeb3
push idunknown
push userunknown
push dateunknown
bugs365336
milestone1.9a8pre
Bug 365336 text-decoration width should be rounded to the device pixels r+sr=roc
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsHTMLContainerFrame.cpp
layout/generic/nsHTMLContainerFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/mathml/base/src/Makefile.in
layout/tables/Makefile.in
layout/xul/base/src/grid/Makefile.in
layout/xul/base/src/nsTextBoxFrame.cpp
layout/xul/base/src/tree/src/Makefile.in
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -4350,8 +4350,133 @@ nsCSSRendering::DrawTableBorderSegment(n
 
 #ifdef MOZ_CAIRO_GFX
   ctx->SetAntialiasMode(oldMode);
 #endif
 }
 
 // End table border-collapsing section
 
+void
+nsCSSRendering::PaintDecorationLine(gfxContext* aGfxContext,
+                                    const nscolor aColor,
+                                    const gfxPoint& aPt,
+                                    const gfxSize& aLineSize,
+                                    const gfxFloat aAscent,
+                                    const gfxFloat aOffset,
+                                    const gfxFloat aPreferredHeight,
+                                    const PRUint8 aDecoration,
+                                    const PRUint8 aStyle,
+                                    const PRBool aIsRTL)
+{
+  if (aLineSize.width <= 0 || aLineSize.height <= 0 ||
+      aStyle == NS_STYLE_BORDER_STYLE_NONE)
+    return;
+
+  PRBool contextIsSaved = PR_FALSE;
+  gfxFloat totalHeight = aLineSize.height;
+  switch (aStyle) {
+    case NS_STYLE_BORDER_STYLE_SOLID:
+      break;
+    case NS_STYLE_BORDER_STYLE_DASHED: {
+      aGfxContext->Save();
+      contextIsSaved = PR_TRUE;
+      gfxFloat dashWidth = aLineSize.height * DOT_LENGTH * DASH_LENGTH;
+      gfxFloat dash[2] = { dashWidth, dashWidth };
+      aGfxContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
+      aGfxContext->SetDash(dash, 2, 0.0);
+      break;
+    }
+    case NS_STYLE_BORDER_STYLE_DOTTED: {
+      aGfxContext->Save();
+      contextIsSaved = PR_TRUE;
+      gfxFloat dashWidth = aLineSize.height * DOT_LENGTH;
+      gfxFloat dash[2];
+      if (aLineSize.height > 2.0) {
+        dash[0] = 0.0;
+        dash[1] = dashWidth * 2.0;
+        aGfxContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
+      } else {
+        dash[0] = dashWidth;
+        dash[1] = dashWidth;
+      }
+      aGfxContext->SetDash(dash, 2, 0.0);
+      break;
+    }
+    case NS_STYLE_BORDER_STYLE_DOUBLE:
+      totalHeight *= 3.0;
+      break;
+    default:
+      NS_ERROR("Invalid style value!");
+      return;
+  }
+
+  gfxFloat offset = aOffset;
+  switch (aDecoration) {
+    case NS_STYLE_TEXT_DECORATION_UNDERLINE:
+      break;
+    case NS_STYLE_TEXT_DECORATION_OVERLINE:
+      // The offset includes the preferred size, we should remove it
+      offset += aPreferredHeight;
+      // the bottom of the decoration line should be aligned to the top of the
+      // text.
+      offset -= totalHeight;
+      break;
+    case NS_STYLE_TEXT_DECORATION_LINE_THROUGH: {
+      // The offset includes the preferred size, we should remove it
+      offset += aPreferredHeight;
+      // the middle of the decoration line should be aligned to the middle of
+      // the original strike out offset.
+      offset -= PR_MAX(aPreferredHeight, (totalHeight / 2.0));
+      break;
+    }
+    default:
+      NS_ERROR("Invalid decoration value!");
+      if (contextIsSaved)
+        aGfxContext->Restore();
+      return;
+  }
+
+  // round to device pixels for suppressing the AA.
+  gfxFloat x = NS_round(aPt.x);
+  gfxFloat y = NS_round(aPt.y + aAscent - offset);
+  gfxFloat width = NS_round(aLineSize.width);
+  gfxFloat height = NS_round(aLineSize.height);
+  // The y position should be set to the middle of the line.
+  y += height / 2;
+
+  aGfxContext->SetColor(gfxRGBA(aColor));
+  aGfxContext->SetLineWidth(height);
+  switch (aStyle) {
+    case NS_STYLE_BORDER_STYLE_SOLID:
+      aGfxContext->NewPath();
+      aGfxContext->MoveTo(gfxPoint(x, y));
+      aGfxContext->LineTo(gfxPoint(x + width, y));
+      aGfxContext->Stroke();
+      break;
+    case NS_STYLE_BORDER_STYLE_DOUBLE:
+      aGfxContext->NewPath();
+      aGfxContext->MoveTo(gfxPoint(x, y));
+      aGfxContext->LineTo(gfxPoint(x + width, y));
+      aGfxContext->MoveTo(gfxPoint(x, y + height * 2.0));
+      aGfxContext->LineTo(gfxPoint(x + width, y + height * 2.0));
+      aGfxContext->Stroke();
+      break;
+    case NS_STYLE_BORDER_STYLE_DOTTED:
+    case NS_STYLE_BORDER_STYLE_DASHED:
+      aGfxContext->NewPath();
+      if (aIsRTL) {
+        aGfxContext->MoveTo(gfxPoint(x + width, y));
+        aGfxContext->LineTo(gfxPoint(x, y));
+      } else {
+        aGfxContext->MoveTo(gfxPoint(x, y));
+        aGfxContext->LineTo(gfxPoint(x + width, y));
+      }
+      aGfxContext->Stroke();
+      aGfxContext->Restore();
+      contextIsSaved = PR_FALSE;
+      break;
+    default:
+      NS_ERROR("Invalid style value!");
+      break;
+  }
+  NS_ASSERTION(!contextIsSaved, "The gfxContext has been saved, but not restored!");
+}
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 /* utility functions for drawing borders and backgrounds */
 
 #ifndef nsCSSRendering_h___
 #define nsCSSRendering_h___
 
 #include "nsIRenderingContext.h"
+#include "gfxContext.h"
 struct nsPoint;
 class nsStyleContext;
 class nsPresContext;
 
 class nsCSSRendering {
 public:
   /**
    * Initialize any static variables used by nsCSSRendering.
@@ -193,16 +194,55 @@ public:
   /**
    * transform a color to a color that will show up on a printer if needed
    * aMapColor - color to evaluate
    * aIsPrinter - Is this a printing device
    * return - the transformed color
    */
   static nscolor TransformColor(nscolor  aMapColor,PRBool aNoBackGround);
 
+  /**
+   * Function for painting the decoration lines for the text.
+   * NOTE: aPt, aLineSize, aAscent, aOffset and aReferredHeight are non-rounded
+   *       device pixels, not app units.
+   *   input:
+   *     @param aGfxContext
+   *     @param aColor            the color of the decoration line
+   *     @param aPt               the top/left edge of the text
+   *     @param aLineSize         the width and the height of the decoration
+   *                              line
+   *     @param aAscent           the ascent of the text
+   *     @param aOffset           the offset of the decoration line from
+   *                              the baseline of the text (if the value is
+   *                              positive, the line is lifted up)
+   *     @param aPreferredHeight  the preferred size of the decoration line by
+   *                              the font of the text
+   *     @param aDecoration       which line will be painted. The value can be
+   *                              NS_STYLE_TEXT_DECORATION_UNDERLINE or
+   *                              NS_STYLE_TEXT_DECORATION_OVERLINE or
+   *                              NS_STYLE_TEXT_DECORATION_LINE_THROUGH.
+   *     @param aStyle            the style of the decoration line. The value
+   *                              can be NS_STYLE_BORDER_STYLE_SOLID or
+   *                              NS_STYLE_BORDER_STYLE_DOTTED or
+   *                              NS_STYLE_BORDER_STYLE_DASHED or
+   *                              NS_STYLE_BORDER_STYLE_DOUBLE or
+   *                              NS_STYLE_BORDER_STYLE_NONE.
+   *     @param aIsRTL            when the text is RTL, it is true.
+   */
+  static void PaintDecorationLine(gfxContext* aGfxContext,
+                                  const nscolor aColor,
+                                  const gfxPoint& aPt,
+                                  const gfxSize& aLineSize,
+                                  const gfxFloat aAscent,
+                                  const gfxFloat aOffset,
+                                  const gfxFloat aPreferredSize,
+                                  const PRUint8 aDecoration,
+                                  const PRUint8 aStyle,
+                                  const PRBool aIsRTL);
+
 protected:
 
   static void PaintBackgroundColor(nsPresContext* aPresContext,
                                    nsIRenderingContext& aRenderingContext,
                                    nsIFrame* aForFrame,
                                    const nsRect& aBgClipArea,
                                    const nsStyleBackground& aColor,
                                    const nsStyleBorder& aBorder,
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -83,16 +83,17 @@
 #include "nsIDOMHTMLDocument.h"
 #include "nsIAccessibilityService.h"
 #endif
 #include "nsLayoutUtils.h"
 #include "nsBoxLayoutState.h"
 #include "nsDisplayList.h"
 #include "nsContentErrors.h"
 #include "nsCSSAnonBoxes.h"
+#include "nsCSSRendering.h"
 
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif // IBMBIDI
 
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLHtmlElement.h"
 
@@ -5658,19 +5659,19 @@ nsBlockFrame::IsVisibleInSelection(nsISe
 
 /* virtual */ void
 nsBlockFrame::PaintTextDecorationLine(nsIRenderingContext& aRenderingContext, 
                                       nsPoint aPt,
                                       nsLineBox* aLine,
                                       nscolor aColor, 
                                       nscoord aOffset, 
                                       nscoord aAscent, 
-                                      nscoord aSize) 
+                                      nscoord aSize,
+                                      const PRUint8 aDecoration) 
 {
-  aRenderingContext.SetColor(aColor);
   NS_ASSERTION(!aLine->IsBlock(), "Why did we ask for decorations on a block?");
 
   nscoord start = aLine->mBounds.x;
   nscoord width = aLine->mBounds.width;
 
   if (aLine == begin_lines().get()) {
     // Adjust for the text-indent.  See similar code in
     // nsLineLayout::BeginLineReflow.
@@ -5693,19 +5694,28 @@ nsBlockFrame::PaintTextDecorationLine(ns
     // It'll just increase the width (which can also happen to be
     // negative!).
     start += indent;
     width -= indent;
   }
       
   // Only paint if we have a positive width
   if (width > 0) {
-    aRenderingContext.FillRect(start + aPt.x,
-                               aLine->mBounds.y + aLine->GetAscent() - aOffset + aPt.y, 
-                               width, aSize);
+    const nsStyleVisibility* visibility = GetStyleVisibility();
+    PRBool isRTL = visibility->mDirection == NS_STYLE_DIRECTION_RTL;
+    nsRefPtr<gfxContext> ctx = (gfxContext*)
+      aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
+    gfxFloat a2p = 1.0 / PresContext()->AppUnitsPerDevPixel();
+    gfxPoint pt((start + aPt.x) * a2p, (aLine->mBounds.y + aPt.y) * a2p);
+    gfxSize size(width * a2p, aSize * a2p);
+    nsCSSRendering::PaintDecorationLine(ctx, aColor, pt, size,
+                                        aLine->GetAscent() * a2p, aOffset * a2p,
+                                        aSize * a2p, aDecoration,
+                                        NS_STYLE_BORDER_STYLE_SOLID,
+                                        isRTL);
   }
 }
 
 #ifdef DEBUG
 static void DebugOutputDrawLine(PRInt32 aDepth, nsLineBox* aLine, PRBool aDrawn) {
   if (nsBlockFrame::gNoisyDamageRepair) {
     nsFrame::IndentBy(stdout, aDepth+1);
     nsRect lineArea = aLine->GetCombinedArea();
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -311,17 +311,18 @@ protected:
    * lines in a nsBlockFrame properly.
    */
   virtual void PaintTextDecorationLine(nsIRenderingContext& aRenderingContext,
                                        nsPoint aPt,
                                        nsLineBox* aLine,
                                        nscolor aColor,
                                        nscoord aOffset,
                                        nscoord aAscent,
-                                       nscoord aSize);
+                                       nscoord aSize,
+                                       const PRUint8 aDecoration);
 
   void TryAllLines(nsLineList::iterator* aIterator,
                    nsLineList::iterator* aEndIterator,
                    PRBool* aInOverflowLines);
 
   void SetFlags(PRUint32 aFlags) {
     mState &= ~NS_BLOCK_FLAGS_MASK;
     mState |= aFlags;
--- a/layout/generic/nsHTMLContainerFrame.cpp
+++ b/layout/generic/nsHTMLContainerFrame.cpp
@@ -62,16 +62,17 @@
 #include "nsCOMPtr.h"
 #include "nsIDeviceContext.h"
 #include "nsIFontMetrics.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDisplayList.h"
 #include "nsBlockFrame.h"
 #include "nsLineBox.h"
 #include "nsDisplayList.h"
+#include "nsCSSRendering.h"
 
 class nsDisplayTextDecoration : public nsDisplayItem {
 public:
   nsDisplayTextDecoration(nsHTMLContainerFrame* aFrame, PRUint8 aDecoration,
                           nscolor aColor, nsLineBox* aLine)
     : nsDisplayItem(aFrame), mLine(aLine), mColor(aColor),
       mDecoration(aDecoration) {
     MOZ_COUNT_CTOR(nsDisplayTextDecoration);
@@ -112,23 +113,26 @@ nsDisplayTextDecoration::Paint(nsDisplay
 
   // REVIEW: From nsHTMLContainerFrame::PaintTextDecorations
   nscoord ascent, offset, size;
   nsHTMLContainerFrame* f = static_cast<nsHTMLContainerFrame*>(mFrame);
   fm->GetMaxAscent(ascent);
   if (mDecoration != NS_STYLE_TEXT_DECORATION_LINE_THROUGH) {
     fm->GetUnderline(offset, size);
     if (mDecoration == NS_STYLE_TEXT_DECORATION_UNDERLINE) {
-      f->PaintTextDecorationLine(*aCtx, pt, mLine, mColor, offset, ascent, size);
+      f->PaintTextDecorationLine(*aCtx, pt, mLine, mColor,
+                                 offset, ascent, size, mDecoration);
     } else if (mDecoration == NS_STYLE_TEXT_DECORATION_OVERLINE) {
-      f->PaintTextDecorationLine(*aCtx, pt, mLine, mColor, ascent, ascent, size);
+      f->PaintTextDecorationLine(*aCtx, pt, mLine, mColor,
+                                 ascent, ascent, size, mDecoration);
     }
   } else {
     fm->GetStrikeout(offset, size);
-    f->PaintTextDecorationLine(*aCtx, pt, mLine, mColor, offset, ascent, size);
+    f->PaintTextDecorationLine(*aCtx, pt, mLine, mColor,
+                               offset, ascent, size, mDecoration);
   }
 }
 
 nsresult
 nsHTMLContainerFrame::DisplayTextDecorations(nsDisplayListBuilder* aBuilder,
                                              nsDisplayList* aBelowTextDecorations,
                                              nsDisplayList* aAboveTextDecorations,
                                              nsLineBox* aLine)
@@ -198,30 +202,38 @@ HasTextFrameDescendantOrInFlow(nsPresCon
 /*virtual*/ void
 nsHTMLContainerFrame::PaintTextDecorationLine(
                    nsIRenderingContext& aRenderingContext, 
                    nsPoint aPt,
                    nsLineBox* aLine,
                    nscolor aColor, 
                    nscoord aOffset, 
                    nscoord aAscent, 
-                   nscoord aSize) 
+                   nscoord aSize,
+                   const PRUint8 aDecoration) 
 {
   NS_ASSERTION(!aLine, "Should not have passed a linebox to a non-block frame");
   nsMargin bp = GetUsedBorderAndPadding();
   PRIntn skip = GetSkipSides();
   NS_FOR_CSS_SIDES(side) {
     if (skip & (1 << side)) {
       bp.side(side) = 0;
     }
   }
-  aRenderingContext.SetColor(aColor);
+  const nsStyleVisibility* visibility = GetStyleVisibility();
+  PRBool isRTL = visibility->mDirection == NS_STYLE_DIRECTION_RTL;
   nscoord innerWidth = mRect.width - bp.left - bp.right;
-  aRenderingContext.FillRect(bp.left + aPt.x, 
-                             bp.top + aAscent - aOffset + aPt.y, innerWidth, aSize);
+  nsRefPtr<gfxContext> ctx = (gfxContext*)
+    aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
+  gfxFloat a2p = 1.0 / PresContext()->AppUnitsPerDevPixel();
+  gfxPoint pt((bp.left + aPt.x) * a2p, (bp.top + aPt.y) * a2p);
+  gfxSize size(innerWidth * a2p, aSize * a2p);
+  nsCSSRendering::PaintDecorationLine(ctx, aColor, pt, size, aAscent * a2p,
+                                      aOffset * a2p, aSize * a2p, aDecoration,
+                                      NS_STYLE_BORDER_STYLE_SOLID, isRTL);
 }
 
 void
 nsHTMLContainerFrame::GetTextDecorations(nsPresContext* aPresContext, 
                                          PRBool aIsBlock,
                                          PRUint8& aDecorations,
                                          nscolor& aUnderColor, 
                                          nscolor& aOverColor, 
--- a/layout/generic/nsHTMLContainerFrame.h
+++ b/layout/generic/nsHTMLContainerFrame.h
@@ -165,21 +165,26 @@ protected:
    *    @param aColor             the color of the text-decoration
    *    @param aAscent            ascent of the font from which the
    *                                text-decoration was derived. 
    *    @param aOffset            distance *above* baseline where the
    *                                text-decoration should be drawn,
    *                                i.e. negative offsets draws *below*
    *                                the baseline.
    *    @param aSize              the thickness of the line
+   *    @param aDecoration        which line will be painted
+   *                                i.e., NS_STYLE_TEXT_DECORATION_UNDERLINE or
+   *                                      NS_STYLE_TEXT_DECORATION_OVERLINE or
+   *                                      NS_STYLE_TEXT_DECORATION_LINE_THROUGH.
    */
   virtual void PaintTextDecorationLine(nsIRenderingContext& aRenderingContext,
                                        nsPoint aPt,
                                        nsLineBox* aLine,
                                        nscolor aColor,
                                        nscoord aOffset,
                                        nscoord aAscent,
-                                       nscoord aSize);
-                                       
+                                       nscoord aSize,
+                                       const PRUint8 aDecoration);
+
   friend class nsDisplayTextDecoration;
 };
 
 #endif /* nsHTMLContainerFrame_h___ */
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -3686,17 +3686,17 @@ nsTextFrame::GetSelectionDetails()
 }
 
 static void
 FillClippedRect(gfxContext* aCtx, nsPresContext* aPresContext,
                 nscolor aColor, const gfxRect& aDirtyRect, const gfxRect& aRect)
 {
   gfxRect r = aRect.Intersect(aDirtyRect);
   // For now, we need to put this in pixel coordinates
-  float t2p = 1.0/aPresContext->AppUnitsPerDevPixel();
+  float t2p = 1.0f / aPresContext->AppUnitsPerDevPixel();
   aCtx->NewPath();
   // pixel-snap
   aCtx->Rectangle(gfxRect(r.X()*t2p, r.Y()*t2p, r.Width()*t2p, r.Height()*t2p), PR_TRUE);
   aCtx->SetColor(gfxRGBA(aColor));
   aCtx->Fill();
 }
 
 void 
@@ -3760,102 +3760,113 @@ nsTextFrame::PaintTextDecorations(gfxCon
       break;
     hasDecorations = context->HasTextDecorations();
   }
 
   if (!decorations)
     return;
 
   gfxFont::Metrics fontMetrics = GetFontMetrics(aProvider.GetFontGroup());
-  gfxFloat pix2app = mTextRun->GetAppUnitsPerDevUnit();
+  gfxFloat a2p = 1.0 / aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
+
+  // XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
+  gfxPoint pt(aFramePt.x * a2p, aFramePt.y * a2p);
+  gfxSize size(GetRect().width * a2p, 0);
+  gfxFloat ascent = mAscent * a2p;
 
   if (decorations & NS_FONT_DECORATION_OVERLINE) {
-    FillClippedRect(aCtx, aTextPaintStyle.PresContext(), overColor, aDirtyRect,
-                    gfxRect(aFramePt.x, aFramePt.y,
-                            GetRect().width, NS_round(fontMetrics.underlineSize)*pix2app));
+    size.height = fontMetrics.underlineSize;
+    nsCSSRendering::PaintDecorationLine(
+      aCtx, overColor, pt, size, ascent, ascent, size.height,
+      NS_STYLE_TEXT_DECORATION_OVERLINE, NS_STYLE_BORDER_STYLE_SOLID,
+      mTextRun->IsRightToLeft());
   }
   if (decorations & NS_FONT_DECORATION_UNDERLINE) {
-    FillClippedRect(aCtx, aTextPaintStyle.PresContext(), underColor, aDirtyRect,
-                    gfxRect(aFramePt.x,
-                            GetSnappedBaselineY(aCtx, aFramePt.y) - NS_round(fontMetrics.underlineOffset)*pix2app,
-                            GetRect().width, NS_round(fontMetrics.underlineSize)*pix2app));
+    size.height = fontMetrics.underlineSize;
+    gfxFloat offset = fontMetrics.underlineOffset;
+    nsCSSRendering::PaintDecorationLine(
+      aCtx, underColor, pt, size, ascent, offset, size.height,
+      NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_SOLID,
+      mTextRun->IsRightToLeft());
   }
   if (decorations & NS_FONT_DECORATION_LINE_THROUGH) {
-    FillClippedRect(aCtx, aTextPaintStyle.PresContext(), strikeColor, aDirtyRect,
-                    gfxRect(aFramePt.x,
-                            GetSnappedBaselineY(aCtx, aFramePt.y) - NS_round(fontMetrics.strikeoutOffset)*pix2app,
-                            GetRect().width, NS_round(fontMetrics.strikeoutSize)*pix2app));
+    size.height = fontMetrics.strikeoutSize;
+    gfxFloat offset = fontMetrics.strikeoutOffset;
+    nsCSSRendering::PaintDecorationLine(
+      aCtx, strikeColor, pt, size, ascent, offset, size.height,
+      NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_SOLID,
+      mTextRun->IsRightToLeft());
   }
 }
 
 // Make sure this stays in sync with DrawSelectionDecorations below
 static const SelectionType SelectionTypesWithDecorations =
   nsISelectionController::SELECTION_SPELLCHECK |
   nsISelectionController::SELECTION_IME_RAWINPUT |
   nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT |
   nsISelectionController::SELECTION_IME_CONVERTEDTEXT |
   nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT;
 
 static void DrawIMEUnderline(gfxContext* aContext, PRInt32 aIndex,
-    nsTextPaintStyle& aTextPaintStyle, const gfxPoint& aBaselinePt, gfxFloat aWidth,
-    const gfxRect& aDirtyRect, const gfxFont::Metrics& aFontMetrics)
+    nsTextPaintStyle& aTextPaintStyle, const gfxPoint& aPt, gfxFloat aWidth,
+    gfxFloat aAscent, gfxFloat aSize, gfxFloat aOffset, PRBool aIsRTL)
 {
-  float p2t = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
   nscolor color;
   float relativeSize;
   if (!aTextPaintStyle.GetIMEUnderline(aIndex, &color, &relativeSize))
     return;
 
-  gfxFloat y = aBaselinePt.y - aFontMetrics.underlineOffset*p2t;
-  gfxFloat size = aFontMetrics.underlineSize*p2t;
-  FillClippedRect(aContext, aTextPaintStyle.PresContext(),
-                  color, aDirtyRect,
-                  gfxRect(aBaselinePt.x + size, y,
-                          PR_MAX(0, aWidth - 2*size), relativeSize*size));
+  gfxFloat actualSize = relativeSize * aSize;
+  gfxFloat width = PR_MAX(0, aWidth - 2.0 * aSize);
+  gfxPoint pt(aPt.x + 1.0, aPt.y);
+  nsCSSRendering::PaintDecorationLine(
+    aContext, color, pt, gfxSize(width, actualSize), aAscent, aOffset, aSize,
+    NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_SOLID, aIsRTL);
 }
 
 /**
  * This, plus SelectionTypesWithDecorations, encapsulates all knowledge about
  * drawing text decoration for selections.
  */
 static void DrawSelectionDecorations(gfxContext* aContext, SelectionType aType,
-    nsTextPaintStyle& aTextPaintStyle, const gfxPoint& aBaselinePt, gfxFloat aWidth,
-    const gfxRect& aDirtyRect, const gfxFont::Metrics& aFontMetrics)
+    nsTextPaintStyle& aTextPaintStyle, const gfxPoint& aPt, gfxFloat aWidth,
+    gfxFloat aAscent, const gfxFont::Metrics& aFontMetrics, PRBool aIsRTL)
 {
-  float p2t = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
-  float t2p = 1/p2t;
+  gfxSize size(aWidth, aFontMetrics.underlineSize);
+  gfxFloat offset = aFontMetrics.underlineOffset;
 
   switch (aType) {
     case nsISelectionController::SELECTION_SPELLCHECK: {
-      gfxFloat y = aBaselinePt.y*t2p - aFontMetrics.underlineOffset;
-      aContext->SetDash(gfxContext::gfxLineDotted);
-      aContext->SetColor(gfxRGBA(1.0, 0.0, 0.0));
-      aContext->SetLineWidth(1.0);
-      aContext->NewPath();
-      aContext->Line(gfxPoint(aBaselinePt.x*t2p, y),
-                     gfxPoint((aBaselinePt.x + aWidth)*t2p, y));
-      aContext->Stroke();
+      nsCSSRendering::PaintDecorationLine(
+        aContext, NS_RGB(255,0,0),
+        aPt, size, aAscent, aFontMetrics.underlineOffset, size.height,
+        NS_STYLE_TEXT_DECORATION_UNDERLINE, NS_STYLE_BORDER_STYLE_DOTTED,
+        aIsRTL);
       break;
     }
 
     case nsISelectionController::SELECTION_IME_RAWINPUT:
-      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexRawInput, aTextPaintStyle,
-                       aBaselinePt, aWidth, aDirtyRect, aFontMetrics);
+      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexRawInput,
+                       aTextPaintStyle, aPt, aWidth, aAscent, size.height,
+                       aFontMetrics.underlineOffset, aIsRTL);
       break;
     case nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT:
-      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexSelRawText, aTextPaintStyle,
-                       aBaselinePt, aWidth, aDirtyRect, aFontMetrics);
+      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexSelRawText,
+                       aTextPaintStyle, aPt, aWidth, aAscent, size.height,
+                       aFontMetrics.underlineOffset, aIsRTL);
       break;
     case nsISelectionController::SELECTION_IME_CONVERTEDTEXT:
-      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexConvText, aTextPaintStyle,
-                       aBaselinePt, aWidth, aDirtyRect, aFontMetrics);
+      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexConvText,
+                       aTextPaintStyle, aPt, aWidth, aAscent, size.height,
+                       aFontMetrics.underlineOffset, aIsRTL);
       break;
     case nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT:
-      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexSelConvText, aTextPaintStyle,
-                       aBaselinePt, aWidth, aDirtyRect, aFontMetrics);
+      DrawIMEUnderline(aContext, nsTextPaintStyle::eIndexSelConvText,
+                       aTextPaintStyle, aPt, aWidth, aAscent, size.height,
+                       aFontMetrics.underlineOffset, aIsRTL);
       break;
 
     default:
       NS_WARNING("Requested selection decorations when there aren't any");
       break;
   }
 }
 
@@ -4132,20 +4143,24 @@ nsTextFrame::PaintTextSelectionDecoratio
                              aProvider, mTextRun);
   gfxFloat xOffset, hyphenWidth;
   PRUint32 offset, length;
   SelectionType type;
   while (iterator.GetNextSegment(&xOffset, &offset, &length, &hyphenWidth, &type)) {
     gfxFloat advance = hyphenWidth +
       mTextRun->GetAdvanceWidth(offset, length, &aProvider);
     if (type == aSelectionType) {
-      gfxFloat x = aTextBaselinePt.x + xOffset - (mTextRun->IsRightToLeft() ? advance : 0);
+      gfxFloat a2p = 1.0 / aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
+      // XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint?
+      gfxPoint pt((aTextBaselinePt.x + xOffset) * a2p,
+                  (aTextBaselinePt.y - mAscent) * a2p);
+      gfxFloat width = PR_ABS(advance) * a2p;
       DrawSelectionDecorations(aCtx, aSelectionType, aTextPaintStyle,
-                               gfxPoint(x, aTextBaselinePt.y), advance,
-                               aDirtyRect, decorationMetrics);
+                               pt, width, mAscent * a2p, decorationMetrics,
+                               mTextRun->IsRightToLeft());
     }
     iterator.UpdateWithAdvance(advance);
   }
 }
 
 PRBool
 nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
     const gfxPoint& aFramePt,
--- a/layout/mathml/base/src/Makefile.in
+++ b/layout/mathml/base/src/Makefile.in
@@ -50,16 +50,17 @@ LIBXUL_LIBRARY	= 1
 
 PACKAGE_FILE = mathml.pkg
 
 REQUIRES	= xpcom \
 		  string \
 		  dom \
 		  content \
 		  gfx \
+		  thebes \
 		  widget \
 		  view \
 		  webshell \
 		  locale \
 		  intl \
 		  unicharutil \
 		  necko \
 		  docshell \
--- a/layout/tables/Makefile.in
+++ b/layout/tables/Makefile.in
@@ -46,16 +46,17 @@ MODULE		= layout
 LIBRARY_NAME	= gktable_s
 LIBXUL_LIBRARY	= 1
 
 REQUIRES	= xpcom \
 		  string \
 		  dom \
 		  content \
 		  gfx \
+		  thebes \
 		  widget \
 		  locale \
 		  view \
 		  accessibility \
 		  necko \
 		  webshell \
 		  js \
 		  xpconnect \
--- a/layout/xul/base/src/grid/Makefile.in
+++ b/layout/xul/base/src/grid/Makefile.in
@@ -44,16 +44,17 @@ include $(DEPTH)/config/autoconf.mk
 
 MODULE		= layout
 LIBRARY_NAME	= gkxulgrid_s
 LIBXUL_LIBRARY  = 1
 REQUIRES	= xpcom \
 		  string \
 		  content \
 		  gfx \
+		  thebes \
 		  widget \
 		  locale \
 		  view \
 		  necko \
 		  dom \
 		  webshell \
 		  $(NULL)
 
--- a/layout/xul/base/src/nsTextBoxFrame.cpp
+++ b/layout/xul/base/src/nsTextBoxFrame.cpp
@@ -64,16 +64,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMXULLabelElement.h"
 #include "nsIEventStateManager.h"
 #include "nsITheme.h"
 #include "nsUnicharUtils.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
+#include "nsCSSRendering.h"
 
 #ifdef IBMBIDI
 #include "nsBidiUtils.h"
 #include "nsBidiPresUtils.h"
 #endif // IBMBIDI
 #include "nsReadableUtils.h"
 
 #define ELLIPSIS "..."
@@ -396,32 +397,58 @@ nsTextBoxFrame::PaintTitle(nsIRenderingC
     
     nscoord offset;
     nscoord size;
     nscoord baseline;
     nsCOMPtr<nsIFontMetrics> fontMet;
     presContext->DeviceContext()->GetMetricsFor(fontStyle->mFont,
                                                 *getter_AddRefs(fontMet));
     fontMet->GetMaxAscent(baseline);
+    PRBool isRTL = vis->mDirection == NS_STYLE_DIRECTION_RTL;
 
+    nsRefPtr<gfxContext> ctx = (gfxContext*)
+      aRenderingContext.GetNativeGraphicData(nsIRenderingContext::NATIVE_THEBES_CONTEXT);
+    gfxFloat a2p = 1.0 / presContext->AppUnitsPerDevPixel();
+    gfxPoint pt(textRect.x * a2p, textRect.y * a2p);
+    gfxFloat width = textRect.width * a2p;
+    gfxFloat baselinePixel = baseline * a2p;
     if (decorations & (NS_FONT_DECORATION_OVERLINE | NS_FONT_DECORATION_UNDERLINE)) {
       fontMet->GetUnderline(offset, size);
+      gfxFloat offsetPixel = offset * a2p;
+      gfxFloat sizePixel = size * a2p;
       if (decorations & NS_FONT_DECORATION_OVERLINE) {
-        aRenderingContext.SetColor(overColor);
-        aRenderingContext.FillRect(textRect.x, textRect.y, textRect.width, size);
+        nsCSSRendering::PaintDecorationLine(ctx, overColor,
+                                            pt, gfxSize(width, sizePixel),
+                                            baselinePixel, baselinePixel,
+                                            sizePixel,
+                                            NS_STYLE_TEXT_DECORATION_OVERLINE,
+                                            NS_STYLE_BORDER_STYLE_SOLID,
+                                            isRTL);
       }
       if (decorations & NS_FONT_DECORATION_UNDERLINE) {
-        aRenderingContext.SetColor(underColor);
-        aRenderingContext.FillRect(textRect.x, textRect.y + baseline - offset, textRect.width, size);
+        nsCSSRendering::PaintDecorationLine(ctx, underColor,
+                                            pt, gfxSize(width, sizePixel),
+                                            baselinePixel, offsetPixel,
+                                            sizePixel,
+                                            NS_STYLE_TEXT_DECORATION_UNDERLINE,
+                                            NS_STYLE_BORDER_STYLE_SOLID,
+                                            isRTL);
       }
     }
     if (decorations & NS_FONT_DECORATION_LINE_THROUGH) {
       fontMet->GetStrikeout(offset, size);
-      aRenderingContext.SetColor(strikeColor);
-      aRenderingContext.FillRect(textRect.x, textRect.y + baseline - offset, textRect.width, size);
+      gfxFloat offsetPixel = offset * a2p;
+      gfxFloat sizePixel = size * a2p;
+      nsCSSRendering::PaintDecorationLine(ctx, underColor,
+                                          pt, gfxSize(width, sizePixel),
+                                          baselinePixel, offsetPixel,
+                                          sizePixel,
+                                          NS_STYLE_TEXT_DECORATION_LINE_THROUGH,
+                                          NS_STYLE_BORDER_STYLE_SOLID,
+                                          isRTL);
     }
  
     aRenderingContext.SetFont(fontStyle->mFont, nsnull);
 
     CalculateUnderline(aRenderingContext);
 
     aRenderingContext.SetColor(GetStyleColor()->mColor);
 
--- a/layout/xul/base/src/tree/src/Makefile.in
+++ b/layout/xul/base/src/tree/src/Makefile.in
@@ -46,16 +46,17 @@ MODULE		= layout
 LIBRARY_NAME	= gkxultree_s
 LIBXUL_LIBRARY  = 1
 REQUIRES	= xpcom \
 		  string \
 		  dom \
 		  content \
 		  xul \
 		  gfx \
+		  thebes \
 		  widget \
 		  locale \
 		  view \
 		  xultmpl \
 		  rdf \
 		  necko \
 		  imglib2 \
 		  xpconnect \