Bug 1022624 - Implement support for radial gradients with ExtendMode::REFLECT in DrawTargetCG. r=jrmuizel, a=lmandel
authorMarkus Stange <mstange@themasta.com>
Tue, 10 Jun 2014 22:26:58 +0200
changeset 208206 f3007d054fe20d265b838f88fd70beee4aee76be
parent 208205 610390beb394f20bc2a86e44e65c920f231cd3f4
child 208207 f5dc2ae02b195567eedc10630425f9b06d691214
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, lmandel
bugs1022624
milestone32.0a2
Bug 1022624 - Implement support for radial gradients with ExtendMode::REFLECT in DrawTargetCG. r=jrmuizel, a=lmandel
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