Bug 1341101 part 1 - Move nsCSSRendering::PaintGradient into its own file r=jrmuizel draft
authorRyan Hunt <rhunt@eqrion.net>
Tue, 14 Mar 2017 01:05:41 -0500
changeset 552229 d49f122a6732fe91900cbf24d3fb7bab89ee2553
parent 552073 a6f35285bd1e674553527873614c55e0b7366bdb
child 552230 de2c6224e989eceffba02612fe9f25232b52f2ab
push id51292
push userbmo:rhunt@eqrion.net
push dateTue, 28 Mar 2017 06:03:40 +0000
reviewersjrmuizel
bugs1341101
milestone55.0a1
Bug 1341101 part 1 - Move nsCSSRendering::PaintGradient into its own file r=jrmuizel MozReview-Commit-ID: 1DyZ8TpcA3m
layout/painting/moz.build
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRenderingGradients.cpp
layout/painting/nsCSSRenderingGradients.h
layout/painting/nsImageRenderer.cpp
--- a/layout/painting/moz.build
+++ b/layout/painting/moz.build
@@ -11,16 +11,17 @@ EXPORTS += [
     'ActiveLayerTracker.h',
     'DisplayItemClip.h',
     'DisplayItemClipChain.h',
     'DisplayItemScrollClip.h',
     'DisplayListClipState.h',
     'FrameLayerBuilder.h',
     'LayerState.h',
     'nsCSSRenderingBorders.h',
+    'nsCSSRenderingGradients.h',
     'nsDisplayItemTypes.h',
     'nsDisplayItemTypesList.h',
     'nsDisplayList.h',
     'nsDisplayListInvalidation.h',
     'nsImageRenderer.h',
 ]
 
 EXPORTS.mozilla += [
@@ -34,16 +35,17 @@ UNIFIED_SOURCES += [
     'DisplayItemClipChain.cpp',
     'DisplayItemScrollClip.cpp',
     'DisplayListClipState.cpp',
     'DottedCornerFinder.cpp',
     'FrameLayerBuilder.cpp',
     'MaskLayerImageCache.cpp',
     'nsCSSRendering.cpp',
     'nsCSSRenderingBorders.cpp',
+    'nsCSSRenderingGradients.cpp',
     'nsDisplayList.cpp',
     'nsDisplayListInvalidation.cpp',
     'nsImageRenderer.cpp',
     'PaintTracker.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -413,27 +413,16 @@ protected:
       }
       MOZ_ASSERT_UNREACHABLE("None of the frames is a descendant of this rtc?");
     }
     MOZ_ASSERT_UNREACHABLE("Do we have any other type of line container?");
     return false;
   }
 };
 
-// A resolved color stop, with a specific position along the gradient line and
-// a color.
-struct ColorStop {
-  ColorStop(): mPosition(0), mIsMidpoint(false) {}
-  ColorStop(double aPosition, bool aIsMidPoint, const Color& aColor) :
-    mPosition(aPosition), mIsMidpoint(aIsMidPoint), mColor(aColor) {}
-  double mPosition; // along the gradient line; 0=start, 1=end
-  bool mIsMidpoint;
-  Color mColor;
-};
-
 /* Local functions */
 static nscolor MakeBevelColor(mozilla::Side whichSide, uint8_t style,
                               nscolor aBackgroundColor,
                               nscolor aBorderColor);
 
 static InlineBackgroundData* gInlineBGData = nullptr;
 
 // Initialize any static variables used by nsCSSRendering.
@@ -2395,959 +2384,16 @@ nsCSSRendering::DetermineBackgroundColor
       bg->BottomLayer().mImage.IsOpaque() &&
       bg->BottomLayer().mBlendMode == NS_STYLE_BLEND_NORMAL) {
     aDrawBackgroundColor = false;
   }
 
   return bgColor;
 }
 
