Bug 1085529, part 2 - Port nsCSSRendering::PaintDecorationLine() to Moz2D. r=mattwoodrow
authorJonathan Watt <jwatt@jwatt.org>
Sun, 26 Oct 2014 01:15:26 +0100
changeset 212806 7a8948248cbdc29e540813b40abdcfb939aec78d
parent 212805 79b64654f809b9294d5142e31c0c33471c85532f
child 212807 01eedb9f44d9c4a15d2e433c42ac33ea51bed324
push id51054
push userjwatt@jwatt.org
push dateWed, 29 Oct 2014 02:12:46 +0000
treeherdermozilla-inbound@7a8948248cbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1085529
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1085529, part 2 - Port nsCSSRendering::PaintDecorationLine() to Moz2D. r=mattwoodrow
layout/base/nsCSSRendering.cpp
layout/base/nsCSSRendering.h
layout/generic/nsTextFrame.cpp
layout/generic/test/test_selection_underline.html
layout/xul/nsTextBoxFrame.cpp
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -3,18 +3,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* utility functions for drawing borders and backgrounds */
 
 #include <ctime>
 
+#include "gfx2DGlue.h"
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Helpers.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsIFrame.h"
 #include "nsPoint.h"
 #include "nsRect.h"
@@ -4009,23 +4012,23 @@ nsCSSRendering::DrawTableBorderSegment(n
     break;
   }
 
   ctx->SetAntialiasMode(oldMode);
 }
 
 // End table border-collapsing section
 
-gfxRect
+Rect
 nsCSSRendering::ExpandPaintingRectForDecorationLine(
                   nsIFrame* aFrame,
                   const uint8_t aStyle,
-                  const gfxRect& aClippedRect,
-                  const gfxFloat aICoordInFrame,
-                  const gfxFloat aCycleLength,
+                  const Rect& aClippedRect,
+                  const Float aICoordInFrame,
+                  const Float aCycleLength,
                   bool aVertical)
 {
   switch (aStyle) {
     case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
     case NS_STYLE_TEXT_DECORATION_STYLE_DASHED:
     case NS_STYLE_TEXT_DECORATION_STYLE_WAVY:
       break;
     default:
@@ -4044,183 +4047,173 @@ nsCSSRendering::ExpandPaintingRectForDec
     }
     framePosInBlockAppUnits += aVertical ?
       f->GetNormalPosition().y : f->GetNormalPosition().x;
   }
 
   NS_ENSURE_TRUE(block, aClippedRect);
 
   nsPresContext *pc = aFrame->PresContext();
-  gfxFloat framePosInBlock = pc->AppUnitsToGfxUnits(framePosInBlockAppUnits);
+  Float framePosInBlock = Float(pc->AppUnitsToGfxUnits(framePosInBlockAppUnits));
   int32_t rectPosInBlock =
     int32_t(NS_round(framePosInBlock + aICoordInFrame));
   int32_t extraStartEdge =
     rectPosInBlock - (rectPosInBlock / int32_t(aCycleLength) * aCycleLength);
-  gfxRect rect(aClippedRect);
+  Rect rect(aClippedRect);
   if (aVertical) {
     rect.y -= extraStartEdge;
     rect.height += extraStartEdge;
   } else {
     rect.x -= extraStartEdge;
     rect.width += extraStartEdge;
   }
   return rect;
 }
 
 void
 nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
-                                    gfxContext* aGfxContext,
-                                    const gfxRect& aDirtyRect,
+                                    DrawTarget& aDrawTarget,
+                                    const Rect& aDirtyRect,
                                     const nscolor aColor,
                                     const gfxPoint& aPt,
