Bug 1022624 - Implement support for radial gradients with ExtendMode::REFLECT in DrawTargetCG. r=jrmuizel
authorMarkus Stange <mstange@themasta.com>
Tue, 10 Jun 2014 22:26:58 +0200
changeset 188018 ebe4b9991f913967831351d83c4c8ccc9239de9e
parent 188017 9c5a6ce4e2fc6a46ebb369ca738a6be229562413
child 188019 2b76bb4c21c28eb93cbe590e97262c46e16a94c3
push id26944
push useremorley@mozilla.com
push dateWed, 11 Jun 2014 15:14:00 +0000
treeherdermozilla-central@c7391b84d9c2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1022624
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1022624 - Implement support for radial gradients with ExtendMode::REFLECT in DrawTargetCG. r=jrmuizel
gfx/2d/DrawTargetCG.cpp
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -576,65 +576,74 @@ static CGPoint CGRectBottomRight(CGRect 
 
 static CGFloat
 CGPointDistance(CGPoint a, CGPoint b)
 {
   return hypot(a.x-b.x, a.y-b.y);
 }
 
 static void
-DrawRadialRepeatingGradient(CGContextRef cg, const RadialGradientPattern &aPattern, const CGRect &aExtents)
+DrawRadialRepeatingGradient(CGContextRef cg, const RadialGradientPattern &aPattern,
+                            const CGRect &aExtents, bool aReflect)
 {
   GradientStopsCG *stops = static_cast<GradientStopsCG*>(aPattern.mStops.get());
   CGPoint startCenter = { aPattern.mCenter1.x, aPattern.mCenter1.y };
   CGFloat startRadius = aPattern.mRadius1;
   CGPoint endCenter   = { aPattern.mCenter2.x, aPattern.mCenter2.y };
   CGFloat endRadius   = aPattern.mRadius2;
 
   // find the maximum distance from endCenter to a corner of aExtents
   CGFloat minimumEndRadius = endRadius;
   minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectTopLeft(aExtents)));
   minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectBottomLeft(aExtents)));
   minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectTopRight(aExtents)));
   minimumEndRadius = max(minimumEndRadius, CGPointDistance(endCenter, CGRectBottomRight(aExtents)));
 
   CGFloat length = endRadius - startRadius;
-  int repeatCount = 1;
+  int repeatStartFactor = 0, repeatEndFactor = 1;
   while (endRadius < minimumEndRadius) {
     endRadius += length;
-    repeatCount++;
+    repeatEndFactor++;
   }
 
   while (startRadius-length >= 0) {
     startRadius -= length;
-    repeatCount++;
+    repeatStartFactor--;
   }
 
+  int repeatCount = repeatEndFactor - repeatStartFactor;
+  uint32_t numStops = stops->mStops.size();
   double scale = 1./repeatCount;
 
   std::vector<CGFloat> colors;
   std::vector<CGFloat> offsets;
-  colors.reserve(stops->mStops.size()*repeatCount*4);
-  offsets.reserve(stops->mStops.size()*repeatCount);
-  for (int j = 0; j < repeatCount; j++) {
-    for (uint32_t i = 0; i < stops->mStops.size(); i++) {
-      colors.push_back(stops->mStops[i].color.r);
-      colors.push_back(stops->mStops[i].color.g);
-      colors.push_back(stops->mStops[i].color.b);
-      colors.push_back(stops->mStops[i].color.a);
+  colors.reserve(numStops*repeatCount*4);
+  offsets.reserve(numStops*repeatCount);
+  for (int j = repeatStartFactor; j < repeatEndFactor; j++) {
+    bool isReflected = aReflect && (j % 2) != 0;
+    for (uint32_t i = 0; i < numStops; i++) {
+      uint32_t stopIndex = isReflected ? numStops - i - 1 : i;
+      colors.push_back(stops->mStops[stopIndex].color.r);
+      colors.push_back(stops->mStops[stopIndex].color.g);
+      colors.push_back(stops->mStops[stopIndex].color.b);
+      colors.push_back(stops->mStops[stopIndex].color.a);
 
-      offsets.push_back((stops->mStops[i].offset + j)*scale);
+      CGFloat offset = stops->mStops[stopIndex].offset;
+      if (isReflected) {
+        offset = 1 - offset;
+      }
+      offsets.push_back((offset + (j - repeatStartFactor)) * scale);
     }
   }
 
   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
   CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace,
                                                                &colors.front(),
                                                                &offsets.front(),
-                                                               repeatCount*stops->mStops.size());
+                                                               repeatCount*numStops);
   CGColorSpaceRelease(colorSpace);
 
   //XXX: are there degenerate radial gradients that we should avoid drawing?
   CGContextDrawRadialGradient(cg, gradient, startCenter, startRadius, endCenter, endRadius,
                               kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
   CGGradientRelease(gradient);
 }
 
@@ -674,18 +683,18 @@ DrawGradient(CGContextRef cg, const Patt
       CGPoint startCenter = { pat.mCenter1.x, pat.mCenter1.y };
       CGFloat startRadius = pat.mRadius1;
       CGPoint endCenter   = { pat.mCenter2.x, pat.mCenter2.y };
       CGFloat endRadius   = pat.mRadius2;
 
       //XXX: are there degenerate radial gradients that we should avoid drawing?
       CGContextDrawRadialGradient(cg, stops->mGradient, startCenter, startRadius, endCenter, endRadius,
                                   kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
-    } else if (stops->mExtend == ExtendMode::REPEAT) {
-      DrawRadialRepeatingGradient(cg, pat, aExtents);
+    } else if (stops->mExtend == ExtendMode::REPEAT || stops->mExtend == ExtendMode::REFLECT) {
+      DrawRadialRepeatingGradient(cg, pat, aExtents, stops->mExtend == ExtendMode::REFLECT);
     }
   } else {
     assert(0);
   }
 
 }
 
 static void