-static gfxFloat
-ConvertGradientValueToPixels(const nsStyleCoord& aCoord,
-                             gfxFloat aFillLength,
-                             int32_t aAppUnitsPerPixel)
-{
-  switch (aCoord.GetUnit()) {
-    case eStyleUnit_Percent:
-      return aCoord.GetPercentValue() * aFillLength;
-    case eStyleUnit_Coord:
-      return NSAppUnitsToFloatPixels(aCoord.GetCoordValue(), aAppUnitsPerPixel);
-    case eStyleUnit_Calc: {
-      const nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
-      return calc->mPercent * aFillLength +
-             NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
-    }
-    default:
-      NS_WARNING("Unexpected coord unit");
-      return 0;
-  }
-}
-
-// Given a box with size aBoxSize and origin (0,0), and an angle aAngle,
-// and a starting point for the gradient line aStart, find the endpoint of
-// the gradient line --- the intersection of the gradient line with a line
-// perpendicular to aAngle that passes through the farthest corner in the
-// direction aAngle.
-static gfxPoint
-ComputeGradientLineEndFromAngle(const gfxPoint& aStart,
-                                double aAngle,
-                                const gfxSize& aBoxSize)
-{
-  double dx = cos(-aAngle);
-  double dy = sin(-aAngle);
-  gfxPoint farthestCorner(dx > 0 ? aBoxSize.width : 0,
-                          dy > 0 ? aBoxSize.height : 0);
-  gfxPoint delta = farthestCorner - aStart;
-  double u = delta.x*dy - delta.y*dx;
-  return farthestCorner + gfxPoint(-u*dy, u*dx);
-}
-
-// Compute the start and end points of the gradient line for a linear gradient.
-static void
-ComputeLinearGradientLine(nsPresContext* aPresContext,
-                          nsStyleGradient* aGradient,
-                          const gfxSize& aBoxSize,
-                          gfxPoint* aLineStart,
-                          gfxPoint* aLineEnd)
-{
-  if (aGradient->mBgPosX.GetUnit() == eStyleUnit_None) {
-    double angle;
-    if (aGradient->mAngle.IsAngleValue()) {
-      angle = aGradient->mAngle.GetAngleValueInRadians();
-      if (!aGradient->mLegacySyntax) {
-        angle = M_PI_2 - angle;
-      }
-    } else {
-      angle = -M_PI_2; // defaults to vertical gradient starting from top
-    }
-    gfxPoint center(aBoxSize.width/2, aBoxSize.height/2);
-    *aLineEnd = ComputeGradientLineEndFromAngle(center, angle, aBoxSize);
-    *aLineStart = gfxPoint(aBoxSize.width, aBoxSize.height) - *aLineEnd;
-  } else if (!aGradient->mLegacySyntax) {
-    float xSign = aGradient->mBgPosX.GetPercentValue() * 2 - 1;
-    float ySign = 1 - aGradient->mBgPosY.GetPercentValue() * 2;
-    double angle = atan2(ySign * aBoxSize.width, xSign * aBoxSize.height);
-    gfxPoint center(aBoxSize.width/2, aBoxSize.height/2);
-    *aLineEnd = ComputeGradientLineEndFromAngle(center, angle, aBoxSize);
-    *aLineStart = gfxPoint(aBoxSize.width, aBoxSize.height) - *aLineEnd;
-  } else {
-    int32_t appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
-    *aLineStart = gfxPoint(
-      ConvertGradientValueToPixels(aGradient->mBgPosX, aBoxSize.width,
-                                   appUnitsPerPixel),
-      ConvertGradientValueToPixels(aGradient->mBgPosY, aBoxSize.height,
-                                   appUnitsPerPixel));
-    if (aGradient->mAngle.IsAngleValue()) {
-      MOZ_ASSERT(aGradient->mLegacySyntax);
-      double angle = aGradient->mAngle.GetAngleValueInRadians();
-      *aLineEnd = ComputeGradientLineEndFromAngle(*aLineStart, angle, aBoxSize);
-    } else {
-      // No angle, the line end is just the reflection of the start point
-      // through the center of the box
-      *aLineEnd = gfxPoint(aBoxSize.width, aBoxSize.height) - *aLineStart;
-    }
-  }
-}
-
-// Compute the start and end points of the gradient line for a radial gradient.
-// Also returns the horizontal and vertical radii defining the circle or
-// ellipse to use.
-static void
-ComputeRadialGradientLine(nsPresContext* aPresContext,
-                          nsStyleGradient* aGradient,
-                          const gfxSize& aBoxSize,
-                          gfxPoint* aLineStart,
-                          gfxPoint* aLineEnd,
-                          double* aRadiusX,
-                          double* aRadiusY)
-{
-  if (aGradient->mBgPosX.GetUnit() == eStyleUnit_None) {
-    // Default line start point is the center of the box
-    *aLineStart = gfxPoint(aBoxSize.width/2, aBoxSize.height/2);
-  } else {
-    int32_t appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
-    *aLineStart = gfxPoint(
-      ConvertGradientValueToPixels(aGradient->mBgPosX, aBoxSize.width,
-                                   appUnitsPerPixel),
-      ConvertGradientValueToPixels(aGradient->mBgPosY, aBoxSize.height,
-                                   appUnitsPerPixel));
-  }
-
-  // Compute gradient shape: the x and y radii of an ellipse.
-  double radiusX, radiusY;
-  double leftDistance = Abs(aLineStart->x);
-  double rightDistance = Abs(aBoxSize.width - aLineStart->x);
-  double topDistance = Abs(aLineStart->y);
-  double bottomDistance = Abs(aBoxSize.height - aLineStart->y);
-  switch (aGradient->mSize) {
-  case NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE:
-    radiusX = std::min(leftDistance, rightDistance);
-    radiusY = std::min(topDistance, bottomDistance);
-    if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
-      radiusX = radiusY = std::min(radiusX, radiusY);
-    }
-    break;
-  case NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER: {
-    // Compute x and y distances to nearest corner
-    double offsetX = std::min(leftDistance, rightDistance);
-    double offsetY = std::min(topDistance, bottomDistance);
-    if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
-      radiusX = radiusY = NS_hypot(offsetX, offsetY);
-    } else {
-      // maintain aspect ratio
-      radiusX = offsetX*M_SQRT2;
-      radiusY = offsetY*M_SQRT2;
-    }
-    break;
-  }
-  case NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE:
-    radiusX = std::max(leftDistance, rightDistance);
-    radiusY = std::max(topDistance, bottomDistance);
-    if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
-      radiusX = radiusY = std::max(radiusX, radiusY);
-    }
-    break;
-  case NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER: {
-    // Compute x and y distances to nearest corner
-    double offsetX = std::max(leftDistance, rightDistance);
-    double offsetY = std::max(topDistance, bottomDistance);
-    if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR) {
-      radiusX = radiusY = NS_hypot(offsetX, offsetY);
-    } else {
-      // maintain aspect ratio
-      radiusX = offsetX*M_SQRT2;
-      radiusY = offsetY*M_SQRT2;
-    }
-    break;
-  }
-  case NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE: {
-    int32_t appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
-    radiusX = ConvertGradientValueToPixels(aGradient->mRadiusX,
-                                           aBoxSize.width, appUnitsPerPixel);
-    radiusY = ConvertGradientValueToPixels(aGradient->mRadiusY,
-                                           aBoxSize.height, appUnitsPerPixel);
-    break;
-  }
-  default:
-    radiusX = radiusY = 0;
-    MOZ_ASSERT(false, "unknown radial gradient sizing method");
-  }
-  *aRadiusX = radiusX;
-  *aRadiusY = radiusY;
-
-  double angle;
-  if (aGradient->mAngle.IsAngleValue()) {
-    angle = aGradient->mAngle.GetAngleValueInRadians();
-  } else {
-    // Default angle is 0deg
-    angle = 0.0;
-  }
-
-  // The gradient line end point is where the gradient line intersects
-  // the ellipse.
-  *aLineEnd = *aLineStart + gfxPoint(radiusX*cos(-angle), radiusY*sin(-angle));
-}
-
-
-static float Interpolate(float aF1, float aF2, float aFrac)
-{
-  return aF1 + aFrac * (aF2 - aF1);
-}
-
-// Returns aFrac*aC2 + (1 - aFrac)*C1. The interpolation is done
-// in unpremultiplied space, which is what SVG gradients and cairo
-// gradients expect.
-static Color
-InterpolateColor(const Color& aC1, const Color& aC2, float aFrac)
-{
-  double other = 1 - aFrac;
-  return Color(aC2.r*aFrac + aC1.r*other,
-               aC2.g*aFrac + aC1.g*other,
-               aC2.b*aFrac + aC1.b*other,
-               aC2.a*aFrac + aC1.a*other);
-}
-
-static nscoord
-FindTileStart(nscoord aDirtyCoord, nscoord aTilePos, nscoord aTileDim)
-{
-  NS_ASSERTION(aTileDim > 0, "Non-positive tile dimension");
-  double multiples = floor(double(aDirtyCoord - aTilePos)/aTileDim);
-  return NSToCoordRound(multiples*aTileDim + aTilePos);
-}
-
-static gfxFloat
-LinearGradientStopPositionForPoint(const gfxPoint& aGradientStart,
-                                   const gfxPoint& aGradientEnd,
-                                   const gfxPoint& aPoint)
-{
-  gfxPoint d = aGradientEnd - aGradientStart;
-  gfxPoint p = aPoint - aGradientStart;
-  /**
-   * Compute a parameter t such that a line perpendicular to the
-   * d vector, passing through aGradientStart + d*t, also
-   * passes through aPoint.
-   *
-   * t is given by
-   *   (p.x - d.x*t)*d.x + (p.y - d.y*t)*d.y = 0
-   *
-   * Solving for t we get
-   *   numerator = d.x*p.x + d.y*p.y
-   *   denominator = d.x^2 + d.y^2
-   *   t = numerator/denominator
-   *
-   * In nsCSSRendering::PaintGradient we know the length of d
-   * is not zero.
-   */
-  double numerator = d.x * p.x + d.y * p.y;
-  double denominator = d.x * d.x + d.y * d.y;
-  return numerator / denominator;
-}
-
-static bool
-RectIsBeyondLinearGradientEdge(const gfxRect& aRect,
-                               const gfxMatrix& aPatternMatrix,
-                               const nsTArray<ColorStop>& aStops,
-                               const gfxPoint& aGradientStart,
-                               const gfxPoint& aGradientEnd,
-                               Color* aOutEdgeColor)
-{
-  gfxFloat topLeft = LinearGradientStopPositionForPoint(
-    aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.TopLeft()));
-  gfxFloat topRight = LinearGradientStopPositionForPoint(
-    aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.TopRight()));
-  gfxFloat bottomLeft = LinearGradientStopPositionForPoint(
-    aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.BottomLeft()));
-  gfxFloat bottomRight = LinearGradientStopPositionForPoint(
-    aGradientStart, aGradientEnd, aPatternMatrix.Transform(aRect.BottomRight()));
-
-  const ColorStop& firstStop = aStops[0];
-  if (topLeft < firstStop.mPosition && topRight < firstStop.mPosition &&
-      bottomLeft < firstStop.mPosition && bottomRight < firstStop.mPosition) {
-    *aOutEdgeColor = firstStop.mColor;
-    return true;
-  }
-
-  const ColorStop& lastStop = aStops.LastElement();
-  if (topLeft >= lastStop.mPosition && topRight >= lastStop.mPosition &&
-      bottomLeft >= lastStop.mPosition && bottomRight >= lastStop.mPosition) {
-    *aOutEdgeColor = lastStop.mColor;
-    return true;
-  }
-
-  return false;
-}
-
-static void ResolveMidpoints(nsTArray<ColorStop>& stops)
-{
-  for (size_t x = 1; x < stops.Length() - 1;) {
-    if (!stops[x].mIsMidpoint) {
-      x++;
-      continue;
-    }
-
-    Color color1 = stops[x-1].mColor;
-    Color color2 = stops[x+1].mColor;
-    float offset1 = stops[x-1].mPosition;
-    float offset2 = stops[x+1].mPosition;
-    float offset = stops[x].mPosition;
-    // check if everything coincides. If so, ignore the midpoint.
-    if (offset - offset1 == offset2 - offset) {
-      stops.RemoveElementAt(x);
-      continue;
-    }
-
-    // Check if we coincide with the left colorstop.
-    if (offset1 == offset) {
-      // Morph the midpoint to a regular stop with the color of the next
-      // color stop.
-      stops[x].mColor = color2;
-      stops[x].mIsMidpoint = false;
-      continue;
-    }
-
-    // Check if we coincide with the right colorstop.
-    if (offset2 == offset) {
-      // Morph the midpoint to a regular stop with the color of the previous
-      // color stop.
-      stops[x].mColor = color1;
-      stops[x].mIsMidpoint = false;
-      continue;
-    }
-
-    float midpoint = (offset - offset1) / (offset2 - offset1);
-    ColorStop newStops[9];
-    if (midpoint > .5f) {
-      for (size_t y = 0; y < 7; y++) {
-        newStops[y].mPosition = offset1 + (offset - offset1) * (7 + y) / 13;
-      }
-
-      newStops[7].mPosition = offset + (offset2 - offset) / 3;
-      newStops[8].mPosition = offset + (offset2 - offset) * 2 / 3;
-    } else {
-      newStops[0].mPosition = offset1 + (offset - offset1) / 3;
-      newStops[1].mPosition = offset1 + (offset - offset1) * 2 / 3;
-
-      for (size_t y = 0; y < 7; y++) {
-        newStops[y+2].mPosition = offset + (offset2 - offset) * y / 13;
-      }
-    }
-    // calculate colors
-
-    for (size_t y = 0; y < 9; y++) {
-      // Calculate the intermediate color stops per the formula of the CSS images
-      // spec. http://dev.w3.org/csswg/css-images/#color-stop-syntax
-      // 9 points were chosen since it is the minimum number of stops that always
-      // give the smoothest appearace regardless of midpoint position and difference
-      // in luminance of the end points.
-      float relativeOffset = (newStops[y].mPosition - offset1) / (offset2 - offset1);
-      float multiplier = powf(relativeOffset, logf(.5f) / logf(midpoint));
-
-      gfx::Float red = color1.r + multiplier * (color2.r - color1.r);
-      gfx::Float green = color1.g + multiplier * (color2.g - color1.g);
-      gfx::Float blue = color1.b + multiplier * (color2.b - color1.b);
-      gfx::Float alpha = color1.a + multiplier * (color2.a - color1.a);
-
-      newStops[y].mColor = Color(red, green, blue, alpha);
-    }
-
-    stops.ReplaceElementsAt(x, 1, newStops, 9);
-    x += 9;
-  }
-}
-
-static Color
-Premultiply(const Color& aColor)
-{
-  gfx::Float a = aColor.a;
-  return Color(aColor.r * a, aColor.g * a, aColor.b * a, a);
-}
-
-static Color
-Unpremultiply(const Color& aColor)
-{
-  gfx::Float a = aColor.a;
-  return (a > 0.f)
-       ? Color(aColor.r / a, aColor.g / a, aColor.b / a, a)
-       : aColor;
-}
-
-static Color
-TransparentColor(Color aColor) {
-  aColor.a = 0;
-  return aColor;
-}
-
-// Adjusts and adds color stops in such a way that drawing the gradient with
-// unpremultiplied interpolation looks nearly the same as if it were drawn with
-// premultiplied interpolation.
-static const float kAlphaIncrementPerGradientStep = 0.1f;
-static void
-ResolvePremultipliedAlpha(nsTArray<ColorStop>& aStops)
-{
-  for (size_t x = 1; x < aStops.Length(); x++) {
-    const ColorStop leftStop = aStops[x - 1];
-    const ColorStop rightStop = aStops[x];
-
-    // if the left and right stop have the same alpha value, we don't need
-    // to do anything
-    if (leftStop.mColor.a == rightStop.mColor.a) {
-      continue;
-    }
-
-    // Is the stop on the left 100% transparent? If so, have it adopt the color
-    // of the right stop
-    if (leftStop.mColor.a == 0) {
-      aStops[x - 1].mColor = TransparentColor(rightStop.mColor);
-      continue;
-    }
-
-    // Is the stop on the right completely transparent?
-    // If so, duplicate it and assign it the color on the left.
-    if (rightStop.mColor.a == 0) {
-      ColorStop newStop = rightStop;
-      newStop.mColor = TransparentColor(leftStop.mColor);
-      aStops.InsertElementAt(x, newStop);
-      x++;
-      continue;
-    }
-
-    // Now handle cases where one or both of the stops are partially transparent.
-    if (leftStop.mColor.a != 1.0f || rightStop.mColor.a != 1.0f) {
-      Color premulLeftColor = Premultiply(leftStop.mColor);
-      Color premulRightColor = Premultiply(rightStop.mColor);
-      // Calculate how many extra steps. We do a step per 10% transparency.
-      size_t stepCount = NSToIntFloor(fabsf(leftStop.mColor.a - rightStop.mColor.a) / kAlphaIncrementPerGradientStep);
-      for (size_t y = 1; y < stepCount; y++) {
-        float frac = static_cast<float>(y) / stepCount;
-        ColorStop newStop(Interpolate(leftStop.mPosition, rightStop.mPosition, frac), false,
-                          Unpremultiply(InterpolateColor(premulLeftColor, premulRightColor, frac)));
-        aStops.InsertElementAt(x, newStop);
-        x++;
-      }
-    }
-  }
-}
-
-static ColorStop
-InterpolateColorStop(const ColorStop& aFirst, const ColorStop& aSecond,
-                     double aPosition, const Color& aDefault)
-{
-  MOZ_ASSERT(aFirst.mPosition <= aPosition);
-  MOZ_ASSERT(aPosition <= aSecond.mPosition);
-
-  double delta = aSecond.mPosition - aFirst.mPosition;
-
-  if (delta < 1e-6) {
-    return ColorStop(aPosition, false, aDefault);
-  }
-
-  return ColorStop(aPosition, false,
-                   Unpremultiply(InterpolateColor(Premultiply(aFirst.mColor),
-                                                  Premultiply(aSecond.mColor),
-                                                  (aPosition - aFirst.mPosition) / delta)));
-}
-
-// Clamp and extend the given ColorStop array in-place to fit exactly into the
-// range [0, 1].
-static void
-ClampColorStops(nsTArray<ColorStop>& aStops)
-{
-  MOZ_ASSERT(aStops.Length() > 0);
-
-  // If all stops are outside the range, then get rid of everything and replace
-  // with a single colour.
-  if (aStops.Length() < 2 || aStops[0].mPosition > 1 ||
-      aStops.LastElement().mPosition < 0) {
-    Color c = aStops[0].mPosition > 1 ? aStops[0].mColor : aStops.LastElement().mColor;
-    aStops.Clear();
-    aStops.AppendElement(ColorStop(0, false, c));
-    return;
-  }
-
-  // Create the 0 and 1 points if they fall in the range of |aStops|, and discard
-  // all stops outside the range [0, 1].
-  // XXX: If we have stops positioned at 0 or 1, we only keep the innermost of
-  // those stops. This should be fine for the current user(s) of this function.
-  for (size_t i = aStops.Length() - 1; i > 0; i--) {
-    if (aStops[i - 1].mPosition < 1 && aStops[i].mPosition >= 1) {
-      // Add a point to position 1.
-      aStops[i] = InterpolateColorStop(aStops[i - 1], aStops[i],
-                                       /* aPosition = */ 1,
-                                       aStops[i - 1].mColor);
-      // Remove all the elements whose position is greater than 1.
-      aStops.RemoveElementsAt(i + 1, aStops.Length() - (i + 1));
-    }
-    if (aStops[i - 1].mPosition <= 0 && aStops[i].mPosition > 0) {
-      // Add a point to position 0.
-      aStops[i - 1] = InterpolateColorStop(aStops[i - 1], aStops[i],
-                                           /* aPosition = */ 0,
-                                           aStops[i].mColor);
-      // Remove all of the preceding stops -- they are all negative.
-      aStops.RemoveElementsAt(0, i - 1);
-      break;
-    }
-  }
-
-  MOZ_ASSERT(aStops[0].mPosition >= -1e6);
-  MOZ_ASSERT(aStops.LastElement().mPosition - 1 <= 1e6);
-
-  // The end points won't exist yet if they don't fall in the original range of
-  // |aStops|. Create them if needed.
-  if (aStops[0].mPosition > 0) {
-    aStops.InsertElementAt(0, ColorStop(0, false, aStops[0].mColor));
-  }
-  if (aStops.LastElement().mPosition < 1) {
-    aStops.AppendElement(ColorStop(1, false, aStops.LastElement().mColor));
-  }
-}
-
-void
-nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
-                              gfxContext& aContext,
-                              nsStyleGradient* aGradient,
-                              const nsRect& aDirtyRect,
-                              const nsRect& aDest,
-                              const nsRect& aFillArea,
-                              const nsSize& aRepeatSize,
-                              const CSSIntRect& aSrc,
-                              const nsSize& aIntrinsicSize,
-                              float aOpacity)
-{
-  PROFILER_LABEL("nsCSSRendering", "PaintGradient",
-    js::ProfileEntry::Category::GRAPHICS);
-
-  Telemetry::AutoTimer<Telemetry::GRADIENT_DURATION, Telemetry::Microsecond> gradientTimer;
-  if (aDest.IsEmpty() || aFillArea.IsEmpty()) {
-    return;
-  }
-
-  nscoord appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
-  gfxSize srcSize = gfxSize(gfxFloat(aIntrinsicSize.width)/appUnitsPerDevPixel,
-                            gfxFloat(aIntrinsicSize.height)/appUnitsPerDevPixel);
-
-  bool cellContainsFill = aDest.Contains(aFillArea);
-
-  // Compute "gradient line" start and end relative to the intrinsic size of
-  // the gradient.
-  gfxPoint lineStart, lineEnd;
-  double radiusX = 0, radiusY = 0; // for radial gradients only
-  if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
-    ComputeLinearGradientLine(aPresContext, aGradient, srcSize,
-                              &lineStart, &lineEnd);
-  } else {
-    ComputeRadialGradientLine(aPresContext, aGradient, srcSize,
-                              &lineStart, &lineEnd, &radiusX, &radiusY);
-  }
-  // Avoid sending Infs or Nans to downwind draw targets.
-  if (!lineStart.IsFinite() || !lineEnd.IsFinite()) {
-    lineStart = lineEnd = gfxPoint(0, 0);
-  }
-  gfxFloat lineLength = NS_hypot(lineEnd.x - lineStart.x,
-                                  lineEnd.y - lineStart.y);
-
-  MOZ_ASSERT(aGradient->mStops.Length() >= 2,
-             "The parser should reject gradients with less than two stops");
-
-  // Build color stop array and compute stop positions
-  nsTArray<ColorStop> stops;
-  // If there is a run of stops before stop i that did not have specified
-  // positions, then this is the index of the first stop in that run, otherwise
-  // it's -1.
-  int32_t firstUnsetPosition = -1;
-  for (uint32_t i = 0; i < aGradient->mStops.Length(); ++i) {
-    const nsStyleGradientStop& stop = aGradient->mStops[i];
-    double position;
-    switch (stop.mLocation.GetUnit()) {
-    case eStyleUnit_None:
-      if (i == 0) {
-        // First stop defaults to position 0.0
-        position = 0.0;
-      } else if (i == aGradient->mStops.Length() - 1) {
-        // Last stop defaults to position 1.0
-        position = 1.0;
-      } else {
-        // Other stops with no specified position get their position assigned
-        // later by interpolation, see below.
-        // Remeber where the run of stops with no specified position starts,
-        // if it starts here.
-        if (firstUnsetPosition < 0) {
-          firstUnsetPosition = i;
-        }
-        stops.AppendElement(ColorStop(0, stop.mIsInterpolationHint,
-                                      Color::FromABGR(stop.mColor)));
-        continue;
-      }
-      break;
-    case eStyleUnit_Percent:
-      position = stop.mLocation.GetPercentValue();
-      break;
-    case eStyleUnit_Coord:
-      position = lineLength < 1e-6 ? 0.0 :
-          stop.mLocation.GetCoordValue() / appUnitsPerDevPixel / lineLength;
-      break;
-    case eStyleUnit_Calc:
-      nsStyleCoord::Calc *calc;
-      calc = stop.mLocation.GetCalcValue();
-      position = calc->mPercent +
-          ((lineLength < 1e-6) ? 0.0 :
-          (NSAppUnitsToFloatPixels(calc->mLength, appUnitsPerDevPixel) / lineLength));
-      break;
-    default:
-      MOZ_ASSERT(false, "Unknown stop position type");
-    }
-
-    if (i > 0) {
-      // Prevent decreasing stop positions by advancing this position
-      // to the previous stop position, if necessary
-      position = std::max(position, stops[i - 1].mPosition);
-    }
-    stops.AppendElement(ColorStop(position, stop.mIsInterpolationHint,
-                                  Color::FromABGR(stop.mColor)));
-    if (firstUnsetPosition > 0) {
-      // Interpolate positions for all stops that didn't have a specified position
-      double p = stops[firstUnsetPosition - 1].mPosition;
-      double d = (stops[i].mPosition - p)/(i - firstUnsetPosition + 1);
-      for (uint32_t j = firstUnsetPosition; j < i; ++j) {
-        p += d;
-        stops[j].mPosition = p;
-      }
-      firstUnsetPosition = -1;
-    }
-  }
-
-  // If a non-repeating linear gradient is axis-aligned and there are no gaps
-  // between tiles, we can optimise away most of the work by converting to a
-  // repeating linear gradient and filling the whole destination rect at once.
-  bool forceRepeatToCoverTiles =
-    aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR &&
-    (lineStart.x == lineEnd.x) != (lineStart.y == lineEnd.y) &&
-    aRepeatSize.width == aDest.width && aRepeatSize.height == aDest.height &&
-    !aGradient->mRepeating && !aSrc.IsEmpty() && !cellContainsFill;
-
-  gfxMatrix matrix;
-  if (forceRepeatToCoverTiles) {
-    // Length of the source rectangle along the gradient axis.
-    double rectLen;
-    // The position of the start of the rectangle along the gradient.
-    double offset;
-
-    // The gradient line is "backwards". Flip the line upside down to make
-    // things easier, and then rotate the matrix to turn everything back the
-    // right way up.
-    if (lineStart.x > lineEnd.x || lineStart.y > lineEnd.y) {
-      std::swap(lineStart, lineEnd);
-      matrix.Scale(-1, -1);
-    }
-
-    // Fit the gradient line exactly into the source rect.
-    // aSrc is relative to aIntrinsincSize.
-    // srcRectDev will be relative to srcSize, so in the same coordinate space
-    // as lineStart / lineEnd.
-    gfxRect srcRectDev = nsLayoutUtils::RectToGfxRect(
-      CSSPixel::ToAppUnits(aSrc), appUnitsPerDevPixel);
-    if (lineStart.x != lineEnd.x) {
-      rectLen = srcRectDev.width;
-      offset = (srcRectDev.x - lineStart.x) / lineLength;
-      lineStart.x = srcRectDev.x;
-      lineEnd.x = srcRectDev.XMost();
-    } else {
-      rectLen = srcRectDev.height;
-      offset = (srcRectDev.y - lineStart.y) / lineLength;
-      lineStart.y = srcRectDev.y;
-      lineEnd.y = srcRectDev.YMost();
-    }
-
-    // Adjust gradient stop positions for the new gradient line.
-    double scale = lineLength / rectLen;
-    for (size_t i = 0; i < stops.Length(); i++) {
-      stops[i].mPosition = (stops[i].mPosition - offset) * fabs(scale);
-    }
-
-    // Clamp or extrapolate gradient stops to exactly [0, 1].
-    ClampColorStops(stops);
-
-    lineLength = rectLen;
-  }
-
-  // Eliminate negative-position stops if the gradient is radial.
-  double firstStop = stops[0].mPosition;
-  if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR && firstStop < 0.0) {
-    if (aGradient->mRepeating) {
-      // Choose an instance of the repeated pattern that gives us all positive
-      // stop-offsets.
-      double lastStop = stops[stops.Length() - 1].mPosition;
-      double stopDelta = lastStop - firstStop;
-      // If all the stops are in approximately the same place then logic below
-      // will kick in that makes us draw just the last stop color, so don't
-      // try to do anything in that case. We certainly need to avoid
-      // dividing by zero.
-      if (stopDelta >= 1e-6) {
-        double instanceCount = ceil(-firstStop/stopDelta);
-        // Advance stops by instanceCount multiples of the period of the
-        // repeating gradient.
-        double offset = instanceCount*stopDelta;
-        for (uint32_t i = 0; i < stops.Length(); i++) {
-          stops[i].mPosition += offset;
-        }
-      }
-    } else {
-      // Move negative-position stops to position 0.0. We may also need
-      // to set the color of the stop to the color the gradient should have
-      // at the center of the ellipse.
-      for (uint32_t i = 0; i < stops.Length(); i++) {
-        double pos = stops[i].mPosition;
-        if (pos < 0.0) {
-          stops[i].mPosition = 0.0;
-          // If this is the last stop, we don't need to adjust the color,
-          // it will fill the entire area.
-          if (i < stops.Length() - 1) {
-            double nextPos = stops[i + 1].mPosition;
-            // If nextPos is approximately equal to pos, then we don't
-            // need to adjust the color of this stop because it's
-            // not going to be displayed.
-            // If nextPos is negative, we don't need to adjust the color of
-            // this stop since it's not going to be displayed because
-            // nextPos will also be moved to 0.0.
-            if (nextPos >= 0.0 && nextPos - pos >= 1e-6) {
-              // Compute how far the new position 0.0 is along the interval
-              // between pos and nextPos.
-              // XXX Color interpolation (in cairo, too) should use the
-              // CSS 'color-interpolation' property!
-              float frac = float((0.0 - pos)/(nextPos - pos));
-              stops[i].mColor =
-                InterpolateColor(stops[i].mColor, stops[i + 1].mColor, frac);
-            }
-          }
-        }
-      }
-    }
-    firstStop = stops[0].mPosition;
-    MOZ_ASSERT(firstStop >= 0.0, "Failed to fix stop offsets");
-  }
-
-  if (aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR && !aGradient->mRepeating) {
-    // Direct2D can only handle a particular class of radial gradients because
-    // of the way the it specifies gradients. Setting firstStop to 0, when we
-    // can, will help us stay on the fast path. Currently we don't do this
-    // for repeating gradients but we could by adjusting the stop collection
-    // to start at 0
-    firstStop = 0;
-  }
-
-  double lastStop = stops[stops.Length() - 1].mPosition;
-  // Cairo gradients must have stop positions in the range [0, 1]. So,
-  // stop positions will be normalized below by subtracting firstStop and then
-  // multiplying by stopScale.
-  double stopScale;
-  double stopOrigin = firstStop;
-  double stopEnd = lastStop;
-  double stopDelta = lastStop - firstStop;
-  bool zeroRadius = aGradient->mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR &&
-                      (radiusX < 1e-6 || radiusY < 1e-6);
-  if (stopDelta < 1e-6 || lineLength < 1e-6 || zeroRadius) {
-    // Stops are all at the same place. Map all stops to 0.0.
-    // For repeating radial gradients, or for any radial gradients with
-    // a zero radius, we need to fill with the last stop color, so just set
-    // both radii to 0.
-    if (aGradient->mRepeating || zeroRadius) {
-      radiusX = radiusY = 0.0;
-    }
-    stopDelta = 0.0;
-    lastStop = firstStop;
-  }
-
-  // Don't normalize non-repeating or degenerate gradients below 0..1
-  // This keeps the gradient line as large as the box and doesn't
-  // lets us avoiding having to get padding correct for stops
-  // at 0 and 1
-  if (!aGradient->mRepeating || stopDelta == 0.0) {
-    stopOrigin = std::min(stopOrigin, 0.0);
-    stopEnd = std::max(stopEnd, 1.0);
-  }
-  stopScale = 1.0/(stopEnd - stopOrigin);
-
-  // Create the gradient pattern.
-  RefPtr<gfxPattern> gradientPattern;
-  gfxPoint gradientStart;
-  gfxPoint gradientEnd;
-  if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
-    // Compute the actual gradient line ends we need to pass to cairo after
-    // stops have been normalized.
-    gradientStart = lineStart + (lineEnd - lineStart)*stopOrigin;
-    gradientEnd = lineStart + (lineEnd - lineStart)*stopEnd;
-    gfxPoint gradientStopStart = lineStart + (lineEnd - lineStart)*firstStop;
-    gfxPoint gradientStopEnd = lineStart + (lineEnd - lineStart)*lastStop;
-
-    if (stopDelta == 0.0) {
-      // Stops are all at the same place. For repeating gradients, this will
-      // just paint the last stop color. We don't need to do anything.
-      // For non-repeating gradients, this should render as two colors, one
-      // on each "side" of the gradient line segment, which is a point. All
-      // our stops will be at 0.0; we just need to set the direction vector
-      // correctly.
-      gradientEnd = gradientStart + (lineEnd - lineStart);
-      gradientStopEnd = gradientStopStart + (lineEnd - lineStart);
-    }
-
-    gradientPattern = new gfxPattern(gradientStart.x, gradientStart.y,
-                                      gradientEnd.x, gradientEnd.y);
-  } else {
-    NS_ASSERTION(firstStop >= 0.0,
-                  "Negative stops not allowed for radial gradients");
-
-    // To form an ellipse, we'll stretch a circle vertically, if necessary.
-    // So our radii are based on radiusX.
-    double innerRadius = radiusX*stopOrigin;
-    double outerRadius = radiusX*stopEnd;
-    if (stopDelta == 0.0) {
-      // Stops are all at the same place.  See above (except we now have
-      // the inside vs. outside of an ellipse).
-      outerRadius = innerRadius + 1;
-    }
-    gradientPattern = new gfxPattern(lineStart.x, lineStart.y, innerRadius,
-                                     lineStart.x, lineStart.y, outerRadius);
-    if (radiusX != radiusY) {
-      // Stretch the circles into ellipses vertically by setting a transform
-      // in the pattern.
-      // Recall that this is the transform from user space to pattern space.
-      // So to stretch the ellipse by factor of P vertically, we scale
-      // user coordinates by 1/P.
-      matrix.Translate(lineStart);
-      matrix.Scale(1.0, radiusX/radiusY);
-      matrix.Translate(-lineStart);
-    }
-  }
-  // Use a pattern transform to take account of source and dest rects
-  matrix.Translate(gfxPoint(aPresContext->CSSPixelsToDevPixels(aSrc.x),
-                            aPresContext->CSSPixelsToDevPixels(aSrc.y)));
-  matrix.Scale(gfxFloat(aPresContext->CSSPixelsToAppUnits(aSrc.width))/aDest.width,
-               gfxFloat(aPresContext->CSSPixelsToAppUnits(aSrc.height))/aDest.height);
-  gradientPattern->SetMatrix(matrix);
-
-  if (stopDelta == 0.0) {
-    // Non-repeating gradient with all stops in same place -> just add
-    // first stop and last stop, both at position 0.
-    // Repeating gradient with all stops in the same place, or radial
-    // gradient with radius of 0 -> just paint the last stop color.
-    // We use firstStop offset to keep |stops| with same units (will later normalize to 0).
-    Color firstColor(stops[0].mColor);
-    Color lastColor(stops.LastElement().mColor);
-    stops.Clear();
-
-    if (!aGradient->mRepeating && !zeroRadius) {
-      stops.AppendElement(ColorStop(firstStop, false, firstColor));
-    }
-    stops.AppendElement(ColorStop(firstStop, false, lastColor));
-  }
-
-  ResolveMidpoints(stops);
-  ResolvePremultipliedAlpha(stops);
-
-  bool isRepeat = aGradient->mRepeating || forceRepeatToCoverTiles;
-
-  // Now set normalized color stops in pattern.
-  // Offscreen gradient surface cache (not a tile):
-  // On some backends (e.g. D2D), the GradientStops object holds an offscreen surface
-  // which is a lookup table used to evaluate the gradient. This surface can use
-  // much memory (ram and/or GPU ram) and can be expensive to create. So we cache it.
-  // The cache key correlates 1:1 with the arguments for CreateGradientStops (also the implied backend type)
-  // Note that GradientStop is a simple struct with a stop value (while GradientStops has the surface).
-  nsTArray<gfx::GradientStop> rawStops(stops.Length());
-  rawStops.SetLength(stops.Length());
-  for(uint32_t i = 0; i < stops.Length(); i++) {
-    rawStops[i].color = stops[i].mColor;
-    rawStops[i].color.a *= aOpacity;
-    rawStops[i].offset = stopScale * (stops[i].mPosition - stopOrigin);
-  }
-  RefPtr<mozilla::gfx::GradientStops> gs =
-    gfxGradientCache::GetOrCreateGradientStops(aContext.GetDrawTarget(),
-                                               rawStops,
-                                               isRepeat ? gfx::ExtendMode::REPEAT : gfx::ExtendMode::CLAMP);
-  gradientPattern->SetColorStops(gs);
-
-  // Paint gradient tiles. This isn't terribly efficient, but doing it this
-  // way is simple and sure to get pixel-snapping right. We could speed things
-  // up by drawing tiles into temporary surfaces and copying those to the
-  // destination, but after pixel-snapping tiles may not all be the same size.
-  nsRect dirty;
-  if (!dirty.IntersectRect(aDirtyRect, aFillArea))
-    return;
-
-  gfxRect areaToFill =
-    nsLayoutUtils::RectToGfxRect(aFillArea, appUnitsPerDevPixel);
-  gfxRect dirtyAreaToFill = nsLayoutUtils::RectToGfxRect(dirty, appUnitsPerDevPixel);
-  dirtyAreaToFill.RoundOut();
-
-  gfxMatrix ctm = aContext.CurrentMatrix();
-  bool isCTMPreservingAxisAlignedRectangles = ctm.PreservesAxisAlignedRectangles();
-
-  // xStart/yStart are the top-left corner of the top-left tile.
-  nscoord xStart = FindTileStart(dirty.x, aDest.x, aRepeatSize.width);
-  nscoord yStart = FindTileStart(dirty.y, aDest.y, aRepeatSize.height);
-  nscoord xEnd = forceRepeatToCoverTiles ? xStart + aDest.width : dirty.XMost();
-  nscoord yEnd = forceRepeatToCoverTiles ? yStart + aDest.height : dirty.YMost();
-
-  // x and y are the top-left corner of the tile to draw
-  for (nscoord y = yStart; y < yEnd; y += aRepeatSize.height) {
-    for (nscoord x = xStart; x < xEnd; x += aRepeatSize.width) {
-      // The coordinates of the tile
-      gfxRect tileRect = nsLayoutUtils::RectToGfxRect(
-                      nsRect(x, y, aDest.width, aDest.height),
-                      appUnitsPerDevPixel);
-      // The actual area to fill with this tile is the intersection of this
-      // tile with the overall area we're supposed to be filling
-      gfxRect fillRect =
-        forceRepeatToCoverTiles ? areaToFill : tileRect.Intersect(areaToFill);
-      // Try snapping the fill rect. Snap its top-left and bottom-right
-      // independently to preserve the orientation.
-      gfxPoint snappedFillRectTopLeft = fillRect.TopLeft();
-      gfxPoint snappedFillRectTopRight = fillRect.TopRight();
-      gfxPoint snappedFillRectBottomRight = fillRect.BottomRight();
-      // Snap three points instead of just two to ensure we choose the
-      // correct orientation if there's a reflection.
-      if (isCTMPreservingAxisAlignedRectangles &&
-          aContext.UserToDevicePixelSnapped(snappedFillRectTopLeft, true) &&
-          aContext.UserToDevicePixelSnapped(snappedFillRectBottomRight, true) &&
-          aContext.UserToDevicePixelSnapped(snappedFillRectTopRight, true)) {
-        if (snappedFillRectTopLeft.x == snappedFillRectBottomRight.x ||
-            snappedFillRectTopLeft.y == snappedFillRectBottomRight.y) {
-          // Nothing to draw; avoid scaling by zero and other weirdness that
-          // could put the context in an error state.
-          continue;
-        }
-        // Set the context's transform to the transform that maps fillRect to
-        // snappedFillRect. The part of the gradient that was going to
-        // exactly fill fillRect will fill snappedFillRect instead.
-        gfxMatrix transform = gfxUtils::TransformRectToRect(fillRect,
-            snappedFillRectTopLeft, snappedFillRectTopRight,
-            snappedFillRectBottomRight);
-        aContext.SetMatrix(transform);
-      }
-      aContext.NewPath();
-      aContext.Rectangle(fillRect);
-
-      gfxRect dirtyFillRect = fillRect.Intersect(dirtyAreaToFill);
-      gfxRect fillRectRelativeToTile = dirtyFillRect - tileRect.TopLeft();
-      Color edgeColor;
-      if (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR && !isRepeat &&
-          RectIsBeyondLinearGradientEdge(fillRectRelativeToTile, matrix, stops,
-                                         gradientStart, gradientEnd, &edgeColor)) {
-        edgeColor.a *= aOpacity;
-        aContext.SetColor(edgeColor);
-      } else {
-        aContext.SetMatrix(
-          aContext.CurrentMatrix().Copy().Translate(tileRect.TopLeft()));
-        aContext.SetPattern(gradientPattern);
-      }
-      aContext.Fill();
-      aContext.SetMatrix(ctm);
-    }
-  }
-}
-
 static CompositionOp
 DetermineCompositionOp(const nsCSSRendering::PaintBGParams& aParams,
                        const nsStyleImageLayers& aLayers,
                        uint32_t aLayerIndex)
 {
   if (aParams.layer >= 0) {
     // When drawing a single layer, use the specified composition op.
     return aParams.compositionOp;
copy from layout/painting/nsCSSRendering.cpp
copy to layout/painting/nsCSSRenderingGradients.cpp
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -1,2409 +1,53 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 // vim:cindent:ts=2:et:sw=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/. */
 
 /* utility functions for drawing borders and backgrounds */
 
-#include <ctime>
+#include "nsCSSRenderingGradients.h"
 
 #include "gfx2DGlue.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Helpers.h"
-#include "mozilla/gfx/PathHelpers.h"
-#include "mozilla/HashFunctions.h"
 #include "mozilla/MathAlgorithms.h"
 
-#include "BorderConsts.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
-#include "nsIFrame.h"
-#include "nsIFrameInlines.h"
 #include "nsPoint.h"
 #include "nsRect.h"
-#include "nsIPresShell.h"
-#include "nsFrameManager.h"
 #include "nsStyleContext.h"
-#include "nsGkAtoms.h"
-#include "nsCSSAnonBoxes.h"
-#include "nsIContent.h"
-#include "nsIDocumentInlines.h"
-#include "nsIScrollableFrame.h"
-#include "imgIRequest.h"
-#include "imgIContainer.h"
-#include "ImageOps.h"
-#include "nsCSSRendering.h"
 #include "nsCSSColorUtils.h"
-#include "nsITheme.h"
-#include "nsThemeConstants.h"
-#include "nsLayoutUtils.h"
-#include "nsBlockFrame.h"
 #include "gfxContext.h"
 #include "nsRenderingContext.h"
 #include "nsStyleStructInlines.h"
-#include "nsCSSFrameConstructor.h"
 #include "nsCSSProps.h"
-#include "nsContentUtils.h"
-#include "nsSVGEffects.h"
-#include "nsSVGIntegrationUtils.h"
-#include "gfxDrawable.h"
-#include "GeckoProfiler.h"
-#include "nsCSSRenderingBorders.h"
-#include "mozilla/css/ImageLoader.h"
-#include "ImageContainer.h"
 #include "mozilla/Telemetry.h"
 #include "gfxUtils.h"
 #include "gfxGradientCache.h"
-#include "nsInlineFrame.h"
-#include "nsRubyTextContainerFrame.h"
-#include <algorithm>
-#include "SVGImageContext.h"
 
 using namespace mozilla;
-using namespace mozilla::css;
 using namespace mozilla::gfx;
-using namespace mozilla::image;
-using mozilla::CSSSizeOrRatio;
-
-static int gFrameTreeLockCount = 0;
-
-// To avoid storing this data on nsInlineFrame (bloat) and to avoid
-// recalculating this for each frame in a continuation (perf), hold
-// a cache of various coordinate information that we need in order
-// to paint inline backgrounds.
-struct InlineBackgroundData
-{
-  InlineBackgroundData()
-      : mFrame(nullptr), mLineContainer(nullptr)
-  {
-  }
-
-  ~InlineBackgroundData()
-  {
-  }
-
-  void Reset()
-  {
-    mBoundingBox.SetRect(0,0,0,0);
-    mContinuationPoint = mLineContinuationPoint = mUnbrokenMeasure = 0;
-    mFrame = mLineContainer = nullptr;
-    mPIStartBorderData.Reset();
-  }
-
-  /**
-   * Return a continuous rect for (an inline) aFrame relative to the
-   * continuation that draws the left-most part of the background.
-   * This is used when painting backgrounds.
-   */
-  nsRect GetContinuousRect(nsIFrame* aFrame)
-  {
-    MOZ_ASSERT(static_cast<nsInlineFrame*>(do_QueryFrame(aFrame)));
-
-    SetFrame(aFrame);
-
-    nscoord pos; // an x coordinate if writing-mode is horizontal;
-                 // y coordinate if vertical
-    if (mBidiEnabled) {
-      pos = mLineContinuationPoint;
-
-      // Scan continuations on the same line as aFrame and accumulate the widths
-      // of frames that are to the left (if this is an LTR block) or right
-      // (if it's RTL) of the current one.
-      bool isRtlBlock = (mLineContainer->StyleVisibility()->mDirection ==
-                           NS_STYLE_DIRECTION_RTL);
-      nscoord curOffset = mVertical ? aFrame->GetOffsetTo(mLineContainer).y
-                                    : aFrame->GetOffsetTo(mLineContainer).x;
-
-      // If the continuation is fluid we know inlineFrame is not on the same line.
-      // If it's not fluid, we need to test further to be sure.
-      nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
-      while (inlineFrame && !inlineFrame->GetNextInFlow() &&
-             AreOnSameLine(aFrame, inlineFrame)) {
-        nscoord frameOffset = mVertical
-          ? inlineFrame->GetOffsetTo(mLineContainer).y
-          : inlineFrame->GetOffsetTo(mLineContainer).x;
-        if (isRtlBlock == (frameOffset >= curOffset)) {
-          pos += mVertical
-               ? inlineFrame->GetSize().height
-               : inlineFrame->GetSize().width;
-        }
-        inlineFrame = inlineFrame->GetPrevContinuation();
-      }
-
-      inlineFrame = aFrame->GetNextContinuation();
-      while (inlineFrame && !inlineFrame->GetPrevInFlow() &&
-             AreOnSameLine(aFrame, inlineFrame)) {
-        nscoord frameOffset = mVertical
-          ? inlineFrame->GetOffsetTo(mLineContainer).y
-          : inlineFrame->GetOffsetTo(mLineContainer).x;
-        if (isRtlBlock == (frameOffset >= curOffset)) {
-          pos += mVertical
-                 ? inlineFrame->GetSize().height
-                 : inlineFrame->GetSize().width;
-        }
-        inlineFrame = inlineFrame->GetNextContinuation();
-      }
-      if (isRtlBlock) {
-        // aFrame itself is also to the right of its left edge, so add its width.
-        pos += mVertical ? aFrame->GetSize().height : aFrame->GetSize().width;
-        // pos is now the distance from the left [top] edge of aFrame to the right [bottom] edge
-        // of the unbroken content. Change it to indicate the distance from the
-        // left [top] edge of the unbroken content to the left [top] edge of aFrame.
-        pos = mUnbrokenMeasure - pos;
-      }
-    } else {
-      pos = mContinuationPoint;
-    }
-
-    // Assume background-origin: border and return a rect with offsets
-    // relative to (0,0).  If we have a different background-origin,
-    // then our rect should be deflated appropriately by our caller.
-    return mVertical
-      ? nsRect(0, -pos, mFrame->GetSize().width, mUnbrokenMeasure)
-      : nsRect(-pos, 0, mUnbrokenMeasure, mFrame->GetSize().height);
-  }
-
-  /**
-   * Return a continuous rect for (an inline) aFrame relative to the
-   * continuation that should draw the left[top]-border.  This is used when painting
-   * borders and clipping backgrounds.  This may NOT be the same continuous rect
-   * as for drawing backgrounds; the continuation with the left[top]-border might be
-   * somewhere in the middle of that rect (e.g. BIDI), in those cases we need
-   * the reverse background order starting at the left[top]-border continuation.
-   */
-  nsRect GetBorderContinuousRect(nsIFrame* aFrame, nsRect aBorderArea)
-  {
-    // Calling GetContinuousRect(aFrame) here may lead to Reset/Init which
-    // resets our mPIStartBorderData so we save it ...
-    PhysicalInlineStartBorderData saved(mPIStartBorderData);
-    nsRect joinedBorderArea = GetContinuousRect(aFrame);
-    if (!saved.mIsValid || saved.mFrame != mPIStartBorderData.mFrame) {
-      if (aFrame == mPIStartBorderData.mFrame) {
-        if (mVertical) {
-          mPIStartBorderData.SetCoord(joinedBorderArea.y);
-        } else {
-          mPIStartBorderData.SetCoord(joinedBorderArea.x);
-        }
-      } else if (mPIStartBorderData.mFrame) {
-        if (mVertical) {
-          mPIStartBorderData.SetCoord(GetContinuousRect(mPIStartBorderData.mFrame).y);
-        } else {
-          mPIStartBorderData.SetCoord(GetContinuousRect(mPIStartBorderData.mFrame).x);
-        }
-      }
-    } else {
-      // ... and restore it when possible.
-      mPIStartBorderData.mCoord = saved.mCoord;
-    }
-    if (mVertical) {
-      if (joinedBorderArea.y > mPIStartBorderData.mCoord) {
-        joinedBorderArea.y =
-          -(mUnbrokenMeasure + joinedBorderArea.y - aBorderArea.height);
-      } else {
-        joinedBorderArea.y -= mPIStartBorderData.mCoord;
-      }
-    } else {
-      if (joinedBorderArea.x > mPIStartBorderData.mCoord) {
-        joinedBorderArea.x =
-          -(mUnbrokenMeasure + joinedBorderArea.x - aBorderArea.width);
-      } else {
-        joinedBorderArea.x -= mPIStartBorderData.mCoord;
-      }
-    }
-    return joinedBorderArea;
-  }
-
-  nsRect GetBoundingRect(nsIFrame* aFrame)
-  {
-    SetFrame(aFrame);
-
-    // Move the offsets relative to (0,0) which puts the bounding box into
-    // our coordinate system rather than our parent's.  We do this by
-    // moving it the back distance from us to the bounding box.
-    // This also assumes background-origin: border, so our caller will
-    // need to deflate us if needed.
-    nsRect boundingBox(mBoundingBox);
-    nsPoint point = mFrame->GetPosition();
-    boundingBox.MoveBy(-point.x, -point.y);
-
-    return boundingBox;
-  }
-
-protected:
-  // This is a coordinate on the inline axis, but is not a true logical inline-
-  // coord because it is always measured from left to right (if horizontal) or
-  // from top to bottom (if vertical), ignoring any bidi RTL directionality.
-  // We'll call this "physical inline start", or PIStart for short.
-  struct PhysicalInlineStartBorderData {
-    nsIFrame* mFrame;   // the continuation that may have a left-border
-    nscoord   mCoord;   // cached GetContinuousRect(mFrame).x or .y
-    bool      mIsValid; // true if mCoord is valid
-    void Reset() { mFrame = nullptr; mIsValid = false; }
-    void SetCoord(nscoord aCoord) { mCoord = aCoord; mIsValid = true; }
-  };
-
-  nsIFrame*      mFrame;
-  nsIFrame*      mLineContainer;
-  nsRect         mBoundingBox;
-  nscoord        mContinuationPoint;
-  nscoord        mUnbrokenMeasure;
-  nscoord        mLineContinuationPoint;
-  PhysicalInlineStartBorderData mPIStartBorderData;
-  bool           mBidiEnabled;
-  bool           mVertical;
-
-  void SetFrame(nsIFrame* aFrame)
-  {
-    NS_PRECONDITION(aFrame, "Need a frame");
-    NS_ASSERTION(gFrameTreeLockCount > 0,
-                 "Can't call this when frame tree is not locked");
-
-    if (aFrame == mFrame) {
-      return;
-    }
-
-    nsIFrame *prevContinuation = GetPrevContinuation(aFrame);
-
-    if (!prevContinuation || mFrame != prevContinuation) {
-      // Ok, we've got the wrong frame.  We have to start from scratch.
-      Reset();
-      Init(aFrame);
-      return;
-    }
-
-    // Get our last frame's size and add its width to our continuation
-    // point before we cache the new frame.
-    mContinuationPoint += mVertical ? mFrame->GetSize().height
-                                    : mFrame->GetSize().width;
-
-    // If this a new line, update mLineContinuationPoint.
-    if (mBidiEnabled &&
-        (aFrame->GetPrevInFlow() || !AreOnSameLine(mFrame, aFrame))) {
-       mLineContinuationPoint = mContinuationPoint;
-    }
-
-    mFrame = aFrame;
-  }
-
-  nsIFrame* GetPrevContinuation(nsIFrame* aFrame)
-  {
-    nsIFrame* prevCont = aFrame->GetPrevContinuation();
-    if (!prevCont &&
-        (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
-      nsIFrame* block =
-        aFrame->Properties().Get(nsIFrame::IBSplitPrevSibling());
-      if (block) {
-        // The {ib} properties are only stored on first continuations
-        NS_ASSERTION(!block->GetPrevContinuation(),
-                     "Incorrect value for IBSplitPrevSibling");
-        prevCont =
-          block->Properties().Get(nsIFrame::IBSplitPrevSibling());
-        NS_ASSERTION(prevCont, "How did that happen?");
-      }
-    }
-    return prevCont;
-  }
-
-  nsIFrame* GetNextContinuation(nsIFrame* aFrame)
-  {
-    nsIFrame* nextCont = aFrame->GetNextContinuation();
-    if (!nextCont &&
-        (aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
-      // The {ib} properties are only stored on first continuations
-      aFrame = aFrame->FirstContinuation();
-      nsIFrame* block = aFrame->Properties().Get(nsIFrame::IBSplitSibling());
-      if (block) {
-        nextCont = block->Properties().Get(nsIFrame::IBSplitSibling());
-        NS_ASSERTION(nextCont, "How did that happen?");
-      }
-    }
-    return nextCont;
-  }
-
-  void Init(nsIFrame* aFrame)
-  {
-    mPIStartBorderData.Reset();
-    mBidiEnabled = aFrame->PresContext()->BidiEnabled();
-    if (mBidiEnabled) {
-      // Find the line container frame
-      mLineContainer = aFrame;
-      while (mLineContainer &&
-             mLineContainer->IsFrameOfType(nsIFrame::eLineParticipant)) {
-        mLineContainer = mLineContainer->GetParent();
-      }
-
-      MOZ_ASSERT(mLineContainer, "Cannot find line containing frame.");
-      MOZ_ASSERT(mLineContainer != aFrame, "line container frame "
-                 "should be an ancestor of the target frame.");
-    }
-
-    mVertical = aFrame->GetWritingMode().IsVertical();
-
-    // Start with the previous flow frame as our continuation point
-    // is the total of the widths of the previous frames.
-    nsIFrame* inlineFrame = GetPrevContinuation(aFrame);
-    while (inlineFrame) {
-      if (!mPIStartBorderData.mFrame &&
-          !(mVertical ? inlineFrame->GetSkipSides().Top()
-                      : inlineFrame->GetSkipSides().Left())) {
-        mPIStartBorderData.mFrame = inlineFrame;
-      }
-      nsRect rect = inlineFrame->GetRect();
-      mContinuationPoint += mVertical ? rect.height : rect.width;
-      if (mBidiEnabled && !AreOnSameLine(aFrame, inlineFrame)) {
-        mLineContinuationPoint += mVertical ? rect.height : rect.width;
-      }
-      mUnbrokenMeasure += mVertical ? rect.height : rect.width;
-      mBoundingBox.UnionRect(mBoundingBox, rect);
-      inlineFrame = GetPrevContinuation(inlineFrame);
-    }
-
-    // Next add this frame and subsequent frames to the bounding box and
-    // unbroken width.
-    inlineFrame = aFrame;
-    while (inlineFrame) {
-      if (!mPIStartBorderData.mFrame &&
-          !(mVertical ? inlineFrame->GetSkipSides().Top()
-                      : inlineFrame->GetSkipSides().Left())) {
-        mPIStartBorderData.mFrame = inlineFrame;
-      }
-      nsRect rect = inlineFrame->GetRect();
-      mUnbrokenMeasure += mVertical ? rect.height : rect.width;
-      mBoundingBox.UnionRect(mBoundingBox, rect);
-      inlineFrame = GetNextContinuation(inlineFrame);
-    }
-
-    mFrame = aFrame;
-  }
-
-  bool AreOnSameLine(nsIFrame* aFrame1, nsIFrame* aFrame2) {
-    if (nsBlockFrame* blockFrame = do_QueryFrame(mLineContainer)) {
-      bool isValid1, isValid2;
-      nsBlockInFlowLineIterator it1(blockFrame, aFrame1, &isValid1);
-      nsBlockInFlowLineIterator it2(blockFrame, aFrame2, &isValid2);
-      return isValid1 && isValid2 &&
-        // Make sure aFrame1 and aFrame2 are in the same continuation of
-        // blockFrame.
-        it1.GetContainer() == it2.GetContainer() &&
-        // And on the same line in it
-        it1.GetLine() == it2.GetLine();
-    }
-    if (nsRubyTextContainerFrame* rtcFrame = do_QueryFrame(mLineContainer)) {
-      nsBlockFrame* block = nsLayoutUtils::FindNearestBlockAncestor(rtcFrame);
-      // Ruby text container can only hold one line of text, so if they
-      // are in the same continuation, they are in the same line. Since
-      // ruby text containers are bidi isolate, they are never split for
-      // bidi reordering, which means being in different continuation
-      // indicates being in different lines.
-      for (nsIFrame* frame = rtcFrame->FirstContinuation();
-           frame; frame = frame->GetNextContinuation()) {
-        bool isDescendant1 =
-          nsLayoutUtils::IsProperAncestorFrame(frame, aFrame1, block);
-        bool isDescendant2 =
-          nsLayoutUtils::IsProperAncestorFrame(frame, aFrame2, block);
-        if (isDescendant1 && isDescendant2) {
-          return true;
-        }
-        if (isDescendant1 || isDescendant2) {
-          return false;
-        }
-      }
-      MOZ_ASSERT_UNREACHABLE("None of the frames is a descendant of this rtc?");
-    }
-    MOZ_ASSERT_UNREACHABLE("Do we have any other type of line container?");
-    return false;
-  }
-};
 
 // A resolved color stop, with a specific position along the gradient line and
 // a color.
 struct ColorStop {
   ColorStop(): mPosition(0), mIsMidpoint(false) {}
   ColorStop(double aPosition, bool aIsMidPoint, const Color& aColor) :
     mPosition(aPosition), mIsMidpoint(aIsMidPoint), mColor(aColor) {}
   double mPosition; // along the gradient line; 0=start, 1=end
   bool mIsMidpoint;
   Color mColor;
 };
 
-/* Local functions */
-static nscolor MakeBevelColor(mozilla::Side whichSide, uint8_t style,
-                              nscolor aBackgroundColor,
-                              nscolor aBorderColor);
-
-static InlineBackgroundData* gInlineBGData = nullptr;
-
-// Initialize any static variables used by nsCSSRendering.
-void nsCSSRendering::Init()
-{
-  NS_ASSERTION(!gInlineBGData, "Init called twice");
-  gInlineBGData = new InlineBackgroundData();
-}
-
-// Clean up any global variables used by nsCSSRendering.
-void nsCSSRendering::Shutdown()
-{
-  delete gInlineBGData;
-  gInlineBGData = nullptr;
-}
-
-/**
- * Make a bevel color
- */
-static nscolor
-MakeBevelColor(mozilla::Side whichSide, uint8_t style,
-               nscolor aBackgroundColor, nscolor aBorderColor)
-{
-
-  nscolor colors[2];
-  nscolor theColor;
-
-  // Given a background color and a border color
-  // calculate the color used for the shading
-  NS_GetSpecial3DColors(colors, aBackgroundColor, aBorderColor);
-
-  if ((style == NS_STYLE_BORDER_STYLE_OUTSET) ||
-      (style == NS_STYLE_BORDER_STYLE_RIDGE)) {
-    // Flip colors for these two border styles
-    switch (whichSide) {
-    case eSideBottom: whichSide = eSideTop;    break;
-    case eSideRight:  whichSide = eSideLeft;   break;
-    case eSideTop:    whichSide = eSideBottom; break;
-    case eSideLeft:   whichSide = eSideRight;  break;
-    }
-  }
-
-  switch (whichSide) {
-  case eSideBottom:
-    theColor = colors[1];
-    break;
-  case eSideRight:
-    theColor = colors[1];
-    break;
-  case eSideTop:
-    theColor = colors[0];
-    break;
-  case eSideLeft:
-  default:
-    theColor = colors[0];
-    break;
-  }
-  return theColor;
-}
-
-static bool
-GetRadii(nsIFrame* aForFrame, const nsStyleBorder& aBorder,
-         const nsRect& aOrigBorderArea, const nsRect& aBorderArea,
-         nscoord aRadii[8])
-{
-  bool haveRoundedCorners;
-  nsSize sz = aBorderArea.Size();
-  nsSize frameSize = aForFrame->GetSize();
-  if (&aBorder == aForFrame->StyleBorder() &&
-      frameSize == aOrigBorderArea.Size()) {
-    haveRoundedCorners = aForFrame->GetBorderRadii(sz, sz, Sides(), aRadii);
-   } else {
-    haveRoundedCorners =
-      nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius, frameSize, sz, Sides(), aRadii);
-  }
-
-  return haveRoundedCorners;
-}
-
-static bool
-GetRadii(nsIFrame* aForFrame, const nsStyleBorder& aBorder,
-         const nsRect& aOrigBorderArea, const nsRect& aBorderArea,
-         RectCornerRadii* aBgRadii)
-{
-  nscoord radii[8];
-  bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aOrigBorderArea, aBorderArea, radii);
-
-  if (haveRoundedCorners) {
-    auto d2a = aForFrame->PresContext()->AppUnitsPerDevPixel();
-    nsCSSRendering::ComputePixelRadii(radii, d2a, aBgRadii);
-  }
-  return haveRoundedCorners;
-}
-
-static nsRect
-JoinBoxesForBlockAxisSlice(nsIFrame* aFrame, const nsRect& aBorderArea)
-{
-  // Inflate the block-axis size as if our continuations were laid out
-  // adjacent in that axis.  Note that we don't touch the inline size.
-  nsRect borderArea = aBorderArea;
-  nscoord bSize = 0;
-  auto wm = aFrame->GetWritingMode();
-  nsIFrame* f = aFrame->GetNextContinuation();
-  for (; f; f = f->GetNextContinuation()) {
-    MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
-               "anonymous ib-split block shouldn't have border/background");
-    bSize += f->BSize(wm);
-  }
-  (wm.IsVertical() ? borderArea.width : borderArea.height) += bSize;
-  bSize = 0;
-  f = aFrame->GetPrevContinuation();
-  for (; f; f = f->GetPrevContinuation()) {
-    MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
-               "anonymous ib-split block shouldn't have border/background");
-    bSize += f->BSize(wm);
-  }
-  (wm.IsVertical() ? borderArea.x : borderArea.y) -= bSize;
-  (wm.IsVertical() ? borderArea.width : borderArea.height) += bSize;
-  return borderArea;
-}
-
-/**
- * Inflate aBorderArea which is relative to aFrame's origin to calculate
- * a hypothetical non-split frame area for all the continuations.
- * See "Joining Boxes for 'slice'" in
- * http://dev.w3.org/csswg/css-break/#break-decoration
- */
-enum InlineBoxOrder { eForBorder, eForBackground };
-static nsRect
-JoinBoxesForSlice(nsIFrame* aFrame, const nsRect& aBorderArea,
-                  InlineBoxOrder aOrder)
-{
-  if (static_cast<nsInlineFrame*>(do_QueryFrame(aFrame))) {
-    return (aOrder == eForBorder
-            ? gInlineBGData->GetBorderContinuousRect(aFrame, aBorderArea)
-            : gInlineBGData->GetContinuousRect(aFrame)) +
-      aBorderArea.TopLeft();
-  }
-  return JoinBoxesForBlockAxisSlice(aFrame, aBorderArea);
-}
-
-static bool
-IsBoxDecorationSlice(const nsStyleBorder& aStyleBorder)
-{
-  return aStyleBorder.mBoxDecorationBreak == StyleBoxDecorationBreak::Slice;
-}
-
-static nsRect
-BoxDecorationRectForBorder(nsIFrame* aFrame, const nsRect& aBorderArea,
-                           Sides aSkipSides,
-                           const nsStyleBorder* aStyleBorder = nullptr)
-{
-  if (!aStyleBorder) {
-    aStyleBorder = aFrame->StyleBorder();
-  }
-  // If aSkipSides.IsEmpty() then there are no continuations, or it's
-  // a ::first-letter that wants all border sides on the first continuation.
-  return ::IsBoxDecorationSlice(*aStyleBorder) && !aSkipSides.IsEmpty()
-           ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBorder)
-           : aBorderArea;
-}
-
-static nsRect
-BoxDecorationRectForBackground(nsIFrame* aFrame, const nsRect& aBorderArea,
-                               Sides aSkipSides,
-                               const nsStyleBorder* aStyleBorder = nullptr)
-{
-  if (!aStyleBorder) {
-    aStyleBorder = aFrame->StyleBorder();
-  }
-  // If aSkipSides.IsEmpty() then there are no continuations, or it's
-  // a ::first-letter that wants all border sides on the first continuation.
-  return ::IsBoxDecorationSlice(*aStyleBorder) && !aSkipSides.IsEmpty()
-           ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBackground)
-           : aBorderArea;
-}
-
-//----------------------------------------------------------------------
-// Thebes Border Rendering Code Start
-
-/*
- * Compute the float-pixel radii that should be used for drawing
- * this border/outline, given the various input bits.
- */
-/* static */ void
-nsCSSRendering::ComputePixelRadii(const nscoord *aAppUnitsRadii,
-                                  nscoord aAppUnitsPerPixel,
-                                  RectCornerRadii *oBorderRadii)
-{
-  Float radii[8];
-  NS_FOR_CSS_HALF_CORNERS(corner)
-    radii[corner] = Float(aAppUnitsRadii[corner]) / aAppUnitsPerPixel;
-
-  (*oBorderRadii)[C_TL] = Size(radii[eCornerTopLeftX],
-                               radii[eCornerTopLeftY]);
-  (*oBorderRadii)[C_TR] = Size(radii[eCornerTopRightX],
-                               radii[eCornerTopRightY]);
-  (*oBorderRadii)[C_BR] = Size(radii[eCornerBottomRightX],
-                               radii[eCornerBottomRightY]);
-  (*oBorderRadii)[C_BL] = Size(radii[eCornerBottomLeftX],
-                               radii[eCornerBottomLeftY]);
-}
-
-DrawResult
-nsCSSRendering::PaintBorder(nsPresContext* aPresContext,
-                            nsRenderingContext& aRenderingContext,
-                            nsIFrame* aForFrame,
-                            const nsRect& aDirtyRect,
-                            const nsRect& aBorderArea,
-                            nsStyleContext* aStyleContext,
-                            PaintBorderFlags aFlags,
-                            Sides aSkipSides)
-{
-  PROFILER_LABEL("nsCSSRendering", "PaintBorder",
-    js::ProfileEntry::Category::GRAPHICS);
-
-  nsStyleContext *styleIfVisited = aStyleContext->GetStyleIfVisited();
-  const nsStyleBorder *styleBorder = aStyleContext->StyleBorder();
-  // Don't check RelevantLinkVisited here, since we want to take the
-  // same amount of time whether or not it's true.
-  if (!styleIfVisited) {
-    return PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
-                                      aDirtyRect, aBorderArea, *styleBorder,
-                                      aStyleContext, aFlags, aSkipSides);
-  }
-
-  nsStyleBorder newStyleBorder(*styleBorder);
-
-  NS_FOR_CSS_SIDES(side) {
-    nscolor color = aStyleContext->
-      GetVisitedDependentColor(nsStyleBorder::BorderColorFieldFor(side));
-    newStyleBorder.mBorderColor[side] = StyleComplexColor::FromColor(color);
-  }
-  return PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
-                                    aDirtyRect, aBorderArea, newStyleBorder,
-                                    aStyleContext, aFlags, aSkipSides);
-}
-
-Maybe<nsCSSBorderRenderer>
-nsCSSRendering::CreateBorderRenderer(nsPresContext* aPresContext,
-                                     DrawTarget* aDrawTarget,
-                                     nsIFrame* aForFrame,
-                                     const nsRect& aDirtyRect,
-                                     const nsRect& aBorderArea,
-                                     nsStyleContext* aStyleContext,
-                                     Sides aSkipSides)
-{
-  nsStyleContext *styleIfVisited = aStyleContext->GetStyleIfVisited();
-  const nsStyleBorder *styleBorder = aStyleContext->StyleBorder();
-  // Don't check RelevantLinkVisited here, since we want to take the
-  // same amount of time whether or not it's true.
-  if (!styleIfVisited) {
-    return CreateBorderRendererWithStyleBorder(aPresContext, aDrawTarget,
-                                               aForFrame, aDirtyRect,
-                                               aBorderArea, *styleBorder,
-                                               aStyleContext, aSkipSides);
-  }
-
-  nsStyleBorder newStyleBorder(*styleBorder);
-
-  NS_FOR_CSS_SIDES(side) {
-    nscolor color = aStyleContext->
-      GetVisitedDependentColor(nsStyleBorder::BorderColorFieldFor(side));
-    newStyleBorder.mBorderColor[side] = StyleComplexColor::FromColor(color);
-  }
-  return CreateBorderRendererWithStyleBorder(aPresContext, aDrawTarget,
-                                             aForFrame, aDirtyRect, aBorderArea,
-                                             newStyleBorder, aStyleContext,
-                                             aSkipSides);
-}
-
-nsCSSBorderRenderer
-ConstructBorderRenderer(nsPresContext* aPresContext,
-                        nsStyleContext* aStyleContext,
-                        DrawTarget* aDrawTarget,
-                        nsIFrame* aForFrame,
-                        const nsRect& aDirtyRect,
-                        const nsRect& aBorderArea,
-                        const nsStyleBorder& aStyleBorder,
-                        Sides aSkipSides,
-                        bool* aNeedsClip)
-{
-  nsMargin border = aStyleBorder.GetComputedBorder();
-
-  // Get our style context's color struct.
-  const nsStyleColor* ourColor = aStyleContext->StyleColor();
-
-  // In NavQuirks mode we want to use the parent's context as a starting point
-  // for determining the background color.
-  bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
-  nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(aForFrame, quirks);
-  nsStyleContext* bgContext = bgFrame->StyleContext();
-  nscolor bgColor = bgContext->
-    GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
-
-  // Compute the outermost boundary of the area that might be painted.
-  // Same coordinate space as aBorderArea & aBGClipRect.
-  nsRect joinedBorderArea =
-    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, aSkipSides, &aStyleBorder);
-  RectCornerRadii bgRadii;
-  ::GetRadii(aForFrame, aStyleBorder, aBorderArea, joinedBorderArea, &bgRadii);
-
-  PrintAsFormatString(" joinedBorderArea: %d %d %d %d\n", joinedBorderArea.x, joinedBorderArea.y,
-     joinedBorderArea.width, joinedBorderArea.height);
-
-  // start drawing
-  if (::IsBoxDecorationSlice(aStyleBorder)) {
-    if (joinedBorderArea.IsEqualEdges(aBorderArea)) {
-      // No need for a clip, just skip the sides we don't want.
-      border.ApplySkipSides(aSkipSides);
-    } else {
-      // We're drawing borders around the joined continuation boxes so we need
-      // to clip that to the slice that we want for this frame.
-      *aNeedsClip = true;
-    }
-  } else {
-    MOZ_ASSERT(joinedBorderArea.IsEqualEdges(aBorderArea),
-               "Should use aBorderArea for box-decoration-break:clone");
-    MOZ_ASSERT(aForFrame->GetSkipSides().IsEmpty() ||
-               IS_TRUE_OVERFLOW_CONTAINER(aForFrame),
-               "Should not skip sides for box-decoration-break:clone except "
-               "::first-letter/line continuations or other frame types that "
-               "don't have borders but those shouldn't reach this point. "
-               "Overflow containers do reach this point though.");
-    border.ApplySkipSides(aSkipSides);
-  }
-
-  // Convert to dev pixels.
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-  Rect joinedBorderAreaPx = NSRectToRect(joinedBorderArea, twipsPerPixel);
-  Float borderWidths[4] = { Float(border.top) / twipsPerPixel,
-                                   Float(border.right) / twipsPerPixel,
-                                   Float(border.bottom) / twipsPerPixel,
-                                   Float(border.left) / twipsPerPixel };
-  Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel);
-
-  uint8_t borderStyles[4];
-  nscolor borderColors[4];
-  nsBorderColors* compositeColors[4];
-
-  // pull out styles, colors, composite colors
-  NS_FOR_CSS_SIDES (i) {
-    borderStyles[i] = aStyleBorder.GetBorderStyle(i);
-    borderColors[i] = ourColor->CalcComplexColor(aStyleBorder.mBorderColor[i]);
-    aStyleBorder.GetCompositeColors(i, &compositeColors[i]);
-  }
-
-  PrintAsFormatString(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
-
-  nsIDocument* document = nullptr;
-  nsIContent* content = aForFrame->GetContent();
-  if (content) {
-    document = content->OwnerDoc();
-  }
-
-  return nsCSSBorderRenderer(aPresContext,
-                             document,
-                             aDrawTarget,
-                             dirtyRect,
-                             joinedBorderAreaPx,
-                             borderStyles,
-                             borderWidths,
-                             bgRadii,
-                             borderColors,
-                             compositeColors,
-                             bgColor);
-}
-
-
-DrawResult
-nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
-                                           nsRenderingContext& aRenderingContext,
-                                           nsIFrame* aForFrame,
-                                           const nsRect& aDirtyRect,
-                                           const nsRect& aBorderArea,
-                                           const nsStyleBorder& aStyleBorder,
-                                           nsStyleContext* aStyleContext,
-                                           PaintBorderFlags aFlags,
-                                           Sides aSkipSides)
-{
-  DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget();
-
-  PrintAsStringNewline("++ PaintBorder");
-
-  // Check to see if we have an appearance defined.  If so, we let the theme
-  // renderer draw the border.  DO not get the data from aForFrame, since the passed in style context
-  // may be different!  Always use |aStyleContext|!
-  const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
-  if (displayData->UsedAppearance()) {
-    nsITheme *theme = aPresContext->GetTheme();
-    if (theme &&
-        theme->ThemeSupportsWidget(aPresContext, aForFrame,
-                                   displayData->UsedAppearance())) {
-      return DrawResult::SUCCESS; // Let the theme handle it.
-    }
-  }
-
-  if (aStyleBorder.IsBorderImageLoaded()) {
-    DrawResult result;
-
-    uint32_t irFlags = 0;
-    if (aFlags & PaintBorderFlags::SYNC_DECODE_IMAGES) {
-      irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
-    }
-
-    Maybe<nsCSSBorderImageRenderer> renderer =
-      nsCSSBorderImageRenderer::CreateBorderImageRenderer(aPresContext, aForFrame, aBorderArea,
-                                                          aStyleBorder, aDirtyRect, aSkipSides,
-                                                          irFlags, &result);
-    if (!renderer) {
-      return result;
-    }
-
-    return renderer->DrawBorderImage(aPresContext, aRenderingContext,
-                                     aForFrame, aDirtyRect);
-  }
-
-  DrawResult result = DrawResult::SUCCESS;
-
-  // If we had a border-image, but it wasn't loaded, then we should return
-  // DrawResult::NOT_READY; we'll want to try again if we do a paint with sync
-  // decoding enabled.
-  if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
-    result = DrawResult::NOT_READY;
-  }
-
-  nsMargin border = aStyleBorder.GetComputedBorder();
-  if (0 == border.left && 0 == border.right &&
-      0 == border.top  && 0 == border.bottom) {
-    // Empty border area
-    return result;
-  }
-
-  bool needsClip = false;
-  nsCSSBorderRenderer br = ConstructBorderRenderer(aPresContext,
-                                                   aStyleContext,
-                                                   &aDrawTarget,
-                                                   aForFrame,
-                                                   aDirtyRect,
-                                                   aBorderArea,
-                                                   aStyleBorder,
-                                                   aSkipSides,
-                                                   &needsClip);
-  if (needsClip) {
-    aDrawTarget.PushClipRect(
-        NSRectToSnappedRect(aBorderArea,
-                            aForFrame->PresContext()->AppUnitsPerDevPixel(),
-                            aDrawTarget));
-  }
-
-  br.DrawBorders();
-
-  if (needsClip) {
-    aDrawTarget.PopClip();
-  }
-
-  PrintAsStringNewline();
-
-  return result;
-}
-
-Maybe<nsCSSBorderRenderer>
-nsCSSRendering::CreateBorderRendererWithStyleBorder(nsPresContext* aPresContext,
-                                                    DrawTarget* aDrawTarget,
-                                                    nsIFrame* aForFrame,
-                                                    const nsRect& aDirtyRect,
-                                                    const nsRect& aBorderArea,
-                                                    const nsStyleBorder& aStyleBorder,
-                                                    nsStyleContext* aStyleContext,
-                                                    Sides aSkipSides)
-{
-  const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
-  if (displayData->UsedAppearance()) {
-    nsITheme *theme = aPresContext->GetTheme();
-    if (theme &&
-        theme->ThemeSupportsWidget(aPresContext, aForFrame,
-                                   displayData->UsedAppearance())) {
-      return Nothing();
-    }
-  }
-
-  if (aStyleBorder.mBorderImageSource.GetType() != eStyleImageType_Null) {
-    return Nothing();
-  }
-
-  nsMargin border = aStyleBorder.GetComputedBorder();
-  if (0 == border.left && 0 == border.right &&
-      0 == border.top  && 0 == border.bottom) {
-    // Empty border area
-    return Nothing();
-  }
-
-  bool needsClip = false;
-  nsCSSBorderRenderer br = ConstructBorderRenderer(aPresContext,
-                                                   aStyleContext,
-                                                   aDrawTarget,
-                                                   aForFrame,
-                                                   aDirtyRect,
-                                                   aBorderArea,
-                                                   aStyleBorder,
-                                                   aSkipSides,
-                                                   &needsClip);
-  if (needsClip) {
-    return Nothing();
-  }
-  return Some(br);
-}
-
-static nsRect
-GetOutlineInnerRect(nsIFrame* aFrame)
-{
-  nsRect* savedOutlineInnerRect =
-    aFrame->Properties().Get(nsIFrame::OutlineInnerRectProperty());
-  if (savedOutlineInnerRect)
-    return *savedOutlineInnerRect;
-  NS_NOTREACHED("we should have saved a frame property");
-  return nsRect(nsPoint(0, 0), aFrame->GetSize());
-}
-
-Maybe<nsCSSBorderRenderer>
-nsCSSRendering::CreateBorderRendererForOutline(nsPresContext* aPresContext,
-                                               nsRenderingContext* aRenderingContext,
-                                               nsIFrame* aForFrame,
-                                               const nsRect& aDirtyRect,
-                                               const nsRect& aBorderArea,
-                                               nsStyleContext* aStyleContext)
-{
-  nscoord             twipsRadii[8];
-
-  // Get our style context's color struct.
-  const nsStyleOutline* ourOutline = aStyleContext->StyleOutline();
-
-  if (!ourOutline->ShouldPaintOutline()) {
-    // Empty outline
-    return Nothing();
-  }
-
-  nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame
-    (aForFrame, false);
-  nsStyleContext* bgContext = bgFrame->StyleContext();
-  nscolor bgColor = bgContext->
-    GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
-
-  nsRect innerRect;
-  if (
-#ifdef MOZ_XUL
-      aStyleContext->GetPseudoType() == CSSPseudoElementType::XULTree
-#else
-      false
-#endif
-     ) {
-    innerRect = aBorderArea;
-  } else {
-    innerRect = GetOutlineInnerRect(aForFrame) + aBorderArea.TopLeft();
-  }
-  nscoord offset = ourOutline->mOutlineOffset;
-  innerRect.Inflate(offset, offset);
-  // If the dirty rect is completely inside the border area (e.g., only the
-  // content is being painted), then we can skip out now
-  // XXX this isn't exactly true for rounded borders, where the inside curves may
-  // encroach into the content area.  A safer calculation would be to
-  // shorten insideRect by the radius one each side before performing this test.
-  if (innerRect.Contains(aDirtyRect))
-    return Nothing();
-
-  nscoord width = ourOutline->GetOutlineWidth();
-
-  nsRect outerRect = innerRect;
-  outerRect.Inflate(width, width);
-
-  // get the radius for our outline
-  nsIFrame::ComputeBorderRadii(ourOutline->mOutlineRadius, aBorderArea.Size(),
-                               outerRect.Size(), Sides(), twipsRadii);
-
-  // Get our conversion values
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
-  // get the outer rectangles
-  Rect oRect(NSRectToRect(outerRect, twipsPerPixel));
-
-  // convert the radii
-  nsMargin outlineMargin(width, width, width, width);
-  RectCornerRadii outlineRadii;
-  ComputePixelRadii(twipsRadii, twipsPerPixel, &outlineRadii);
-
-  uint8_t outlineStyle = ourOutline->mOutlineStyle;
-  if (outlineStyle == NS_STYLE_BORDER_STYLE_AUTO) {
-    if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) {
-      nsITheme* theme = aPresContext->GetTheme();
-      if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame,
-                                              NS_THEME_FOCUS_OUTLINE)) {
-        theme->DrawWidgetBackground(aRenderingContext, aForFrame,
-                                    NS_THEME_FOCUS_OUTLINE, innerRect,
-                                    aDirtyRect);
-        return Nothing();
-      }
-    }
-    if (width == 0) {
-      return Nothing(); // empty outline
-    }
-    // http://dev.w3.org/csswg/css-ui/#outline
-    // "User agents may treat 'auto' as 'solid'."
-    outlineStyle = NS_STYLE_BORDER_STYLE_SOLID;
-  }
-
-  uint8_t outlineStyles[4] = { outlineStyle, outlineStyle,
-                               outlineStyle, outlineStyle };
-
-  // This handles treating the initial color as 'currentColor'; if we
-  // ever want 'invert' back we'll need to do a bit of work here too.
-  nscolor outlineColor =
-    aStyleContext->GetVisitedDependentColor(&nsStyleOutline::mOutlineColor);
-  nscolor outlineColors[4] = { outlineColor,
-                               outlineColor,
-                               outlineColor,
-                               outlineColor };
-
-  // convert the border widths
-  Float outlineWidths[4] = { Float(width / twipsPerPixel),
-                             Float(width / twipsPerPixel),
-                             Float(width / twipsPerPixel),
-                             Float(width / twipsPerPixel) };
-  Rect dirtyRect = NSRectToRect(aDirtyRect, twipsPerPixel);
-
-  nsIDocument* document = nullptr;
-  nsIContent* content = aForFrame->GetContent();
-  if (content) {
-    document = content->OwnerDoc();
-  }
-
-  DrawTarget* dt = aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
-  nsCSSBorderRenderer br(aPresContext,
-                         document,
-                         dt,
-                         dirtyRect,
-                         oRect,
-                         outlineStyles,
-                         outlineWidths,
-                         outlineRadii,
-                         outlineColors,
-                         nullptr,
-                         bgColor);
-
-  return Some(br);
-}
-
-void
-nsCSSRendering::PaintOutline(nsPresContext* aPresContext,
-                             nsRenderingContext& aRenderingContext,
-                             nsIFrame* aForFrame,
-                             const nsRect& aDirtyRect,
-                             const nsRect& aBorderArea,
-                             nsStyleContext* aStyleContext)
-{
-  Maybe<nsCSSBorderRenderer> br = CreateBorderRendererForOutline(aPresContext,
-                                                                 &aRenderingContext,
-                                                                 aForFrame,
-                                                                 aDirtyRect,
-                                                                 aBorderArea,
-                                                                 aStyleContext);
-  if (!br) {
-    return;
-  }
-
-  // start drawing
-  br->DrawBorders();
-
-  PrintAsStringNewline();
-}
-
-void
-nsCSSRendering::PaintFocus(nsPresContext* aPresContext,
-                           DrawTarget* aDrawTarget,
-                           const nsRect& aFocusRect,
-                           nscolor aColor)
-{
-  nscoord oneCSSPixel = nsPresContext::CSSPixelsToAppUnits(1);
-  nscoord oneDevPixel = aPresContext->DevPixelsToAppUnits(1);
-
-  Rect focusRect(NSRectToRect(aFocusRect, oneDevPixel));
-
-  RectCornerRadii focusRadii;
-  {
-    nscoord twipsRadii[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-    ComputePixelRadii(twipsRadii, oneDevPixel, &focusRadii);
-  }
-  Float focusWidths[4] = { Float(oneCSSPixel / oneDevPixel),
-                           Float(oneCSSPixel / oneDevPixel),
-                           Float(oneCSSPixel / oneDevPixel),
-                           Float(oneCSSPixel / oneDevPixel) };
-
-  uint8_t focusStyles[4] = { NS_STYLE_BORDER_STYLE_DOTTED,
-                             NS_STYLE_BORDER_STYLE_DOTTED,
-                             NS_STYLE_BORDER_STYLE_DOTTED,
-                             NS_STYLE_BORDER_STYLE_DOTTED };
-  nscolor focusColors[4] = { aColor, aColor, aColor, aColor };
-
-  // Because this renders a dotted border, the background color
-  // should not be used.  Therefore, we provide a value that will
-  // be blatantly wrong if it ever does get used.  (If this becomes
-  // something that CSS can style, this function will then have access
-  // to a style context and can use the same logic that PaintBorder
-  // and PaintOutline do.)
-  nsCSSBorderRenderer br(aPresContext,
-                         nullptr,
-                         aDrawTarget,
-                         focusRect,
-                         focusRect,
-                         focusStyles,
-                         focusWidths,
-                         focusRadii,
-                         focusColors,
-                         nullptr,
-                         NS_RGB(255, 0, 0));
-  br.DrawBorders();
-
-  PrintAsStringNewline();
-}
-
-// Thebes Border Rendering Code End
-//----------------------------------------------------------------------
-
-
-//----------------------------------------------------------------------
-
-/**
- * Helper for ComputeObjectAnchorPoint; parameters are the same as for
- * that function, except they're for a single coordinate / a single size
- * dimension. (so, x/width vs. y/height)
- */
-static void
-ComputeObjectAnchorCoord(const Position::Coord& aCoord,
-                         const nscoord aOriginBounds,
-                         const nscoord aImageSize,
-                         nscoord* aTopLeftCoord,
-                         nscoord* aAnchorPointCoord)
-{
-  *aAnchorPointCoord = aCoord.mLength;
-  *aTopLeftCoord = aCoord.mLength;
-
-  if (aCoord.mHasPercent) {
-    // Adjust aTopLeftCoord by the specified % of the extra space.
-    nscoord extraSpace = aOriginBounds - aImageSize;
-    *aTopLeftCoord += NSToCoordRound(aCoord.mPercent * extraSpace);
-
-    // The anchor-point doesn't care about our image's size; just the size
-    // of the region we're rendering into.
-    *aAnchorPointCoord += NSToCoordRound(aCoord.mPercent * aOriginBounds);
-  }
-}
-
-void
-nsImageRenderer::ComputeObjectAnchorPoint(
-  const Position& aPos,
-  const nsSize& aOriginBounds,
-  const nsSize& aImageSize,
-  nsPoint* aTopLeft,
-  nsPoint* aAnchorPoint)
-{
-  ComputeObjectAnchorCoord(aPos.mXPosition,
-                           aOriginBounds.width, aImageSize.width,
-                           &aTopLeft->x, &aAnchorPoint->x);
-
-  ComputeObjectAnchorCoord(aPos.mYPosition,
-                           aOriginBounds.height, aImageSize.height,
-                           &aTopLeft->y, &aAnchorPoint->y);
-}
-
-nsIFrame*
-nsCSSRendering::FindNonTransparentBackgroundFrame(nsIFrame* aFrame,
-                                                  bool aStartAtParent /*= false*/)
-{
-  NS_ASSERTION(aFrame, "Cannot find NonTransparentBackgroundFrame in a null frame");
-
-  nsIFrame* frame = nullptr;
-  if (aStartAtParent) {
-    frame = nsLayoutUtils::GetParentOrPlaceholderFor(aFrame);
-  }
-  if (!frame) {
-    frame = aFrame;
-  }
-
-  while (frame) {
-    // No need to call GetVisitedDependentColor because it always uses
-    // this alpha component anyway.
-    if (NS_GET_A(frame->StyleBackground()->BackgroundColor(frame)) > 0) {
-      break;
-    }
-
-    if (frame->IsThemed())
-      break;
-
-    nsIFrame* parent = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
-    if (!parent)
-      break;
-
-    frame = parent;
-  }
-  return frame;
-}
-
-// Returns true if aFrame is a canvas frame.
-// We need to treat the viewport as canvas because, even though
-// it does not actually paint a background, we need to get the right
-// background style so we correctly detect transparent documents.
-bool
-nsCSSRendering::IsCanvasFrame(nsIFrame* aFrame)
-{
-  nsIAtom* frameType = aFrame->GetType();
-  return frameType == nsGkAtoms::canvasFrame ||
-         frameType == nsGkAtoms::rootFrame ||
-         frameType == nsGkAtoms::pageContentFrame ||
-         frameType == nsGkAtoms::viewportFrame;
-}
-
-nsIFrame*
-nsCSSRendering::FindBackgroundStyleFrame(nsIFrame* aForFrame)
-{
-  const nsStyleBackground* result = aForFrame->StyleBackground();
-
-  // Check if we need to do propagation from BODY rather than HTML.
-  if (!result->IsTransparent(aForFrame)) {
-    return aForFrame;
-  }
-
-  nsIContent* content = aForFrame->GetContent();
-  // The root element content can't be null. We wouldn't know what
-  // frame to create for aFrame.
-  // Use |OwnerDoc| so it works during destruction.
-  if (!content) {
-    return aForFrame;
-  }
-
-  nsIDocument* document = content->OwnerDoc();
-
-  dom::Element* bodyContent = document->GetBodyElement();
-  // We need to null check the body node (bug 118829) since
-  // there are cases, thanks to the fix for bug 5569, where we
-  // will reflow a document with no body.  In particular, if a
-  // SCRIPT element in the head blocks the parser and then has a
-  // SCRIPT that does "document.location.href = 'foo'", then
-  // nsParser::Terminate will call |DidBuildModel| methods
-  // through to the content sink, which will call |StartLayout|
-  // and thus |Initialize| on the pres shell.  See bug 119351
-  // for the ugly details.
-  if (!bodyContent) {
-    return aForFrame;
-  }
-
-  nsIFrame *bodyFrame = bodyContent->GetPrimaryFrame();
-  if (!bodyFrame) {
-    return aForFrame;
-  }
-
-  return nsLayoutUtils::GetStyleFrame(bodyFrame);
-}
-
-/**
- * |FindBackground| finds the correct style data to use to paint the
- * background.  It is responsible for handling the following two
- * statements in section 14.2 of CSS2:
- *
- *   The background of the box generated by the root element covers the
- *   entire canvas.
- *
- *   For HTML documents, however, we recommend that authors specify the
- *   background for the BODY element rather than the HTML element. User
- *   agents should observe the following precedence rules to fill in the
- *   background: if the value of the 'background' property for the HTML
- *   element is different from 'transparent' then use it, else use the
- *   value of the 'background' property for the BODY element. If the
- *   resulting value is 'transparent', the rendering is undefined.
- *
- * Thus, in our implementation, it is responsible for ensuring that:
- *  + we paint the correct background on the |nsCanvasFrame|,
- *    |nsRootBoxFrame|, or |nsPageFrame|,
- *  + we don't paint the background on the root element, and
- *  + we don't paint the background on the BODY element in *some* cases,
- *    and for SGML-based HTML documents only.
- *
- * |FindBackground| returns true if a background should be painted, and
- * the resulting style context to use for the background information
- * will be filled in to |aBackground|.
- */
-nsStyleContext*
-nsCSSRendering::FindRootFrameBackground(nsIFrame* aForFrame)
-{
-  return FindBackgroundStyleFrame(aForFrame)->StyleContext();
-}
-
-inline bool
-FindElementBackground(nsIFrame* aForFrame, nsIFrame* aRootElementFrame,
-                      nsStyleContext** aBackgroundSC)
-{
-  if (aForFrame == aRootElementFrame) {
-    // We must have propagated our background to the viewport or canvas. Abort.
-    return false;
-  }
-
-  *aBackgroundSC = aForFrame->StyleContext();
-
-  // Return true unless the frame is for a BODY element whose background
-  // was propagated to the viewport.
-
-  nsIContent* content = aForFrame->GetContent();
-  if (!content || content->NodeInfo()->NameAtom() != nsGkAtoms::body)
-    return true; // not frame for a "body" element
-  // It could be a non-HTML "body" element but that's OK, we'd fail the
-  // bodyContent check below
-
-  if (aForFrame->StyleContext()->GetPseudo())
-    return true; // A pseudo-element frame.
-
-  // We should only look at the <html> background if we're in an HTML document
-  nsIDocument* document = content->OwnerDoc();
-
-  dom::Element* bodyContent = document->GetBodyElement();
-  if (bodyContent != content)
-    return true; // this wasn't the background that was propagated
-
-  // This can be called even when there's no root element yet, during frame
-  // construction, via nsLayoutUtils::FrameHasTransparency and
-  // nsContainerFrame::SyncFrameViewProperties.
-  if (!aRootElementFrame)
-    return true;
-
-  const nsStyleBackground* htmlBG = aRootElementFrame->StyleBackground();
-  return !htmlBG->IsTransparent(aRootElementFrame);
-}
-
-bool
-nsCSSRendering::FindBackground(nsIFrame* aForFrame,
-                               nsStyleContext** aBackgroundSC)
-{
-  nsIFrame* rootElementFrame =
-    aForFrame->PresContext()->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
-  if (IsCanvasFrame(aForFrame)) {
-    *aBackgroundSC = FindCanvasBackground(aForFrame, rootElementFrame);
-    return true;
-  } else {
-    return FindElementBackground(aForFrame, rootElementFrame, aBackgroundSC);
-  }
-}
-
-void
-nsCSSRendering::BeginFrameTreesLocked()
-{
-  ++gFrameTreeLockCount;
-}
-
-void
-nsCSSRendering::EndFrameTreesLocked()
-{
-  NS_ASSERTION(gFrameTreeLockCount > 0, "Unbalanced EndFrameTreeLocked");
-  --gFrameTreeLockCount;
-  if (gFrameTreeLockCount == 0) {
-    gInlineBGData->Reset();
-  }
-}
-
-bool
-nsCSSRendering::HasBoxShadowNativeTheme(nsIFrame* aFrame,
-                                        bool& aMaybeHasBorderRadius)
-{
-  const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
-  nsITheme::Transparency transparency;
-  if (aFrame->IsThemed(styleDisplay, &transparency)) {
-    aMaybeHasBorderRadius = false;
-    // For opaque (rectangular) theme widgets we can take the generic
-    // border-box path with border-radius disabled.
-    return transparency != nsITheme::eOpaque;
-  }
-
-  aMaybeHasBorderRadius = true;
-  return false;
-}
-
-gfx::Color
-nsCSSRendering::GetShadowColor(nsCSSShadowItem* aShadow,
-                               nsIFrame* aFrame,
-                               float aOpacity)
-{
-  // Get the shadow color; if not specified, use the foreground color
-  nscolor shadowColor;
-  if (aShadow->mHasColor)
-    shadowColor = aShadow->mColor;
-  else
-    shadowColor = aFrame->StyleColor()->mColor;
-
-  Color color = Color::FromABGR(shadowColor);
-  color.a *= aOpacity;
-  return color;
-}
-
-nsRect
-nsCSSRendering::GetShadowRect(const nsRect aFrameArea,
-                              bool aNativeTheme,
-                              nsIFrame* aForFrame)
-{
-  nsRect frameRect = aNativeTheme ?
-    aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
-    aFrameArea;
-  Sides skipSides = aForFrame->GetSkipSides();
-  frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides);
-
-  // Explicitly do not need to account for the spread radius here
-  // Webrender does it for us or PaintBoxShadow will for non-WR
-  return frameRect;
-}
-
-bool
-nsCSSRendering::GetBorderRadii(const nsRect& aFrameRect,
-                               const nsRect& aBorderRect,
-                               nsIFrame* aFrame,
-                               RectCornerRadii& aOutRadii)
-{
-  const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
-  nscoord twipsRadii[8];
-  NS_ASSERTION(aBorderRect.Size() == aFrame->VisualBorderRectRelativeToSelf().Size(),
-              "unexpected size");
-  nsSize sz = aFrameRect.Size();
-  bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
-  if (hasBorderRadius) {
-    ComputePixelRadii(twipsRadii, twipsPerPixel, &aOutRadii);
-  }
-
-  return hasBorderRadius;
-}
-
-void
-nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
-                                    nsRenderingContext& aRenderingContext,
-                                    nsIFrame* aForFrame,
-                                    const nsRect& aFrameArea,
-                                    const nsRect& aDirtyRect,
-                                    float aOpacity)
-{
-  DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget();
-  nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
-  if (!shadows)
-    return;
-
-  bool hasBorderRadius;
-  // mutually exclusive with hasBorderRadius
-  bool nativeTheme = HasBoxShadowNativeTheme(aForFrame, hasBorderRadius);
-  const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
-
-  nsRect frameRect = GetShadowRect(aFrameArea, nativeTheme, aForFrame);
-
-  // Get any border radius, since box-shadow must also have rounded corners if
-  // the frame does.
-  RectCornerRadii borderRadii;
-  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-  if (hasBorderRadius) {
-    nscoord twipsRadii[8];
-    NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
-                 "unexpected size");
-    nsSize sz = frameRect.Size();
-    hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
-    if (hasBorderRadius) {
-      ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
-    }
-  }
-
-
-  // We don't show anything that intersects with the frame we're blurring on. So tell the
-  // blurrer not to do unnecessary work there.
-  gfxRect skipGfxRect = ThebesRect(NSRectToRect(frameRect, twipsPerPixel));
-  skipGfxRect.Round();
-  bool useSkipGfxRect = true;
-  if (nativeTheme) {
-    // Optimize non-leaf native-themed frames by skipping computing pixels
-    // in the padding-box. We assume the padding-box is going to be painted
-    // opaquely for non-leaf frames.
-    // XXX this may not be a safe assumption; we should make this go away
-    // by optimizing box-shadow drawing more for the cases where we don't have a skip-rect.
-    useSkipGfxRect = !aForFrame->IsLeaf();
-    nsRect paddingRect =
-      aForFrame->GetPaddingRect() - aForFrame->GetPosition() + aFrameArea.TopLeft();
-    skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
-  } else if (hasBorderRadius) {
-    skipGfxRect.Deflate(gfxMargin(
-        std::max(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
-        std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
-  }
-
-  gfxContext* renderContext = aRenderingContext.ThebesContext();
-
-  for (uint32_t i = shadows->Length(); i > 0; --i) {
-    nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
-    if (shadowItem->mInset)
-      continue;
-
-    nsRect shadowRect = frameRect;
-    shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
-    if (!nativeTheme) {
-      shadowRect.Inflate(shadowItem->mSpread, shadowItem->mSpread);
-    }
-
-    // shadowRect won't include the blur, so make an extra rect here that includes the blur
-    // for use in the even-odd rule below.
-    nsRect shadowRectPlusBlur = shadowRect;
-    nscoord blurRadius = shadowItem->mRadius;
-    shadowRectPlusBlur.Inflate(
-      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel));
-
-    Rect shadowGfxRectPlusBlur =
-      NSRectToRect(shadowRectPlusBlur, twipsPerPixel);
-    shadowGfxRectPlusBlur.RoundOut();
-    MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true);
-
-    Color gfxShadowColor = GetShadowColor(shadowItem, aForFrame, aOpacity);
-
-    if (nativeTheme) {
-      nsContextBoxBlur blurringArea;
-
-      // When getting the widget shape from the native theme, we're going
-      // to draw the widget into the shadow surface to create a mask.
-      // We need to ensure that there actually *is* a shadow surface
-      // and that we're not going to draw directly into renderContext.
-      gfxContext* shadowContext =
-        blurringArea.Init(shadowRect, shadowItem->mSpread,
-                          blurRadius, twipsPerPixel, renderContext, aDirtyRect,
-                          useSkipGfxRect ? &skipGfxRect : nullptr,
-                          nsContextBoxBlur::FORCE_MASK);
-      if (!shadowContext)
-        continue;
-
-      MOZ_ASSERT(shadowContext == blurringArea.GetContext());
-
-      renderContext->Save();
-      renderContext->SetColor(gfxShadowColor);
-
-      // Draw the shape of the frame so it can be blurred. Recall how nsContextBoxBlur
-      // doesn't make any temporary surfaces if blur is 0 and it just returns the original
-      // surface? If we have no blur, we're painting this fill on the actual content surface
-      // (renderContext == shadowContext) which is why we set up the color and clip
-      // before doing this.
-
-      // We don't clip the border-box from the shadow, nor any other box.
-      // We assume that the native theme is going to paint over the shadow.
-
-      // Draw the widget shape
-      gfxContextMatrixAutoSaveRestore save(shadowContext);
-      gfxPoint devPixelOffset =
-        nsLayoutUtils::PointToGfxPoint(nsPoint(shadowItem->mXOffset,
-                                               shadowItem->mYOffset),
-                                       aPresContext->AppUnitsPerDevPixel());
-      shadowContext->SetMatrix(
-        shadowContext->CurrentMatrix().Translate(devPixelOffset));
-
-      nsRect nativeRect = aDirtyRect;
-      nativeRect.MoveBy(-nsPoint(shadowItem->mXOffset, shadowItem->mYOffset));
-      nativeRect.IntersectRect(frameRect, nativeRect);
-      nsRenderingContext wrapperCtx(shadowContext);
-      aPresContext->GetTheme()->DrawWidgetBackground(&wrapperCtx, aForFrame,
-          styleDisplay->UsedAppearance(), aFrameArea, nativeRect);
-
-      blurringArea.DoPaint();
-      renderContext->Restore();
-    } else {
-      renderContext->Save();
-
-      {
-        Rect innerClipRect = NSRectToRect(frameRect, twipsPerPixel);
-        if (!MaybeSnapToDevicePixels(innerClipRect, aDrawTarget, true)) {
-          innerClipRect.Round();
-        }
-
-        // Clip out the interior of the frame's border edge so that the shadow
-        // is only painted outside that area.
-        RefPtr<PathBuilder> builder =
-          aDrawTarget.CreatePathBuilder(FillRule::FILL_EVEN_ODD);
-        AppendRectToPath(builder, shadowGfxRectPlusBlur);
-        if (hasBorderRadius) {
-          AppendRoundedRectToPath(builder, innerClipRect, borderRadii);
-        } else {
-          AppendRectToPath(builder, innerClipRect);
-        }
-        RefPtr<Path> path = builder->Finish();
-        renderContext->Clip(path);
-      }
-
-      // Clip the shadow so that we only get the part that applies to aForFrame.
-      nsRect fragmentClip = shadowRectPlusBlur;
-      Sides skipSides = aForFrame->GetSkipSides();
-      if (!skipSides.IsEmpty()) {
-        if (skipSides.Left()) {
-          nscoord xmost = fragmentClip.XMost();
-          fragmentClip.x = aFrameArea.x;
-          fragmentClip.width = xmost - fragmentClip.x;
-        }
-        if (skipSides.Right()) {
-          nscoord xmost = fragmentClip.XMost();
-          nscoord overflow = xmost - aFrameArea.XMost();
-          if (overflow > 0) {
-            fragmentClip.width -= overflow;
-          }
-        }
-        if (skipSides.Top()) {
-          nscoord ymost = fragmentClip.YMost();
-          fragmentClip.y = aFrameArea.y;
-          fragmentClip.height = ymost - fragmentClip.y;
-        }
-        if (skipSides.Bottom()) {
-          nscoord ymost = fragmentClip.YMost();
-          nscoord overflow = ymost - aFrameArea.YMost();
-          if (overflow > 0) {
-            fragmentClip.height -= overflow;
-          }
-        }
-      }
-      fragmentClip = fragmentClip.Intersect(aDirtyRect);
-      renderContext->
-        Clip(NSRectToSnappedRect(fragmentClip,
-                                 aForFrame->PresContext()->AppUnitsPerDevPixel(),
-                                 aDrawTarget));
-
-      RectCornerRadii clipRectRadii;
-      if (hasBorderRadius) {
-        Float spreadDistance = shadowItem->mSpread / twipsPerPixel;
-
-        Float borderSizes[4];
-
-        borderSizes[eSideLeft] = spreadDistance;
-        borderSizes[eSideTop] = spreadDistance;
-        borderSizes[eSideRight] = spreadDistance;
-        borderSizes[eSideBottom] = spreadDistance;
-
-        nsCSSBorderRenderer::ComputeOuterRadii(borderRadii, borderSizes,
-            &clipRectRadii);
-
-      }
-      nsContextBoxBlur::BlurRectangle(renderContext,
-                                      shadowRect,
-                                      twipsPerPixel,
-                                      hasBorderRadius ? &clipRectRadii : nullptr,
-                                      blurRadius,
-                                      gfxShadowColor,
-                                      aDirtyRect,
-                                      skipGfxRect);
-      renderContext->Restore();
-    }
-
-  }
-}
-
-nsRect
-nsCSSRendering::GetBoxShadowInnerPaddingRect(nsIFrame* aFrame,
-                                             const nsRect& aFrameArea)
-{
-  Sides skipSides = aFrame->GetSkipSides();
-  nsRect frameRect =
-    ::BoxDecorationRectForBorder(aFrame, aFrameArea, skipSides);
-
-  nsRect paddingRect = frameRect;
-  nsMargin border = aFrame->GetUsedBorder();
-  paddingRect.Deflate(border);
-  return paddingRect;
-}
-
-bool
-nsCSSRendering::ShouldPaintBoxShadowInner(nsIFrame* aFrame)
-{
-  nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
-  if (!shadows)
-    return false;
-
-  if (aFrame->IsThemed() && aFrame->GetContent() &&
-      !nsContentUtils::IsChromeDoc(aFrame->GetContent()->GetUncomposedDoc())) {
-    // There's no way of getting hold of a shape corresponding to a
-    // "padding-box" for native-themed widgets, so just don't draw
-    // inner box-shadows for them. But we allow chrome to paint inner
-    // box shadows since chrome can be aware of the platform theme.
-    return false;
-  }
-
-  return true;
-}
-
-bool
-nsCSSRendering::GetShadowInnerRadii(nsIFrame* aFrame,
-                                    const nsRect& aFrameArea,
-                                    RectCornerRadii& aOutInnerRadii)
-{
-  // Get any border radius, since box-shadow must also have rounded corners
-  // if the frame does.
-  nscoord twipsRadii[8];
-  nsRect frameRect =
-    ::BoxDecorationRectForBorder(aFrame, aFrameArea, aFrame->GetSkipSides());
-  nsSize sz = frameRect.Size();
-  nsMargin border = aFrame->GetUsedBorder();
-  bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
-  const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1);
-
-  RectCornerRadii borderRadii;
-
-  hasBorderRadius = GetBorderRadii(frameRect, aFrameArea, aFrame, borderRadii);
-  if (hasBorderRadius) {
-    ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
-
-    Float borderSizes[4] = {
-      Float(border.top / twipsPerPixel),
-      Float(border.right / twipsPerPixel),
-      Float(border.bottom / twipsPerPixel),
-      Float(border.left / twipsPerPixel)
-    };
-    nsCSSBorderRenderer::ComputeInnerRadii(borderRadii,
-                                           borderSizes,
-                                           &aOutInnerRadii);
-  }
-
-  return hasBorderRadius;
-}
-
-void
-nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
-                                    nsRenderingContext& aRenderingContext,
-                                    nsIFrame* aForFrame,
-                                    const nsRect& aFrameArea)
-{
-  if (!ShouldPaintBoxShadowInner(aForFrame)) {
-    return;
-  }
-
-  nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
-  NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
-               aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
-
-  nsRect paddingRect = GetBoxShadowInnerPaddingRect(aForFrame, aFrameArea);
-
-  RectCornerRadii innerRadii;
-  bool hasBorderRadius = GetShadowInnerRadii(aForFrame,
-                                             aFrameArea,
-                                             innerRadii);
-
-  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
-  for (uint32_t i = shadows->Length(); i > 0; --i) {
-    nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
-    if (!shadowItem->mInset)
-      continue;
-
-    // shadowPaintRect: the area to paint on the temp surface
-    // shadowClipRect: the area on the temporary surface within shadowPaintRect
-    //                 that we will NOT paint in
-    nscoord blurRadius = shadowItem->mRadius;
-    nsMargin blurMargin =
-      nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
-    nsRect shadowPaintRect = paddingRect;
-    shadowPaintRect.Inflate(blurMargin);
-
-    // Round the spread radius to device pixels (by truncation).
-    // This mostly matches what we do for borders, except that we don't round
-    // up values between zero and one device pixels to one device pixel.
-    // This way of rounding is symmetric around zero, which makes sense for
-    // the spread radius.
-    int32_t spreadDistance = shadowItem->mSpread / twipsPerPixel;
-    nscoord spreadDistanceAppUnits = aPresContext->DevPixelsToAppUnits(spreadDistance);
-
-    nsRect shadowClipRect = paddingRect;
-    shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
-    shadowClipRect.Deflate(spreadDistanceAppUnits, spreadDistanceAppUnits);
-
-    Rect shadowClipGfxRect = NSRectToRect(shadowClipRect, twipsPerPixel);
-    shadowClipGfxRect.Round();
-
-    RectCornerRadii clipRectRadii;
-    if (hasBorderRadius) {
-      // Calculate the radii the inner clipping rect will have
-      Float borderSizes[4] = {0, 0, 0, 0};
-
-      // See PaintBoxShadowOuter and bug 514670
-      if (innerRadii[C_TL].width > 0 || innerRadii[C_BL].width > 0) {
-        borderSizes[eSideLeft] = spreadDistance;
-      }
-
-      if (innerRadii[C_TL].height > 0 || innerRadii[C_TR].height > 0) {
-        borderSizes[eSideTop] = spreadDistance;
-      }
-
-      if (innerRadii[C_TR].width > 0 || innerRadii[C_BR].width > 0) {
-        borderSizes[eSideRight] = spreadDistance;
-      }
-
-      if (innerRadii[C_BL].height > 0 || innerRadii[C_BR].height > 0) {
-        borderSizes[eSideBottom] = spreadDistance;
-      }
-
-      nsCSSBorderRenderer::ComputeInnerRadii(innerRadii, borderSizes,
-                                             &clipRectRadii);
-    }
-
-    // Set the "skip rect" to the area within the frame that we don't paint in,
-    // including after blurring.
-    nsRect skipRect = shadowClipRect;
-    skipRect.Deflate(blurMargin);
-    gfxRect skipGfxRect = nsLayoutUtils::RectToGfxRect(skipRect, twipsPerPixel);
-    if (hasBorderRadius) {
-      skipGfxRect.Deflate(gfxMargin(
-          std::max(clipRectRadii[C_TL].height, clipRectRadii[C_TR].height), 0,
-          std::max(clipRectRadii[C_BL].height, clipRectRadii[C_BR].height), 0));
-    }
-
-    // When there's a blur radius, gfxAlphaBoxBlur leaves the skiprect area
-    // unchanged. And by construction the gfxSkipRect is not touched by the
-    // rendered shadow (even after blurring), so those pixels must be completely
-    // transparent in the shadow, so drawing them changes nothing.
-    gfxContext* renderContext = aRenderingContext.ThebesContext();
-    DrawTarget* drawTarget = renderContext->GetDrawTarget();
-
-    // Clip the context to the area of the frame's padding rect, so no part of the
-    // shadow is painted outside. Also cut out anything beyond where the inset shadow
-    // will be.
-    Rect shadowGfxRect = NSRectToRect(paddingRect, twipsPerPixel);
-    shadowGfxRect.Round();
-
-    Color shadowColor = GetShadowColor(shadowItem, aForFrame, 1.0);
-    renderContext->Save();
-
-    // This clips the outside border radius.
-    // clipRectRadii is the border radius inside the inset shadow.
-    if (hasBorderRadius) {
-      RefPtr<Path> roundedRect =
-        MakePathForRoundedRect(*drawTarget, shadowGfxRect, innerRadii);
-      renderContext->Clip(roundedRect);
-    } else {
-      renderContext->Clip(shadowGfxRect);
-    }
-
-    nsContextBoxBlur insetBoxBlur;
-    gfxRect destRect = nsLayoutUtils::RectToGfxRect(shadowPaintRect, twipsPerPixel);
-    Point shadowOffset(shadowItem->mXOffset / twipsPerPixel,
-                       shadowItem->mYOffset / twipsPerPixel);
-
-    insetBoxBlur.InsetBoxBlur(renderContext, ToRect(destRect),
-                              shadowClipGfxRect, shadowColor,
-                              blurRadius, spreadDistanceAppUnits,
-                              twipsPerPixel, hasBorderRadius,
-                              clipRectRadii, ToRect(skipGfxRect),
-                              shadowOffset);
-    renderContext->Restore();
-  }
-}
-
-/* static */
-nsCSSRendering::PaintBGParams
-nsCSSRendering::PaintBGParams::ForAllLayers(nsPresContext& aPresCtx,
-                                            nsRenderingContext& aRenderingCtx,
-                                            const nsRect& aDirtyRect,
-                                            const nsRect& aBorderArea,
-                                            nsIFrame *aFrame,
-                                            uint32_t aPaintFlags,
-                                            float aOpacity)
-{
-  MOZ_ASSERT(aFrame);
-
-  PaintBGParams result(aPresCtx, aRenderingCtx, aDirtyRect, aBorderArea,
-                       aFrame, aPaintFlags, -1, CompositionOp::OP_OVER,
-                       aOpacity);
-
-  return result;
-}
-
-/* static */
-nsCSSRendering::PaintBGParams
-nsCSSRendering::PaintBGParams::ForSingleLayer(nsPresContext& aPresCtx,
-                                              nsRenderingContext& aRenderingCtx,
-                                              const nsRect& aDirtyRect,
-                                              const nsRect& aBorderArea,
-                                              nsIFrame *aFrame,
-                                              uint32_t aPaintFlags,
-                                              int32_t aLayer,
-                                              CompositionOp aCompositionOp,
-                                              float aOpacity)
-{
-  MOZ_ASSERT(aFrame && (aLayer != -1));
-
-  PaintBGParams result(aPresCtx, aRenderingCtx, aDirtyRect, aBorderArea,
-                       aFrame, aPaintFlags, aLayer, aCompositionOp,
-                       aOpacity);
-
-  return result;
-}
-
-DrawResult
-nsCSSRendering::PaintStyleImageLayer(const PaintBGParams& aParams)
-{
-  PROFILER_LABEL("nsCSSRendering", "PaintBackground",
-    js::ProfileEntry::Category::GRAPHICS);
-
-  NS_PRECONDITION(aParams.frame,
-                  "Frame is expected to be provided to PaintBackground");
-
-  nsStyleContext *sc;
-  if (!FindBackground(aParams.frame, &sc)) {
-    // We don't want to bail out if moz-appearance is set on a root
-    // node. If it has a parent content node, bail because it's not
-    // a root, otherwise keep going in order to let the theme stuff
-    // draw the background. The canvas really should be drawing the
-    // bg, but there's no way to hook that up via css.
-    if (!aParams.frame->StyleDisplay()->UsedAppearance()) {
-      return DrawResult::SUCCESS;
-    }
-
-    nsIContent* content = aParams.frame->GetContent();
-    if (!content || content->GetParent()) {
-      return DrawResult::SUCCESS;
-    }
-
-    sc = aParams.frame->StyleContext();
-  }
-
-  return PaintStyleImageLayerWithSC(aParams, sc, *aParams.frame->StyleBorder());
-}
-
-static bool
-IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide)
-{
-  if (aBorder.GetComputedBorder().Side(aSide) == 0)
-    return true;
-  switch (aBorder.GetBorderStyle(aSide)) {
-  case NS_STYLE_BORDER_STYLE_SOLID:
-  case NS_STYLE_BORDER_STYLE_GROOVE:
-  case NS_STYLE_BORDER_STYLE_RIDGE:
-  case NS_STYLE_BORDER_STYLE_INSET:
-  case NS_STYLE_BORDER_STYLE_OUTSET:
-    break;
-  default:
-    return false;
-  }
-
-  // If we're using a border image, assume it's not fully opaque,
-  // because we may not even have the image loaded at this point, and
-  // even if we did, checking whether the relevant tile is fully
-  // opaque would be too much work.
-  if (aBorder.mBorderImageSource.GetType() != eStyleImageType_Null)
-    return false;
-
-  StyleComplexColor color = aBorder.mBorderColor[aSide];
-  // We don't know the foreground color here, so if it's being used
-  // we must assume it might be transparent.
-  if (!color.IsNumericColor()) {
-    return false;
-  }
-  return NS_GET_A(color.mColor) == 255;
-}
-
-/**
- * Returns true if all border edges are either missing or opaque.
- */
-static bool
-IsOpaqueBorder(const nsStyleBorder& aBorder)
-{
-  if (aBorder.mBorderColors)
-    return false;
-  NS_FOR_CSS_SIDES(i) {
-    if (!IsOpaqueBorderEdge(aBorder, i))
-      return false;
-  }
-  return true;
-}
-
-static inline void
-SetupDirtyRects(const nsRect& aBGClipArea, const nsRect& aCallerDirtyRect,
-                nscoord aAppUnitsPerPixel,
-                /* OUT: */
-                nsRect* aDirtyRect, gfxRect* aDirtyRectGfx)
-{
-  aDirtyRect->IntersectRect(aBGClipArea, aCallerDirtyRect);
-
-  // Compute the Thebes equivalent of the dirtyRect.
-  *aDirtyRectGfx = nsLayoutUtils::RectToGfxRect(*aDirtyRect, aAppUnitsPerPixel);
-  NS_WARNING_ASSERTION(aDirtyRect->IsEmpty() || !aDirtyRectGfx->IsEmpty(),
-                       "converted dirty rect should not be empty");
-  MOZ_ASSERT(!aDirtyRect->IsEmpty() || aDirtyRectGfx->IsEmpty(),
-             "second should be empty if first is");
-}
-
-static bool
-IsSVGStyleGeometryBox(StyleGeometryBox aBox)
-{
-  return (aBox == StyleGeometryBox::FillBox ||
-          aBox == StyleGeometryBox::StrokeBox ||
-          aBox == StyleGeometryBox::ViewBox);
-}
-
-static bool
-IsHTMLStyleGeometryBox(StyleGeometryBox aBox)
-{
-  return (aBox == StyleGeometryBox::ContentBox ||
-          aBox == StyleGeometryBox::PaddingBox ||
-          aBox == StyleGeometryBox::BorderBox ||
-          aBox == StyleGeometryBox::MarginBox);
-}
-
-static StyleGeometryBox
-ComputeBoxValue(nsIFrame* aForFrame, StyleGeometryBox aBox)
-{
-  if (!(aForFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
-    // For elements with associated CSS layout box, the values fill-box,
-    // stroke-box and view-box compute to the initial value of mask-clip.
-    if (IsSVGStyleGeometryBox(aBox)) {
-      return StyleGeometryBox::BorderBox;
-    }
-  } else {
-    // For SVG elements without associated CSS layout box, the values
-    // content-box, padding-box, border-box and margin-box compute to fill-box.
-    if (IsHTMLStyleGeometryBox(aBox)) {
-      return StyleGeometryBox::FillBox;
-    }
-  }
-
-  return aBox;
-}
-
-bool
-nsCSSRendering::ImageLayerClipState::IsValid() const
-{
-  // mDirtyRectInDevPx comes from mDirtyRectInAppUnits. mDirtyRectInAppUnits
-  // can not be empty if mDirtyRectInDevPx is not.
-  if (!mDirtyRectInDevPx.IsEmpty() && mDirtyRectInAppUnits.IsEmpty()) {
-    return false;
-  }
-
-  if (mHasRoundedCorners == mClippedRadii.IsEmpty()) {
-    return false;
-  }
-
-  return true;
-}
-
-/* static */ void
-nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
-                                  nsIFrame* aForFrame, const nsStyleBorder& aBorder,
-                                  const nsRect& aBorderArea, const nsRect& aCallerDirtyRect,
-                                  bool aWillPaintBorder, nscoord aAppUnitsPerPixel,
-                                  /* out */ ImageLayerClipState* aClipState)
-{
-  aClipState->mHasRoundedCorners = false;
-  aClipState->mHasAdditionalBGClipArea = false;
-  aClipState->mAdditionalBGClipArea.SetEmpty();
-  aClipState->mCustomClip = false;
-
-  StyleGeometryBox layerClip = ComputeBoxValue(aForFrame, aLayer.mClip);
-  if (IsSVGStyleGeometryBox(layerClip)) {
-    MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
-               (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame));
-
-    // The coordinate space of clipArea is svg user space.
-    nsRect clipArea =
-      nsLayoutUtils::ComputeGeometryBox(aForFrame, layerClip);
-
-    nsRect strokeBox = (layerClip == StyleGeometryBox::StrokeBox)
-      ? clipArea
-      : nsLayoutUtils::ComputeGeometryBox(aForFrame, StyleGeometryBox::StrokeBox);
-    nsRect clipAreaRelativeToStrokeBox = clipArea - strokeBox.TopLeft();
-
-    // aBorderArea is the stroke-box area in a coordinate space defined by
-    // the caller. This coordinate space can be svg user space of aForFrame,
-    // the space of aForFrame's reference-frame, or anything else.
-    //
-    // Which coordinate space chosen for aBorderArea is not matter. What
-    // matter is to ensure returning aClipState->mBGClipArea in the consistent
-    // coordiante space with aBorderArea. So we evaluate the position of clip
-    // area base on the position of aBorderArea here.
-    aClipState->mBGClipArea =
-      clipAreaRelativeToStrokeBox + aBorderArea.TopLeft();
-
-    SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
-                    aAppUnitsPerPixel, &aClipState->mDirtyRectInAppUnits,
-                    &aClipState->mDirtyRectInDevPx);
-    MOZ_ASSERT(aClipState->IsValid());
-    return;
-  }
-
-  if (layerClip == StyleGeometryBox::NoClip) {
-    aClipState->mBGClipArea = aCallerDirtyRect;
-
-    SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect,
-                    aAppUnitsPerPixel, &aClipState->mDirtyRectInAppUnits,
-                    &aClipState->mDirtyRectInDevPx);
-    MOZ_ASSERT(aClipState->IsValid());
-    return;
-  }
-
-  MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) ||
-             aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame);
-
-  // Compute the outermost boundary of the area that might be painted.
-  // Same coordinate space as aBorderArea.
-  Sides skipSides = aForFrame->GetSkipSides();
-  nsRect clipBorderArea =
-    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, skipSides, &aBorder);
-
-  bool haveRoundedCorners = GetRadii(aForFrame, aBorder, aBorderArea,
-                                     clipBorderArea, aClipState->mRadii);
-
-  bool isSolidBorder =
-      aWillPaintBorder && IsOpaqueBorder(aBorder);
-  if (isSolidBorder && layerClip == StyleGeometryBox::BorderBox) {
-    // If we have rounded corners, we need to inflate the background
-    // drawing area a bit to avoid seams between the border and
-    // background.
-    layerClip = haveRoundedCorners
-                     ? StyleGeometryBox::MozAlmostPadding
-                     : StyleGeometryBox::PaddingBox;
-  }
-
-  aClipState->mBGClipArea = clipBorderArea;
-
-  if (aForFrame->GetType() == nsGkAtoms::scrollFrame &&
-      NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment) {
-    // As of this writing, this is still in discussion in the CSS Working Group
-    // http://lists.w3.org/Archives/Public/www-style/2013Jul/0250.html
-
-    // The rectangle for 'background-clip' scrolls with the content,
-    // but the background is also clipped at a non-scrolling 'padding-box'
-    // like the content. (See below.)
-    // Therefore, only 'content-box' makes a difference here.
-    if (layerClip == StyleGeometryBox::ContentBox) {
-      nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
-      // Clip at a rectangle attached to the scrolled content.
-      aClipState->mHasAdditionalBGClipArea = true;
-      aClipState->mAdditionalBGClipArea = nsRect(
-        aClipState->mBGClipArea.TopLeft()
-          + scrollableFrame->GetScrolledFrame()->GetPosition()
-          // For the dir=rtl case:
-          + scrollableFrame->GetScrollRange().TopLeft(),
-        scrollableFrame->GetScrolledRect().Size());
-      nsMargin padding = aForFrame->GetUsedPadding();
-      // padding-bottom is ignored on scrollable frames:
-      // https://bugzilla.mozilla.org/show_bug.cgi?id=748518
-      padding.bottom = 0;
-      padding.ApplySkipSides(skipSides);
-      aClipState->mAdditionalBGClipArea.Deflate(padding);
-    }
-
-    // Also clip at a non-scrolling, rounded-corner 'padding-box',
-    // same as the scrolled content because of the 'overflow' property.
-    layerClip = StyleGeometryBox::PaddingBox;
-  }
-
-  // See the comment of StyleGeometryBox::Margin.
-  // Hitting this assertion means we decide to turn on margin-box support for
-  // positioned mask from CSS parser and style system. In this case, you
-  // should *inflate* mBGClipArea by the margin returning from
-  // aForFrame->GetUsedMargin() in the code chunk bellow.
-  MOZ_ASSERT(layerClip != StyleGeometryBox::MarginBox,
-             "StyleGeometryBox::MarginBox rendering is not supported yet.\n");
-
-  if (layerClip != StyleGeometryBox::BorderBox &&
-      layerClip != StyleGeometryBox::Text) {
-    nsMargin border = aForFrame->GetUsedBorder();
-    if (layerClip == StyleGeometryBox::MozAlmostPadding) {
-      // Reduce |border| by 1px (device pixels) on all sides, if
-      // possible, so that we don't get antialiasing seams between the
-      // {background|mask} and border.
-      border.top = std::max(0, border.top - aAppUnitsPerPixel);
-      border.right = std::max(0, border.right - aAppUnitsPerPixel);
-      border.bottom = std::max(0, border.bottom - aAppUnitsPerPixel);
-      border.left = std::max(0, border.left - aAppUnitsPerPixel);
-    } else if (layerClip != StyleGeometryBox::PaddingBox) {
-      NS_ASSERTION(layerClip == StyleGeometryBox::ContentBox,
-                   "unexpected background-clip");
-      border += aForFrame->GetUsedPadding();
-    }
-    border.ApplySkipSides(skipSides);
-    aClipState->mBGClipArea.Deflate(border);
-
-    if (haveRoundedCorners) {
-      nsIFrame::InsetBorderRadii(aClipState->mRadii, border);
-    }
-  }
-
-  if (haveRoundedCorners) {
-    auto d2a = aForFrame->PresContext()->AppUnitsPerDevPixel();
-    nsCSSRendering::ComputePixelRadii(aClipState->mRadii, d2a, &aClipState->mClippedRadii);
-    aClipState->mHasRoundedCorners = !aClipState->mClippedRadii.IsEmpty();
-  }
-
-
-  if (!haveRoundedCorners && aClipState->mHasAdditionalBGClipArea) {
-    // Do the intersection here to account for the fast path(?) below.
-    aClipState->mBGClipArea =
-      aClipState->mBGClipArea.Intersect(aClipState->mAdditionalBGClipArea);
-    aClipState->mHasAdditionalBGClipArea = false;
-  }
-
-  SetupDirtyRects(aClipState->mBGClipArea, aCallerDirtyRect, aAppUnitsPerPixel,
-                  &aClipState->mDirtyRectInAppUnits,
-                  &aClipState->mDirtyRectInDevPx);
-
-  MOZ_ASSERT(aClipState->IsValid());
-}
-
-static void
-SetupImageLayerClip(nsCSSRendering::ImageLayerClipState& aClipState,
-                    gfxContext *aCtx, nscoord aAppUnitsPerPixel,
-                    gfxContextAutoSaveRestore* aAutoSR)
-{
-  if (aClipState.mDirtyRectInDevPx.IsEmpty()) {
-    // Our caller won't draw anything under this condition, so no need
-    // to set more up.
-    return;
-  }
-
-  if (aClipState.mCustomClip) {
-    // We don't support custom clips and rounded corners, arguably a bug, but
-    // table painting seems to depend on it.
-    return;
-  }
-
-  // If we have rounded corners, clip all subsequent drawing to the
-  // rounded rectangle defined by bgArea and bgRadii (we don't know
-  // whether the rounded corners intrude on the dirtyRect or not).
-  // Do not do this if we have a caller-provided clip rect --
-  // as above with bgArea, arguably a bug, but table painting seems
-  // to depend on it.
-
-  if (aClipState.mHasAdditionalBGClipArea) {
-    gfxRect bgAreaGfx = nsLayoutUtils::RectToGfxRect(
-      aClipState.mAdditionalBGClipArea, aAppUnitsPerPixel);
-    bgAreaGfx.Round();
-    bgAreaGfx.Condition();
-
-    aAutoSR->EnsureSaved(aCtx);
-    aCtx->NewPath();
-    aCtx->Rectangle(bgAreaGfx, true);
-    aCtx->Clip();
-  }
-
-  if (aClipState.mHasRoundedCorners) {
-    Rect bgAreaGfx = NSRectToRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
-    bgAreaGfx.Round();
-
-    if (bgAreaGfx.IsEmpty()) {
-      // I think it's become possible to hit this since
-      // https://hg.mozilla.org/mozilla-central/rev/50e934e4979b landed.
-      NS_WARNING("converted background area should not be empty");
-      // Make our caller not do anything.
-      aClipState.mDirtyRectInDevPx.SizeTo(gfxSize(0.0, 0.0));
-      return;
-    }
-
-    aAutoSR->EnsureSaved(aCtx);
-
-    RefPtr<Path> roundedRect =
-      MakePathForRoundedRect(*aCtx->GetDrawTarget(), bgAreaGfx,
-                             aClipState.mClippedRadii);
-    aCtx->Clip(roundedRect);
-  }
-}
-
-static void
-DrawBackgroundColor(nsCSSRendering::ImageLayerClipState& aClipState,
-                    gfxContext *aCtx, nscoord aAppUnitsPerPixel)
-{
-  if (aClipState.mDirtyRectInDevPx.IsEmpty()) {
-    // Our caller won't draw anything under this condition, so no need
-    // to set more up.
-    return;
-  }
-
-  DrawTarget* drawTarget = aCtx->GetDrawTarget();
-
-  // We don't support custom clips and rounded corners, arguably a bug, but
-  // table painting seems to depend on it.
-  if (!aClipState.mHasRoundedCorners || aClipState.mCustomClip) {
-    aCtx->NewPath();
-    aCtx->Rectangle(aClipState.mDirtyRectInDevPx, true);
-    aCtx->Fill();
-    return;
-  }
-
-  Rect bgAreaGfx = NSRectToRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
-  bgAreaGfx.Round();
-
-  if (bgAreaGfx.IsEmpty()) {
-    // I think it's become possible to hit this since
-    // https://hg.mozilla.org/mozilla-central/rev/50e934e4979b landed.
-    NS_WARNING("converted background area should not be empty");
-    // Make our caller not do anything.
-    aClipState.mDirtyRectInDevPx.SizeTo(gfxSize(0.0, 0.0));
-    return;
-  }
-
-  aCtx->Save();
-  gfxRect dirty = ThebesRect(bgAreaGfx).Intersect(aClipState.mDirtyRectInDevPx);
-
-  aCtx->NewPath();
-  aCtx->Rectangle(dirty, true);
-  aCtx->Clip();
-
-  if (aClipState.mHasAdditionalBGClipArea) {
-    gfxRect bgAdditionalAreaGfx = nsLayoutUtils::RectToGfxRect(
-      aClipState.mAdditionalBGClipArea, aAppUnitsPerPixel);
-    bgAdditionalAreaGfx.Round();
-    bgAdditionalAreaGfx.Condition();
-    aCtx->NewPath();
-    aCtx->Rectangle(bgAdditionalAreaGfx, true);
-    aCtx->Clip();
-  }
-
-  RefPtr<Path> roundedRect =
-    MakePathForRoundedRect(*drawTarget, bgAreaGfx, aClipState.mClippedRadii);
-  aCtx->SetPath(roundedRect);
-  aCtx->Fill();
-  aCtx->Restore();
-}
-
-nscolor
-nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
-                                         nsStyleContext* aStyleContext,
-                                         nsIFrame* aFrame,
-                                         bool& aDrawBackgroundImage,
-                                         bool& aDrawBackgroundColor)
-{
-  aDrawBackgroundImage = true;
-  aDrawBackgroundColor = true;
-
-  const nsStyleVisibility* visibility = aStyleContext->StyleVisibility();
-
-  if (visibility->mColorAdjust != NS_STYLE_COLOR_ADJUST_EXACT &&
-      aFrame->HonorPrintBackgroundSettings()) {
-    aDrawBackgroundImage = aPresContext->GetBackgroundImageDraw();
-    aDrawBackgroundColor = aPresContext->GetBackgroundColorDraw();
-  }
-
-  const nsStyleBackground *bg = aStyleContext->StyleBackground();
-  nscolor bgColor;
-  if (aDrawBackgroundColor) {
-    bgColor = aStyleContext->
-      GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
-    if (NS_GET_A(bgColor) == 0) {
-      aDrawBackgroundColor = false;
-    }
-  } else {
-    // If GetBackgroundColorDraw() is false, we are still expected to
-    // draw color in the background of any frame that's not completely
-    // transparent, but we are expected to use white instead of whatever
-    // color was specified.
-    bgColor = NS_RGB(255, 255, 255);
-    if (aDrawBackgroundImage || !bg->IsTransparent(aStyleContext)) {
-      aDrawBackgroundColor = true;
-    } else {
-      bgColor = NS_RGBA(0,0,0,0);
-    }
-  }
-
-  // We can skip painting the background color if a background image is opaque.
-  nsStyleImageLayers::Repeat repeat = bg->BottomLayer().mRepeat;
-  bool xFullRepeat = repeat.mXRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
-                     repeat.mXRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND;
-  bool yFullRepeat = repeat.mYRepeat == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
-                     repeat.mYRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND;
-  if (aDrawBackgroundColor &&
-      xFullRepeat && yFullRepeat &&
-      bg->BottomLayer().mImage.IsOpaque() &&
-      bg->BottomLayer().mBlendMode == NS_STYLE_BLEND_NORMAL) {
-    aDrawBackgroundColor = false;
-  }
-
-  return bgColor;
-}
 
 static gfxFloat
 ConvertGradientValueToPixels(const nsStyleCoord& aCoord,
                              gfxFloat aFillLength,
                              int32_t aAppUnitsPerPixel)
 {
   switch (aCoord.GetUnit()) {
     case eStyleUnit_Percent:
@@ -2894,27 +538,29 @@ ClampColorStops(nsTArray<ColorStop>& aSt
   if (aStops[0].mPosition > 0) {
     aStops.InsertElementAt(0, ColorStop(0, false, aStops[0].mColor));
   }
   if (aStops.LastElement().mPosition < 1) {
     aStops.AppendElement(ColorStop(1, false, aStops.LastElement().mColor));
   }
 }
 
+namespace mozilla {
+
 void
-nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
-                              gfxContext& aContext,
-                              nsStyleGradient* aGradient,
-                              const nsRect& aDirtyRect,
-                              const nsRect& aDest,
-                              const nsRect& aFillArea,
-                              const nsSize& aRepeatSize,
-                              const CSSIntRect& aSrc,
-                              const nsSize& aIntrinsicSize,
-                              float aOpacity)
+nsCSSGradientRenderer::Paint(nsPresContext* aPresContext,
+                             gfxContext& aContext,
+                             nsStyleGradient* aGradient,
+                             const nsRect& aDirtyRect,
+                             const nsRect& aDest,
+                             const nsRect& aFillArea,
+                             const nsSize& aRepeatSize,
+                             const CSSIntRect& aSrc,
+                             const nsSize& aIntrinsicSize,
+                             float aOpacity)
 {
   PROFILER_LABEL("nsCSSRendering", "PaintGradient",
     js::ProfileEntry::Category::GRAPHICS);
 
   Telemetry::AutoTimer<Telemetry::GRADIENT_DURATION, Telemetry::Microsecond> gradientTimer;
   if (aDest.IsEmpty() || aFillArea.IsEmpty()) {
     return;
   }
@@ -3338,1986 +984,9 @@ nsCSSRendering::PaintGradient(nsPresCont
         aContext.SetPattern(gradientPattern);
       }
       aContext.Fill();
       aContext.SetMatrix(ctm);
     }
   }
 }
 