-                                    const gfxFloat aICoordInFrame,
+                                    const Float aICoordInFrame,
                                     const gfxSize& aLineSize,
                                     const gfxFloat aAscent,
                                     const gfxFloat aOffset,
                                     const uint8_t aDecoration,
                                     const uint8_t aStyle,
                                     bool aVertical,
                                     const gfxFloat aDescentLimit)
 {
   NS_ASSERTION(aStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE, "aStyle is none");
 
-  gfxRect rect =
+  Rect rect = ToRect(
     GetTextDecorationRectInternal(aPt, aLineSize, aAscent, aOffset,
                                   aDecoration, aStyle, aVertical,
-                                  aDescentLimit);
+                                  aDescentLimit));
   if (rect.IsEmpty() || !rect.Intersects(aDirtyRect)) {
     return;
   }
 
   if (aDecoration != NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE &&
       aDecoration != NS_STYLE_TEXT_DECORATION_LINE_OVERLINE &&
       aDecoration != NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
     NS_ERROR("Invalid decoration value!");
     return;
   }
 
-  gfxFloat lineThickness = std::max(NS_round(aLineSize.height), 1.0);
-  bool contextIsSaved = false;
-
-  gfxFloat oldLineWidth;
-  nsRefPtr<gfxPattern> oldPattern;
+  Float lineThickness = std::max(NS_round(aLineSize.height), 1.0);
+
+  ColorPattern color(ToDeviceColor(aColor));
+  StrokeOptions strokeOptions(lineThickness);
+  DrawOptions drawOptions;
+
+  Float dash[2];
+
+  AutoPopClips autoPopClips(&aDrawTarget);
 
   switch (aStyle) {
     case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
     case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE:
-      oldLineWidth = aGfxContext->CurrentLineWidth();
-      oldPattern = aGfxContext->GetPattern();
       break;
     case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: {
-      aGfxContext->Save();
-      contextIsSaved = true;
-      aGfxContext->Clip(rect);
-      gfxFloat dashWidth = lineThickness * DOT_LENGTH * DASH_LENGTH;
-      gfxFloat dash[2] = { dashWidth, dashWidth };
-      aGfxContext->SetLineCap(gfxContext::LINE_CAP_BUTT);
-      aGfxContext->SetDash(dash, 2, 0.0);
+      autoPopClips.PushClipRect(rect);
+      Float dashWidth = lineThickness * DOT_LENGTH * DASH_LENGTH;
+      dash[0] = dashWidth;
+      dash[1] = dashWidth;
+      strokeOptions.mDashPattern = dash;
+      strokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
+      strokeOptions.mLineCap = CapStyle::BUTT;
       rect = ExpandPaintingRectForDecorationLine(aFrame, aStyle, rect,
                                                  aICoordInFrame,
                                                  dashWidth * 2,
                                                  aVertical);
       // We should continue to draw the last dash even if it is not in the rect.
       rect.width += dashWidth;
       break;
     }
     case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED: {
-      aGfxContext->Save();
-      contextIsSaved = true;
-      aGfxContext->Clip(rect);
-      gfxFloat dashWidth = lineThickness * DOT_LENGTH;
-      gfxFloat dash[2];
+      autoPopClips.PushClipRect(rect);
+      Float dashWidth = lineThickness * DOT_LENGTH;
       if (lineThickness > 2.0) {
-        dash[0] = 0.0;
-        dash[1] = dashWidth * 2.0;
-        aGfxContext->SetLineCap(gfxContext::LINE_CAP_ROUND);
+        dash[0] = 0.f;
+        dash[1] = dashWidth * 2.f;
+        strokeOptions.mLineCap = CapStyle::ROUND;
       } else {
         dash[0] = dashWidth;
         dash[1] = dashWidth;
       }
-      aGfxContext->SetDash(dash, 2, 0.0);
+      strokeOptions.mDashPattern = dash;
+      strokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
       rect = ExpandPaintingRectForDecorationLine(aFrame, aStyle, rect,
                                                  aICoordInFrame,
                                                  dashWidth * 2,
                                                  aVertical);
       // We should continue to draw the last dot even if it is not in the rect.
       rect.width += dashWidth;
       break;
     }
     case NS_STYLE_TEXT_DECORATION_STYLE_WAVY:
-      aGfxContext->Save();
-      contextIsSaved = true;
-      aGfxContext->Clip(rect);
+      autoPopClips.PushClipRect(rect);
       if (lineThickness > 2.0) {
-        aGfxContext->SetAntialiasMode(AntialiasMode::SUBPIXEL);
+        drawOptions.mAntialiasMode = AntialiasMode::SUBPIXEL;
       } else {
         // Don't use anti-aliasing here.  Because looks like lighter color wavy
         // line at this case.  And probably, users don't think the
         // non-anti-aliased wavy line is not pretty.
-        aGfxContext->SetAntialiasMode(AntialiasMode::NONE);
+        drawOptions.mAntialiasMode = AntialiasMode::NONE;
       }
       break;
     default:
       NS_ERROR("Invalid style value!");
       return;
   }
 
   // The y position should be set to the middle of the line.
   rect.y += lineThickness / 2;
 
