Bug 716415 - Apply mozilla patches to skia and fix bitrot. r=jrmuizel
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 19 Jan 2012 17:48:35 +1300
changeset 86089 be5d69db8531cc80a74d8b907ed640feb0265e24
parent 86088 7e9a396c0a562c84cef99b8dd2d09b2deec00615
child 86090 e5131d25c42ceac0ffeeaa36dd3f5bcb721b874c
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs716415
milestone12.0a1
Bug 716415 - Apply mozilla patches to skia and fix bitrot. r=jrmuizel
gfx/skia/fix-gradient-clamp.patch
gfx/skia/getpostextpath.patch
gfx/skia/include/core/SkPaint.h
gfx/skia/new-aa.patch
gfx/skia/radial-gradients.patch
gfx/skia/skia_restrict_problem.patch
gfx/skia/src/core/SkPaint.cpp
gfx/skia/src/core/SkScan_AntiPath.cpp
gfx/skia/src/effects/SkGradientShader.cpp
gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
gfx/skia/update.sh
--- a/gfx/skia/fix-gradient-clamp.patch
+++ b/gfx/skia/fix-gradient-clamp.patch
@@ -1,30 +1,30 @@
 diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
 --- a/gfx/skia/src/effects/SkGradientShader.cpp
 +++ b/gfx/skia/src/effects/SkGradientShader.cpp
-@@ -165,16 +165,17 @@ private:
+@@ -167,16 +167,17 @@ private:
  
      mutable uint16_t*   fCache16;   // working ptr. If this is NULL, we need to recompute the cache values
      mutable SkPMColor*  fCache32;   // working ptr. If this is NULL, we need to recompute the cache values
  
      mutable uint16_t*   fCache16Storage;    // storage for fCache16, allocated on demand
      mutable SkMallocPixelRef* fCache32PixelRef;
      mutable unsigned    fCacheAlpha;        // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
  
 +    static SkPMColor PremultiplyColor(SkColor c0, U8CPU alpha);
      static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
      static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
                                  U8CPU alpha);
      void setCacheAlpha(U8CPU alpha) const;
+     void initCommon();
  
      typedef SkShader INHERITED;
  };
