Bug 1464589: Split nsCSSGradientRenderer::Create in smaller functions. r?rhunt draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Sat, 26 May 2018 15:20:41 +0200
changeset 800270 f47ea630bddcf77172155d75624dba36b37b22b4
parent 800269 3e8ed600c36736ea763f00bb5d60a58e87dc55e8
child 800271 3705b86aadc11e64c6262de1b304c17c0bf11725
push id111303
push userbmo:emilio@crisal.io
push dateSat, 26 May 2018 13:27:43 +0000
reviewersrhunt
bugs1464589, 1352643
milestone62.0a1
Bug 1464589: Split nsCSSGradientRenderer::Create in smaller functions. r?rhunt In particular, split the computation of the resolved stops into its own function, and inside of it, the switch computing the specified length of a gradient too, since in bug 1352643 there'll be two of those. MozReview-Commit-ID: FSYzzAxNBbV
layout/painting/nsCSSRenderingGradients.cpp
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -534,16 +534,114 @@ ClampColorStops(nsTArray<ColorStop>& aSt
   }
   if (aStops.LastElement().mPosition < 1) {
     aStops.AppendElement(ColorStop(1, false, aStops.LastElement().mColor));
   }
 }
 
 namespace mozilla {
 
+static Maybe<double>
+GetSpecifiedGradientPosition(const nsStyleCoord& aCoord,
+                             int32_t aAppUnitsPerPixel,
+                             gfxFloat aLineLength)
+{
+  auto GetCoord = [&](nscoord aCoord) -> double {
+    if (aLineLength < 1e-6) {
+      return 0.0;
+    }
+    return NSAppUnitsToFloatPixels(aCoord, aAppUnitsPerPixel) / aLineLength;
+  };
+
+  switch (aCoord.GetUnit()) {
+    case eStyleUnit_None:
+      return Nothing();
+    case eStyleUnit_Percent:
+      return Some(aCoord.GetPercentValue());
+    case eStyleUnit_Coord:
+      return Some(GetCoord(aCoord.GetCoordValue()));
+    case eStyleUnit_Calc: {
+      const nsStyleCoord::Calc* calc = aCoord.GetCalcValue();
+      return Some(calc->mPercent + GetCoord(calc->mLength));
+    }
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown unit in gradient color stop position?");
+      return Nothing();
+  }
+}
+
+static nsTArray<ColorStop>
+ComputeColorStops(const nsStyleGradient& aGradient,
+                  int32_t aAppUnitsPerPixel,
+                  gfxFloat aLineLength)
+{
+  MOZ_ASSERT(aGradient.mStops.Length() >= 2,
+             "The parser should reject gradients with less than two stops");
+
+  nsTArray<ColorStop> stops(aGradient.mStops.Length());
+
+  // 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;
+
+    Maybe<double> specifiedPosition =
+      GetSpecifiedGradientPosition(stop.mLocation,
+                                   aAppUnitsPerPixel,
+                                   aLineLength);
+
+    if (specifiedPosition) {
+      position = *specifiedPosition;
+    } else 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.
+      // Remember 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;
+    }
+
+    if (i > 0) {
+      // Prevent decreasing stop positions by advancing this position
+      // to the previous stop position, if necessary
+      double previousPosition = firstUnsetPosition > 0
+        ? stops[firstUnsetPosition - 1].mPosition
+        : stops[i - 1].mPosition;
+      position = std::max(position, previousPosition);
+    }
+    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;
+    }
+  }
+
+  return stops;
+}
+
 nsCSSGradientRenderer
 nsCSSGradientRenderer::Create(nsPresContext* aPresContext,
                              nsStyleGradient* aGradient,
                              const nsSize& aIntrinsicSize)
 {
   nscoord appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
   gfxSize srcSize = gfxSize(gfxFloat(aIntrinsicSize.width)/appUnitsPerDevPixel,
                             gfxFloat(aIntrinsicSize.height)/appUnitsPerDevPixel);
@@ -561,88 +659,19 @@ nsCSSGradientRenderer::Create(nsPresCont
   }
   // 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
-      double previousPosition = firstUnsetPosition > 0
-        ? stops[firstUnsetPosition - 1].mPosition
-        : stops[i - 1].mPosition;
-      position = std::max(position, previousPosition);
-    }
-    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;
-    }
-  }
+  nsTArray<ColorStop> stops =
+    ComputeColorStops(*aGradient, appUnitsPerDevPixel, lineLength);
 
   ResolveMidpoints(stops);
 
   nsCSSGradientRenderer renderer;
   renderer.mPresContext = aPresContext;
   renderer.mGradient = aGradient;
   renderer.mStops = std::move(stops);
   renderer.mLineStart = lineStart;