Go from a 1x2 to a 2x2 dither cell, and change/simplify the logic for how we
compute the "dithered" version of a color to just a graduated fixed-point-round.
Also, add this new dither to conical and sweep, which before had no dithering.

Disabled for now using SK_IGNORE_GRADIENT_DITHER_FIX. Will enable this and
and rebaseline skia.

http://code.google.com/p/skia/issues/detail?id=1098
Review URL: https://codereview.appspot.com/7248046

git-svn-id: http://skia.googlecode.com/svn/trunk@7549 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index de9ae9e..aa03ecb 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2006 The Android Open Source Project
  *
@@ -327,18 +326,54 @@
     SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
     SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
 
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
     a = SkIntToFixed(a) + 0x8000;
     r = SkIntToFixed(r) + 0x8000;
     g = SkIntToFixed(g) + 0x8000;
     b = SkIntToFixed(b) + 0x8000;
+#else
+    a = SkIntToFixed(a);
+    r = SkIntToFixed(r);
+    g = SkIntToFixed(g);
+    b = SkIntToFixed(b);
+#endif
 
     do {
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
         cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
         cache[kCache32Count] =
             SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a),
                                     dither_fixed_to_8(r),
                                     dither_fixed_to_8(g),
                                     dither_fixed_to_8(b));
+#else
+        /*
+         *  Our dither-cell (spatially) is
+         *      0 2
+         *      3 1
+         *  Where
+         *      [0] -> [-1/8 ... 1/8 ) values near 0
+         *      [1] -> [ 1/8 ... 3/8 ) values near 1/4
+         *      [2] -> [ 3/8 ... 5/8 ) values near 1/2
+         *      [3] -> [ 5/8 ... 7/8 ) values near 3/4
+         */
+        cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0x2000) >> 16,
+                                                         (r + 0x2000) >> 16,
+                                                         (g + 0x2000) >> 16,
+                                                         (b + 0x2000) >> 16);
+        cache[kCache32Count*3] = SkPremultiplyARGBInline((a + 0x6000) >> 16,
+                                                         (r + 0x6000) >> 16,
+                                                         (g + 0x6000) >> 16,
+                                                         (b + 0x6000) >> 16);
+        cache[kCache32Count*1] = SkPremultiplyARGBInline((a + 0xA000) >> 16,
+                                                         (r + 0xA000) >> 16,
+                                                         (g + 0xA000) >> 16,
+                                                         (b + 0xA000) >> 16);
+        cache[kCache32Count*2] = SkPremultiplyARGBInline((a + 0xE000) >> 16,
+                                                         (r + 0xE000) >> 16,
+                                                         (g + 0xE000) >> 16,
+                                                         (b + 0xE000) >> 16);
+#endif
         cache += 1;
         a += da;
         r += dr;
@@ -410,7 +445,7 @@
 const SkPMColor* SkGradientShaderBase::getCache32() const {
     if (fCache32 == NULL) {
         // double the count for dither entries
-        const int entryCount = kCache32Count * 2;
+        const int entryCount = kCache32Count * 4;
         const size_t allocSize = sizeof(SkPMColor) * entryCount;
 
         if (NULL == fCache32PixelRef) {
@@ -446,6 +481,10 @@
                 int index = map->mapUnit16((i << 8) | i) >> 8;
                 mapped[i] = linear[index];
                 mapped[i + kCache32Count] = linear[index + kCache32Count];
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+                mapped[i + kCache32Count*2] = linear[index + kCache32Count*2];
+                mapped[i + kCache32Count*3] = linear[index + kCache32Count*3];
+#endif
             }
             fCache32PixelRef->unref();
             fCache32PixelRef = newPR;
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 4d14dc6..82535de 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2012 Google Inc.
  *
@@ -20,6 +19,8 @@
 #include "SkBitmapCache.h"
 #include "SkShader.h"
 
+#define SK_IGNORE_GRADIENT_DITHER_FIX
+
 #ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
     #define USE_DITHER_32BIT_GRADIENT
 #endif
@@ -108,7 +109,7 @@
         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
         /// it, use a larger cache.
         kCache32Bits    = 8,
-        kCache32Count = (1 << kCache32Bits),
+        kCache32Count   = (1 << kCache32Bits),
         kCache32Shift   = 16 - kCache32Bits,
         kSqrt32Shift    = 8 - kCache32Bits,
 
@@ -176,7 +177,13 @@
 };
 
 static inline int init_dither_toggle(int x, int y) {
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
     return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride32;
+#else
+    x &= 1;
+    y = (y & 1) << 1;
+    return (x | y) * SkGradientShaderBase::kDitherStride32;
+#endif
 }
 
 static inline int next_dither_toggle(int toggle) {
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 03393f7..059cc93 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -94,7 +94,11 @@
 
     unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
     if ((fDstToIndex.getType() & ~mask) == 0) {
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
         fFlags |= SkShader::kConstInY32_Flag;
+#else
+        // when we dither, we are (usually) not const-in-Y
+#endif
         if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
             // only claim this if we do have a 16bit mode (i.e. none of our
             // colors have alpha), and if we are not dithering (which obviously
@@ -328,7 +332,6 @@
     SkASSERT(fi < SkGradientShaderBase::kCache16Count);
     dither_memset16(dstC, cache[toggle + fi],
         cache[next_dither_toggle16(toggle) + fi], count);
-
 }
 
 void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 328fe76..fdca340 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -335,8 +335,7 @@
         if (count) {
             UNPINNED_RADIAL_STEP;
         }
-    }
-    else  {
+    } else  {
         // Specializing for dy == 0 gains us 25% on Skia benchmarks
         if (dy == 0) {
             unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index db18521..458ddbc 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -298,6 +298,11 @@
     SkMatrix::MapXYProc proc = fDstToIndexProc;
     const SkMatrix&     matrix = fDstToIndex;
     const SkPMColor* SK_RESTRICT cache = this->getCache32();
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+    int                 toggle = init_dither_toggle(x, y);
+#else
+    int                 toggle = 0;
+#endif
     SkPoint             srcPt;
 
     if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -319,15 +324,21 @@
         }
 
         for (; count > 0; --count) {
-            *dstC++ = cache[SkATan2_255(fy, fx)];
+            *dstC++ = cache[toggle + SkATan2_255(fy, fx)];
             fx += dx;
             fy += dy;
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+            toggle = next_dither_toggle(toggle);
+#endif
         }
     } else {  // perspective case
         for (int stop = x + count; x < stop; x++) {
             proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
                          SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
-            *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
+            *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)];
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+            toggle = next_dither_toggle(toggle);
+#endif
         }
     }
 }
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index e239530..f1acd55 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -113,11 +113,12 @@
     return SkFloatToFixed(t);
 }
 