- 
-@@ -505,16 +506,31 @@ static inline U8CPU dither_fixed_to_8(Sk
+@@ -512,16 +513,31 @@ static inline U8CPU dither_fixed_to_8(Sk
   *  For dithering with premultiply, we want to ceiling the alpha component,
   *  to ensure that it is always >= any color component.
   */
  static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) {
      n >>= 8;
      return ((n << 1) - (n | (n >> 8))) >> 8;
  }
  
@@ -46,17 +46,17 @@ diff --git a/gfx/skia/src/effects/SkGrad
  void Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
                                        int count, U8CPU paintAlpha) {
      SkASSERT(count > 1);
  
      // need to apply paintAlpha to our two endpoints
      SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
      SkFixed da;
      {
-@@ -606,24 +622,24 @@ const uint16_t* Gradient_Shader::getCach
+@@ -613,24 +629,24 @@ const uint16_t* Gradient_Shader::getCach
          }
      }
      return fCache16;
  }
  
  const SkPMColor* Gradient_Shader::getCache32() const {
      if (fCache32 == NULL) {
          // double the count for dither entries
@@ -73,17 +73,17 @@ diff --git a/gfx/skia/src/effects/SkGrad
          if (fColorCount == 2) {
              Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
                              kCache32Count, fCacheAlpha);
          } else {
              Rec* rec = fRecs;
              int prevIndex = 0;
              for (int i = 1; i < fColorCount; i++) {
                  int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
-@@ -637,28 +653,31 @@ const SkPMColor* Gradient_Shader::getCac
+@@ -644,28 +660,31 @@ const SkPMColor* Gradient_Shader::getCac
              }
              SkASSERT(prevIndex == kCache32Count - 1);
          }
  
          if (fMapper) {
              SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
                                                   (NULL, allocSize, NULL));
              SkPMColor* linear = fCache32;           // just computed linear data
@@ -107,85 +107,86 @@ diff --git a/gfx/skia/src/effects/SkGrad
      return fCache32;
  }
  
  /*
   *  Because our caller might rebuild the same (logically the same) gradient
   *  over and over, we'd like to return exactly the same "bitmap" if possible,
   *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
   *  To do that, we maintain a private cache of built-bitmaps, based on our
-@@ -866,29 +885,37 @@ void Linear_Gradient::shadeSpan(int x, i
+@@ -875,28 +894,38 @@ void Linear_Gradient::shadeSpan(int x, i
              dx = dxStorage[0];
          } else {
              SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
              dx = SkScalarToFixed(fDstToIndex.getScaleX());
          }
  
          if (SkFixedNearlyZero(dx)) {
              // we're a vertical gradient, so no change in a span
--            unsigned fi = proc(fx);
--            SkASSERT(fi <= 0xFFFF);
--            // TODO: dither version
--            sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
+-            unsigned fi = proc(fx) >> (16 - kCache32Bits);
+-            sk_memset32_dither(dstC, cache[toggle + fi],
+-                                     cache[(toggle ^ TOGGLE_MASK) + fi], count);
 +            if (proc == clamp_tileproc) {
 +                if (fx < 0) {
 +                    sk_memset32(dstC, cache[-1], count);
 +                } else if (fx > 0xFFFF) {
 +                    sk_memset32(dstC, cache[kCache32Count * 2], count);
 +                } else {
-+                    sk_memset32(dstC, cache[fx >> (16 - kCache32Bits)], count);
++                    unsigned fi = proc(fx) >> (16 - kCache32Bits);
++                    sk_memset32_dither(dstC, cache[toggle + fi],
++                                       cache[(toggle ^ TOGGLE_MASK) + fi], count);
 +                }
 +            } else {
-+                unsigned fi = proc(fx);
-+                SkASSERT(fi <= 0xFFFF);
-+                // TODO: dither version
-+                sk_memset32(dstC, cache[fi >> (16 - kCache32Bits)], count);
++                unsigned fi = proc(fx) >> (16 - kCache32Bits);
++                sk_memset32_dither(dstC, cache[toggle + fi],
++                                   cache[(toggle ^ TOGGLE_MASK) + fi], count);
 +            }
          } else if (proc == clamp_tileproc) {
              SkClampRange range;
-             range.init(fx, dx, count, 0, 0xFF);
+-            range.init(fx, dx, count, 0, 0xFF);
++            range.init(fx, dx, count, cache[-1], cache[kCache32Count * 2]);
  
              if ((count = range.fCount0) > 0) {
 -                sk_memset32_dither(dstC,
 -                                   cache[toggle + range.fV0],
 -                                   cache[(toggle ^ TOGGLE_MASK) + range.fV0],
 -                                   count);
-+                // Do we really want to dither the clamp values?
-+                sk_memset32(dstC, cache[-1], count);
++                 // Do we really want to dither the clamp values?
++                 sk_memset32(dstC, range.fV0, count);
                  dstC += count;
              }
              if ((count = range.fCount1) > 0) {
                  int unroll = count >> 3;
                  fx = range.fFx1;
                  for (int i = 0; i < unroll; i++) {
                      NO_CHECK_ITER;  NO_CHECK_ITER;
                      NO_CHECK_ITER;  NO_CHECK_ITER;
-@@ -897,20 +924,17 @@ void Linear_Gradient::shadeSpan(int x, i
+@@ -905,20 +934,17 @@ void Linear_Gradient::shadeSpan(int x, i
                  }
                  if ((count &= 7) > 0) {
                      do {
                          NO_CHECK_ITER;
                      } while (--count != 0);
                  }
              }
              if ((count = range.fCount2) > 0) {
 -                sk_memset32_dither(dstC,
 -                                   cache[toggle + range.fV1],
 -                                   cache[(toggle ^ TOGGLE_MASK) + range.fV1],
 -                                   count);
-+                sk_memset32(dstC, cache[kCache32Count * 2], count);
++                sk_memset32(dstC, range.fV1, count);
              }
          } else if (proc == mirror_tileproc) {
              do {
                  unsigned fi = mirror_8bits(fx >> 8);
                  SkASSERT(fi <= 0xFF);
                  fx += dx;
                  *dstC++ = cache[toggle + fi];
                  toggle ^= TOGGLE_MASK;
-@@ -1662,19 +1686,24 @@ public:
+@@ -1670,19 +1699,24 @@ public:
              }
              SkScalar b = (SkScalarMul(fDiff.fX, fx) +
                           SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
              SkScalar db = (SkScalarMul(fDiff.fX, dx) +
                            SkScalarMul(fDiff.fY, dy)) * 2;
              if (proc == clamp_tileproc) {
                  for (; count > 0; --count) {
                      SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
@@ -203,22 +204,8 @@ diff --git a/gfx/skia/src/effects/SkGrad
                      fx += dx;
                      fy += dy;
                      b += db;
                  }
              } else if (proc == mirror_tileproc) {
                  for (; count > 0; --count) {
                      SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
                      SkFixed index = mirror_tileproc(t);
-diff --git a/gfx/skia/update.sh b/gfx/skia/update.sh
---- a/gfx/skia/update.sh
-+++ b/gfx/skia/update.sh
-@@ -90,9 +90,10 @@ if [ -n "$rev" ]; then
-   version=$rev
-   sed -i "" "s/r[0-9][0-9][0-9][0-9]/r$version/" README_MOZILLA
- else
-   echo "Remember to update README_MOZILLA with the version details."
- fi
- 
- # Patch to get arm opts to build with frame pointers enabled. Bug 689069
- patch -p3 < arm-opts.patch
-+patch -p3
- 
new file mode 100644
--- /dev/null
+++ b/gfx/skia/getpostextpath.patch
@@ -0,0 +1,70 @@
+diff --git a/gfx/skia/include/core/SkPaint.h b/gfx/skia/include/core/SkPaint.h
+--- a/gfx/skia/include/core/SkPaint.h
++++ b/gfx/skia/include/core/SkPaint.h
+@@ -836,16 +836,19 @@ public:
+ 
+     /** Return the path (outline) for the specified text.
+         Note: just like SkCanvas::drawText, this will respect the Align setting
+               in the paint.
+     */
+     void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y,
+                      SkPath* path) const;
+ 
++    void getPosTextPath(const void* text, size_t length, 
++                        const SkPoint pos[], SkPath* path) const;
++
+ #ifdef SK_BUILD_FOR_ANDROID
+     const SkGlyph& getUnicharMetrics(SkUnichar);
+     const void* findImage(const SkGlyph&);
+ 
+     uint32_t getGenerationID() const;
+ #endif
+ 
+     // returns true if the paint's settings (e.g. xfermode + alpha) resolve to
+diff --git a/gfx/skia/src/core/SkPaint.cpp b/gfx/skia/src/core/SkPaint.cpp
+--- a/gfx/skia/src/core/SkPaint.cpp
++++ b/gfx/skia/src/core/SkPaint.cpp
+@@ -1242,16 +1242,43 @@ void SkPaint::getTextPath(const void* te
+     const SkPath*   iterPath;
+     while ((iterPath = iter.next(&xpos)) != NULL) {
+         matrix.postTranslate(xpos - prevXPos, 0);
+         path->addPath(*iterPath, matrix);
+         prevXPos = xpos;
+     }
+ }
+ 
++void SkPaint::getPosTextPath(const void* textData, size_t length,
++                             const SkPoint pos[], SkPath* path) const {
++    SkASSERT(length == 0 || textData != NULL);
++
++    const char* text = (const char*)textData;
++    if (text == NULL || length == 0 || path == NULL) {
++        return;
++    }
++
++    SkTextToPathIter    iter(text, length, *this, false, true);
++    SkMatrix            matrix;
++    SkPoint             prevPos;
++    prevPos.set(0, 0);
++
++    matrix.setScale(iter.getPathScale(), iter.getPathScale());
++    path->reset();
++
++    unsigned int    i = 0;
++    const SkPath*   iterPath;
++    while ((iterPath = iter.next(NULL)) != NULL) {
++        matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
++        path->addPath(*iterPath, matrix);
++        prevPos = pos[i];
++        i++;
++    }
++}
++
+ static void add_flattenable(SkDescriptor* desc, uint32_t tag,
+                             SkFlattenableWriteBuffer* buffer) {
+     buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
+ }
+ 
+ // SkFontHost can override this choice in FilterRec()
+ static SkMask::Format computeMaskFormat(const SkPaint& paint) {
+     uint32_t flags = paint.getFlags();
--- a/gfx/skia/include/core/SkPaint.h
+++ b/gfx/skia/include/core/SkPaint.h
@@ -836,16 +836,19 @@ public:
 
     /** Return the path (outline) for the specified text.
         Note: just like SkCanvas::drawText, this will respect the Align setting
               in the paint.
     */
     void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y,
                      SkPath* path) const;
 