-  aGfxContext->SetColor(gfxRGBA(aColor));
-  aGfxContext->SetLineWidth(lineThickness);
   switch (aStyle) {
     case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
     case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
-    case NS_STYLE_TEXT_DECORATION_STYLE_DASHED:
-      aGfxContext->NewPath();
-      if (aVertical) {
-        aGfxContext->MoveTo(rect.TopLeft());
-        aGfxContext->LineTo(rect.BottomLeft());
-      } else {
-        aGfxContext->MoveTo(rect.TopLeft());
-        aGfxContext->LineTo(rect.TopRight());
-      }
-      aGfxContext->Stroke();
-      break;
-    case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE:
+    case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: {
+      Point p1 = rect.TopLeft();
+      Point p2 = aVertical ? rect.BottomLeft() : rect.TopRight();
+      aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions);
+      return;
+    }
+    case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE: {
       /**
        *  We are drawing double line as:
        *
        * +-------------------------------------------+
        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
        * |                                           |
        * |                                           |
        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
        * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
        * +-------------------------------------------+
        */
-      aGfxContext->NewPath();
+      Point p1 = rect.TopLeft();
+      Point p2 = aVertical ? rect.BottomLeft() : rect.TopRight();
+      aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions);
+
       if (aVertical) {
-        aGfxContext->MoveTo(rect.TopLeft());
-        aGfxContext->LineTo(rect.BottomLeft());
         rect.width -= lineThickness;
-        aGfxContext->MoveTo(rect.TopRight());
-        aGfxContext->LineTo(rect.BottomRight());
       } else {
-        aGfxContext->MoveTo(rect.TopLeft());
-        aGfxContext->LineTo(rect.TopRight());
         rect.height -= lineThickness;
-        aGfxContext->MoveTo(rect.BottomLeft());
-        aGfxContext->LineTo(rect.BottomRight());
       }
