Add flipped gradient branch to two point conical gradient

BUG=skia:

Committed: http://code.google.com/p/skia/source/detail?r=14235

R=bsalomon@google.com

Author: egdaniel@google.com

Review URL: https://codereview.chromium.org/227623004

git-svn-id: http://skia.googlecode.com/svn/trunk@14271 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index f155cc5..7f08404 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -118,12 +118,13 @@
             SkFixed dp = SK_Fixed1 / (desc.fCount - 1);
             SkFixed p = dp;
             SkFixed scale = (desc.fCount - 1) << 8;  // (1 << 24) / dp
-            for (int i = 1; i < desc.fCount; i++) {
+            for (int i = 1; i < desc.fCount - 1; i++) {
                 recs->fPos   = p;
                 recs->fScale = scale;
                 recs += 1;
                 p += dp;
             }
+            recs->fPos = SK_Fixed1;
         }
     }
     this->initCommon();
@@ -237,6 +238,30 @@
     return kTexture_GpuColorType;
 }
 
+void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
+                                              SkColor* colorSrc, Rec* recSrc,
+                                              int count) {
+    SkAutoSTArray<8, SkColor> colorsTemp(count);
+    for (int i = 0; i < count; ++i) {
+        int offset = count - i - 1;
+        colorsTemp[i] = colorSrc[offset];
+    }
+    if (count > 2) {
+        SkAutoSTArray<8, Rec> recsTemp(count);
+        for (int i = 0; i < count; ++i) {
+            int offset = count - i - 1;
+            recsTemp[i].fPos = SK_Fixed1 - recSrc[offset].fPos;
+            recsTemp[i].fScale = recSrc[offset].fScale;
+        }
+        memcpy(recDst, recsTemp.get(), count * sizeof(Rec));
+    }
+    memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor));
+}
+
+void SkGradientShaderBase::flipGradientColors() {
+    FlipGradientColors(fOrigColors, fRecs, fOrigColors, fRecs, fColorCount); 
+}
+
 bool SkGradientShaderBase::isOpaque() const {
     return fColorsAreOpaque;
 }
@@ -643,11 +668,23 @@
     }
 }
 
-void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
+void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) const {
     if (info) {
         if (info->fColorCount >= fColorCount) {
+            SkColor* colorLoc;
+            Rec*     recLoc;
+            if (flipGrad && (info->fColors || info->fColorOffsets)) {
+                SkAutoSTArray<8, SkColor> colorStorage(fColorCount);
+                SkAutoSTArray<8, Rec> recStorage(fColorCount);
+                colorLoc = colorStorage.get();
+                recLoc = recStorage.get();
+                FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount);
+            } else {
+                colorLoc = fOrigColors;
+                recLoc = fRecs;
+            }
             if (info->fColors) {
-                memcpy(info->fColors, fOrigColors, fColorCount * sizeof(SkColor));
+                memcpy(info->fColors, colorLoc, fColorCount * sizeof(SkColor));
             }
             if (info->fColorOffsets) {
                 if (fColorCount == 2) {
@@ -655,7 +692,7 @@
                     info->fColorOffsets[1] = SK_Scalar1;
                 } else if (fColorCount > 2) {
                     for (int i = 0; i < fColorCount; ++i) {
-                        info->fColorOffsets[i] = SkFixedToScalar(fRecs[i].fPos);
+                        info->fColorOffsets[i] = SkFixedToScalar(recLoc[i].fPos);
                     }
                 }
             }
@@ -801,12 +838,36 @@
     if (start == end && startRadius == endRadius) {
         return SkNEW(SkEmptyShader);
     }
+
     EXPAND_1_COLOR(colorCount);
 
+    bool flipGradient = startRadius > endRadius;
+
     SkGradientShaderBase::Descriptor desc;
-    desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
-    return SkNEW_ARGS(SkTwoPointConicalGradient,
-                      (start, startRadius, end, endRadius, desc));
+
+    if (!flipGradient) {
+        desc_init(&desc, colors, pos, colorCount, mode, mapper, flags);
+        return SkNEW_ARGS(SkTwoPointConicalGradient,
+                          (start, startRadius, end, endRadius, flipGradient, desc));
+    } else {
+        SkAutoSTArray<8, SkColor> colorsNew(colorCount);
+        SkAutoSTArray<8, SkScalar> posNew(colorCount);
+        for (int i = 0; i < colorCount; ++i) {
+            colorsNew[i] = colors[colorCount - i - 1];
+        }
+
+        if (pos) {
+            for (int i = 0; i < colorCount; ++i) {
+                posNew[i] = 1 - pos[colorCount - i - 1];
+            }
+            desc_init(&desc, colorsNew.get(), posNew.get(), colorCount, mode, mapper, flags);
+        } else {
+            desc_init(&desc, colorsNew.get(), NULL, colorCount, mode, mapper, flags);
+        }
+
+        return SkNEW_ARGS(SkTwoPointConicalGradient,
+                          (end, endRadius, start, startRadius, flipGradient, desc));
+    }
 }
 
 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,