+    void getPosTextPath(const void* text, size_t length, 
+                        const SkPoint pos[], SkPath* path) const;
+
 #ifdef SK_BUILD_FOR_ANDROID
     const SkGlyph& getUnicharMetrics(SkUnichar);
     const void* findImage(const SkGlyph&);
 
     uint32_t getGenerationID() const;
 #endif
 
     // returns true if the paint's settings (e.g. xfermode + alpha) resolve to
--- a/gfx/skia/new-aa.patch
+++ b/gfx/skia/new-aa.patch
@@ -1,22 +1,22 @@
 diff --git a/gfx/skia/src/core/SkScan_AntiPath.cpp b/gfx/skia/src/core/SkScan_AntiPath.cpp
 --- a/gfx/skia/src/core/SkScan_AntiPath.cpp
 +++ b/gfx/skia/src/core/SkScan_AntiPath.cpp
-@@ -26,17 +26,17 @@
-         this is often faster for large objects with big spans
+@@ -31,17 +31,17 @@
+     - supersampled coordinates, scale equal to the output * SCALE
  
      NEW_AA is a set of code-changes to try to make both paths produce identical
      results. Its not quite there yet, though the remaining differences may be
      in the subsequent blits, and not in the different masks/runs...
   */
  //#define FORCE_SUPERMASK
  //#define FORCE_RLE
 -//#define SK_SUPPORT_NEW_AA
 +#define SK_SUPPORT_NEW_AA
  
  ///////////////////////////////////////////////////////////////////////////////
  
+ /// Base class for a single-pass supersampled blitter.
  class BaseSuperBlitter : public SkBlitter {
  public:
      BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
                       const SkRegion& clip);
- 
--- a/gfx/skia/radial-gradients.patch
+++ b/gfx/skia/radial-gradients.patch
@@ -1,17 +1,17 @@
 diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
 --- a/gfx/skia/src/effects/SkGradientShader.cpp
 +++ b/gfx/skia/src/effects/SkGradientShader.cpp
-@@ -1652,17 +1652,20 @@ public:
+@@ -1665,17 +1665,20 @@ public:
          }
          return kRadial2_GradientType;
      }
  
-     virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) {
+     virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) SK_OVERRIDE {
          SkASSERT(count > 0);
  
          // Zero difference between radii:  fill with transparent black.
 -        if (fDiffRadius == 0) {
 +        // TODO: Is removing this actually correct? Two circles with the 
 +        // same radius, but different centers doesn't sound like it
 +        // should be cleared
 +        if (fDiffRadius == 0 && fCenter1 == fCenter2) {
--- a/gfx/skia/skia_restrict_problem.patch
+++ b/gfx/skia/skia_restrict_problem.patch
@@ -1,22 +1,21 @@
 diff --git a/gfx/skia/src/effects/SkGradientShader.cpp b/gfx/skia/src/effects/SkGradientShader.cpp
 --- a/gfx/skia/src/effects/SkGradientShader.cpp
 +++ b/gfx/skia/src/effects/SkGradientShader.cpp
-@@ -1170,117 +1170,18 @@ public:
-           fRadius(radius)
+@@ -1184,116 +1184,17 @@ public:
      {
          // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
          SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
  
          rad_to_unit_matrix(center, radius, &fPtsToUnit);
      }
  
--    virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count);
--    virtual void shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, int count) {
+     virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count) SK_OVERRIDE;
+-    virtual void shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, int count) SK_OVERRIDE {
 -        SkASSERT(count > 0);
 -
 -        SkPoint             srcPt;
 -        SkMatrix::MapXYProc dstProc = fDstToIndexProc;
 -        TileProc            proc = fTileProc;
 -        const uint16_t* SK_RESTRICT cache = this->getCache16();
 -        int                 toggle = ((x ^ y) & 1) << kCache16Bits;
 -
@@ -106,27 +105,26 @@ diff --git a/gfx/skia/src/effects/SkGrad
 -                int index = fi >> (16 - kCache16Bits);
 -                *dstC++ = cache[toggle + index];
 -                toggle ^= (1 << kCache16Bits);
 -
 -                dstX += SK_Scalar1;
 -            } while (--count != 0);
 -        }
 -    }
-+    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
-+    virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
++    virtual void shadeSpan16(int x, int y, uint16_t* dstC, int count) SK_OVERRIDE;
  
      virtual BitmapType asABitmap(SkBitmap* bitmap,
                                   SkMatrix* matrix,
                                   TileMode* xy,
-                                  SkScalar* twoPointRadialParams) const {
+                                  SkScalar* twoPointRadialParams) const SK_OVERRIDE {
          if (bitmap) {
              this->commonAsABitmap(bitmap);
          }
-@@ -1494,16 +1395,117 @@ void Radial_Gradient::shadeSpan(int x, i
+@@ -1507,16 +1408,117 @@ void Radial_Gradient::shadeSpan(int x, i
              unsigned fi = proc(SkScalarToFixed(srcPt.length()));
              SkASSERT(fi <= 0xFFFF);
              *dstC++ = cache[fi >> (16 - kCache32Bits)];
              dstX += SK_Scalar1;
          } while (--count != 0);
      }
  }
  