-      aGfxContext->Stroke();
-      break;
+
+      p1 = aVertical ? rect.TopRight() : rect.BottomLeft();
+      p2 = rect.BottomRight();
+      aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions);
+      return;
+    }
     case NS_STYLE_TEXT_DECORATION_STYLE_WAVY: {
       /**
        *  We are drawing wavy line as:
        *
        *  P: Path, X: Painted pixel
        *
        *     +---------------------------------------+
        *   XX|X            XXXXXX            XXXXXX  |
@@ -4244,100 +4237,95 @@ nsCSSRendering::PaintDecorationLine(nsIF
        *  5. Goes up to top of the area at 45 degrees.
        *  6. Slides to right horizontaly.
        *  7. Repeat from 2 until reached to right-most edge of the area.
        *
        * In the vertical case, swap horizontal and vertical coordinates and
        * directions in the above description.
        */
 
-      gfxFloat& rectICoord = aVertical ? rect.y : rect.x;
-      gfxFloat& rectISize = aVertical ? rect.height : rect.width;
-      const gfxFloat rectBSize = aVertical ? rect.width : rect.height;
-
-      const gfxFloat adv = rectBSize - lineThickness;
-      const gfxFloat flatLengthAtVertex =
+      Float& rectICoord = aVertical ? rect.y : rect.x;
+      Float& rectISize = aVertical ? rect.height : rect.width;
+      const Float rectBSize = aVertical ? rect.width : rect.height;
+
+      const Float adv = rectBSize - lineThickness;
+      const Float flatLengthAtVertex =
         std::max((lineThickness - 1.0) * 2.0, 1.0);
 
       // Align the start of wavy lines to the nearest ancestor block.
-      const gfxFloat cycleLength = 2 * (adv + flatLengthAtVertex);
+      const Float cycleLength = 2 * (adv + flatLengthAtVertex);
       rect = ExpandPaintingRectForDecorationLine(aFrame, aStyle, rect,
                                                  aICoordInFrame, cycleLength,
                                                  aVertical);
       // figure out if we can trim whole cycles from the left and right edges
       // of the line, to try and avoid creating an unnecessarily long and
       // complex path
-      const gfxFloat dirtyRectICoord = aVertical ? aDirtyRect.y : aDirtyRect.x;
+      const Float dirtyRectICoord = aVertical ? aDirtyRect.y : aDirtyRect.x;
       int32_t skipCycles = floor((dirtyRectICoord - rectICoord) / cycleLength);
       if (skipCycles > 0) {
         rectICoord += skipCycles * cycleLength;
         rectISize -= skipCycles * cycleLength;
       }
 
       rectICoord += lineThickness / 2.0;
-      gfxPoint pt(rect.TopLeft());
-      gfxFloat& ptICoord = aVertical ? pt.y : pt.x;
-      gfxFloat& ptBCoord = aVertical ? pt.x : pt.y;
+      Point pt(rect.TopLeft());
+      Float& ptICoord = aVertical ? pt.y : pt.x;
+      Float& ptBCoord = aVertical ? pt.x : pt.y;
       if (aVertical) {
         ptBCoord += adv + lineThickness / 2.0;
       }
-      gfxFloat iCoordLimit = ptICoord + rectISize + lineThickness;
-
-      const gfxFloat dirtyRectIMost = aVertical ?
+      Float iCoordLimit = ptICoord + rectISize + lineThickness;
+
+      const Float dirtyRectIMost = aVertical ?
         aDirtyRect.YMost() : aDirtyRect.XMost();
       skipCycles = floor((iCoordLimit - dirtyRectIMost) / cycleLength);
       if (skipCycles > 0) {
         iCoordLimit -= skipCycles * cycleLength;
       }
 
-      aGfxContext->NewPath();
+      RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
+      RefPtr<Path> path;
 
       ptICoord -= lineThickness;
-      aGfxContext->MoveTo(pt); // 1
+      builder->MoveTo(pt); // 1
 
       ptICoord = rectICoord;
-      aGfxContext->LineTo(pt); // 2
+      builder->LineTo(pt); // 2
 
       // In vertical mode, to go "down" relative to the text we need to
       // decrease the block coordinate, whereas in horizontal we increase
       // it. So the sense of this flag is effectively inverted.
       bool goDown = aVertical ? false : true;
       uint32_t iter = 0;
       while (ptICoord < iCoordLimit) {
         if (++iter > 1000) {
           // stroke the current path and start again, to avoid pathological
           // behavior in cairo with huge numbers of path segments
-          aGfxContext->Stroke();
-          aGfxContext->NewPath();
-          aGfxContext->MoveTo(pt);
+          path = builder->Finish();
+          aDrawTarget.Stroke(path, color, strokeOptions, drawOptions);
+          builder = aDrawTarget.CreatePathBuilder();
+          builder->MoveTo(pt);
           iter = 0;
         }
         ptICoord += adv;
         ptBCoord += goDown ? adv : -adv;
 
-        aGfxContext->LineTo(pt); // 3 and 5
+        builder->LineTo(pt); // 3 and 5
 
         ptICoord += flatLengthAtVertex;
-        aGfxContext->LineTo(pt); // 4 and 6
+        builder->LineTo(pt); // 4 and 6
 
         goDown = !goDown;
       }
-      aGfxContext->Stroke();
-      break;
+      path = builder->Finish();
+      aDrawTarget.Stroke(path, color, strokeOptions, drawOptions);
+      return;
     }
     default:
       NS_ERROR("Invalid style value!");