-static CompositionOp
-DetermineCompositionOp(const nsCSSRendering::PaintBGParams& aParams,
-                       const nsStyleImageLayers& aLayers,
-                       uint32_t aLayerIndex)
-{
-  if (aParams.layer >= 0) {
-    // When drawing a single layer, use the specified composition op.
-    return aParams.compositionOp;
-  }
-
-  const nsStyleImageLayers::Layer& layer = aLayers.mLayers[aLayerIndex];
-  // When drawing all layers, get the compositon op from each image layer.
-  if (aParams.paintFlags & nsCSSRendering::PAINTBG_MASK_IMAGE) {
-    // Always using OP_OVER mode while drawing the bottom mask layer.
-    if (aLayerIndex == (aLayers.mImageCount - 1)) {
-      return CompositionOp::OP_OVER;
-    }
-
-    return nsCSSRendering::GetGFXCompositeMode(layer.mComposite);
-  }
-
-  return nsCSSRendering::GetGFXBlendMode(layer.mBlendMode);
-}
-
-DrawResult
-nsCSSRendering::PaintStyleImageLayerWithSC(const PaintBGParams& aParams,
-                                           nsStyleContext *aBackgroundSC,
-                                           const nsStyleBorder& aBorder)
-{
-  NS_PRECONDITION(aParams.frame,
-                  "Frame is expected to be provided to PaintBackground");
-
-  // If we're drawing all layers, aCompositonOp is ignored, so make sure that
-  // it was left at its default value.
-  MOZ_ASSERT_IF(aParams.layer == -1,
-                aParams.compositionOp == CompositionOp::OP_OVER);
-
-  // Check to see if we have an appearance defined.  If so, we let the theme
-  // renderer draw the background and bail out.
-  // XXXzw this ignores aParams.bgClipRect.
-  const nsStyleDisplay* displayData = aParams.frame->StyleDisplay();
-  if (displayData->UsedAppearance()) {
-    nsITheme *theme = aParams.presCtx.GetTheme();
-    if (theme && theme->ThemeSupportsWidget(&aParams.presCtx,
-                                            aParams.frame,
-                                            displayData->UsedAppearance())) {
-      nsRect drawing(aParams.borderArea);
-      theme->GetWidgetOverflow(aParams.presCtx.DeviceContext(),
-                               aParams.frame, displayData->UsedAppearance(),
-                               &drawing);
-      drawing.IntersectRect(drawing, aParams.dirtyRect);
-      theme->DrawWidgetBackground(&aParams.renderingCtx, aParams.frame,
-                                  displayData->UsedAppearance(), aParams.borderArea,
-                                  drawing);
-      return DrawResult::SUCCESS;
-    }
-  }
-
-  // For canvas frames (in the CSS sense) we draw the background color using
-  // a solid color item that gets added in nsLayoutUtils::PaintFrame,
-  // or nsSubDocumentFrame::BuildDisplayList (bug 488242). (The solid
-  // color may be moved into nsDisplayCanvasBackground by
-  // nsPresShell::AddCanvasBackgroundColorItem, and painted by
-  // nsDisplayCanvasBackground directly.) Either way we don't need to
-  // paint the background color here.
-  bool isCanvasFrame = IsCanvasFrame(aParams.frame);
-
-  // Determine whether we are drawing background images and/or
-  // background colors.
-  bool drawBackgroundImage;
-  bool drawBackgroundColor;
-
-  nscolor bgColor = DetermineBackgroundColor(&aParams.presCtx,
-                                             aBackgroundSC,
-                                             aParams.frame,
-                                             drawBackgroundImage,
-                                             drawBackgroundColor);
-
-  bool paintMask = (aParams.paintFlags & PAINTBG_MASK_IMAGE);
-  const nsStyleImageLayers& layers = paintMask ?
-    aBackgroundSC->StyleSVGReset()->mMask :
-    aBackgroundSC->StyleBackground()->mImage;
-  // If we're drawing a specific layer, we don't want to draw the
-  // background color.
-  if ((drawBackgroundColor && aParams.layer >= 0) || paintMask) {
-    drawBackgroundColor = false;
-  }
-
-  // At this point, drawBackgroundImage and drawBackgroundColor are
-  // true if and only if we are actually supposed to paint an image or
-  // color into aDirtyRect, respectively.
-  if (!drawBackgroundImage && !drawBackgroundColor)
-    return DrawResult::SUCCESS;
-
-  // The 'bgClipArea' (used only by the image tiling logic, far below)
-  // is the caller-provided aParams.bgClipRect if any, or else the area
-  // determined by the value of 'background-clip' in
-  // SetupCurrentBackgroundClip.  (Arguably it should be the
-  // intersection, but that breaks the table painter -- in particular,
-  // taking the intersection breaks reftests/bugs/403249-1[ab].)
-  gfxContext* ctx = aParams.renderingCtx.ThebesContext();
-  nscoord appUnitsPerPixel = aParams.presCtx.AppUnitsPerDevPixel();
-  ImageLayerClipState clipState;
-  if (aParams.bgClipRect) {
-    clipState.mBGClipArea = *aParams.bgClipRect;
-    clipState.mCustomClip = true;
-    clipState.mHasRoundedCorners = false;
-    SetupDirtyRects(clipState.mBGClipArea, aParams.dirtyRect, appUnitsPerPixel,
-                    &clipState.mDirtyRectInAppUnits,
-                    &clipState.mDirtyRectInDevPx);
-  } else {
-    GetImageLayerClip(layers.BottomLayer(),
-                      aParams.frame, aBorder, aParams.borderArea,
-                      aParams.dirtyRect,
-                      (aParams.paintFlags & PAINTBG_WILL_PAINT_BORDER),
-                      appUnitsPerPixel,
-                      &clipState);
-  }
-
-  // If we might be using a background color, go ahead and set it now.
-  if (drawBackgroundColor && !isCanvasFrame) {
-    ctx->SetColor(Color::FromABGR(bgColor));
-  }
-
-  // If there is no background image, draw a color.  (If there is
-  // neither a background image nor a color, we wouldn't have gotten
-  // this far.)
-  if (!drawBackgroundImage) {
-    if (!isCanvasFrame) {
-      DrawBackgroundColor(clipState, ctx, appUnitsPerPixel);
-    }
-    return DrawResult::SUCCESS;
-  }
-
-  if (layers.mImageCount < 1) {
-    // Return if there are no background layers, all work from this point
-    // onwards happens iteratively on these.
-    return DrawResult::SUCCESS;
-  }
-
-  MOZ_ASSERT((aParams.layer < 0) ||
-             (layers.mImageCount > uint32_t(aParams.layer)));
-  bool drawAllLayers = (aParams.layer < 0);
-
-  // Ensure we get invalidated for loads of the image.  We need to do
-  // this here because this might be the only code that knows about the
-  // association of the style data with the frame.
-  if (aBackgroundSC != aParams.frame->StyleContext()) {
-    uint32_t startLayer = drawAllLayers ? layers.mImageCount - 1
-                                        : aParams.layer;
-    uint32_t count = drawAllLayers ? layers.mImageCount : 1;
-    NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(i, layers, startLayer,
-                                                         count) {
-      aParams.frame->AssociateImage(layers.mLayers[i].mImage,
-                                    &aParams.presCtx);
-    }
-  }
-
-  // The background color is rendered over the entire dirty area,
-  // even if the image isn't.
-  if (drawBackgroundColor && !isCanvasFrame) {
-    DrawBackgroundColor(clipState, ctx, appUnitsPerPixel);
-  }
-
-  if (!drawBackgroundImage) {
-    return DrawResult::SUCCESS; // No need to draw layer image, we can early
-                                // return now.
-  }
-
-  // Compute the outermost boundary of the area that might be painted.
-  // Same coordinate space as aParams.borderArea & aParams.bgClipRect.
-  Sides skipSides = aParams.frame->GetSkipSides();
-  nsRect paintBorderArea =
-    ::BoxDecorationRectForBackground(aParams.frame, aParams.borderArea,
-                                     skipSides, &aBorder);
-  nsRect clipBorderArea =
-    ::BoxDecorationRectForBorder(aParams.frame, aParams.borderArea,
-                                 skipSides, &aBorder);
-
-  DrawResult result = DrawResult::SUCCESS;
-  StyleGeometryBox currentBackgroundClip = StyleGeometryBox::BorderBox;
-  uint32_t count = drawAllLayers
-    ? layers.mImageCount                  // iterate all image layers.
-    : layers.mImageCount - aParams.layer; // iterate from the bottom layer to
-                                          // the 'aParams.layer-th' layer.
-  NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(i, layers,
-                                                       layers.mImageCount - 1,
-                                                       count) {
-    // NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved(ctx)
-    // in the cases we need it.
-    gfxContextAutoSaveRestore autoSR;
-    const nsStyleImageLayers::Layer& layer = layers.mLayers[i];
-
-    if (!aParams.bgClipRect) {
-      bool isBottomLayer = (i == layers.mImageCount - 1);
-      if (currentBackgroundClip != layer.mClip || isBottomLayer) {
-        currentBackgroundClip = layer.mClip;
-        // For  the bottom layer, we already called GetImageLayerClip above
-        // and it stored its results in clipState.
-        if (!isBottomLayer) {
-          GetImageLayerClip(layer, aParams.frame,
-                            aBorder, aParams.borderArea, aParams.dirtyRect,
-                            (aParams.paintFlags & PAINTBG_WILL_PAINT_BORDER),
-                            appUnitsPerPixel, &clipState);
-        }
-        SetupImageLayerClip(clipState, ctx, appUnitsPerPixel, &autoSR);
-        if (!clipBorderArea.IsEqualEdges(aParams.borderArea)) {
-          // We're drawing the background for the joined continuation boxes
-          // so we need to clip that to the slice that we want for this
-          // frame.
-          gfxRect clip =
-            nsLayoutUtils::RectToGfxRect(aParams.borderArea, appUnitsPerPixel);
-          autoSR.EnsureSaved(ctx);
-          ctx->NewPath();
-          ctx->SnappedRectangle(clip);
-          ctx->Clip();
-        }
-      }
-    }
-
-    // Skip the following layer painting code if we found the dirty region is
-    // empty or the current layer is not selected for drawing.
-    if (clipState.mDirtyRectInDevPx.IsEmpty() ||
-        (aParams.layer >= 0 && i != (uint32_t)aParams.layer)) {
-      continue;
-    }
-
-    nsBackgroundLayerState state =
-      PrepareImageLayer(&aParams.presCtx, aParams.frame,
-                        aParams.paintFlags, paintBorderArea,
-                        clipState.mBGClipArea, layer, nullptr);
-    result &= state.mImageRenderer.PrepareResult();
-    if (!state.mFillArea.IsEmpty()) {
-      CompositionOp co = DetermineCompositionOp(aParams, layers, i);
-      if (co != CompositionOp::OP_OVER) {
-        NS_ASSERTION(ctx->CurrentOp() == CompositionOp::OP_OVER,
-                     "It is assumed the initial op is OP_OVER, when it is "
-                     "restored later");
-        ctx->SetOp(co);
-      }
-
-      result &=
-        state.mImageRenderer.DrawLayer(&aParams.presCtx,
-                                       aParams.renderingCtx,
-                                       state.mDestArea, state.mFillArea,
-                                       state.mAnchor + paintBorderArea.TopLeft(),
-                                       clipState.mDirtyRectInAppUnits,
-                                       state.mRepeatSize, aParams.opacity);
-
-      if (co != CompositionOp::OP_OVER) {
-        ctx->SetOp(CompositionOp::OP_OVER);
-      }
-    }
-  }
-
-  return result;
-}
-
-nsRect
-nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
-                                                 nsIFrame* aForFrame,
-                                                 const nsRect& aBorderArea,
-                                                 const nsStyleImageLayers::Layer& aLayer,
-                                                 nsIFrame** aAttachedToFrame,
-                                                 bool* aOutIsTransformedFixed)
-{
-  // Compute {background|mask} origin area relative to aBorderArea now as we
-  // may need  it to compute the effective image size for a CSS gradient.
-  nsRect positionArea;
-
-  StyleGeometryBox layerOrigin =
-    ComputeBoxValue(aForFrame, aLayer.mOrigin);
-
-  if (IsSVGStyleGeometryBox(layerOrigin)) {
-    MOZ_ASSERT(aForFrame->IsFrameOfType(nsIFrame::eSVG) &&
-               (aForFrame->GetType() != nsGkAtoms::svgOuterSVGFrame));
-    *aAttachedToFrame = aForFrame;
-
-    positionArea =
-      nsLayoutUtils::ComputeGeometryBox(aForFrame, layerOrigin);
-
-    nsPoint toStrokeBoxOffset = nsPoint(0, 0);
-    if (layerOrigin != StyleGeometryBox::StrokeBox) {
-      nsRect strokeBox =
-        nsLayoutUtils::ComputeGeometryBox(aForFrame,
-                                          StyleGeometryBox::StrokeBox);
-      toStrokeBoxOffset = positionArea.TopLeft() - strokeBox.TopLeft();
-    }
-
-    // For SVG frames, the return value is relative to the stroke box
-    return nsRect(toStrokeBoxOffset, positionArea.Size());
-  }
-
-  MOZ_ASSERT(!aForFrame->IsFrameOfType(nsIFrame::eSVG) ||
-             aForFrame->GetType() == nsGkAtoms::svgOuterSVGFrame);
-
-  nsIAtom* frameType = aForFrame->GetType();
-  nsIFrame* geometryFrame = aForFrame;
-  if (MOZ_UNLIKELY(frameType == nsGkAtoms::scrollFrame &&
-                   NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment)) {
-    nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
-    positionArea = nsRect(
-      scrollableFrame->GetScrolledFrame()->GetPosition()
-        // For the dir=rtl case:
-        + scrollableFrame->GetScrollRange().TopLeft(),
-      scrollableFrame->GetScrolledRect().Size());
-    // The ScrolledRect’s size does not include the borders or scrollbars,
-    // reverse the handling of background-origin
-    // compared to the common case below.
-    if (layerOrigin == StyleGeometryBox::BorderBox) {
-      nsMargin border = geometryFrame->GetUsedBorder();
-      border.ApplySkipSides(geometryFrame->GetSkipSides());
-      positionArea.Inflate(border);
-      positionArea.Inflate(scrollableFrame->GetActualScrollbarSizes());
-    } else if (layerOrigin != StyleGeometryBox::PaddingBox) {
-      nsMargin padding = geometryFrame->GetUsedPadding();
-      padding.ApplySkipSides(geometryFrame->GetSkipSides());
-      positionArea.Deflate(padding);
-      NS_ASSERTION(layerOrigin == StyleGeometryBox::ContentBox,
-                   "unknown background-origin value");
-    }
-    *aAttachedToFrame = aForFrame;
-    return positionArea;
-  }
-
-  if (MOZ_UNLIKELY(frameType == nsGkAtoms::canvasFrame)) {
-    geometryFrame = aForFrame->PrincipalChildList().FirstChild();
-    // geometryFrame might be null if this canvas is a page created
-    // as an overflow container (e.g. the in-flow content has already
-    // finished and this page only displays the continuations of
-    // absolutely positioned content).
-    if (geometryFrame) {
-      positionArea = geometryFrame->GetRect();
-    }
-  } else {
-    positionArea = nsRect(nsPoint(0,0), aBorderArea.Size());
-  }
-
-  // See the comment of StyleGeometryBox::MarginBox.
-  // Hitting this assertion means we decide to turn on margin-box support for
-  // positioned mask from CSS parser and style system. In this case, you
-  // should *inflate* positionArea by the margin returning from
-  // geometryFrame->GetUsedMargin() in the code chunk bellow.
-  MOZ_ASSERT(aLayer.mOrigin != StyleGeometryBox::MarginBox,
-             "StyleGeometryBox::MarginBox rendering is not supported yet.\n");
-
-  // {background|mask} images are tiled over the '{background|mask}-clip' area
-  // but the origin of the tiling is based on the '{background|mask}-origin'
-  // area.
-  if (layerOrigin != StyleGeometryBox::BorderBox && geometryFrame) {
-    nsMargin border = geometryFrame->GetUsedBorder();
-    if (layerOrigin != StyleGeometryBox::PaddingBox) {
-      border += geometryFrame->GetUsedPadding();
-      NS_ASSERTION(layerOrigin == StyleGeometryBox::ContentBox,
-                   "unknown background-origin value");
-    }
-    positionArea.Deflate(border);
-  }
-
-  nsIFrame* attachedToFrame = aForFrame;
-  if (NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED == aLayer.mAttachment) {
-    // If it's a fixed background attachment, then the image is placed
-    // relative to the viewport, which is the area of the root frame
-    // in a screen context or the page content frame in a print context.
-    attachedToFrame = aPresContext->PresShell()->FrameManager()->GetRootFrame();
-    NS_ASSERTION(attachedToFrame, "no root frame");
-    nsIFrame* pageContentFrame = nullptr;
-    if (aPresContext->IsPaginated()) {
-      pageContentFrame =
-        nsLayoutUtils::GetClosestFrameOfType(aForFrame, nsGkAtoms::pageContentFrame);
-      if (pageContentFrame) {
-        attachedToFrame = pageContentFrame;
-      }
-      // else this is an embedded shell and its root frame is what we want
-    }
-
-    // If the background is affected by a transform, treat is as if it
-    // wasn't fixed.
-    if (nsLayoutUtils::IsTransformed(aForFrame, attachedToFrame)) {
-      attachedToFrame = aForFrame;
-      *aOutIsTransformedFixed = true;
-    } else {
-      // Set the background positioning area to the viewport's area
-      // (relative to aForFrame)
-      positionArea =
-        nsRect(-aForFrame->GetOffsetTo(attachedToFrame), attachedToFrame->GetSize());
-
-      if (!pageContentFrame) {
-        // Subtract the size of scrollbars.
-        nsIScrollableFrame* scrollableFrame =
-          aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
-        if (scrollableFrame) {
-          nsMargin scrollbars = scrollableFrame->GetActualScrollbarSizes();
-          positionArea.Deflate(scrollbars);
-        }
-      }
-    }
-  }
-  *aAttachedToFrame = attachedToFrame;
-
-  return positionArea;
-}
-
-// Implementation of the formula for computation of background-repeat round
-// See http://dev.w3.org/csswg/css3-background/#the-background-size
-// This function returns the adjusted size of the background image.
-static nscoord
-ComputeRoundedSize(nscoord aCurrentSize, nscoord aPositioningSize)
-{
-  float repeatCount = NS_roundf(float(aPositioningSize) / float(aCurrentSize));
-  if (repeatCount < 1.0f) {
-    return aPositioningSize;
-  }
-  return nscoord(NS_lround(float(aPositioningSize) / repeatCount));
-}
-
-// Apply the CSS image sizing algorithm as it applies to background images.
-// See http://www.w3.org/TR/css3-background/#the-background-size .
-// aIntrinsicSize is the size that the background image 'would like to be'.
-// It can be found by calling nsImageRenderer::ComputeIntrinsicSize.
-static nsSize
-ComputeDrawnSizeForBackground(const CSSSizeOrRatio& aIntrinsicSize,
-                              const nsSize& aBgPositioningArea,
-                              const nsStyleImageLayers::Size& aLayerSize,
-                              uint8_t aXRepeat, uint8_t aYRepeat)
-{
-  nsSize imageSize;
-
-  // Size is dictated by cover or contain rules.
-  if (aLayerSize.mWidthType == nsStyleImageLayers::Size::eContain ||
-      aLayerSize.mWidthType == nsStyleImageLayers::Size::eCover) {
-    nsImageRenderer::FitType fitType =
-      aLayerSize.mWidthType == nsStyleImageLayers::Size::eCover
-        ? nsImageRenderer::COVER
-        : nsImageRenderer::CONTAIN;
-    imageSize = nsImageRenderer::ComputeConstrainedSize(aBgPositioningArea,
-                                                        aIntrinsicSize.mRatio,
-                                                        fitType);
-  } else {
-    // No cover/contain constraint, use default algorithm.
-    CSSSizeOrRatio specifiedSize;
-    if (aLayerSize.mWidthType == nsStyleImageLayers::Size::eLengthPercentage) {
-      specifiedSize.SetWidth(
-        aLayerSize.ResolveWidthLengthPercentage(aBgPositioningArea));
-    }
-    if (aLayerSize.mHeightType == nsStyleImageLayers::Size::eLengthPercentage) {
-      specifiedSize.SetHeight(
-        aLayerSize.ResolveHeightLengthPercentage(aBgPositioningArea));
-    }
-
-    imageSize = nsImageRenderer::ComputeConcreteSize(specifiedSize,
-                                                     aIntrinsicSize,
-                                                     aBgPositioningArea);
-  }
-
-  // See https://www.w3.org/TR/css3-background/#background-size .
-  // "If 'background-repeat' is 'round' for one (or both) dimensions, there is a second
-  //  step. The UA must scale the image in that dimension (or both dimensions) so that
-  //  it fits a whole number of times in the background positioning area."
-  // "If 'background-repeat' is 'round' for one dimension only and if 'background-size'
-  //  is 'auto' for the other dimension, then there is a third step: that other dimension
-  //  is scaled so that the original aspect ratio is restored."
-  bool isRepeatRoundInBothDimensions = aXRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND &&
-                                       aYRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND;
-
-  // Calculate the rounded size only if the background-size computation
-  // returned a correct size for the image.
-  if (imageSize.width && aXRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND) {
-    imageSize.width = ComputeRoundedSize(imageSize.width, aBgPositioningArea.width);
-    if (!isRepeatRoundInBothDimensions &&
-        aLayerSize.mHeightType == nsStyleImageLayers::Size::DimensionType::eAuto) {
-      // Restore intrinsic rato
-      if (aIntrinsicSize.mRatio.width) {
-        float scale = float(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width;
-        imageSize.height = NSCoordSaturatingNonnegativeMultiply(imageSize.width, scale);
-      }
-    }
-  }
-
-  // Calculate the rounded size only if the background-size computation
-  // returned a correct size for the image.
-  if (imageSize.height && aYRepeat == NS_STYLE_IMAGELAYER_REPEAT_ROUND) {
-    imageSize.height = ComputeRoundedSize(imageSize.height, aBgPositioningArea.height);
-    if (!isRepeatRoundInBothDimensions &&
-        aLayerSize.mWidthType == nsStyleImageLayers::Size::DimensionType::eAuto) {
-      // Restore intrinsic rato
-      if (aIntrinsicSize.mRatio.height) {
-        float scale = float(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height;
-        imageSize.width = NSCoordSaturatingNonnegativeMultiply(imageSize.height, scale);
-      }
-    }
-  }
-
-  return imageSize;
-}
-
-/* ComputeSpacedRepeatSize
- * aImageDimension: the image width/height
- * aAvailableSpace: the background positioning area width/height
- * aRepeat: determine whether the image is repeated
- * Returns the image size plus gap size of app units for use as spacing
- */
-static nscoord
-ComputeSpacedRepeatSize(nscoord aImageDimension,
-                        nscoord aAvailableSpace,
-                        bool& aRepeat) {
-  float ratio = static_cast<float>(aAvailableSpace) / aImageDimension;
-
-  if (ratio < 2.0f) { // If you can't repeat at least twice, then don't repeat.
-    aRepeat = false;
-    return aImageDimension;
-  } else {
-    aRepeat = true;
-    return (aAvailableSpace - aImageDimension) / (NSToIntFloor(ratio) - 1);
-  }
-}
-
-/* ComputeBorderSpacedRepeatSize
- * aImageDimension: the image width/height
- * aAvailableSpace: the background positioning area width/height
- * aSpace: the space between each image
- * Returns the image size plus gap size of app units for use as spacing
- */
-static nscoord
-ComputeBorderSpacedRepeatSize(nscoord aImageDimension,
-                              nscoord aAvailableSpace,
-                              nscoord& aSpace)
-{
-  int32_t count = aAvailableSpace / aImageDimension;
-  aSpace = (aAvailableSpace - aImageDimension * count) / (count + 1);
-  return aSpace + aImageDimension;
-}
-
-nsBackgroundLayerState
-nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
-                                  nsIFrame* aForFrame,
-                                  uint32_t aFlags,
-                                  const nsRect& aBorderArea,
-                                  const nsRect& aBGClipRect,
-                                  const nsStyleImageLayers::Layer& aLayer,
-                                  bool* aOutIsTransformedFixed)
-{
-  /*
-   * The properties we need to keep in mind when drawing style image
-   * layers are:
-   *
-   *   background-image/ mask-image
-   *   background-repeat/ mask-repeat
-   *   background-attachment
-   *   background-position/ mask-position
-   *   background-clip/ mask-clip
-   *   background-origin/ mask-origin
-   *   background-size/ mask-size
-   *   background-blend-mode
-   *   box-decoration-break
-   *   mask-mode
-   *   mask-composite
-   *
-   * (background-color applies to the entire element and not to individual
-   * layers, so it is irrelevant to this method.)
-   *
-   * These properties have the following dependencies upon each other when
-   * determining rendering:
-   *
-   *   background-image/ mask-image
-   *     no dependencies
-   *   background-repeat/ mask-repeat
-   *     no dependencies
-   *   background-attachment
-   *     no dependencies
-   *   background-position/ mask-position
-   *     depends upon background-size/mask-size (for the image's scaled size)
-   *     and background-break (for the background positioning area)
-   *   background-clip/ mask-clip
-   *     no dependencies
-   *   background-origin/ mask-origin
-   *     depends upon background-attachment (only in the case where that value
-   *     is 'fixed')
-   *   background-size/ mask-size
-   *     depends upon box-decoration-break (for the background positioning area
-   *     for resolving percentages), background-image (for the image's intrinsic
-   *     size), background-repeat (if that value is 'round'), and
-   *     background-origin (for the background painting area, when
-   *     background-repeat is 'round')
-   *   background-blend-mode
-   *     no dependencies
-   *   mask-mode
-   *     no dependencies
-   *   mask-composite
-   *     no dependencies
-   *   box-decoration-break
-   *     no dependencies
-   *
-   * As a result of only-if dependencies we don't strictly do a topological
-   * sort of the above properties when processing, but it's pretty close to one:
-   *
-   *   background-clip/mask-clip (by caller)
-   *   background-image/ mask-image
-   *   box-decoration-break, background-origin/ mask origin
-   *   background-attachment (postfix for background-origin if 'fixed')
-   *   background-size/ mask-size
-   *   background-position/ mask-position
-   *   background-repeat/ mask-repeat
-   */
-
-  uint32_t irFlags = 0;
-  if (aFlags & nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES) {
-    irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
-  }
-  if (aFlags & nsCSSRendering::PAINTBG_TO_WINDOW) {
-    irFlags |= nsImageRenderer::FLAG_PAINTING_TO_WINDOW;
-  }
-
-  nsBackgroundLayerState state(aForFrame, &aLayer.mImage, irFlags);
-  if (!state.mImageRenderer.PrepareImage()) {
-    // There's no image or it's not ready to be painted.
-    if (aOutIsTransformedFixed) {
-      *aOutIsTransformedFixed = false;
-    }
-    return state;
-  }
-
-  // The frame to which the background is attached
-  nsIFrame* attachedToFrame = aForFrame;
-  // Is the background marked 'fixed', but affected by a transform?
-  bool transformedFixed = false;
-  // Compute background origin area relative to aBorderArea now as we may need
-  // it to compute the effective image size for a CSS gradient.
-  nsRect positionArea =
-    ComputeImageLayerPositioningArea(aPresContext, aForFrame, aBorderArea,
-                                     aLayer, &attachedToFrame, &transformedFixed);
-  if (aOutIsTransformedFixed) {
-    *aOutIsTransformedFixed = transformedFixed;
-  }
-
-  // For background-attachment:fixed backgrounds, we'll override the area
-  // where the background can be drawn to the viewport.
-  nsRect bgClipRect = aBGClipRect;
-
-  if (NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED == aLayer.mAttachment &&
-      !transformedFixed &&
-      (aFlags & nsCSSRendering::PAINTBG_TO_WINDOW)) {
-    bgClipRect = positionArea + aBorderArea.TopLeft();
-  }
-
-  int repeatX = aLayer.mRepeat.mXRepeat;
-  int repeatY = aLayer.mRepeat.mYRepeat;
-
-  // Scale the image as specified for background-size and background-repeat.
-  // Also as required for proper background positioning when background-position
-  // is defined with percentages.
-  CSSSizeOrRatio intrinsicSize = state.mImageRenderer.ComputeIntrinsicSize();
-  nsSize bgPositionSize = positionArea.Size();
-  nsSize imageSize = ComputeDrawnSizeForBackground(intrinsicSize,
-                                                   bgPositionSize,
-                                                   aLayer.mSize,
-                                                   repeatX,
-                                                   repeatY);
-
-  if (imageSize.width <= 0 || imageSize.height <= 0)
-    return state;
-
-  state.mImageRenderer.SetPreferredSize(intrinsicSize,
-                                        imageSize);
-
-  // Compute the anchor point.
-  //
-  // relative to aBorderArea.TopLeft() (which is where the top-left
-  // of aForFrame's border-box will be rendered)
-  nsPoint imageTopLeft;
-
-  // Compute the position of the background now that the background's size is
-  // determined.
-  nsImageRenderer::ComputeObjectAnchorPoint(aLayer.mPosition,
-                                            bgPositionSize, imageSize,
-                                            &imageTopLeft, &state.mAnchor);
-  state.mRepeatSize = imageSize;
-  if (repeatX == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
-    bool isRepeat;
-    state.mRepeatSize.width = ComputeSpacedRepeatSize(imageSize.width,
-                                                      bgPositionSize.width,
-                                                      isRepeat);
-    if (isRepeat) {
-      imageTopLeft.x = 0;
-      state.mAnchor.x = 0;
-    } else {
-      repeatX = NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
-    }
-  }
-
-  if (repeatY == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
-    bool isRepeat;
-    state.mRepeatSize.height = ComputeSpacedRepeatSize(imageSize.height,
-                                                       bgPositionSize.height,
-                                                       isRepeat);
-    if (isRepeat) {
-      imageTopLeft.y = 0;
-      state.mAnchor.y = 0;
-    } else {
-      repeatY = NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT;
-    }
-  }
-
-  imageTopLeft += positionArea.TopLeft();
-  state.mAnchor += positionArea.TopLeft();
-  state.mDestArea = nsRect(imageTopLeft + aBorderArea.TopLeft(), imageSize);
-  state.mFillArea = state.mDestArea;
-
-  ExtendMode repeatMode = ExtendMode::CLAMP;
-  if (repeatX == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
-      repeatX == NS_STYLE_IMAGELAYER_REPEAT_ROUND ||
-      repeatX == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
-    state.mFillArea.x = bgClipRect.x;
-    state.mFillArea.width = bgClipRect.width;
-    repeatMode = ExtendMode::REPEAT_X;
-  }
-  if (repeatY == NS_STYLE_IMAGELAYER_REPEAT_REPEAT ||
-      repeatY == NS_STYLE_IMAGELAYER_REPEAT_ROUND ||
-      repeatY == NS_STYLE_IMAGELAYER_REPEAT_SPACE) {
-    state.mFillArea.y = bgClipRect.y;
-    state.mFillArea.height = bgClipRect.height;
-
-    /***
-     * We're repeating on the X axis already,
-     * so if we have to repeat in the Y axis,
-     * we really need to repeat in both directions.
-     */
-    if (repeatMode == ExtendMode::REPEAT_X) {
-      repeatMode = ExtendMode::REPEAT;
-    } else {
-      repeatMode = ExtendMode::REPEAT_Y;
-    }
-  }
-  state.mImageRenderer.SetExtendMode(repeatMode);
-  state.mImageRenderer.SetMaskOp(aLayer.mMaskMode);
-
-  state.mFillArea.IntersectRect(state.mFillArea, bgClipRect);
-
-  return state;
-}
-
-nsRect
-nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
-                                       nsIFrame* aForFrame,
-                                       const nsRect& aBorderArea,
-                                       const nsRect& aClipRect,
-                                       const nsStyleImageLayers::Layer& aLayer,
-                                       uint32_t aFlags)
-{
-  Sides skipSides = aForFrame->GetSkipSides();
-  nsRect borderArea =
-    ::BoxDecorationRectForBackground(aForFrame, aBorderArea, skipSides);
-  nsBackgroundLayerState state =
-      PrepareImageLayer(aPresContext, aForFrame, aFlags, borderArea,
-                             aClipRect, aLayer);
-  return state.mFillArea;
-}
-
-// Begin table border-collapsing section
-// These functions were written to not disrupt the normal ones and yet satisfy some additional requirements
-// At some point, all functions should be unified to include the additional functionality that these provide
-
-static nscoord
-RoundIntToPixel(nscoord aValue,
-                nscoord aTwipsPerPixel,
-                bool    aRoundDown = false)
-{
-  if (aTwipsPerPixel <= 0)
-    // We must be rendering to a device that has a resolution greater than Twips!
-    // In that case, aValue is as accurate as it's going to get.
-    return aValue;
-
-  nscoord halfPixel = NSToCoordRound(aTwipsPerPixel / 2.0f);
-  nscoord extra = aValue % aTwipsPerPixel;
-  nscoord finalValue = (!aRoundDown && (extra >= halfPixel)) ? aValue + (aTwipsPerPixel - extra) : aValue - extra;
-  return finalValue;
-}
-
-static nscoord
-RoundFloatToPixel(float   aValue,
-                  nscoord aTwipsPerPixel,
-                  bool    aRoundDown = false)
-{
-  return RoundIntToPixel(NSToCoordRound(aValue), aTwipsPerPixel, aRoundDown);
-}
-
-static void SetPoly(const Rect& aRect, Point* poly)
-{
-  poly[0].x = aRect.x;
-  poly[0].y = aRect.y;
-  poly[1].x = aRect.x + aRect.width;
-  poly[1].y = aRect.y;
-  poly[2].x = aRect.x + aRect.width;
-  poly[2].y = aRect.y + aRect.height;
-  poly[3].x = aRect.x;
-  poly[3].y = aRect.y + aRect.height;
-}
-
-static void
-DrawDashedSegment(DrawTarget&          aDrawTarget,
-                  nsRect               aRect,
-                  nscoord              aDashLength,
-                  nscolor              aColor,
-                  int32_t              aAppUnitsPerDevPixel,
-                  nscoord              aTwipsPerPixel,
-                  bool                 aHorizontal)
-{
-  ColorPattern color(ToDeviceColor(aColor));
-  DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE);
-  StrokeOptions strokeOptions;
-
-  Float dash[2];
-  dash[0] = Float(aDashLength) / aAppUnitsPerDevPixel;
-  dash[1] = dash[0];
-
-  strokeOptions.mDashPattern = dash;
-  strokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
-
-  if (aHorizontal) {
-    nsPoint left = (aRect.TopLeft() + aRect.BottomLeft()) / 2;
-    nsPoint right = (aRect.TopRight() + aRect.BottomRight()) / 2;
-    strokeOptions.mLineWidth = Float(aRect.height) / aAppUnitsPerDevPixel;
-    StrokeLineWithSnapping(left, right,
-                           aAppUnitsPerDevPixel, aDrawTarget,
-                           color, strokeOptions, drawOptions);
-  } else {
-    nsPoint top = (aRect.TopLeft() + aRect.TopRight()) / 2;
-    nsPoint bottom = (aRect.BottomLeft() + aRect.BottomRight()) / 2;
-    strokeOptions.mLineWidth = Float(aRect.width) / aAppUnitsPerDevPixel;
-    StrokeLineWithSnapping(top, bottom,
-                           aAppUnitsPerDevPixel, aDrawTarget,
-                           color, strokeOptions, drawOptions);
-  }
-}
-
-static void
-DrawSolidBorderSegment(DrawTarget&          aDrawTarget,
-                       nsRect               aRect,
-                       nscolor              aColor,
-                       int32_t              aAppUnitsPerDevPixel,
-                       nscoord              aTwipsPerPixel,
-                       uint8_t              aStartBevelSide = 0,
-                       nscoord              aStartBevelOffset = 0,
-                       uint8_t              aEndBevelSide = 0,
-                       nscoord              aEndBevelOffset = 0)
-{
-  ColorPattern color(ToDeviceColor(aColor));
-  DrawOptions drawOptions(1.f, CompositionOp::OP_OVER, AntialiasMode::NONE);
-
-  // We don't need to bevel single pixel borders
-  if ((aRect.width == aTwipsPerPixel) || (aRect.height == aTwipsPerPixel) ||
-      ((0 == aStartBevelOffset) && (0 == aEndBevelOffset))) {
-    // simple rectangle
-    aDrawTarget.FillRect(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel,
-                                             aDrawTarget),
-                         color, drawOptions);
-  }
-  else {
-    // polygon with beveling
-    Point poly[4];
-    SetPoly(NSRectToSnappedRect(aRect, aAppUnitsPerDevPixel, aDrawTarget),
-            poly);
-
-    Float startBevelOffset =
-      NSAppUnitsToFloatPixels(aStartBevelOffset, aAppUnitsPerDevPixel);
-    switch(aStartBevelSide) {
-    case eSideTop:
-      poly[0].x += startBevelOffset;
-      break;
-    case eSideBottom:
-      poly[3].x += startBevelOffset;
-      break;
-    case eSideRight:
-      poly[1].y += startBevelOffset;
-      break;
-    case eSideLeft:
-      poly[0].y += startBevelOffset;
-    }
-
-    Float endBevelOffset =
-      NSAppUnitsToFloatPixels(aEndBevelOffset, aAppUnitsPerDevPixel);
-    switch(aEndBevelSide) {
-    case eSideTop:
-      poly[1].x -= endBevelOffset;
-      break;
-    case eSideBottom:
-      poly[2].x -= endBevelOffset;
-      break;
-    case eSideRight:
-      poly[2].y -= endBevelOffset;
-      break;
-    case eSideLeft:
-      poly[3].y -= endBevelOffset;
-    }
-
-    RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
-    builder->MoveTo(poly[0]);
-    builder->LineTo(poly[1]);
-    builder->LineTo(poly[2]);
-    builder->LineTo(poly[3]);
-    builder->Close();
-    RefPtr<Path> path = builder->Finish();
-    aDrawTarget.Fill(path, color, drawOptions);
-  }
-}
-
-static void
-GetDashInfo(nscoord  aBorderLength,
-            nscoord  aDashLength,
-            nscoord  aTwipsPerPixel,
-            int32_t& aNumDashSpaces,
-            nscoord& aStartDashLength,
-            nscoord& aEndDashLength)
-{
-  aNumDashSpaces = 0;
-  if (aStartDashLength + aDashLength + aEndDashLength >= aBorderLength) {
-    aStartDashLength = aBorderLength;
-    aEndDashLength = 0;
-  }
-  else {
-    aNumDashSpaces = (aBorderLength - aDashLength)/ (2 * aDashLength); // round down
-    nscoord extra = aBorderLength - aStartDashLength - aEndDashLength - (((2 * aNumDashSpaces) - 1) * aDashLength);
-    if (extra > 0) {
-      nscoord half = RoundIntToPixel(extra / 2, aTwipsPerPixel);
-      aStartDashLength += half;
-      aEndDashLength += (extra - half);
-    }
-  }
-}
-
-void
-nsCSSRendering::DrawTableBorderSegment(DrawTarget&   aDrawTarget,
-                                       uint8_t       aBorderStyle,
-                                       nscolor       aBorderColor,
-                                       nscolor       aBGColor,
-                                       const nsRect& aBorder,
-                                       int32_t       aAppUnitsPerDevPixel,
-                                       int32_t       aAppUnitsPerCSSPixel,
-                                       uint8_t       aStartBevelSide,
-                                       nscoord       aStartBevelOffset,
-                                       uint8_t       aEndBevelSide,
-                                       nscoord       aEndBevelOffset)
-{
-  bool horizontal = ((eSideTop == aStartBevelSide) || (eSideBottom == aStartBevelSide));
-  nscoord twipsPerPixel = NSIntPixelsToAppUnits(1, aAppUnitsPerCSSPixel);
-  uint8_t ridgeGroove = NS_STYLE_BORDER_STYLE_RIDGE;
-
-  if ((twipsPerPixel >= aBorder.width) || (twipsPerPixel >= aBorder.height) ||
-      (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) || (NS_STYLE_BORDER_STYLE_DOTTED == aBorderStyle)) {
-    // no beveling for 1 pixel border, dash or dot
-    aStartBevelOffset = 0;
-    aEndBevelOffset = 0;
-  }
-
-  switch (aBorderStyle) {
-  case NS_STYLE_BORDER_STYLE_NONE:
-  case NS_STYLE_BORDER_STYLE_HIDDEN:
-    //NS_ASSERTION(false, "style of none or hidden");
-    break;
-  case NS_STYLE_BORDER_STYLE_DOTTED:
-  case NS_STYLE_BORDER_STYLE_DASHED:
-    {
-      nscoord dashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle) ? DASH_LENGTH : DOT_LENGTH;
-      // make the dash length proportional to the border thickness
-      dashLength *= (horizontal) ? aBorder.height : aBorder.width;
-      // make the min dash length for the ends 1/2 the dash length
-      nscoord minDashLength = (NS_STYLE_BORDER_STYLE_DASHED == aBorderStyle)
-                              ? RoundFloatToPixel(((float)dashLength) / 2.0f, twipsPerPixel) : dashLength;
-      minDashLength = std::max(minDashLength, twipsPerPixel);
-      nscoord numDashSpaces = 0;
-      nscoord startDashLength = minDashLength;
-      nscoord endDashLength   = minDashLength;
-      if (horizontal) {
-        GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces,
-                    startDashLength, endDashLength);
-        nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height);
-        DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
-
-        rect.x += startDashLength + dashLength;
-        rect.width = aBorder.width
-                     - (startDashLength + endDashLength + dashLength);
-        DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor,
-                          aAppUnitsPerDevPixel, twipsPerPixel, horizontal);
-
-        rect.x += rect.width;
-        rect.width = endDashLength;
-        DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
-      }
-      else {
-        GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces,
-                    startDashLength, endDashLength);
-        nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength);
-        DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
-
-        rect.y += rect.height + dashLength;
-        rect.height = aBorder.height
-                      - (startDashLength + endDashLength + dashLength);
-        DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor,
-                          aAppUnitsPerDevPixel, twipsPerPixel, horizontal);
-
-        rect.y += rect.height;
-        rect.height = endDashLength;
-        DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel);
-      }
-    }
-    break;
-  case NS_STYLE_BORDER_STYLE_GROOVE:
-    ridgeGroove = NS_STYLE_BORDER_STYLE_GROOVE; // and fall through to ridge
-    MOZ_FALLTHROUGH;
-  case NS_STYLE_BORDER_STYLE_RIDGE:
-    if ((horizontal && (twipsPerPixel >= aBorder.height)) ||
-        (!horizontal && (twipsPerPixel >= aBorder.width))) {
-      // a one pixel border
-      DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor,
-                             aAppUnitsPerDevPixel, twipsPerPixel,
-                             aStartBevelSide, aStartBevelOffset,
-                             aEndBevelSide, aEndBevelOffset);
-    }
-    else {
-      nscoord startBevel = (aStartBevelOffset > 0)
-                            ? RoundFloatToPixel(0.5f * (float)aStartBevelOffset, twipsPerPixel, true) : 0;
-      nscoord endBevel =   (aEndBevelOffset > 0)
-                            ? RoundFloatToPixel(0.5f * (float)aEndBevelOffset, twipsPerPixel, true) : 0;
-      mozilla::Side ridgeGrooveSide = (horizontal) ? eSideTop : eSideLeft;
-      // FIXME: In theory, this should use the visited-dependent
-      // background color, but I don't care.
-      nscolor bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove,
-                                          aBGColor, aBorderColor);
-      nsRect rect(aBorder);
-      nscoord half;
-      if (horizontal) { // top, bottom
-        half = RoundFloatToPixel(0.5f * (float)aBorder.height, twipsPerPixel);
-        rect.height = half;
-        if (eSideTop == aStartBevelSide) {
-          rect.x += startBevel;
-          rect.width -= startBevel;
-        }
-        if (eSideTop == aEndBevelSide) {
-          rect.width -= endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-      }
-      else { // left, right
-        half = RoundFloatToPixel(0.5f * (float)aBorder.width, twipsPerPixel);
-        rect.width = half;
-        if (eSideLeft == aStartBevelSide) {
-          rect.y += startBevel;
-          rect.height -= startBevel;
-        }
-        if (eSideLeft == aEndBevelSide) {
-          rect.height -= endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-      }
-
-      rect = aBorder;
-      ridgeGrooveSide = (eSideTop == ridgeGrooveSide) ? eSideBottom : eSideRight;
-      // FIXME: In theory, this should use the visited-dependent
-      // background color, but I don't care.
-      bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove,
-                                  aBGColor, aBorderColor);
-      if (horizontal) {
-        rect.y = rect.y + half;
-        rect.height = aBorder.height - half;
-        if (eSideBottom == aStartBevelSide) {
-          rect.x += startBevel;
-          rect.width -= startBevel;
-        }
-        if (eSideBottom == aEndBevelSide) {
-          rect.width -= endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-      }
-      else {
-        rect.x = rect.x + half;
-        rect.width = aBorder.width - half;
-        if (eSideRight == aStartBevelSide) {
-          rect.y += aStartBevelOffset - startBevel;
-          rect.height -= startBevel;
-        }
-        if (eSideRight == aEndBevelSide) {
-          rect.height -= endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, rect, bevelColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-      }
-    }
-    break;
-  case NS_STYLE_BORDER_STYLE_DOUBLE:
-    // We can only do "double" borders if the thickness of the border
-    // is more than 2px.  Otherwise, we fall through to painting a
-    // solid border.
-    if ((aBorder.width > 2*twipsPerPixel || horizontal) &&
-        (aBorder.height > 2*twipsPerPixel || !horizontal)) {
-      nscoord startBevel = (aStartBevelOffset > 0)
-                            ? RoundFloatToPixel(0.333333f * (float)aStartBevelOffset, twipsPerPixel) : 0;
-      nscoord endBevel =   (aEndBevelOffset > 0)
-                            ? RoundFloatToPixel(0.333333f * (float)aEndBevelOffset, twipsPerPixel) : 0;
-      if (horizontal) { // top, bottom
-        nscoord thirdHeight = RoundFloatToPixel(0.333333f * (float)aBorder.height, twipsPerPixel);
-
-        // draw the top line or rect
-        nsRect topRect(aBorder.x, aBorder.y, aBorder.width, thirdHeight);
-        if (eSideTop == aStartBevelSide) {
-          topRect.x += aStartBevelOffset - startBevel;
-          topRect.width -= aStartBevelOffset - startBevel;
-        }
-        if (eSideTop == aEndBevelSide) {
-          topRect.width -= aEndBevelOffset - endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, topRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-
-        // draw the botom line or rect
-        nscoord heightOffset = aBorder.height - thirdHeight;
-        nsRect bottomRect(aBorder.x, aBorder.y + heightOffset, aBorder.width, aBorder.height - heightOffset);
-        if (eSideBottom == aStartBevelSide) {
-          bottomRect.x += aStartBevelOffset - startBevel;
-          bottomRect.width -= aStartBevelOffset - startBevel;
-        }
-        if (eSideBottom == aEndBevelSide) {
-          bottomRect.width -= aEndBevelOffset - endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, bottomRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-      }
-      else { // left, right
-        nscoord thirdWidth = RoundFloatToPixel(0.333333f * (float)aBorder.width, twipsPerPixel);
-
-        nsRect leftRect(aBorder.x, aBorder.y, thirdWidth, aBorder.height);
-        if (eSideLeft == aStartBevelSide) {
-          leftRect.y += aStartBevelOffset - startBevel;
-          leftRect.height -= aStartBevelOffset - startBevel;
-        }
-        if (eSideLeft == aEndBevelSide) {
-          leftRect.height -= aEndBevelOffset - endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, leftRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-
-        nscoord widthOffset = aBorder.width - thirdWidth;
-        nsRect rightRect(aBorder.x + widthOffset, aBorder.y, aBorder.width - widthOffset, aBorder.height);
-        if (eSideRight == aStartBevelSide) {
-          rightRect.y += aStartBevelOffset - startBevel;
-          rightRect.height -= aStartBevelOffset - startBevel;
-        }
-        if (eSideRight == aEndBevelSide) {
-          rightRect.height -= aEndBevelOffset - endBevel;
-        }
-        DrawSolidBorderSegment(aDrawTarget, rightRect, aBorderColor,
-                               aAppUnitsPerDevPixel, twipsPerPixel,
-                               aStartBevelSide, startBevel, aEndBevelSide,
-                               endBevel);
-      }
-      break;
-    }
-    // else fall through to solid
-    MOZ_FALLTHROUGH;
-  case NS_STYLE_BORDER_STYLE_SOLID:
-    DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor,
-                           aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide,
-                           aStartBevelOffset, aEndBevelSide, aEndBevelOffset);
-    break;
-  case NS_STYLE_BORDER_STYLE_OUTSET:
-  case NS_STYLE_BORDER_STYLE_INSET:
-    NS_ASSERTION(false, "inset, outset should have been converted to groove, ridge");
-    break;
-  case NS_STYLE_BORDER_STYLE_AUTO:
-    NS_ASSERTION(false, "Unexpected 'auto' table border");
-    break;
-  }
-}
-
-// End table border-collapsing section
-
-Rect
-nsCSSRendering::ExpandPaintingRectForDecorationLine(
-                  nsIFrame* aFrame,
-                  const uint8_t aStyle,
-                  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:
-      NS_ERROR("Invalid style was specified");
-      return aClippedRect;
-  }
-
-  nsBlockFrame* block = nullptr;
-  // Note that when we paint the decoration lines in relative positioned
-  // box, we should paint them like all of the boxes are positioned as static.
-  nscoord framePosInBlockAppUnits = 0;
-  for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
-    block = do_QueryFrame(f);
-    if (block) {
-      break;
-    }
-    framePosInBlockAppUnits += aVertical ?
-      f->GetNormalPosition().y : f->GetNormalPosition().x;
-  }
-
-  NS_ENSURE_TRUE(block, aClippedRect);
-
-  nsPresContext *pc = aFrame->PresContext();
-  Float framePosInBlock = Float(pc->AppUnitsToGfxUnits(framePosInBlockAppUnits));
-  int32_t rectPosInBlock =
-    int32_t(NS_round(framePosInBlock + aICoordInFrame));
-  int32_t extraStartEdge =
-    rectPosInBlock - (rectPosInBlock / int32_t(aCycleLength) * aCycleLength);
-  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, DrawTarget& aDrawTarget,
-                                    const PaintDecorationLineParams& aParams)
-{
-  NS_ASSERTION(aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_NONE,
-               "aStyle is none");
-
-  Rect rect = ToRect(GetTextDecorationRectInternal(aParams.pt, aParams));
-  if (rect.IsEmpty() || !rect.Intersects(aParams.dirtyRect)) {
-    return;
-  }
-
-  if (aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE &&
-      aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_OVERLINE &&
-      aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
-    NS_ERROR("Invalid decoration value!");
-    return;
-  }
-
-  Float lineThickness = std::max(NS_round(aParams.lineSize.height), 1.0);
-
-  ColorPattern color(ToDeviceColor(aParams.color));
-  StrokeOptions strokeOptions(lineThickness);
-  DrawOptions drawOptions;
-
-  Float dash[2];
-
-  AutoPopClips autoPopClips(&aDrawTarget);
-
-  switch (aParams.style) {
-    case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
-    case NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE:
-      break;
-    case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: {
-      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, aParams.style,
-                                                 rect, aParams.icoordInFrame,
-                                                 dashWidth * 2,
-                                                 aParams.vertical);
-      // 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: {
-      autoPopClips.PushClipRect(rect);
-      Float dashWidth = lineThickness * DOT_LENGTH;
-      if (lineThickness > 2.0) {
-        dash[0] = 0.f;
-        dash[1] = dashWidth * 2.f;
-        strokeOptions.mLineCap = CapStyle::ROUND;
-      } else {
-        dash[0] = dashWidth;
-        dash[1] = dashWidth;
-      }
-      strokeOptions.mDashPattern = dash;
-      strokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
-      rect = ExpandPaintingRectForDecorationLine(aFrame, aParams.style,
-                                                 rect, aParams.icoordInFrame,
-                                                 dashWidth * 2,
-                                                 aParams.vertical);
-      // 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:
-      autoPopClips.PushClipRect(rect);
-      if (lineThickness > 2.0) {
-        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.
-        drawOptions.mAntialiasMode = AntialiasMode::NONE;
-      }
-      break;
-    default:
-      NS_ERROR("Invalid style value!");
-      return;
-  }
-
-  // The block-direction position should be set to the middle of the line.
-  if (aParams.vertical) {
-    rect.x += lineThickness / 2;
-  } else {
-    rect.y += lineThickness / 2;
-  }
-
-  switch (aParams.style) {
-    case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
-    case NS_STYLE_TEXT_DECORATION_STYLE_DOTTED:
-    case NS_STYLE_TEXT_DECORATION_STYLE_DASHED: {
-      Point p1 = rect.TopLeft();
-      Point p2 = aParams.vertical ? 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
-       * +-------------------------------------------+
-       */
-      Point p1 = rect.TopLeft();
-      Point p2 = aParams.vertical ? rect.BottomLeft() : rect.TopRight();
-      aDrawTarget.StrokeLine(p1, p2, color, strokeOptions, drawOptions);
-
-      if (aParams.vertical) {
-        rect.width -= lineThickness;
-      } else {
-        rect.height -= lineThickness;
-      }
-
-      p1 = aParams.vertical ? 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  |
-       *   PP|PX          XPPPPPPX          XPPPPPPX |    ^
-       *   XX|XPX        XPXXXXXXPX        XPXXXXXXPX|    |
-       *     | XPX      XPX      XPX      XPX      XP|X   |adv
-       *     |  XPXXXXXXPX        XPXXXXXXPX        X|PX  |
-       *     |   XPPPPPPX          XPPPPPPX          |XPX v
-       *     |    XXXXXX            XXXXXX           | XX
-       *     +---------------------------------------+
-       *      <---><--->                                ^
-       *      adv  flatLengthAtVertex                   rightMost
-       *
-       *  1. Always starts from top-left of the drawing area, however, we need
-       *     to draw  the line from outside of the rect.  Because the start
-       *     point of the line is not good style if we draw from inside it.
-       *  2. First, draw horizontal line from outside the rect to top-left of
-       *     the rect;
-       *  3. Goes down to bottom of the area at 45 degrees.
-       *  4. Slides to right horizontaly, see |flatLengthAtVertex|.
-       *  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.
-       */
-
-      Float& rectICoord = aParams.vertical ? rect.y : rect.x;
-      Float& rectISize = aParams.vertical ? rect.height : rect.width;
-      const Float rectBSize = aParams.vertical ? 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 Float cycleLength = 2 * (adv + flatLengthAtVertex);
-      rect = ExpandPaintingRectForDecorationLine(aFrame, aParams.style, rect,
-                                                 aParams.icoordInFrame,
-                                                 cycleLength, aParams.vertical);
-      // 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 Float dirtyRectICoord = aParams.vertical ? aParams.dirtyRect.y
-                                                     : aParams.dirtyRect.x;
-      int32_t skipCycles = floor((dirtyRectICoord - rectICoord) / cycleLength);
-      if (skipCycles > 0) {
-        rectICoord += skipCycles * cycleLength;
-        rectISize -= skipCycles * cycleLength;
-      }
-
-      rectICoord += lineThickness / 2.0;
-      Point pt(rect.TopLeft());
-      Float& ptICoord = aParams.vertical ? pt.y : pt.x;
-      Float& ptBCoord = aParams.vertical ? pt.x : pt.y;
-      if (aParams.vertical) {
-        ptBCoord += adv + lineThickness / 2.0;
-      }
-      Float iCoordLimit = ptICoord + rectISize + lineThickness;
-
-      const Float dirtyRectIMost = aParams.vertical ?
-        aParams.dirtyRect.YMost() : aParams.dirtyRect.XMost();
-      skipCycles = floor((iCoordLimit - dirtyRectIMost) / cycleLength);
-      if (skipCycles > 0) {
-        iCoordLimit -= skipCycles * cycleLength;
-      }
-
-      RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
-      RefPtr<Path> path;
-
-      ptICoord -= lineThickness;
-      builder->MoveTo(pt); // 1
-
-      ptICoord = rectICoord;
-      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 = aParams.vertical ? 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
-          path = builder->Finish();
-          aDrawTarget.Stroke(path, color, strokeOptions, drawOptions);
-          builder = aDrawTarget.CreatePathBuilder();
-          builder->MoveTo(pt);
-          iter = 0;
-        }
-        ptICoord += adv;
-        ptBCoord += goDown ? adv : -adv;
-
-        builder->LineTo(pt); // 3 and 5
-
-        ptICoord += flatLengthAtVertex;
-        builder->LineTo(pt); // 4 and 6
-
-        goDown = !goDown;
-      }
-      path = builder->Finish();
-      aDrawTarget.Stroke(path, color, strokeOptions, drawOptions);
-      return;
-    }
-    default:
-      NS_ERROR("Invalid style value!");
-  }
-}
-
-Rect
-nsCSSRendering::DecorationLineToPath(const PaintDecorationLineParams& aParams)
-{
-  NS_ASSERTION(aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_NONE,
-               "aStyle is none");
-
-  Rect path; // To benefit from RVO, we return this from all return points
-
-  Rect rect = ToRect(GetTextDecorationRectInternal(aParams.pt, aParams));
-  if (rect.IsEmpty() || !rect.Intersects(aParams.dirtyRect)) {
-    return path;
-  }
-
-  if (aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE &&
-      aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_OVERLINE &&
-      aParams.decoration != NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
-    NS_ERROR("Invalid decoration value!");
-    return path;
-  }
-
-  if (aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_SOLID) {
-    // For the moment, we support only solid text decorations.
-    return path;
-  }
-
-  Float lineThickness = std::max(NS_round(aParams.lineSize.height), 1.0);
-
-  // The block-direction position should be set to the middle of the line.
-  if (aParams.vertical) {
-    rect.x += lineThickness / 2;
-    path = Rect(rect.TopLeft() - Point(lineThickness / 2, 0.0),
-                Size(lineThickness, rect.Height()));
-  } else {
-    rect.y += lineThickness / 2;
-    path = Rect(rect.TopLeft() - Point(0.0, lineThickness / 2),
-                Size(rect.Width(), lineThickness));
-  }
-
-  return path;
-}
-
-nsRect
-nsCSSRendering::GetTextDecorationRect(nsPresContext* aPresContext,
-                                      const DecorationRectParams& aParams)
-{
-  NS_ASSERTION(aPresContext, "aPresContext is null");
-  NS_ASSERTION(aParams.style != NS_STYLE_TEXT_DECORATION_STYLE_NONE,
-               "aStyle is none");
-
-  gfxRect rect = GetTextDecorationRectInternal(Point(0, 0), aParams);
-  // The rect values are already rounded to nearest device pixels.
-  nsRect r;
-  r.x = aPresContext->GfxUnitsToAppUnits(rect.X());
-  r.y = aPresContext->GfxUnitsToAppUnits(rect.Y());
-  r.width = aPresContext->GfxUnitsToAppUnits(rect.Width());
-  r.height = aPresContext->GfxUnitsToAppUnits(rect.Height());
-  return r;
-}
-
-gfxRect
-nsCSSRendering::GetTextDecorationRectInternal(const Point& aPt,
-                                              const DecorationRectParams& aParams)
-{
-  NS_ASSERTION(aParams.style <= NS_STYLE_TEXT_DECORATION_STYLE_WAVY,
-               "Invalid aStyle value");
-
-  if (aParams.style == NS_STYLE_TEXT_DECORATION_STYLE_NONE)
-    return gfxRect(0, 0, 0, 0);
-
-  bool canLiftUnderline = aParams.descentLimit >= 0.0;
-
-  gfxFloat iCoord = aParams.vertical ? aPt.y : aPt.x;
-  gfxFloat bCoord = aParams.vertical ? aPt.x : aPt.y;
-
-  // 'left' and 'right' are relative to the line, so for vertical writing modes
-  // they will actually become top and bottom of the rendered line.
-  // Similarly, aLineSize.width and .height are actually length and thickness
-  // of the line, which runs horizontally or vertically according to aVertical.
-  const gfxFloat left  = floor(iCoord + 0.5),
-                 right = floor(iCoord + aParams.lineSize.width + 0.5);
-
-  // We compute |r| as if for a horizontal text run, and then swap vertical
-  // and horizontal coordinates at the end if vertical was requested.
-  gfxRect r(left, 0, right - left, 0);
-
-  gfxFloat lineThickness = NS_round(aParams.lineSize.height);
-  lineThickness = std::max(lineThickness, 1.0);
-
-  gfxFloat ascent = NS_round(aParams.ascent);
-  gfxFloat descentLimit = floor(aParams.descentLimit);
-
-  gfxFloat suggestedMaxRectHeight = std::max(std::min(ascent, descentLimit), 1.0);
-  r.height = lineThickness;
-  if (aParams.style == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE) {
-    /**
-     *  We will draw double line as:
-     *
-     * +-------------------------------------------+
-     * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
-     * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
-     * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
-     * |                                           | ^
-     * |                                           | | gap
-     * |                                           | v
-     * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| ^
-     * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| | lineThickness
-     * |XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX| v
-     * +-------------------------------------------+
-     */
-    gfxFloat gap = NS_round(lineThickness / 2.0);
-    gap = std::max(gap, 1.0);
-    r.height = lineThickness * 2.0 + gap;
-    if (canLiftUnderline) {
-      if (r.Height() > suggestedMaxRectHeight) {
-        // Don't shrink the line height, because the thickness has some meaning.
-        // We can just shrink the gap at this time.
-        r.height = std::max(suggestedMaxRectHeight, lineThickness * 2.0 + 1.0);
-      }
-    }
-  } else if (aParams.style == NS_STYLE_TEXT_DECORATION_STYLE_WAVY) {
-    /**
-     *  We will draw wavy line as:
-     *
-     * +-------------------------------------------+
-     * |XXXXX            XXXXXX            XXXXXX  | ^
-     * |XXXXXX          XXXXXXXX          XXXXXXXX | | lineThickness
-     * |XXXXXXX        XXXXXXXXXX        XXXXXXXXXX| v
-     * |     XXX      XXX      XXX      XXX      XX|
-     * |      XXXXXXXXXX        XXXXXXXXXX        X|
-     * |       XXXXXXXX          XXXXXXXX          |
-     * |        XXXXXX            XXXXXX           |
-     * +-------------------------------------------+
-     */
-    r.height = lineThickness > 2.0 ? lineThickness * 4.0 : lineThickness * 3.0;
-    if (canLiftUnderline) {
-      if (r.Height() > suggestedMaxRectHeight) {
-        // Don't shrink the line height even if there is not enough space,
-        // because the thickness has some meaning.  E.g., the 1px wavy line and
-        // 2px wavy line can be used for different meaning in IME selections
-        // at same time.
-        r.height = std::max(suggestedMaxRectHeight, lineThickness * 2.0);
-      }
-    }
-  }
-
-  gfxFloat baseline = floor(bCoord + aParams.ascent + 0.5);
-  gfxFloat offset = 0.0;
-  switch (aParams.decoration) {
-    case NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE:
-      offset = aParams.offset;
-      if (canLiftUnderline) {
-        if (descentLimit < -offset + r.Height()) {
-          // If we can ignore the offset and the decoration line is overflowing,
-          // we should align the bottom edge of the decoration line rect if it's
-          // possible.  Otherwise, we should lift up the top edge of the rect as
-          // far as possible.
-          gfxFloat offsetBottomAligned = -descentLimit + r.Height();
-          gfxFloat offsetTopAligned = 0.0;
-          offset = std::min(offsetBottomAligned, offsetTopAligned);
-        }
-      }
-      break;
-    case NS_STYLE_TEXT_DECORATION_LINE_OVERLINE:
-      offset = aParams.offset - lineThickness + r.Height();
-      break;
-    case NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH: {
-      gfxFloat extra = floor(r.Height() / 2.0 + 0.5);
-      extra = std::max(extra, lineThickness);
-      offset = aParams.offset - lineThickness + extra;
-      break;
-    }
-    default:
-      NS_ERROR("Invalid decoration value!");
-  }
-
-  if (aParams.vertical) {
-    r.y = baseline + floor(offset + 0.5);
-    Swap(r.x, r.y);
-    Swap(r.width, r.height);
-  } else {
-    r.y = baseline - floor(offset + 0.5);
-  }
-
-  return r;
-}
-
-#define MAX_BLUR_RADIUS 300
-#define MAX_SPREAD_RADIUS 50
-
-static inline gfxPoint ComputeBlurStdDev(nscoord aBlurRadius,
-                                         int32_t aAppUnitsPerDevPixel,
-                                         gfxFloat aScaleX,
-                                         gfxFloat aScaleY)
-{
-  // http://dev.w3.org/csswg/css3-background/#box-shadow says that the
-  // standard deviation of the blur should be half the given blur value.
-  gfxFloat blurStdDev = gfxFloat(aBlurRadius) / gfxFloat(aAppUnitsPerDevPixel);
-
-  return gfxPoint(std::min((blurStdDev * aScaleX),
-                           gfxFloat(MAX_BLUR_RADIUS)) / 2.0,
-                  std::min((blurStdDev * aScaleY),
-                           gfxFloat(MAX_BLUR_RADIUS)) / 2.0);
-}
-
-static inline IntSize
-ComputeBlurRadius(nscoord aBlurRadius,
-                  int32_t aAppUnitsPerDevPixel,
-                  gfxFloat aScaleX = 1.0,
-                  gfxFloat aScaleY = 1.0)
-{
-  gfxPoint scaledBlurStdDev = ComputeBlurStdDev(aBlurRadius, aAppUnitsPerDevPixel,
-                                                aScaleX, aScaleY);
-  return
-    gfxAlphaBoxBlur::CalculateBlurRadius(scaledBlurStdDev);
-}
-
-// -----
-// nsContextBoxBlur
-// -----
-gfxContext*
-nsContextBoxBlur::Init(const nsRect& aRect, nscoord aSpreadRadius,
-                       nscoord aBlurRadius,
-                       int32_t aAppUnitsPerDevPixel,
-                       gfxContext* aDestinationCtx,
-                       const nsRect& aDirtyRect,
-                       const gfxRect* aSkipRect,
-                       uint32_t aFlags)
-{
-  if (aRect.IsEmpty()) {
-    mContext = nullptr;
-    return nullptr;
-  }
-
-  IntSize blurRadius;
-  IntSize spreadRadius;
-  GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(), aAppUnitsPerDevPixel,
-                         aBlurRadius, aSpreadRadius,
-                         blurRadius, spreadRadius);
-
-  mDestinationCtx = aDestinationCtx;
-
-  // If not blurring, draw directly onto the destination device
-  if (blurRadius.width <= 0 && blurRadius.height <= 0 &&
-      spreadRadius.width <= 0 && spreadRadius.height <= 0 &&
-      !(aFlags & FORCE_MASK)) {
-    mContext = aDestinationCtx;
-    return mContext;
-  }
-
-  // Convert from app units to device pixels
-  gfxRect rect = nsLayoutUtils::RectToGfxRect(aRect, aAppUnitsPerDevPixel);
-
-  gfxRect dirtyRect =
-    nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
-  dirtyRect.RoundOut();
-
-  gfxMatrix transform = aDestinationCtx->CurrentMatrix();
-  rect = transform.TransformBounds(rect);
-
-  mPreTransformed = !transform.IsIdentity();
-
-  // Create the temporary surface for blurring
-  dirtyRect = transform.TransformBounds(dirtyRect);
-  if (aSkipRect) {
-    gfxRect skipRect = transform.TransformBounds(*aSkipRect);
-    mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
-                                  blurRadius, &dirtyRect, &skipRect);
-  } else {
-    mContext = mAlphaBoxBlur.Init(aDestinationCtx, rect, spreadRadius,
-                                  blurRadius, &dirtyRect, nullptr);
-  }
-
-  if (mContext) {
-    // we don't need to blur if skipRect is equal to rect
-    // and mContext will be nullptr
-    mContext->Multiply(transform);
-  }
-  return mContext;
-}
-
-void
-nsContextBoxBlur::DoPaint()
-{
-  if (mContext == mDestinationCtx) {
-    return;
-  }
-
-  gfxContextMatrixAutoSaveRestore saveMatrix(mDestinationCtx);
-
-  if (mPreTransformed) {
-    mDestinationCtx->SetMatrix(gfxMatrix());
-  }
-
-  mAlphaBoxBlur.Paint(mDestinationCtx);
-}
-
-gfxContext*
-nsContextBoxBlur::GetContext()
-{
-  return mContext;
-}
-
-/* static */ nsMargin
-nsContextBoxBlur::GetBlurRadiusMargin(nscoord aBlurRadius,
-                                      int32_t aAppUnitsPerDevPixel)
-{
-  IntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel);
-
-  nsMargin result;
-  result.top = result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
-  result.left = result.right = blurRadius.width  * aAppUnitsPerDevPixel;
-  return result;
-}
-
-/* static */ void
-nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
-                                const nsRect& aRect,
-                                int32_t aAppUnitsPerDevPixel,
-                                RectCornerRadii* aCornerRadii,
-                                nscoord aBlurRadius,
-                                const Color& aShadowColor,
-                                const nsRect& aDirtyRect,
-                                const gfxRect& aSkipRect)
-{
-  DrawTarget& aDestDrawTarget = *aDestinationCtx->GetDrawTarget();
-
-  if (aRect.IsEmpty()) {
-    return;
-  }
-
-  Rect shadowGfxRect = NSRectToRect(aRect, aAppUnitsPerDevPixel);
-
-  if (aBlurRadius <= 0) {
-    ColorPattern color(ToDeviceColor(aShadowColor));
-    if (aCornerRadii) {
-      RefPtr<Path> roundedRect = MakePathForRoundedRect(aDestDrawTarget,
-                                                        shadowGfxRect,
-                                                        *aCornerRadii);
-      aDestDrawTarget.Fill(roundedRect, color);
-    } else {
-      aDestDrawTarget.FillRect(shadowGfxRect, color);
-    }
-    return;
-  }
-
-  gfxFloat scaleX = 1;
-  gfxFloat scaleY = 1;
-
-  // Do blurs in device space when possible.
-  // Chrome/Skia always does the blurs in device space
-  // and will sometimes get incorrect results (e.g. rotated blurs)
-  gfxMatrix transform = aDestinationCtx->CurrentMatrix();
-  // XXX: we could probably handle negative scales but for now it's easier just to fallback
-  if (!transform.HasNonAxisAlignedTransform() && transform._11 > 0.0 && transform._22 > 0.0) {
-    scaleX = transform._11;
-    scaleY = transform._22;
-    aDestinationCtx->SetMatrix(gfxMatrix());
-  } else {
-    transform = gfxMatrix();
-  }
-
-  gfxPoint blurStdDev = ComputeBlurStdDev(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
-
-  gfxRect dirtyRect =
-    nsLayoutUtils::RectToGfxRect(aDirtyRect, aAppUnitsPerDevPixel);
-  dirtyRect.RoundOut();
-
-  gfxRect shadowThebesRect = transform.TransformBounds(ThebesRect(shadowGfxRect));
-  dirtyRect = transform.TransformBounds(dirtyRect);
-  gfxRect skipRect = transform.TransformBounds(aSkipRect);
-
-  if (aCornerRadii) {
-    aCornerRadii->Scale(scaleX, scaleY);
-  }
-
-  gfxAlphaBoxBlur::BlurRectangle(aDestinationCtx,
-                                 shadowThebesRect,
-                                 aCornerRadii,
-                                 blurStdDev,
-                                 aShadowColor,
-                                 dirtyRect,
-                                 skipRect);
-}
-
-/* static */ void
-nsContextBoxBlur::GetBlurAndSpreadRadius(DrawTarget* aDestDrawTarget,
-                                         int32_t aAppUnitsPerDevPixel,
-                                         nscoord aBlurRadius,
-                                         nscoord aSpreadRadius,
-                                         IntSize& aOutBlurRadius,
-                                         IntSize& aOutSpreadRadius,
-                                         bool aConstrainSpreadRadius)
-{
-  // Do blurs in device space when possible.
-  // Chrome/Skia always does the blurs in device space
-  // and will sometimes get incorrect results (e.g. rotated blurs)
-  Matrix transform = aDestDrawTarget->GetTransform();
-  // XXX: we could probably handle negative scales but for now it's easier just to fallback
-  gfxFloat scaleX, scaleY;
-  if (transform.HasNonAxisAlignedTransform() || transform._11 <= 0.0 || transform._22 <= 0.0) {
-    scaleX = 1;
-    scaleY = 1;
-  } else {
-    scaleX = transform._11;
-    scaleY = transform._22;
-  }
-
-  // compute a large or smaller blur radius
-  aOutBlurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel, scaleX, scaleY);
-  aOutSpreadRadius =
-      IntSize(int32_t(aSpreadRadius * scaleX / aAppUnitsPerDevPixel),
-              int32_t(aSpreadRadius * scaleY / aAppUnitsPerDevPixel));
-
-
-  if (aConstrainSpreadRadius) {
-    aOutSpreadRadius.width = std::min(aOutSpreadRadius.width, int32_t(MAX_SPREAD_RADIUS));
-    aOutSpreadRadius.height = std::min(aOutSpreadRadius.height, int32_t(MAX_SPREAD_RADIUS));
-  }
-}
-
-/* static */ bool
-nsContextBoxBlur::InsetBoxBlur(gfxContext* aDestinationCtx,
-                               Rect aDestinationRect,
-                               Rect aShadowClipRect,
-                               Color& aShadowColor,
-                               nscoord aBlurRadiusAppUnits,
-                               nscoord aSpreadDistanceAppUnits,
-                               int32_t aAppUnitsPerDevPixel,
-                               bool aHasBorderRadius,
-                               RectCornerRadii& aInnerClipRectRadii,
-                               Rect aSkipRect, Point aShadowOffset)
-{
-  if (aDestinationRect.IsEmpty()) {
-    mContext = nullptr;
-    return false;
-  }
-
-  gfxContextAutoSaveRestore autoRestore(aDestinationCtx);
-
-  IntSize blurRadius;
-  IntSize spreadRadius;
-  // Convert the blur and spread radius to device pixels
-  bool constrainSpreadRadius = false;
-  GetBlurAndSpreadRadius(aDestinationCtx->GetDrawTarget(), aAppUnitsPerDevPixel,
-                         aBlurRadiusAppUnits, aSpreadDistanceAppUnits,
-                         blurRadius, spreadRadius, constrainSpreadRadius);
-
-  // The blur and spread radius are scaled already, so scale all
-  // input data to the blur. This way, we don't have to scale the min
-  // inset blur to the invert of the dest context, then rescale it back
-  // when we draw to the destination surface.
-  gfxSize scale = aDestinationCtx->CurrentMatrix().ScaleFactors(true);
-  Matrix transform = ToMatrix(aDestinationCtx->CurrentMatrix());
-
-  // XXX: we could probably handle negative scales but for now it's easier just to fallback
-  if (!transform.HasNonAxisAlignedTransform() && transform._11 > 0.0 && transform._22 > 0.0) {
-    // If we don't have a rotation, we're pre-transforming all the rects.
-    aDestinationCtx->SetMatrix(gfxMatrix());
-  } else {
-    // Don't touch anything, we have a rotation.
-    transform = Matrix();
-  }
-
-  Rect transformedDestRect = transform.TransformBounds(aDestinationRect);
-  Rect transformedShadowClipRect = transform.TransformBounds(aShadowClipRect);
-  Rect transformedSkipRect = transform.TransformBounds(aSkipRect);
-
-  transformedDestRect.Round();
-  transformedShadowClipRect.Round();
-  transformedSkipRect.RoundIn();
-
-  for (size_t i = 0; i < 4; i++) {
-    aInnerClipRectRadii[i].width = std::floor(scale.width * aInnerClipRectRadii[i].width);
-    aInnerClipRectRadii[i].height = std::floor(scale.height * aInnerClipRectRadii[i].height);
-  }
-
-  mAlphaBoxBlur.BlurInsetBox(aDestinationCtx, transformedDestRect,
-                             transformedShadowClipRect,
-                             blurRadius, aShadowColor,
-                             aHasBorderRadius ? &aInnerClipRectRadii : nullptr,
-                             transformedSkipRect, aShadowOffset);
-  return true;
-}
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/painting/nsCSSRenderingGradients.h
@@ -0,0 +1,41 @@
+/* -*- 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/. */
+
+#ifndef nsCSSRenderingGradients_h__
+#define nsCSSRenderingGradients_h__
+
+#include "nsLayoutUtils.h"
+#include "nsStyleStruct.h"
+#include "Units.h"
+
+namespace mozilla {
+
+class nsCSSGradientRenderer final {
+public:
+  /**
+   * Render a gradient for an element.
+   * aDest is the rect for a single tile of the gradient on the destination.
+   * aFill is the rect on the destination to be covered by repeated tiling of
+   * the gradient.
+   * aSrc is the part of the gradient to be rendered into a tile (aDest), if
+   * aSrc and aDest are different sizes, the image will be scaled to map aSrc
+   * onto aDest.
+   * aIntrinsicSize is the size of the source gradient.
+   */
+  static void Paint(nsPresContext* aPresContext,
+                    gfxContext& aContext,
+                    nsStyleGradient* aGradient,
+                    const nsRect& aDirtyRect,
+                    const nsRect& aDest,
+                    const nsRect& aFill,
+                    const nsSize& aRepeatSize,
+                    const mozilla::CSSIntRect& aSrc,
+                    const nsSize& aIntrinsiceSize,
+                    float aOpacity = 1.0);
+};
+
+} // namespace mozilla
+
+#endif /* nsCSSRenderingGradients_h__ */
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -2,16 +2,17 @@
 // vim:cindent:ts=2:et:sw=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/. */
 
 /* utility functions for drawing borders and backgrounds */
 
 #include "nsImageRenderer.h"