@@ -234,26 +232,26 @@ diff --git a/gfx/skia/src/effects/SkGrad
  /* Two-point radial gradients are specified by two circles, each with a center
     point and radius.  The gradient can be considered to be a series of
     concentric circles, with the color interpolated from the start circle
     (at t=0) to the end circle (at t=1).
  
     For each point (x, y) in the span, we want to find the
     interpolated circle that intersects that point.  The center
     of the desired circle (Cx, Cy) falls at some distance t
-@@ -1648,109 +1650,17 @@ public:
+@@ -1661,109 +1663,17 @@ public:
              info->fPoint[0] = fCenter1;
              info->fPoint[1] = fCenter2;
              info->fRadius[0] = fRadius1;
              info->fRadius[1] = fRadius2;
          }
          return kRadial2_GradientType;
      }
  
--    virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) {
+-    virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) SK_OVERRIDE {
 -        SkASSERT(count > 0);
 -
 -        // Zero difference between radii:  fill with transparent black.
 -        // TODO: Is removing this actually correct? Two circles with the 
 -        // same radius, but different centers doesn't sound like it
 -        // should be cleared
 -        if (fDiffRadius == 0 && fCenter1 == fCenter2) {
 -          sk_bzero(dstC, count * sizeof(*dstC));
@@ -336,26 +334,26 @@ diff --git a/gfx/skia/src/effects/SkGrad
 -                SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
 -                SkFixed index = proc(t);
 -                SkASSERT(index <= 0xFFFF);
 -                *dstC++ = cache[index >> (16 - kCache32Bits)];
 -                dstX += SK_Scalar1;
 -            }
 -        }
 -    }
-+    virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
++    virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count) SK_OVERRIDE;
  
      virtual bool setContext(const SkBitmap& device,
                              const SkPaint& paint,
-                             const SkMatrix& matrix) {
+                             const SkMatrix& matrix) SK_OVERRIDE {
          if (!this->INHERITED::setContext(device, paint, matrix)) {
              return false;
          }
  
-@@ -1804,16 +1714,110 @@ private:
+@@ -1817,16 +1727,110 @@ private:
          fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
          fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
  
          fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
          fPtsToUnit.postScale(inv, inv);
      }
  };
  
@@ -374,17 +372,17 @@ diff --git a/gfx/skia/src/effects/SkGrad
 +    TileProc            proc = fTileProc;
 +    const SkPMColor* SK_RESTRICT cache = this->getCache32();
 +
 +    SkScalar foura = fA * 4;
 +    bool posRoot = fDiffRadius < 0;
 +    if (fDstToIndexClass != kPerspective_MatrixClass) {
 +        SkPoint srcPt;
 +        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
-+                                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
++                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
 +        SkScalar dx, fx = srcPt.fX;
 +        SkScalar dy, fy = srcPt.fY;
 +
 +        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
 +            SkFixed fixedX, fixedY;
 +            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
 +            dx = SkFixedToScalar(fixedX);
 +            dy = SkFixedToScalar(fixedY);
--- a/gfx/skia/src/core/SkPaint.cpp
+++ b/gfx/skia/src/core/SkPaint.cpp
@@ -1242,16 +1242,43 @@ void SkPaint::getTextPath(const void* te
     const SkPath*   iterPath;
     while ((iterPath = iter.next(&xpos)) != NULL) {
         matrix.postTranslate(xpos - prevXPos, 0);
         path->addPath(*iterPath, matrix);
         prevXPos = xpos;
     }
 }
 
+void SkPaint::getPosTextPath(const void* textData, size_t length,
+                             const SkPoint pos[], SkPath* path) const {
+    SkASSERT(length == 0 || textData != NULL);
+
+    const char* text = (const char*)textData;
+    if (text == NULL || length == 0 || path == NULL) {
+        return;
+    }
+
+    SkTextToPathIter    iter(text, length, *this, false, true);
+    SkMatrix            matrix;
+    SkPoint             prevPos;
+    prevPos.set(0, 0);
+
+    matrix.setScale(iter.getPathScale(), iter.getPathScale());
+    path->reset();
+
+    unsigned int    i = 0;
+    const SkPath*   iterPath;
+    while ((iterPath = iter.next(NULL)) != NULL) {
+        matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY);
+        path->addPath(*iterPath, matrix);
+        prevPos = pos[i];
+        i++;
+    }
+}
+
 static void add_flattenable(SkDescriptor* desc, uint32_t tag,
                             SkFlattenableWriteBuffer* buffer) {
     buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
 }
 
 // SkFontHost can override this choice in FilterRec()
 static SkMask::Format computeMaskFormat(const SkPaint& paint) {
     uint32_t flags = paint.getFlags();
--- a/gfx/skia/src/core/SkScan_AntiPath.cpp
+++ b/gfx/skia/src/core/SkScan_AntiPath.cpp
@@ -31,17 +31,17 @@
     - supersampled coordinates, scale equal to the output * SCALE
 
     NEW_AA is a set of code-changes to try to make both paths produce identical
     results. Its not quite there yet, though the remaining differences may be
     in the subsequent blits, and not in the different masks/runs...
  */
 //#define FORCE_SUPERMASK
 //#define FORCE_RLE
-//#define SK_SUPPORT_NEW_AA
+#define SK_SUPPORT_NEW_AA
 
 ///////////////////////////////////////////////////////////////////////////////
 
 /// Base class for a single-pass supersampled blitter.
 class BaseSuperBlitter : public SkBlitter {
 public:
     BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
                      const SkRegion& clip);
--- a/gfx/skia/src/effects/SkGradientShader.cpp
+++ b/gfx/skia/src/effects/SkGradientShader.cpp
@@ -167,16 +167,17 @@ private:
 
     mutable uint16_t*   fCache16;   // working ptr. If this is NULL, we need to recompute the cache values
     mutable SkPMColor*  fCache32;   // working ptr. If this is NULL, we need to recompute the cache values
 
     mutable uint16_t*   fCache16Storage;    // storage for fCache16, allocated on demand
     mutable SkMallocPixelRef* fCache32PixelRef;
     mutable unsigned    fCacheAlpha;        // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
 
+    static SkPMColor PremultiplyColor(SkColor c0, U8CPU alpha);
     static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
     static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
                                 U8CPU alpha);
     void setCacheAlpha(U8CPU alpha) const;
     void initCommon();
 
     typedef SkShader INHERITED;
 };