-typedef void (*TwoPointRadialProc)(TwoPtRadial* rec, SkPMColor* dstC,
-                                   const SkPMColor* cache, int count);
+typedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC,
+                                    const SkPMColor* cache, int toggle, int count);
 
 static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
-                           const SkPMColor* SK_RESTRICT cache, int count) {
+                           const SkPMColor* SK_RESTRICT cache, int toggle,
+                           int count) {
     for (; count > 0; --count) {
         SkFixed t = rec->nextT();
         if (TwoPtRadial::DontDrawT(t)) {
@@ -125,13 +126,18 @@
         } else {
             SkFixed index = SkClampMax(t, 0xFFFF);
             SkASSERT(index <= 0xFFFF);
-            *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+            *dstC++ = cache[toggle +
+                            (index >> SkGradientShaderBase::kCache32Shift)];
         }
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+        toggle = next_dither_toggle(toggle);
+#endif
     }
 }
 
 static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
-                            const SkPMColor* SK_RESTRICT cache, int count) {
+                            const SkPMColor* SK_RESTRICT cache, int toggle,
+                            int count) {
     for (; count > 0; --count) {
         SkFixed t = rec->nextT();
         if (TwoPtRadial::DontDrawT(t)) {
@@ -139,13 +145,18 @@
         } else {
             SkFixed index = repeat_tileproc(t);
             SkASSERT(index <= 0xFFFF);
-            *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+            *dstC++ = cache[toggle +
+                            (index >> SkGradientShaderBase::kCache32Shift)];
         }
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+        toggle = next_dither_toggle(toggle);
+#endif
     }
 }
 
 static void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
-                            const SkPMColor* SK_RESTRICT cache, int count) {
+                            const SkPMColor* SK_RESTRICT cache, int toggle,
+                            int count) {
     for (; count > 0; --count) {
         SkFixed t = rec->nextT();
         if (TwoPtRadial::DontDrawT(t)) {
@@ -153,8 +164,12 @@
         } else {
             SkFixed index = mirror_tileproc(t);
             SkASSERT(index <= 0xFFFF);
-            *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+            *dstC++ = cache[toggle +
+                            (index >> SkGradientShaderBase::kCache32Shift)];
         }
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+        toggle = next_dither_toggle(toggle);
+#endif
     }
 }
 
@@ -183,6 +198,12 @@
 
 void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
                                           int count) {
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+    int toggle = init_dither_toggle(x, y);
+#else
+    int toggle = 0;
+#endif
+
     SkASSERT(count > 0);
 
     SkPMColor* SK_RESTRICT dstC = dstCParam;
@@ -191,7 +212,7 @@
 
     const SkPMColor* SK_RESTRICT cache = this->getCache32();
 
-    TwoPointRadialProc shadeProc = twopoint_repeat;
+    TwoPointConicalProc shadeProc = twopoint_repeat;
     if (SkShader::kClamp_TileMode == fTileMode) {
         shadeProc = twopoint_clamp;
     } else if (SkShader::kMirror_TileMode == fTileMode) {
@@ -219,7 +240,7 @@
         }
 
         fRec.setup(fx, fy, dx, dy);
-        (*shadeProc)(&fRec, dstC, cache, count);
+        (*shadeProc)(&fRec, dstC, cache, toggle, count);
     } else {    // perspective case
         SkScalar dstX = SkIntToScalar(x);
         SkScalar dstY = SkIntToScalar(y);
@@ -229,7 +250,10 @@
             dstX += SK_Scalar1;
 
             fRec.setup(srcPt.fX, srcPt.fY, 0, 0);
-            (*shadeProc)(&fRec, dstC, cache, 1);
+            (*shadeProc)(&fRec, dstC, cache, toggle, 1);
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+            toggle = next_dither_toggle(toggle);
+#endif
         }
     }
 }