-      break;
-  }
-
-  if (contextIsSaved) {
-    aGfxContext->Restore();
-  } else {
-    aGfxContext->SetPattern(oldPattern);
-    aGfxContext->SetLineWidth(oldLineWidth);
   }
 }
 
 void
 nsCSSRendering::DecorationLineToPath(nsIFrame* aFrame,
                                      gfxContext* aGfxContext,
                                      const gfxRect& aDirtyRect,
                                      const nscolor aColor,
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -5,27 +5,32 @@
 
 /* utility functions for drawing borders and backgrounds */
 
 #ifndef nsCSSRendering_h___
 #define nsCSSRendering_h___
 
 #include "gfxBlur.h"
 #include "gfxContext.h"
+#include "mozilla/gfx/Rect.h"
 #include "nsLayoutUtils.h"
 #include "nsStyleStruct.h"
 #include "nsIFrame.h"
 
 class gfxDrawable;
 class nsStyleContext;
 class nsPresContext;
 class nsRenderingContext;
 
 namespace mozilla {
 
+namespace gfx {
+class DrawTarget;
+}
+
 namespace layers {
 class ImageContainer;
 }
 
 // A CSSSizeOrRatio represents a (possibly partially specified) size for use
 // in computing image sizes. Either or both of the width and height might be
 // given. A ratio of width to height may also be given. If we at least two
 // of these then we can compute a concrete size, that is a width and height.
@@ -306,16 +311,19 @@ struct nsBackgroundLayerState {
   nsPoint mAnchor;
   /**
    * The compositing operation that the image should use
    */
   gfxContext::GraphicsOperator mCompositingOp;
 };
 
 struct nsCSSRendering {
+  typedef mozilla::gfx::DrawTarget DrawTarget;
+  typedef mozilla::gfx::Float Float;
+  typedef mozilla::gfx::Rect Rect;
   typedef nsIFrame::Sides Sides;
 
   /**
    * Initialize any static variables used by nsCSSRendering.
    */
   static void Init();
   
   /**
@@ -664,21 +672,21 @@ struct nsCSSRendering {
    *                              limitation.  Because if the underline is
    *                              positioned to the baseline or upper, it causes
    *                              unreadability.  Note that if this is zero
    *                              or larger, the underline rect may be shrunken
    *                              if it's possible.  Therefore, this value is
    *                              used for strikeout line and overline too.
    */
   static void PaintDecorationLine(nsIFrame* aFrame,
-                                  gfxContext* aGfxContext,
-                                  const gfxRect& aDirtyRect,
+                                  DrawTarget& aDrawTarget,
+                                  const Rect& aDirtyRect,
                                   const nscolor aColor,
                                   const gfxPoint& aPt,
-                                  const gfxFloat aICoordInFrame,
+                                  const Float aICoordInFrame,
                                   const gfxSize& aLineSize,
                                   const gfxFloat aAscent,
                                   const gfxFloat aOffset,
                                   const uint8_t aDecoration,
                                   const uint8_t aStyle,
                                   bool aVertical,
                                   const gfxFloat aDescentLimit = -1.0);
 
@@ -793,22 +801,22 @@ protected:
    *                              NS_STYLE_TEXT_DECORATION_STYLE_DASHED or
    *                              NS_STYLE_TEXT_DECORATION_STYLE_WAVY.
    *     @param aClippedRect      the clipped rect for the decoration line.
    *                              in other words, visible area of the line.
    *     @param aICoordInFrame  the distance between inline-start edge of aFrame
    *                              and aClippedRect.pos.
    *     @param aCycleLength      the width of one cycle of the line style.
    */
-  static gfxRect ExpandPaintingRectForDecorationLine(
+  static Rect ExpandPaintingRectForDecorationLine(
                    nsIFrame* aFrame,
                    const uint8_t aStyle,
-                   const gfxRect &aClippedRect,
-                   const gfxFloat aICoordInFrame,
-                   const gfxFloat aCycleLength,
+                   const Rect &aClippedRect,
+                   const Float aICoordInFrame,
+                   const Float aCycleLength,
                    bool aVertical);
 };
 
 /*
  * nsContextBoxBlur
  * Creates an 8-bit alpha channel context for callers to draw in, blurs the
  * contents of that context and applies it as a 1-color mask on a
  * different existing context. Uses gfxAlphaBoxBlur as its back end.
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* rendering object for textual content of elements */
 
 #include "nsTextFrame.h"
 
+#include "gfx2DGlue.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/BinarySearch.h"
 
 #include "nsCOMPtr.h"
@@ -83,16 +84,17 @@
 #endif
 
 #ifdef DrawText
 #undef DrawText
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::gfx;
 
 struct TabWidth {
   TabWidth(uint32_t aOffset, uint32_t aWidth)
     : mOffset(aOffset), mWidth(float(aWidth))
   { }
 
   uint32_t mOffset; // DOM offset relative to the current frame's offset.
   float    mWidth;  // extra space to be added at this position (in app units)
@@ -5149,18 +5151,19 @@ PaintDecorationLine(nsIFrame* aFrame,
       aPt, aICoordInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
       aVertical, aDescentLimit);
     if (aDecorationType == eNormalDecoration) {
       aCallbacks->NotifyDecorationLinePathEmitted();
     } else {
       aCallbacks->NotifySelectionDecorationLinePathEmitted();
     }
   } else {
-    nsCSSRendering::PaintDecorationLine(aFrame, aCtx, aDirtyRect, lineColor,
-      aPt, aICoordInFrame, aLineSize, aAscent, aOffset, aDecoration, aStyle,
+    nsCSSRendering::PaintDecorationLine(aFrame, *aCtx->GetDrawTarget(),
+                                        ToRect(aDirtyRect), lineColor,
+      aPt, Float(aICoordInFrame), aLineSize, aAscent, aOffset, aDecoration, aStyle,
       aVertical, aDescentLimit);
   }
 }
 
 /**
  * This, plus SelectionTypesWithDecorations, encapsulates all knowledge about
  * drawing text decoration for selections.
  */
--- a/layout/generic/test/test_selection_underline.html
+++ b/layout/generic/test/test_selection_underline.html
@@ -190,16 +190,28 @@ const kDecorations = [
   { relativeSize: 1.0, style: kDecorationStyleDashed, styleName: "dashed"    },
   { relativeSize: 1.0, style: kDecorationStyleDouble, styleName: "double"    },
   { relativeSize: 1.0, style: kDecorationStyleWavy,   styleName: "wavy"      },
 
 // XXX relativeSize 2.0 cannot be tested by CSS3 text-decoration
 
 ];
 
+function getFuzz(test) {
+  // Only failing on Windows 8, and only for 16 permutations.
+  if (navigator.userAgent.indexOf("Windows NT 6.2") > -1 &&
+      test.decoration.styleName == "solid" &&
+      test.decoration.relativeSize == "1" &&
+      test.font.family == "mplusTest" &&
+      test.selection.typeName != "SpellCheck") {
+    return { numDifferentPixels: 194, maxDifference: 1 };
+  }
+  return null;
+}
+
 function run()
 {
   if (++gSelectionIndex == kSelections.length) {
     if (++gFontIndex == kFonts.length) {
       if (++gDecorationIndex == kDecorations.length) {
         SimpleTest.finish();
         cleanup();
         return;
@@ -258,17 +270,17 @@ function doTest(aTest)
     // If the decoration line is thick and the descender of the text isn't
     // enough for containing it, selection underline may be painted lower
     // if it's possible.  Then, we cannot test it with CSS3 text-decoration.
     if (aTest.decoration.style == kDecorationStyleDouble ||
         aTest.decoration.style == kDecorationStyleWavy) {
       todo(false, "Rendering of" + description);
     } else {
       assertSnapshots(result.snapshot, reference.snapshot, true,
-                      null /*no fuzz*/, description, "");
+                      getFuzz(aTest), description, "");
     }
 
     canvases = [];
 
     run();
   }
 
   var testCanvas = new RemoteCanvas(document.getElementById("result"), aTest);
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsTextBoxFrame.h"
 
+#include "gfx2DGlue.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "nsFontMetrics.h"
 #include "nsReadableUtils.h"
 #include "nsCOMPtr.h"
 #include "nsGkAtoms.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
@@ -462,40 +463,42 @@ nsTextBoxFrame::DrawText(nsRenderingCont
 
     nscoord baseline =
       presContext->RoundAppUnitsToNearestDevPixels(aTextRect.y + ascent);
     nsRefPtr<gfxContext> ctx = aRenderingContext.ThebesContext();
     gfxPoint pt(presContext->AppUnitsToGfxUnits(aTextRect.x),
                 presContext->AppUnitsToGfxUnits(aTextRect.y));
     gfxFloat width = presContext->AppUnitsToGfxUnits(aTextRect.width);
     gfxFloat ascentPixel = presContext->AppUnitsToGfxUnits(ascent);
-    gfxFloat xInFrame = PresContext()->AppUnitsToGfxUnits(mTextDrawRect.x);
+    Float xInFrame = Float(PresContext()->AppUnitsToGfxUnits(mTextDrawRect.x));
     gfxRect dirtyRect(presContext->AppUnitsToGfxUnits(aDirtyRect));
 
     // Underlines are drawn before overlines, and both before the text
     // itself, per http://www.w3.org/TR/CSS21/zindex.html point 7.2.1.4.1.1.
     // (We don't apply this rule to the access-key underline because we only
     // find out where that is as a side effect of drawing the text, in the
     // general case -- see below.)
     if (decorations & (NS_FONT_DECORATION_OVERLINE |
                        NS_FONT_DECORATION_UNDERLINE)) {
       fontMet->GetUnderline(offset, size);
       gfxFloat offsetPixel = presContext->AppUnitsToGfxUnits(offset);
       gfxFloat sizePixel = presContext->AppUnitsToGfxUnits(size);
       if ((decorations & NS_FONT_DECORATION_UNDERLINE) &&
           underStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
-        nsCSSRendering::PaintDecorationLine(this, ctx, dirtyRect, underColor,
+        nsCSSRendering::PaintDecorationLine(this, *drawTarget,
+                                            ToRect(dirtyRect), underColor,
                           pt, xInFrame, gfxSize(width, sizePixel),
                           ascentPixel, offsetPixel,
                           NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, underStyle,
                           vertical);
       }
       if ((decorations & NS_FONT_DECORATION_OVERLINE) &&
           overStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
-        nsCSSRendering::PaintDecorationLine(this, ctx, dirtyRect, overColor,
+        nsCSSRendering::PaintDecorationLine(this, *drawTarget,
+                                            ToRect(dirtyRect), overColor,
                           pt, xInFrame, gfxSize(width, sizePixel),
                           ascentPixel, ascentPixel,
                           NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, overStyle,
                           vertical);
       }
     }
 
     nsRefPtr<nsRenderingContext> refContext =
@@ -567,17 +570,18 @@ nsTextBoxFrame::DrawText(nsRenderingCont
 
     // Strikeout is drawn on top of the text, per
     // http://www.w3.org/TR/CSS21/zindex.html point 7.2.1.4.1.1.
     if ((decorations & NS_FONT_DECORATION_LINE_THROUGH) &&
         strikeStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
       fontMet->GetStrikeout(offset, size);
       gfxFloat offsetPixel = presContext->AppUnitsToGfxUnits(offset);
       gfxFloat sizePixel = presContext->AppUnitsToGfxUnits(size);
-      nsCSSRendering::PaintDecorationLine(this, ctx, dirtyRect, strikeColor,
+      nsCSSRendering::PaintDecorationLine(this, *drawTarget, ToRect(dirtyRect),
+                                          strikeColor,
                         pt, xInFrame, gfxSize(width, sizePixel), ascentPixel,
                         offsetPixel, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
                         strikeStyle, vertical);
     }
 }
 
 void
 nsTextBoxFrame::CalculateUnderline(nsRenderingContext& aRenderingContext,