@@ -512,16 +513,31 @@ static inline U8CPU dither_fixed_to_8(Sk
  *  For dithering with premultiply, we want to ceiling the alpha component,
  *  to ensure that it is always >= any color component.
  */
 static inline U8CPU dither_ceil_fixed_to_8(SkFixed n) {
     n >>= 8;
     return ((n << 1) - (n | (n >> 8))) >> 8;
 }
 
+SkPMColor Gradient_Shader::PremultiplyColor(SkColor c0, U8CPU paintAlpha)
+{
+    SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
+    SkFixed r = SkColorGetR(c0);
+    SkFixed g = SkColorGetG(c0);
+    SkFixed b = SkColorGetB(c0);
+    
+    a = SkIntToFixed(a) + 0x8000;
+    r = SkIntToFixed(r) + 0x8000;
+    g = SkIntToFixed(g) + 0x8000;
+    b = SkIntToFixed(b) + 0x8000;
+        
+    return SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
+}
+
 void Gradient_Shader::Build32bitCache(SkPMColor cache[], SkColor c0, SkColor c1,
                                       int count, U8CPU paintAlpha) {
     SkASSERT(count > 1);
 
     // need to apply paintAlpha to our two endpoints
     SkFixed a = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
     SkFixed da;
     {
@@ -613,24 +629,24 @@ const uint16_t* Gradient_Shader::getCach
         }
     }
     return fCache16;
 }
 
 const SkPMColor* Gradient_Shader::getCache32() const {
     if (fCache32 == NULL) {
         // double the count for dither entries
-        const int entryCount = kCache32Count * 2;
+        const int entryCount = kCache32Count * 2 + 2;
         const size_t allocSize = sizeof(SkPMColor) * entryCount;
 
         if (NULL == fCache32PixelRef) {
             fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef,
                                           (NULL, allocSize, NULL));
         }
-        fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
+        fCache32 = (SkPMColor*)fCache32PixelRef->getAddr() + 1;
         if (fColorCount == 2) {
             Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
                             kCache32Count, fCacheAlpha);
         } else {
             Rec* rec = fRecs;
             int prevIndex = 0;
             for (int i = 1; i < fColorCount; i++) {
                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> (16 - kCache32Bits);
@@ -644,28 +660,31 @@ const SkPMColor* Gradient_Shader::getCac
             }
             SkASSERT(prevIndex == kCache32Count - 1);
         }
 
         if (fMapper) {
             SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
                                                  (NULL, allocSize, NULL));
             SkPMColor* linear = fCache32;           // just computed linear data
-            SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
+            SkPMColor* mapped = (SkPMColor*)newPR->getAddr() + 1;    // storage for mapped data
             SkUnitMapper* map = fMapper;
             for (int i = 0; i < kCache32Count; i++) {
                 int index = map->mapUnit16((i << 8) | i) >> 8;
                 mapped[i] = linear[index];
                 mapped[i + kCache32Count] = linear[index + kCache32Count];
             }
             fCache32PixelRef->unref();
             fCache32PixelRef = newPR;
-            fCache32 = (SkPMColor*)newPR->getAddr();
+            fCache32 = (SkPMColor*)newPR->getAddr() + 1;
         }
     }