+#include "nsCSSRenderingGradients.h"
 
 nsSize
 CSSSizeOrRatio::ComputeConcreteSize() const
 {
   NS_ASSERTION(CanComputeConcreteSize(), "Cannot compute");
   if (mHasWidth && mHasHeight) {
     return nsSize(mWidth, mHeight);
   }
@@ -503,20 +504,20 @@ nsImageRenderer::Draw(nsPresContext*    
                                            aDest, aFill, aRepeatSize,
                                            aAnchor, aDirtyRect,
                                            ConvertImageRendererToDrawFlags(mFlags),
                                            mExtendMode, aOpacity);
       break;
     }
     case eStyleImageType_Gradient:
     {
-      nsCSSRendering::PaintGradient(aPresContext, *ctx,
-                                    mGradientData, aDirtyRect,
-                                    aDest, aFill, aRepeatSize, aSrc, mSize,
-                                    aOpacity);
+      nsCSSGradientRenderer::Paint(aPresContext, *ctx,
+                                   mGradientData, aDirtyRect,
+                                   aDest, aFill, aRepeatSize, aSrc, mSize,
+                                   aOpacity);
       break;
     }
     case eStyleImageType_Element:
     {
       RefPtr<gfxDrawable> drawable = DrawableForElement(aDest, *ctx);
       if (!drawable) {
         NS_WARNING("Could not create drawable for element");
         return DrawResult::TEMPORARY_ERROR;