+    //Write the clamp colours into the first and last entries of fCache32
+    fCache32[-1] = PremultiplyColor(fOrigColors[0], fCacheAlpha);
+    fCache32[kCache32Count * 2] = PremultiplyColor(fOrigColors[fColorCount - 1], fCacheAlpha);
     return fCache32;
 }
 
 /*
  *  Because our caller might rebuild the same (logically the same) gradient
  *  over and over, we'd like to return exactly the same "bitmap" if possible,
  *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
  *  To do that, we maintain a private cache of built-bitmaps, based on our
@@ -875,28 +894,38 @@ void Linear_Gradient::shadeSpan(int x, i
             dx = dxStorage[0];
         } else {
             SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
             dx = SkScalarToFixed(fDstToIndex.getScaleX());
         }
 
         if (SkFixedNearlyZero(dx)) {
             // we're a vertical gradient, so no change in a span
-            unsigned fi = proc(fx) >> (16 - kCache32Bits);
-            sk_memset32_dither(dstC, cache[toggle + fi],
-                                     cache[(toggle ^ TOGGLE_MASK) + fi], count);
+            if (proc == clamp_tileproc) {
+                if (fx < 0) {
+                    sk_memset32(dstC, cache[-1], count);
+                } else if (fx > 0xFFFF) {
+                    sk_memset32(dstC, cache[kCache32Count * 2], count);
+                } else {
+                    unsigned fi = proc(fx) >> (16 - kCache32Bits);
+                    sk_memset32_dither(dstC, cache[toggle + fi],
+                                       cache[(toggle ^ TOGGLE_MASK) + fi], count);
+                }
+            } else {
+                unsigned fi = proc(fx) >> (16 - kCache32Bits);
+                sk_memset32_dither(dstC, cache[toggle + fi],
+                                   cache[(toggle ^ TOGGLE_MASK) + fi], count);
+            }
         } else if (proc == clamp_tileproc) {
             SkClampRange range;
-            range.init(fx, dx, count, 0, 0xFF);
+            range.init(fx, dx, count, cache[-1], cache[kCache32Count * 2]);
 
             if ((count = range.fCount0) > 0) {
-                sk_memset32_dither(dstC,
-                                   cache[toggle + range.fV0],
-                                   cache[(toggle ^ TOGGLE_MASK) + range.fV0],
-                                   count);
+                 // Do we really want to dither the clamp values?
+                 sk_memset32(dstC, range.fV0, count);
                 dstC += count;
             }
             if ((count = range.fCount1) > 0) {
                 int unroll = count >> 3;
                 fx = range.fFx1;
                 for (int i = 0; i < unroll; i++) {
                     NO_CHECK_ITER;  NO_CHECK_ITER;
                     NO_CHECK_ITER;  NO_CHECK_ITER;
@@ -905,20 +934,17 @@ void Linear_Gradient::shadeSpan(int x, i
                 }
                 if ((count &= 7) > 0) {
                     do {
                         NO_CHECK_ITER;
                     } while (--count != 0);
                 }
             }
             if ((count = range.fCount2) > 0) {
-                sk_memset32_dither(dstC,
-                                   cache[toggle + range.fV1],
-                                   cache[(toggle ^ TOGGLE_MASK) + range.fV1],
-                                   count);
+                sk_memset32(dstC, range.fV1, count);
             }
         } else if (proc == mirror_tileproc) {
             do {
                 unsigned fi = mirror_8bits(fx >> 8);
                 SkASSERT(fi <= 0xFF);
                 fx += dx;
                 *dstC++ = cache[toggle + fi];
                 toggle ^= TOGGLE_MASK;
@@ -1155,116 +1181,17 @@ public:
     {
         // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE
         SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE);
 
         rad_to_unit_matrix(center, radius, &fPtsToUnit);
     }
 
     virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count) SK_OVERRIDE;
-    virtual void shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, int count) SK_OVERRIDE {
-        SkASSERT(count > 0);
-
-        SkPoint             srcPt;
-        SkMatrix::MapXYProc dstProc = fDstToIndexProc;
-        TileProc            proc = fTileProc;
-        const uint16_t* SK_RESTRICT cache = this->getCache16();
-        int                 toggle = ((x ^ y) & 1) << kCache16Bits;
-
-        if (fDstToIndexClass != kPerspective_MatrixClass) {
-            dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
-                                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
-            SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
-            SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
-
-            if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
-                SkFixed storage[2];
-                (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
-                dx = storage[0];
-                dy = storage[1];
-            } else {
-                SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
-                dx = SkScalarToFixed(fDstToIndex.getScaleX());
-                dy = SkScalarToFixed(fDstToIndex.getSkewY());
-            }
-
-            if (proc == clamp_tileproc) {
-                const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
-
-                /* knock these down so we can pin against +- 0x7FFF, which is an immediate load,
-                    rather than 0xFFFF which is slower. This is a compromise, since it reduces our
-                    precision, but that appears to be visually OK. If we decide this is OK for
-                    all of our cases, we could (it seems) put this scale-down into fDstToIndex,
-                    to avoid having to do these extra shifts each time.
-                */
-                fx >>= 1;
-                dx >>= 1;
-                fy >>= 1;
-                dy >>= 1;
-                if (dy == 0) {    // might perform this check for the other modes, but the win will be a smaller % of the total
-                    fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
-                    fy *= fy;
-                    do {
-                        unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
-                        unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
-                        fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
-                        fx += dx;
-                        *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
-                        toggle ^= (1 << kCache16Bits);
-                    } while (--count != 0);
-                } else {
-                    do {
-                        unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
-                        unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
-                        fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
-                        fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
-                        fx += dx;
-                        fy += dy;
-                        *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
-                        toggle ^= (1 << kCache16Bits);
-                    } while (--count != 0);
-                }
-            } else if (proc == mirror_tileproc) {
-                do {
-                    SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
-                    unsigned fi = mirror_tileproc(dist);
-                    SkASSERT(fi <= 0xFFFF);
-                    fx += dx;
-                    fy += dy;
-                    *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
-                    toggle ^= (1 << kCache16Bits);
-                } while (--count != 0);
-            } else {
-                SkASSERT(proc == repeat_tileproc);
-                do {
-                    SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
-                    unsigned fi = repeat_tileproc(dist);
-                    SkASSERT(fi <= 0xFFFF);
-                    fx += dx;
-                    fy += dy;
-                    *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
-                    toggle ^= (1 << kCache16Bits);
-                } while (--count != 0);
-            }
-        } else {    // perspective case
-            SkScalar dstX = SkIntToScalar(x);
-            SkScalar dstY = SkIntToScalar(y);
-            do {
-                dstProc(fDstToIndex, dstX, dstY, &srcPt);
-                unsigned fi = proc(SkScalarToFixed(srcPt.length()));
-                SkASSERT(fi <= 0xFFFF);
-
-                int index = fi >> (16 - kCache16Bits);
-                *dstC++ = cache[toggle + index];
-                toggle ^= (1 << kCache16Bits);
-
-                dstX += SK_Scalar1;
-            } while (--count != 0);
-        }
-    }
+    virtual void shadeSpan16(int x, int y, uint16_t* dstC, int count) SK_OVERRIDE;
 
     virtual BitmapType asABitmap(SkBitmap* bitmap,
                                  SkMatrix* matrix,
                                  TileMode* xy,
                                  SkScalar* twoPointRadialParams) const SK_OVERRIDE {
         if (bitmap) {
             this->commonAsABitmap(bitmap);
         }
@@ -1478,16 +1405,117 @@ void Radial_Gradient::shadeSpan(int x, i
             unsigned fi = proc(SkScalarToFixed(srcPt.length()));
             SkASSERT(fi <= 0xFFFF);
             *dstC++ = cache[fi >> (16 - kCache32Bits)];
             dstX += SK_Scalar1;
         } while (--count != 0);
     }
 }
 
+void Radial_Gradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, int count) {
+    SkASSERT(count > 0);
+
+    SkPoint             srcPt;
+    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
+    TileProc            proc = fTileProc;
+    const uint16_t* SK_RESTRICT cache = this->getCache16();
+    int                 toggle = ((x ^ y) & 1) << kCache16Bits;
+
+    if (fDstToIndexClass != kPerspective_MatrixClass) {
+        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
+                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
+        SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+        SkFixed dy, fy = SkScalarToFixed(srcPt.fY);
+
+        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
+            SkFixed storage[2];
+            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &storage[0], &storage[1]);
+            dx = storage[0];
+            dy = storage[1];
+        } else {
+            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+            dx = SkScalarToFixed(fDstToIndex.getScaleX());
+            dy = SkScalarToFixed(fDstToIndex.getSkewY());
+        }
+
+        if (proc == clamp_tileproc) {
+            const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table;
+
+            /* knock these down so we can pin against +- 0x7FFF, which is an immediate load,
+                rather than 0xFFFF which is slower. This is a compromise, since it reduces our
+                precision, but that appears to be visually OK. If we decide this is OK for
+                all of our cases, we could (it seems) put this scale-down into fDstToIndex,
+                to avoid having to do these extra shifts each time.
+            */
+            fx >>= 1;
+            dx >>= 1;
+            fy >>= 1;
+            dy >>= 1;
+            if (dy == 0) {    // might perform this check for the other modes, but the win will be a smaller % of the total
+                fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
+                fy *= fy;
+                do {
+                    unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
+                    unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS);
+                    fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
+                    fx += dx;
+                    *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
+                    toggle ^= (1 << kCache16Bits);
+                } while (--count != 0);
+            } else {
+                do {
+                    unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1);
+                    unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
+                    fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS);
+                    fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS));
+                    fx += dx;
+                    fy += dy;
+                    *dstC++ = cache[toggle + (sqrt_table[fi] >> (8 - kCache16Bits))];
+                    toggle ^= (1 << kCache16Bits);
+                } while (--count != 0);
+            }
+        } else if (proc == mirror_tileproc) {
+            do {
+                SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+                unsigned fi = mirror_tileproc(dist);
+                SkASSERT(fi <= 0xFFFF);
+                fx += dx;
+                fy += dy;
+                *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
+                toggle ^= (1 << kCache16Bits);
+            } while (--count != 0);
+        } else {
+            SkASSERT(proc == repeat_tileproc);
+            do {
+                SkFixed dist = SkFixedSqrt(SkFixedSquare(fx) + SkFixedSquare(fy));
+                unsigned fi = repeat_tileproc(dist);
+                SkASSERT(fi <= 0xFFFF);
+                fx += dx;
+                fy += dy;
+                *dstC++ = cache[toggle + (fi >> (16 - kCache16Bits))];
+                toggle ^= (1 << kCache16Bits);
+            } while (--count != 0);
+        }
+    } else {    // perspective case
+        SkScalar dstX = SkIntToScalar(x);
+        SkScalar dstY = SkIntToScalar(y);
+        do {
+            dstProc(fDstToIndex, dstX, dstY, &srcPt);
+            unsigned fi = proc(SkScalarToFixed(srcPt.length()));
+            SkASSERT(fi <= 0xFFFF);
+
+            int index = fi >> (16 - kCache16Bits);
+            *dstC++ = cache[toggle + index];
+            toggle ^= (1 << kCache16Bits);
+
+            dstX += SK_Scalar1;
+        } while (--count != 0);
+    }
+}
+
 /* Two-point radial gradients are specified by two circles, each with a center
    point and radius.  The gradient can be considered to be a series of
    concentric circles, with the color interpolated from the start circle
    (at t=0) to the end circle (at t=1).
 
    For each point (x, y) in the span, we want to find the
    interpolated circle that intersects that point.  The center
    of the desired circle (Cx, Cy) falls at some distance t
@@ -1632,101 +1660,17 @@ public:
             info->fPoint[0] = fCenter1;
             info->fPoint[1] = fCenter2;
             info->fRadius[0] = fRadius1;
             info->fRadius[1] = fRadius2;
         }
         return kRadial2_GradientType;
     }
 
-    virtual void shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) SK_OVERRIDE {
-        SkASSERT(count > 0);
-
-        // Zero difference between radii:  fill with transparent black.
-        if (fDiffRadius == 0) {
-          sk_bzero(dstC, count * sizeof(*dstC));
-          return;
-        }
-        SkMatrix::MapXYProc dstProc = fDstToIndexProc;
-        TileProc            proc = fTileProc;
-        const SkPMColor* SK_RESTRICT cache = this->getCache32();
-
-        SkScalar foura = fA * 4;
-        bool posRoot = fDiffRadius < 0;
-        if (fDstToIndexClass != kPerspective_MatrixClass) {
-            SkPoint srcPt;
-            dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
-                                 SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
-            SkScalar dx, fx = srcPt.fX;
-            SkScalar dy, fy = srcPt.fY;
-
-            if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
-                SkFixed fixedX, fixedY;
-                (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
-                dx = SkFixedToScalar(fixedX);
-                dy = SkFixedToScalar(fixedY);
-            } else {
-                SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
-                dx = fDstToIndex.getScaleX();
-                dy = fDstToIndex.getSkewY();
-            }
-            SkScalar b = (SkScalarMul(fDiff.fX, fx) +
-                         SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
-            SkScalar db = (SkScalarMul(fDiff.fX, dx) +
-                          SkScalarMul(fDiff.fY, dy)) * 2;
-            if (proc == clamp_tileproc) {
-                for (; count > 0; --count) {
-                    SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
-                    SkFixed index = SkClampMax(t, 0xFFFF);
-                    SkASSERT(index <= 0xFFFF);
-                    *dstC++ = cache[index >> (16 - kCache32Bits)];
-                    fx += dx;
-                    fy += dy;
-                    b += db;
-                }
-            } else if (proc == mirror_tileproc) {
-                for (; count > 0; --count) {
-                    SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
-                    SkFixed index = mirror_tileproc(t);
-                    SkASSERT(index <= 0xFFFF);
-                    *dstC++ = cache[index >> (16 - kCache32Bits)];
-                    fx += dx;
-                    fy += dy;
-                    b += db;
-                }
-            } else {
-                SkASSERT(proc == repeat_tileproc);
-                for (; count > 0; --count) {
-                    SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
-                    SkFixed index = repeat_tileproc(t);
-                    SkASSERT(index <= 0xFFFF);
-                    *dstC++ = cache[index >> (16 - kCache32Bits)];
-                    fx += dx;
-                    fy += dy;
-                    b += db;
-                }
-            }
-        } else {    // perspective case
-            SkScalar dstX = SkIntToScalar(x);
-            SkScalar dstY = SkIntToScalar(y);
-            for (; count > 0; --count) {
-                SkPoint             srcPt;
-                dstProc(fDstToIndex, dstX, dstY, &srcPt);
-                SkScalar fx = srcPt.fX;
-                SkScalar fy = srcPt.fY;
-                SkScalar b = (SkScalarMul(fDiff.fX, fx) +
-                             SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
-                SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
-                SkFixed index = proc(t);
-                SkASSERT(index <= 0xFFFF);
-                *dstC++ = cache[index >> (16 - kCache32Bits)];
-                dstX += SK_Scalar1;
-            }
-        }
-    }
+    virtual void shadeSpan(int x, int y, SkPMColor* dstC, int count) SK_OVERRIDE;
 
     virtual bool setContext(const SkBitmap& device,
                             const SkPaint& paint,
                             const SkMatrix& matrix) SK_OVERRIDE {
         if (!this->INHERITED::setContext(device, paint, matrix)) {
             return false;
         }
 
@@ -1780,16 +1724,110 @@ private:
         fA = SkScalarSquare(fDiff.fX) + SkScalarSquare(fDiff.fY) - SK_Scalar1;
         fOneOverTwoA = fA ? SkScalarInvert(fA * 2) : 0;
 
         fPtsToUnit.setTranslate(-fCenter1.fX, -fCenter1.fY);
         fPtsToUnit.postScale(inv, inv);
     }
 };
 
+void Two_Point_Radial_Gradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, int count) {
+    SkASSERT(count > 0);
+
+    // Zero difference between radii:  fill with transparent black.
+    // TODO: Is removing this actually correct? Two circles with the 
+    // same radius, but different centers doesn't sound like it
+    // should be cleared
+    if (fDiffRadius == 0 && fCenter1 == fCenter2) {
+      sk_bzero(dstC, count * sizeof(*dstC));
+      return;
+    }
+    SkMatrix::MapXYProc dstProc = fDstToIndexProc;
+    TileProc            proc = fTileProc;
+    const SkPMColor* SK_RESTRICT cache = this->getCache32();
+
+    SkScalar foura = fA * 4;
+    bool posRoot = fDiffRadius < 0;
+    if (fDstToIndexClass != kPerspective_MatrixClass) {
+        SkPoint srcPt;
+        dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
+                             SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
+        SkScalar dx, fx = srcPt.fX;
+        SkScalar dy, fy = srcPt.fY;
+
+        if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
+            SkFixed fixedX, fixedY;
+            (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), &fixedX, &fixedY);
+            dx = SkFixedToScalar(fixedX);
+            dy = SkFixedToScalar(fixedY);
+        } else {
+            SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
+            dx = fDstToIndex.getScaleX();
+            dy = fDstToIndex.getSkewY();
+        }
+        SkScalar b = (SkScalarMul(fDiff.fX, fx) +
+                     SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
+        SkScalar db = (SkScalarMul(fDiff.fX, dx) +
+                      SkScalarMul(fDiff.fY, dy)) * 2;
+        if (proc == clamp_tileproc) {
+            for (; count > 0; --count) {
+                SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
+                if (t < 0) {
+                  *dstC++ = cache[-1];
+                } else if (t > 0xFFFF) {
+                  *dstC++ = cache[kCache32Count * 2];
+                } else {
+                  SkASSERT(t <= 0xFFFF);
+                  *dstC++ = cache[t >> (16 - kCache32Bits)];
+                }
+                fx += dx;
+                fy += dy;
+                b += db;
+            }
+        } else if (proc == mirror_tileproc) {
+            for (; count > 0; --count) {
+                SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
+                SkFixed index = mirror_tileproc(t);
+                SkASSERT(index <= 0xFFFF);
+                *dstC++ = cache[index >> (16 - kCache32Bits)];
+                fx += dx;
+                fy += dy;
+                b += db;
+            }
+        } else {
+            SkASSERT(proc == repeat_tileproc);
+            for (; count > 0; --count) {
+                SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
+                SkFixed index = repeat_tileproc(t);
+                SkASSERT(index <= 0xFFFF);
+                *dstC++ = cache[index >> (16 - kCache32Bits)];
+                fx += dx;
+                fy += dy;
+                b += db;
+            }
+        }
+    } else {    // perspective case
+        SkScalar dstX = SkIntToScalar(x);
+        SkScalar dstY = SkIntToScalar(y);
+        for (; count > 0; --count) {
+            SkPoint             srcPt;
+            dstProc(fDstToIndex, dstX, dstY, &srcPt);
+            SkScalar fx = srcPt.fX;
+            SkScalar fy = srcPt.fY;
+            SkScalar b = (SkScalarMul(fDiff.fX, fx) +
+                         SkScalarMul(fDiff.fY, fy) - fStartRadius) * 2;
+            SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura, fOneOverTwoA, posRoot);
+            SkFixed index = proc(t);
+            SkASSERT(index <= 0xFFFF);
+            *dstC++ = cache[index >> (16 - kCache32Bits)];
+            dstX += SK_Scalar1;
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 class Sweep_Gradient : public Gradient_Shader {
 public:
     Sweep_Gradient(SkScalar cx, SkScalar cy, const SkColor colors[],
                    const SkScalar pos[], int count, SkUnitMapper* mapper)
     : Gradient_Shader(colors, pos, count, SkShader::kClamp_TileMode, mapper),
       fCenter(SkPoint::Make(cx, cy))
--- a/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
+++ b/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
@@ -545,17 +545,17 @@ static void S32A_Opaque_BlitRow32_neon(S
 #define	S32A_Opaque_BlitRow32_PROC	S32A_Opaque_BlitRow32_neon
 
 #else
 
 #ifdef TEST_SRC_ALPHA
 #error The ARM asm version of S32A_Opaque_BlitRow32 does not support TEST_SRC_ALPHA
 #endif
 
-static void S32A_Opaque_BlitRow32_arm(SkPMColor* SK_RESTRICT dst,
+static void  __attribute((noinline,optimize("-fomit-frame-pointer"))) S32A_Opaque_BlitRow32_arm(SkPMColor* SK_RESTRICT dst,
                                   const SkPMColor* SK_RESTRICT src,
                                   int count, U8CPU alpha) {
 
     SkASSERT(255 == alpha);
 
     /* Does not support the TEST_SRC_ALPHA case */
     asm volatile (
                   "cmp    %[count], #0               \n\t" /* comparing count with 0 */
@@ -642,17 +642,17 @@ static void S32A_Opaque_BlitRow32_arm(Sk
                   );
 }
 #define	S32A_Opaque_BlitRow32_PROC	S32A_Opaque_BlitRow32_arm
 #endif
 
 /*
  * ARM asm version of S32A_Blend_BlitRow32
  */
-static void S32A_Blend_BlitRow32_arm(SkPMColor* SK_RESTRICT dst,
+static void __attribute((noinline,optimize("-fomit-frame-pointer"))) S32A_Blend_BlitRow32_arm(SkPMColor* SK_RESTRICT dst,
                                  const SkPMColor* SK_RESTRICT src,
                                  int count, U8CPU alpha) {
     asm volatile (
                   "cmp    %[count], #0               \n\t" /* comparing count with 0 */
                   "beq    3f                         \n\t" /* if zero exit */
 
                   "mov    r12, #0xff                 \n\t" /* load the 0xff mask in r12 */
                   "orr    r12, r12, r12, lsl #16     \n\t" /* convert it to 0xff00ff in r12 */
--- a/gfx/skia/update.sh
+++ b/gfx/skia/update.sh
@@ -99,11 +99,9 @@ patch -p3 < fix-gradient-clamp.patch
 # Bug 687189 - Implement SkPaint::getPosTextPath.
 patch -p3 < getpostextpath.patch
 # Bug 688365 - Enable Skia 'New AA' mode.
 patch -p3 < new-aa.patch
 # Bug 688366 - Fix Skia marking radial gradients with the same radius as invalid.
 patch -p3 < radial-gradients.patch
 # Fix restrict keyword problem for VS2005
 patch -p3 < skia_restrict_problem.patch
-# Bug 705656 - Broken SKIA compilation on mingw
-patch -p3 < mingw-fix.patch