SkCanvas::drawPatch param SkPoint[12]

drawPatch now receives as parameter const SkPoint cubics[12]

Adjusted derived classes and serialization.

Ajusted GM's and benches that take into account combinations of optional
parameters, the scale of the patch and 4 different types of patches.

Planning on adding the extra functionality of SkPatch in another CL.

BUG=skia:
R=egdaniel@google.com, reed@google.com

Author: dandov@google.com

Review URL: https://codereview.chromium.org/463493002
diff --git a/bench/PatchBench.cpp b/bench/PatchBench.cpp
new file mode 100644
index 0000000..2e99e4e
--- /dev/null
+++ b/bench/PatchBench.cpp
@@ -0,0 +1,325 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Benchmark.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkGradientShader.h"
+#include "SkPaint.h"
+#include "SkPatchUtils.h"
+#include "SkRandom.h"
+#include "SkShader.h"
+#include "SkString.h"
+#include "SkTArray.h"
+
+class PatchBench : public Benchmark {
+    
+public:
+    
+    enum VertexMode {
+        kNone_VertexMode,
+        kColors_VertexMode,
+        kTexCoords_VertexMode,
+        kBoth_VertexMode
+    };
+    
+    PatchBench(SkPoint scale, VertexMode vertexMode)
+    : fScale(scale)
+    , fVertexMode(vertexMode) { }
+
+    // to add name of specific class override this method
+    virtual void appendName(SkString* name) {
+        name->append("normal");
+    }
+    
+    // to make other type of patches override this method
+    virtual void setCubics() {
+        const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
+            //top points
+            {100,100},{150,50},{250,150}, {300,100},
+            //right points
+            {350, 150},{250,200},
+            //bottom points
+            {300,300},{250,250},{150,350},{100,300},
+            //left points
+            {50,250},{150,50}
+        };
+        memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
+    }
+    
+    virtual void setColors() {
+        const SkColor colors[SkPatchUtils::kNumCorners] = {
+            SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN
+        };
+        memcpy(fColors, colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
+    }
+    
+    virtual void setTexCoords() {
+        const SkPoint texCoords[SkPatchUtils::kNumCorners] = {
+            {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f,1.0f}, {0.0f, 1.0f}
+        };
+        memcpy(fTexCoords, texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
+    }
+    
+    // override this method to change the shader
+    virtual SkShader* getShader() {
+        const SkColor colors[] = {
+            SK_ColorRED, SK_ColorCYAN, SK_ColorGREEN, SK_ColorWHITE,
+            SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorYELLOW,
+        };
+        const SkPoint pts[] = { { 200.f / 4.f, 0.f }, { 3.f * 200.f / 4, 200.f } };
+        
+        return SkGradientShader::CreateLinear(pts, colors, NULL,
+                                              SK_ARRAY_COUNT(colors),
+                                              SkShader::kMirror_TileMode);
+    }
+
+protected:
+    virtual const char* onGetName() SK_OVERRIDE {
+        SkString vertexMode;
+        switch (fVertexMode) {
+            case kNone_VertexMode:
+                vertexMode.set("meshlines");
+                break;
+            case kColors_VertexMode:
+                vertexMode.set("colors");
+                break;
+            case kTexCoords_VertexMode:
+                vertexMode.set("texs");
+                break;
+            case kBoth_VertexMode:
+                vertexMode.set("colors&texs");
+                break;
+            default:
+                break;
+        }
+        SkString type;
+        this->appendName(&type);
+        fName.printf("patch_%s_%s_[%f,%f]", type.c_str(), vertexMode.c_str(),
+                    fScale.x(), fScale.y());
+        return fName.c_str();
+    }
+    
+    virtual void preDraw() {
+        
+    }
+
+    virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
+        
+        this->setCubics();
+        this->setColors();
+        this->setTexCoords();
+        this->setupPaint(&fPaint);
+        switch (fVertexMode) {
+            case kTexCoords_VertexMode:
+            case kBoth_VertexMode:
+                fPaint.setShader(getShader());
+                break;
+            default:
+                fPaint.setShader(NULL);
+                break;
+        }
+        
+        canvas->scale(fScale.x(), fScale.y());
+        for (int i = 0; i < loops; i++) {
+            switch (fVertexMode) {
+                case kNone_VertexMode:
+                    canvas->drawPatch(fCubics, NULL, NULL, NULL, fPaint);
+                    break;
+                case kColors_VertexMode:
+                    canvas->drawPatch(fCubics, fColors, NULL, NULL, fPaint);
+                    break;
+                case kTexCoords_VertexMode:
+                    canvas->drawPatch(fCubics, NULL, fTexCoords, NULL, fPaint);
+                    break;
+                case kBoth_VertexMode:
+                    canvas->drawPatch(fCubics, fColors, fTexCoords, NULL, fPaint);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    SkPaint     fPaint;
+    SkString    fName;
+    SkVector    fScale;
+    SkPoint     fCubics[12];
+    SkPoint     fTexCoords[4];
+    SkColor     fColors[4];
+    VertexMode  fVertexMode;
+    
+    typedef Benchmark INHERITED;
+};
+
+class SquarePatchBench : public PatchBench {
+public:
+    SquarePatchBench(SkPoint scale, VertexMode vertexMode)
+    : INHERITED(scale, vertexMode) { }
+
+    virtual void appendName(SkString* name) SK_OVERRIDE {
+        name->append("square");
+    }
+    
+    virtual void setCubics() {
+        const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
+            //top points
+            {100,100},{150,100},{250,100}, {300,100},
+            //right points
+            {300, 150},{300,250},
+            //bottom points
+            {300,300},{250,300},{150,300},{100,300},
+            //left points
+            {100,250},{100,150}
+        };
+        memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
+    }
+private:
+    typedef PatchBench INHERITED;
+};
+
+class LODDiffPatchBench : public PatchBench {
+public:
+    LODDiffPatchBench(SkPoint scale, VertexMode vertexMode)
+    : INHERITED(scale, vertexMode) { }
+    
+    virtual void appendName(SkString* name) SK_OVERRIDE {
+        name->append("LOD_Diff");
+    }
+    
+    virtual void setCubics() {
+        const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
+            //top points
+            {100,175},{150,100},{250,100}, {300,0},
+            //right points
+            {300, 150},{300,250},
+            //bottom points
+            {300,400},{250,300},{150,300},{100,225},
+            //left points
+            {100,215},{100,185}
+        };
+        memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
+    }
+private:
+    typedef PatchBench INHERITED;
+};
+
+class LoopPatchBench : public PatchBench {
+public:
+    LoopPatchBench(SkPoint scale, VertexMode vertexMode)
+    : INHERITED(scale, vertexMode) { }
+    
+    virtual void appendName(SkString* name) SK_OVERRIDE {
+        name->append("loop");
+    }
+    
+    virtual void setCubics() {
+        const SkPoint points[SkPatchUtils::kNumCtrlPts] = {
+            //top points
+            {100,100},{300,200},{100,200}, {300,100},
+            //right points
+            {380, 400},{380,0},
+            //bottom points
+            {300,300},{250,250},{30,200},{100,300},
+            //left points
+            {140,325},{150,150}
+        };
+        memcpy(fCubics, points, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
+    }
+private:
+    typedef PatchBench INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(0.1f, 0.1f), PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(1.f, 1.0f), PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(1.0f, 1.0f), PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new PatchBench(SkVector::Make(3.0f, 3.0f), PatchBench::kBoth_VertexMode); )
+
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.f, 1.0f),
+                                       PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
+                                       PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
+                                       PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(1.0f, 1.0f),
+                                       PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new SquarePatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kBoth_VertexMode); )
+
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(0.1f, 0.1f),
+                                       PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.f, 1.0f),
+                                       PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
+                                       PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
+                                       PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(1.0f, 1.0f),
+                                       PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new LODDiffPatchBench(SkVector::Make(3.0f, 3.0f),
+                                       PatchBench::kBoth_VertexMode); )
+
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
+                                        PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
+                                        PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
+                                        PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(0.1f, 0.1f),
+                                        PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.f, 1.0f),
+                                        PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
+                                        PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
+                                        PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(1.0f, 1.0f),
+                                        PatchBench::kBoth_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
+                                        PatchBench::kNone_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
+                                        PatchBench::kColors_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
+                                        PatchBench::kTexCoords_VertexMode); )
+DEF_BENCH( return new LoopPatchBench(SkVector::Make(3.0f, 3.0f),
+                                        PatchBench::kBoth_VertexMode); )
diff --git a/gm/patch.cpp b/gm/patch.cpp
index 3f1e079..d4fe4ff 100644
--- a/gm/patch.cpp
+++ b/gm/patch.cpp
@@ -6,40 +6,45 @@
  * found in the LICENSE file.
  */
 
-// This test only works with the GPU backend.
-
 #include "gm.h"
+#include "SkGradientShader.h"
+#include "SkPatchUtils.h"
 
-#if SK_SUPPORT_GPU
+static SkShader* make_shader() {
+    const SkColor colors[] = {
+        SK_ColorRED, SK_ColorCYAN, SK_ColorGREEN, SK_ColorWHITE, SK_ColorMAGENTA, SK_ColorBLUE,
+        SK_ColorYELLOW,
+    };
+    const SkPoint pts[] = { { 100.f / 4.f, 0.f }, { 3.f * 100.f / 4.f, 100.f } };
+    
+    return SkGradientShader::CreateLinear(pts, colors, NULL, SK_ARRAY_COUNT(colors),
+                                          SkShader::kMirror_TileMode);
+}
 
-#include "GrContext.h"
-#include "GrTest.h"
-#include "SkPatch.h"
-
-static void draw_control_points(SkCanvas* canvas, const SkPatch& patch) {
+static void draw_control_points(SkCanvas* canvas, const SkPoint cubics[12]) {
     //draw control points
     SkPaint paint;
-    SkPoint bottom[SkPatch::kNumPtsCubic];
-    patch.getBottomPoints(bottom);
-    SkPoint top[SkPatch::kNumPtsCubic];
-    patch.getTopPoints(top);
-    SkPoint left[SkPatch::kNumPtsCubic];
-    patch.getLeftPoints(left);
-    SkPoint right[SkPatch::kNumPtsCubic];
-    patch.getRightPoints(right);
+    SkPoint bottom[SkPatchUtils::kNumPtsCubic];
+    SkPatchUtils::getBottomCubic(cubics, bottom);
+    SkPoint top[SkPatchUtils::kNumPtsCubic];
+    SkPatchUtils::getTopCubic(cubics, top);
+    SkPoint left[SkPatchUtils::kNumPtsCubic];
+    SkPatchUtils::getLeftCubic(cubics, left);
+    SkPoint right[SkPatchUtils::kNumPtsCubic];
+    SkPatchUtils::getRightCubic(cubics, right);
 
     paint.setColor(SK_ColorBLACK);
-    paint.setStrokeWidth(0.5);
+    paint.setStrokeWidth(0.5f);
     SkPoint corners[4] = { bottom[0], bottom[3], top[0], top[3] };
     canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, paint);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom+1, paint);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom + 1, paint);
     canvas->drawPoints(SkCanvas::kLines_PointMode, 4, top, paint);
     canvas->drawPoints(SkCanvas::kLines_PointMode, 4, left, paint);
     canvas->drawPoints(SkCanvas::kLines_PointMode, 4, right, paint);
 
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, top+1, paint);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left+1, paint);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right+1, paint);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, top + 1, paint);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left + 1, paint);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right + 1, paint);
 
     paint.setStrokeWidth(2);
 
@@ -47,21 +52,21 @@
     canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, paint);
 
     paint.setColor(SK_ColorBLUE);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom+1, paint);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom + 1, paint);
 
     paint.setColor(SK_ColorCYAN);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top+1, paint);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top + 1, paint);
 
     paint.setColor(SK_ColorYELLOW);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left+1, paint);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left + 1, paint);
 
     paint.setColor(SK_ColorGREEN);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right+1, paint);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right + 1, paint);
 }
 
 namespace skiagm {
 /**
- * This GM draws a SkPatch.
+ * This GM draws a cubics coons patch using the specialized call SkCanvas::drawPatch.
  */
 class SkPatchGM : public GM {
     
@@ -88,44 +93,63 @@
         SkPaint paint;
         
         // The order of the colors and points is clockwise starting at upper-left corner.
-        SkColor colors[SkPatch::kNumColors] = {
+        const SkPoint cubics[SkPatchUtils::kNumCtrlPts] = {
+            //top points
+            {100,100},{150,50},{250,150}, {300,100},
+            //right points
+            {250, 150},{350,250},
+            //bottom points
+            {300,300},{250,250},{150,350},{100,300},
+            //left points
+            {50,250},{150,150}
+        };
+        
+        const SkColor colors[SkPatchUtils::kNumCorners] = {
             SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN
         };
-        SkPoint points[SkPatch::kNumCtrlPts] = {
-            //top points
-            {50,50},{75,20},{125,80}, {150,50},
-            //right points
-            {120,75},{180,125},
-            //bottom points
-            {150,150},{125,120},{75,180},{50,150},
-            //left points
-            {20,125},{80,75}
+        const SkPoint texCoords[SkPatchUtils::kNumCorners] = {
+            {0.0f, 0.0f}, {100.0f, 0.0f}, {100.0f,100.0f}, {0.0f, 100.0f}}
+        ;
+        
+        const SkXfermode::Mode modes[] = {
+            SkXfermode::kSrc_Mode,
+            SkXfermode::kDst_Mode,
+            SkXfermode::kModulate_Mode,
         };
         
-        SkPatch patch(points, colors);
-        static const SkScalar kScale = 0.5f;
-        canvas->translate(100, 100);
+        SkAutoTUnref<SkShader> shader(make_shader());
+        
         canvas->save();
-        for (SkScalar x = 0; x < 4; x++) {
-            canvas->save();
-            canvas->scale(kScale * (x + 1), kScale * (x + 1));
-            canvas->translate(x * 100, 0);
-            canvas->drawPatch(patch, paint);
-            draw_control_points(canvas, patch);
-            canvas->restore();
-        }
-        
-        canvas->translate(0, 270);
-        
-        static const SkScalar kSkew = 0.2f;
-        for (SkScalar x = 0; x < 4; x++) {
-            canvas->save();
-            canvas->scale(kScale * (x + 1), kScale * (x + 1));
-            canvas->translate(x * 100, 0);
-            canvas->skew(kSkew * (x + 1), kSkew * (x + 1));
-            canvas->drawPatch(patch, paint);
-            draw_control_points(canvas, patch);
-            canvas->restore();
+        for (int y = 0; y < 3; y++) {
+            SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(modes[y]));
+
+            for (int x = 0; x < 4; x++) {
+                canvas->save();
+                canvas->translate(x * 350.0f, y * 350.0f);
+                switch (x) {
+                    case 0:
+                        canvas->drawPatch(cubics, NULL, NULL, xfer, paint);
+                        break;
+                    case 1:
+                        canvas->drawPatch(cubics, colors, NULL, xfer, paint);
+                        break;
+                    case 2:
+                        paint.setShader(shader);
+                        canvas->drawPatch(cubics, NULL, texCoords, xfer, paint);
+                        paint.setShader(NULL);
+                        break;
+                    case 3:
+                        paint.setShader(shader);
+                        canvas->drawPatch(cubics, colors, texCoords, xfer, paint);
+                        paint.setShader(NULL);
+                        break;
+                    default:
+                        break;
+                }
+                
+                draw_control_points(canvas, cubics);
+                canvas->restore();
+            }
         }
         canvas->restore();
     }
@@ -137,5 +161,3 @@
 DEF_GM(return SkNEW(SkPatchGM); )
 
 }
-
-#endif
diff --git a/gyp/bench.gypi b/gyp/bench.gypi
index c560523..30f0aa6 100644
--- a/gyp/bench.gypi
+++ b/gyp/bench.gypi
@@ -69,6 +69,7 @@
     '../bench/MergeBench.cpp',
     '../bench/MorphologyBench.cpp',
     '../bench/MutexBench.cpp',
+    '../bench/PatchBench.cpp',
     '../bench/PathBench.cpp',
     '../bench/PathIterBench.cpp',
     '../bench/PathUtilsBench.cpp',
diff --git a/gyp/core.gypi b/gyp/core.gypi
index a6d5635..8a7350e 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -120,7 +120,6 @@
         '<(skia_src_path)/core/SkPaintOptionsAndroid.cpp',
         '<(skia_src_path)/core/SkPaintPriv.cpp',
         '<(skia_src_path)/core/SkPaintPriv.h',
-        '<(skia_src_path)/core/SkPatch.cpp',
         '<(skia_src_path)/core/SkPath.cpp',
         '<(skia_src_path)/core/SkPathEffect.cpp',
         '<(skia_src_path)/core/SkPathHeap.cpp',
@@ -279,7 +278,6 @@
         '<(skia_include_path)/core/SkOSFile.h',
         '<(skia_include_path)/core/SkPackBits.h',
         '<(skia_include_path)/core/SkPaint.h',
-        '<(skia_include_path)/core/SkPatch.h',
         '<(skia_include_path)/core/SkPath.h',
         '<(skia_include_path)/core/SkPathEffect.h',
         '<(skia_include_path)/core/SkPathMeasure.h',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 011e3c3..8afeae6 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -14,7 +14,6 @@
 #include "SkClipStack.h"
 #include "SkPaint.h"
 #include "SkRefCnt.h"
-#include "SkPatch.h"
 #include "SkPath.h"
 #include "SkRegion.h"
 #include "SkXfermode.h"
@@ -1022,14 +1021,21 @@
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint);
     
-    /** 
+    /**
+     Draw a cubic coons patch
      
-     Draw a SkPatch
-     
-     @param patch specifies the 4 bounding cubic bezier curves of a patch.
+     @param cubic specifies the 4 bounding cubic bezier curves of a patch with clockwise order
+                    starting at the top left corner.
+     @param colors specifies the colors for the corners which will be bilerp across the patch,
+                    their order is clockwise starting at the top left corner.
+     @param texCoords specifies the texture coordinates that will be bilerp across the patch, 
+                    their order is the same as the colors.
+     @param xmode specifies how are the colors and the textures combined if both of them are 
+                    present.
      @param paint Specifies the shader/texture if present.
      */
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint);
+    void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                   const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
 
     /** Send a blob of data to the canvas.
         For canvases that draw, this call is effectively a no-op, as the data
@@ -1224,6 +1230,9 @@
     virtual void onDrawTextOnPath(const void* text, size_t byteLength,
                                   const SkPath& path, const SkMatrix* matrix,
                                   const SkPaint& paint);
+    
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                           const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
 
     enum ClipEdgeStyle {
         kHard_ClipEdgeStyle,
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 3d79a65..de2f8dd 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -243,7 +243,8 @@
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint) = 0;
     // default implementation calls drawVertices
-    virtual void drawPatch(const SkDraw&, const SkPatch& patch, const SkPaint& paint);
+    virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
+                           const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint);
     /** The SkDevice passed will be an SkDevice which was returned by a call to
         onCreateDevice on this device with kSaveLayer_Usage.
      */
diff --git a/include/core/SkPatch.h b/include/core/SkPatch.h
deleted file mode 100644
index 698b1cb..0000000
--- a/include/core/SkPatch.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkPatch_DEFINED
-#define SkPatch_DEFINED
-
-#include "SkColor.h"
-#include "SkPreConfig.h"
-#include "SkPoint.h"
-
-/**
- * Class that represents a coons patch.
- */
-class SK_API SkPatch {
-
-public:
-    /**
-     * Structure that holds the vertex data related to the tessellation of a SkPatch. It is passed 
-     * as a parameter to the function getVertexData which sets the points, colors and texture 
-     * coordinates of the vertices and the indices for them to be drawn as triangles.
-     */
-    struct VertexData {
-        int fVertexCount, fIndexCount;
-        SkPoint* fPoints;
-        SkPoint* fTexCoords;
-        uint32_t* fColors;
-        uint16_t* fIndices;
-        
-        VertexData()
-        : fVertexCount(0)
-        , fIndexCount(0)
-        , fPoints(NULL)
-        , fTexCoords(NULL)
-        , fColors(NULL)
-        , fIndices(NULL) { }
-        
-        ~VertexData() {
-            SkDELETE_ARRAY(fPoints);
-            SkDELETE_ARRAY(fTexCoords);
-            SkDELETE_ARRAY(fColors);
-            SkDELETE_ARRAY(fIndices);
-        }
-    };
-    
-    // Enums for control points based on the order specified in the constructor (clockwise).
-    enum CubicCtrlPts {
-        kTopP0_CubicCtrlPts = 0,
-        kTopP1_CubicCtrlPts = 1,
-        kTopP2_CubicCtrlPts = 2,
-        kTopP3_CubicCtrlPts = 3,
-        
-        kRightP0_CubicCtrlPts = 3,
-        kRightP1_CubicCtrlPts = 4,
-        kRightP2_CubicCtrlPts = 5,
-        kRightP3_CubicCtrlPts = 6,
-        
-        kBottomP0_CubicCtrlPts = 9,
-        kBottomP1_CubicCtrlPts = 8,
-        kBottomP2_CubicCtrlPts = 7,
-        kBottomP3_CubicCtrlPts = 6,
-        
-        kLeftP0_CubicCtrlPts = 0,
-        kLeftP1_CubicCtrlPts = 11,
-        kLeftP2_CubicCtrlPts = 10,
-        kLeftP3_CubicCtrlPts = 9,
-    };
-    
-    // Enum for corner colors also clockwise.
-    enum CornerColors {
-        kTopLeft_CornerColors = 0,
-        kTopRight_CornerColors,
-        kBottomRight_CornerColors,
-        kBottomLeft_CornerColors
-    };
-    
-    enum {
-        kNumCtrlPts = 12,
-        kNumColors = 4,
-        kNumPtsCubic = 4
-    };
-    
-    /**
-     * Points are in the following order:
-     *              (top curve)
-     *                0 1 2 3
-     * (left curve)  11     4   (right curve)
-     *               10     5
-     *                9 8 7 6
-     *              (bottom curve)
-     */
-    SkPatch() { }
-    SkPatch(const SkPoint points[12], const SkColor colors[4]);
-
-    /**
-     * Function that evaluates the coons patch interpolation.
-     * data refers to the pointer of the PatchData struct in which the tessellation data is set.
-     * lod refers the level of detail for each axis.
-     */
-    bool getVertexData(SkPatch::VertexData* data, int lodX, int lodY) const;
-
-    void getTopPoints(SkPoint points[4]) const {
-        points[0] = fCtrlPoints[kTopP0_CubicCtrlPts];
-        points[1] = fCtrlPoints[kTopP1_CubicCtrlPts];
-        points[2] = fCtrlPoints[kTopP2_CubicCtrlPts];
-        points[3] = fCtrlPoints[kTopP3_CubicCtrlPts];
-    }
-    
-    void getBottomPoints(SkPoint points[4]) const {
-        points[0] = fCtrlPoints[kBottomP0_CubicCtrlPts];
-        points[1] = fCtrlPoints[kBottomP1_CubicCtrlPts];
-        points[2] = fCtrlPoints[kBottomP2_CubicCtrlPts];
-        points[3] = fCtrlPoints[kBottomP3_CubicCtrlPts];
-    }
-
-    void getLeftPoints(SkPoint points[4]) const {
-        points[0] = fCtrlPoints[kLeftP0_CubicCtrlPts];
-        points[1] = fCtrlPoints[kLeftP1_CubicCtrlPts];
-        points[2] = fCtrlPoints[kLeftP2_CubicCtrlPts];
-        points[3] = fCtrlPoints[kLeftP3_CubicCtrlPts];
-    }
-
-    void getRightPoints(SkPoint points[4]) const {
-        points[0] = fCtrlPoints[kRightP0_CubicCtrlPts];
-        points[1] = fCtrlPoints[kRightP1_CubicCtrlPts];
-        points[2] = fCtrlPoints[kRightP2_CubicCtrlPts];
-        points[3] = fCtrlPoints[kRightP3_CubicCtrlPts];
-    }
-    
-    void getCornerPoints(SkPoint points[4]) const {
-        points[0] = fCtrlPoints[kTopP0_CubicCtrlPts];
-        points[1] = fCtrlPoints[kTopP3_CubicCtrlPts];
-        points[2] = fCtrlPoints[kBottomP3_CubicCtrlPts];
-        points[3] = fCtrlPoints[kBottomP0_CubicCtrlPts];
-    }
-    
-    const SkPoint* getControlPoints() const {
-        return fCtrlPoints;
-    }
-    
-    const SkColor* getColors() const {
-        return fCornerColors;
-    }
-    
-    void setPoints(const SkPoint points[12]) {
-        memcpy(fCtrlPoints, points, kNumCtrlPts * sizeof(SkPoint));
-    }
-    
-    void setColors(const SkColor colors[4]) {
-        memcpy(fCornerColors, colors, kNumColors * sizeof(SkColor));
-    }
-
-    void reset(const SkPoint points[12], const SkColor colors[4]) {
-        this->setPoints(points);
-        this->setColors(colors);
-    }
-
-    /**
-     *  Write the patch to the buffer, and return the number of bytes written.
-     *  If buffer is NULL, it still returns the number of bytes.
-     */
-    size_t writeToMemory(void* buffer) const;
-    
-    /**
-     * Initializes the patch from the buffer
-     *
-     * buffer Memory to read from
-     * length Amount of memory available in the buffer
-     * returns the number of bytes read (must be a multiple of 4) or
-     *         0 if there was not enough memory available
-     */
-    size_t readFromMemory(const void* buffer, size_t length);
-    
-private:
-    SkPoint fCtrlPoints[kNumCtrlPts];
-    SkColor fCornerColors[kNumColors];
-};
-
-#endif
diff --git a/include/core/SkReadBuffer.h b/include/core/SkReadBuffer.h
index e4f33af..2f04614 100644
--- a/include/core/SkReadBuffer.h
+++ b/include/core/SkReadBuffer.h
@@ -108,7 +108,7 @@
     virtual void readIRect(SkIRect* rect);
     virtual void readRect(SkRect* rect);
     virtual void readRegion(SkRegion* region);
-    virtual void readPatch(SkPatch* patch);
+    
     virtual void readPath(SkPath* path);
     void readPaint(SkPaint* paint) { paint->unflatten(*this); }
 
diff --git a/include/core/SkReader32.h b/include/core/SkReader32.h
index 3ee63be..3d874d1 100644
--- a/include/core/SkReader32.h
+++ b/include/core/SkReader32.h
@@ -15,7 +15,6 @@
 #include "SkRegion.h"
 #include "SkRRect.h"
 #include "SkScalar.h"
-#include "SkPatch.h"
 
 class SkString;
 
@@ -106,10 +105,6 @@
     uint16_t readU16() { return (uint16_t)this->readInt(); }
     int32_t readS32() { return this->readInt(); }
     uint32_t readU32() { return this->readInt(); }
-    
-    bool readPatch(SkPatch* patch) {
-        return this->readObjectFromMemory(patch);
-    }
 
     bool readPath(SkPath* path) {
         return this->readObjectFromMemory(path);
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index 737ffd5..fd24ba9 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -12,7 +12,6 @@
 
 #include "SkData.h"
 #include "SkMatrix.h"
-#include "SkPatch.h"
 #include "SkPath.h"
 #include "SkPoint.h"
 #include "SkRRect.h"
@@ -138,12 +137,6 @@
     void writeRRect(const SkRRect& rrect) {
         rrect.writeToMemory(this->reserve(SkRRect::kSizeInMemory));
     }
-    
-    void writePatch(const SkPatch& patch) {
-        size_t size = patch.writeToMemory(NULL);
-        SkASSERT(SkAlign4(size) == size);
-        patch.writeToMemory(this->reserve(size));
-    }
 
     void writePath(const SkPath& path) {
         size_t size = path.writeToMemory(NULL);
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
index 435c569..89cb145 100644
--- a/include/utils/SkDeferredCanvas.h
+++ b/include/utils/SkDeferredCanvas.h
@@ -168,7 +168,6 @@
                               const SkColor colors[], SkXfermode* xmode,
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint) SK_OVERRIDE;
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
     virtual SkDrawFilter* setDrawFilter(SkDrawFilter* filter) SK_OVERRIDE;
 
 protected:
@@ -188,7 +187,10 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
-
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) SK_OVERRIDE;
+    
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
diff --git a/include/utils/SkDumpCanvas.h b/include/utils/SkDumpCanvas.h
index 866b408..043cdaa 100644
--- a/include/utils/SkDumpCanvas.h
+++ b/include/utils/SkDumpCanvas.h
@@ -96,7 +96,6 @@
                               const SkColor colors[], SkXfermode* xmode,
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint) SK_OVERRIDE;
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
     virtual void drawData(const void*, size_t) SK_OVERRIDE;
     virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
     virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
@@ -119,6 +118,9 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) SK_OVERRIDE;
     virtual void onPushCull(const SkRect& cullRect) SK_OVERRIDE;
     virtual void onPopCull() SK_OVERRIDE;
 
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index 8d2854d..5c48a83 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -48,7 +48,6 @@
                               const SkColor colors[], SkXfermode* xmode,
                               const uint16_t indices[], int indexCount,
                               const SkPaint&) SK_OVERRIDE;
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
     virtual void drawData(const void* data, size_t length) SK_OVERRIDE;
 
     virtual SkDrawFilter* setDrawFilter(SkDrawFilter*) SK_OVERRIDE;
@@ -76,7 +75,10 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
-
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) SK_OVERRIDE;
+    
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
diff --git a/include/utils/SkProxyCanvas.h b/include/utils/SkProxyCanvas.h
index b340141..b5018e0 100644
--- a/include/utils/SkProxyCanvas.h
+++ b/include/utils/SkProxyCanvas.h
@@ -47,7 +47,6 @@
                               const SkColor colors[], SkXfermode* xmode,
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint) SK_OVERRIDE;
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
     virtual void drawData(const void* data, size_t length) SK_OVERRIDE;
 
     virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
@@ -73,7 +72,10 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
-
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) SK_OVERRIDE;
+    
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
diff --git a/src/core/SkBBoxRecord.cpp b/src/core/SkBBoxRecord.cpp
index 96e6500..69139ad 100644
--- a/src/core/SkBBoxRecord.cpp
+++ b/src/core/SkBBoxRecord.cpp
@@ -7,6 +7,7 @@
  */
 
 #include "SkBBoxRecord.h"
+#include "SkPatchUtils.h"
 
 SkBBoxRecord::~SkBBoxRecord() {
     fSaveStack.deleteAll();
@@ -284,12 +285,13 @@
     }
 }
 
-void SkBBoxRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
-    const SkPoint* points = patch.getControlPoints();
+void SkBBoxRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                               const SkPoint texCoords[4], SkXfermode* xmode,
+                               const SkPaint& paint) {
     SkRect bbox;
-    bbox.set(points, SkPatch::kNumCtrlPts);
+    bbox.set(cubics, SkPatchUtils::kNumCtrlPts);
     if (this->transformBounds(bbox, &paint)) {
-        INHERITED::drawPatch(patch, paint);
+        INHERITED::onDrawPatch(cubics, colors, texCoords, xmode, paint);
     }
 }
 
diff --git a/src/core/SkBBoxRecord.h b/src/core/SkBBoxRecord.h
index eafd9d4..1d19b70 100644
--- a/src/core/SkBBoxRecord.h
+++ b/src/core/SkBBoxRecord.h
@@ -55,7 +55,6 @@
                               const SkColor colors[], SkXfermode* xfer,
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint) SK_OVERRIDE;
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
 
 protected:
     virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) SK_OVERRIDE;
@@ -67,6 +66,9 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) SK_OVERRIDE;
     virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
     virtual void willSave() SK_OVERRIDE;
     virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index c6b5739..240dc9c 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -15,6 +15,7 @@
 #include "SkDrawLooper.h"
 #include "SkMetaData.h"
 #include "SkPathOps.h"
+#include "SkPatchUtils.h"
 #include "SkPicture.h"
 #include "SkRasterClip.h"
 #include "SkRRect.h"
@@ -2254,20 +2255,30 @@
     LOOPER_END
 }
 
-void SkCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkCanvas::drawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                         const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+    if (NULL == cubics) {
+        return;
+    }
     
     // Since a patch is always within the convex hull of the control points, we discard it when its
     // bounding rectangle is completely outside the current clip.
     SkRect bounds;
-    bounds.set(patch.getControlPoints(), SkPatch::kNumCtrlPts);
+    bounds.set(cubics, SkPatchUtils::kNumCtrlPts);
     if (this->quickReject(bounds)) {
         return;
     }
     
+    this->onDrawPatch(cubics, colors, texCoords, xmode, paint);
+}
+
+void SkCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                           const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+
     LOOPER_BEGIN(paint, SkDrawFilter::kPath_Type, NULL)
     
     while (iter.next()) {
-        iter.fDevice->drawPatch(iter, patch, paint);
+        iter.fDevice->drawPatch(iter, cubics, colors, texCoords, xmode, paint);
     }
     
     LOOPER_END
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 6ceaffe..50755c9 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -79,15 +79,17 @@
     this->drawPath(draw, path, paint, preMatrix, pathIsMutable);
 }
 
-void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPatch& patch, const SkPaint& paint) {
-    SkPatch::VertexData data;
+void SkBaseDevice::drawPatch(const SkDraw& draw, const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+    SkPatchUtils::VertexData data;
     
-    SkISize lod = SkPatchUtils::GetLevelOfDetail(patch, draw.fMatrix);
+    SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, draw.fMatrix);
 
     // It automatically adjusts lodX and lodY in case it exceeds the number of indices.
-    patch.getVertexData(&data, lod.width(), lod.height());
+    SkPatchUtils::getVertexData(&data, cubics, colors, texCoords, lod.width(), lod.height());
     this->drawVertices(draw, SkCanvas::kTriangles_VertexMode, data.fVertexCount, data.fPoints,
-                       data.fTexCoords, data.fColors, NULL, data.fIndices, data.fIndexCount, paint);
+                       data.fTexCoords, data.fColors, xmode, data.fIndices, data.fIndexCount,
+                       paint);
 }
 
 bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) {
diff --git a/src/core/SkPatch.cpp b/src/core/SkPatch.cpp
deleted file mode 100644
index 4cca2ba..0000000
--- a/src/core/SkPatch.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkPatch.h"
-
-#include "SkGeometry.h"
-#include "SkColorPriv.h"
-#include "SkBuffer.h"
-
-////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Evaluator to sample the values of a cubic bezier using forward differences.
- * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only
- * adding precalculated values.
- * For a linear example we have the function f(t) = m*t+b, then the value of that function at t+h
- * would be f(t+h) = m*(t+h)+b. If we want to know the uniform step that we must add to the first
- * evaluation f(t) then we need to substract f(t+h) - f(t) = m*t + m*h + b - m*t + b = mh. After
- * obtaining this value (mh) we could just add this constant step to our first sampled point
- * to compute the next one.
- *
- * For the cubic case the first difference gives as a result a quadratic polynomial to which we can
- * apply again forward differences and get linear function to which we can apply again forward
- * differences to get a constant difference. This is why we keep an array of size 4, the 0th
- * position keeps the sampled value while the next ones keep the quadratic, linear and constant
- * difference values.
- */
-
-class FwDCubicEvaluator {
-    
-public:
-    FwDCubicEvaluator() { }
-    
-    /**
-     * Receives the 4 control points of the cubic bezier.
-     */
-    FwDCubicEvaluator(SkPoint a, SkPoint b, SkPoint c, SkPoint d) {
-        fPoints[0] = a;
-        fPoints[1] = b;
-        fPoints[2] = c;
-        fPoints[3] = d;
-        
-        SkScalar cx[4], cy[4];
-        SkGetCubicCoeff(fPoints, cx, cy);
-        fCoefs[0].set(cx[0], cy[0]);
-        fCoefs[1].set(cx[1], cy[1]);
-        fCoefs[2].set(cx[2], cy[2]);
-        fCoefs[3].set(cx[3], cy[3]);
-        
-        this->restart(1);
-    }
-    
-    explicit FwDCubicEvaluator(SkPoint points[4]) {
-        for (int i = 0; i< 4; i++) {
-            fPoints[i] = points[i];
-        }
-        
-        SkScalar cx[4], cy[4];
-        SkGetCubicCoeff(fPoints, cx, cy);
-        fCoefs[0].set(cx[0], cy[0]);
-        fCoefs[1].set(cx[1], cy[1]);
-        fCoefs[2].set(cx[2], cy[2]);
-        fCoefs[3].set(cx[3], cy[3]);
-        
-        this->restart(1);
-    }
-    
-    /**
-     * Restarts the forward differences evaluator to the first value of t = 0.
-     */
-    void restart(int divisions) {
-        fDivisions = divisions;
-        SkScalar h  = 1.f / fDivisions;
-        fCurrent    = 0;
-        fMax        = fDivisions + 1;
-        fFwDiff[0]  = fCoefs[3];
-        SkScalar h2 = h * h;
-        SkScalar h3 = h2 * h;
-        
-        fFwDiff[3].set(6.f * fCoefs[0].x() * h3, 6.f * fCoefs[0].y() * h3); //6ah^3
-        fFwDiff[2].set(fFwDiff[3].x() + 2.f * fCoefs[1].x() * h2, //6ah^3 + 2bh^2
-                       fFwDiff[3].y() + 2.f * fCoefs[1].y() * h2);
-        fFwDiff[1].set(fCoefs[0].x() * h3 + fCoefs[1].x() * h2 + fCoefs[2].x() * h,//ah^3 + bh^2 +ch
-                       fCoefs[0].y() * h3 + fCoefs[1].y() * h2 + fCoefs[2].y() * h);
-    }
-    
-    /**
-     * Check if the evaluator is still within the range of 0<=t<=1
-     */
-    bool done() const {
-        return fCurrent > fMax;
-    }
-    
-    /**
-     * Call next to obtain the SkPoint sampled and move to the next one.
-     */
-    SkPoint next() {
-        SkPoint point = fFwDiff[0];
-        fFwDiff[0]    += fFwDiff[1];
-        fFwDiff[1]    += fFwDiff[2];
-        fFwDiff[2]    += fFwDiff[3];
-        fCurrent++;
-        return point;
-    }
-    
-    const SkPoint* getCtrlPoints() const {
-        return fPoints;
-    }
-    
-private:
-    int fMax, fCurrent, fDivisions;
-    SkPoint fFwDiff[4], fCoefs[4], fPoints[4];
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-SkPatch::SkPatch(const SkPoint points[12], const SkColor colors[4]) {
-    this->reset(points, colors);
-}
-
-static uint8_t bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01,
-                      SkScalar c11) {
-    SkScalar a = c00 * (1.f - tx) + c10 * tx;
-    SkScalar b = c01 * (1.f - tx) + c11 * tx;
-    return uint8_t(a * (1.f - ty) + b * ty);
-}
-
-bool SkPatch::getVertexData(SkPatch::VertexData* data, int lodX, int lodY) const {
-    
-    if (lodX < 1 || lodY < 1) {
-        return false;
-    }
-    
-    // premultiply colors to avoid color bleeding. 
-    SkPMColor colors[SkPatch::kNumColors];
-    for (int i = 0; i < SkPatch::kNumColors; i++) {
-        colors[i] = SkPreMultiplyColor(fCornerColors[i]);
-    }
-    
-    // number of indices is limited by size of uint16_t, so we clamp it to avoid overflow
-    data->fVertexCount = SkMin32((lodX + 1) * (lodY + 1), 65536);
-    lodX  = SkMin32(lodX, 255);
-    lodY  = SkMin32(lodY, 255);
-    data->fIndexCount = lodX * lodY * 6;
-
-    data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount);
-    data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount);
-    data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
-    data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
-    
-    SkPoint pts[SkPatch::kNumPtsCubic];
-    this->getBottomPoints(pts);
-    FwDCubicEvaluator fBottom(pts);
-    this->getTopPoints(pts);
-    FwDCubicEvaluator fTop(pts);
-    this->getLeftPoints(pts);
-    FwDCubicEvaluator fLeft(pts);
-    this->getRightPoints(pts);
-    FwDCubicEvaluator fRight(pts);
-
-    fBottom.restart(lodX);
-    fTop.restart(lodX);
-
-    SkScalar u = 0.0f;
-    int stride = lodY + 1;
-    for (int x = 0; x <= lodX; x++) {
-        SkPoint bottom = fBottom.next(), top = fTop.next();
-        fLeft.restart(lodY);
-        fRight.restart(lodY);
-        SkScalar v = 0.f;
-        for (int y = 0; y <= lodY; y++) {
-            int dataIndex = x * (lodY + 1) + y;
-
-            SkPoint left = fLeft.next(), right = fRight.next();
-
-            SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
-                                       (1.0f - v) * top.y() + v * bottom.y());
-            SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
-                                       (1.0f - u) * left.y() + u * right.y());
-            SkPoint s2 = SkPoint::Make(
-                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
-                                        + u * fTop.getCtrlPoints()[3].x())
-                                        + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
-                                        + u * fBottom.getCtrlPoints()[3].x()),
-                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
-                                        + u * fTop.getCtrlPoints()[3].y())
-                                        + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
-                                        + u * fBottom.getCtrlPoints()[3].y()));
-            data->fPoints[dataIndex] = s0 + s1 - s2;
-
-            uint8_t a = bilerp(u, v,
-                            SkScalar(SkColorGetA(colors[kTopLeft_CornerColors])),
-                            SkScalar(SkColorGetA(colors[kTopRight_CornerColors])),
-                            SkScalar(SkColorGetA(colors[kBottomLeft_CornerColors])),
-                            SkScalar(SkColorGetA(colors[kBottomRight_CornerColors])));
-            uint8_t r = bilerp(u, v,
-                            SkScalar(SkColorGetR(colors[kTopLeft_CornerColors])),
-                            SkScalar(SkColorGetR(colors[kTopRight_CornerColors])),
-                            SkScalar(SkColorGetR(colors[kBottomLeft_CornerColors])),
-                            SkScalar(SkColorGetR(colors[kBottomRight_CornerColors])));
-            uint8_t g = bilerp(u, v,
-                            SkScalar(SkColorGetG(colors[kTopLeft_CornerColors])),
-                            SkScalar(SkColorGetG(colors[kTopRight_CornerColors])),
-                            SkScalar(SkColorGetG(colors[kBottomLeft_CornerColors])),
-                            SkScalar(SkColorGetG(colors[kBottomRight_CornerColors])));
-            uint8_t b = bilerp(u, v, 
-                            SkScalar(SkColorGetB(colors[kTopLeft_CornerColors])),
-                            SkScalar(SkColorGetB(colors[kTopRight_CornerColors])),
-                            SkScalar(SkColorGetB(colors[kBottomLeft_CornerColors])),
-                            SkScalar(SkColorGetB(colors[kBottomRight_CornerColors])));
-            data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
-            
-            data->fTexCoords[dataIndex] = SkPoint::Make(u, v);
-
-            if(x < lodX && y < lodY) {
-                int i = 6 * (x * lodY + y);
-                data->fIndices[i] = x * stride + y;
-                data->fIndices[i + 1] = x * stride + 1 + y;
-                data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
-                data->fIndices[i + 3] = data->fIndices[i];
-                data->fIndices[i + 4] = data->fIndices[i + 2];
-                data->fIndices[i + 5] = (x + 1) * stride + y;
-            }
-            v = SkScalarClampMax(v + 1.f / lodY, 1);
-        }
-        u = SkScalarClampMax(u + 1.f / lodX, 1);
-    }
-    return true;
-}
-
-size_t SkPatch::writeToMemory(void* storage) const {
-    int byteCount =  kNumCtrlPts * sizeof(SkPoint) + kNumColors * sizeof(SkColor);
-    
-    if (NULL == storage) {
-        return SkAlign4(byteCount);
-    }
-    
-    SkWBuffer buffer(storage);
-    
-    buffer.write(fCtrlPoints, kNumCtrlPts * sizeof(SkPoint));
-    buffer.write(fCornerColors, kNumColors * sizeof(SkColor));
-    
-    buffer.padToAlign4();
-    return buffer.pos();
-}
-
-size_t SkPatch::readFromMemory(const void* storage, size_t length) {
-    SkRBufferWithSizeCheck buffer(storage, length);
-    
-    if (!buffer.read(fCtrlPoints, kNumCtrlPts * sizeof(SkPoint))) {
-        return 0;
-    }
-    
-    if (!buffer.read(fCornerColors, kNumColors * sizeof(SkColor))) {
-        return 0;
-    }
-    return kNumCtrlPts * sizeof(SkPoint) + kNumColors * sizeof(SkColor);
-}
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index fd359fe..7f3f9d7 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkCanvas.h"
+#include "SkPatchUtils.h"
 #include "SkPictureData.h"
 #include "SkPicturePlayback.h"
 #include "SkPictureRecord.h"
@@ -308,9 +309,28 @@
             break;
         case DRAW_PATCH: {
             const SkPaint& paint = *fPictureData->getPaint(reader);
-            SkPatch patch;
-            reader->readPatch(&patch);
-            canvas->drawPatch(patch, paint);
+            
+            const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts *
+                                                                 sizeof(SkPoint));
+            uint32_t flag = reader->readInt();
+            const SkColor* colors = NULL;
+            if (flag & DRAW_VERTICES_HAS_COLORS) {
+                colors = (const SkColor*)reader->skip(SkPatchUtils::kNumCorners * sizeof(SkColor));
+            }
+            const SkPoint* texCoords = NULL;
+            if (flag & DRAW_VERTICES_HAS_TEXS) {
+                texCoords = (const SkPoint*)reader->skip(SkPatchUtils::kNumCorners *
+                                                         sizeof(SkPoint));
+            }
+            SkAutoTUnref<SkXfermode> xfer;
+            if (flag & DRAW_VERTICES_HAS_XFER) {
+                int mode = reader->readInt();
+                if (mode < 0 || mode > SkXfermode::kLastMode) {
+                    mode = SkXfermode::kModulate_Mode;
+                }
+                xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
+            }
+            canvas->drawPatch(cubics, colors, texCoords, xfer, paint);
         } break;
         case DRAW_PATH: {
             const SkPaint& paint = *fPictureData->getPaint(reader);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index fc0b291..7fc48e3 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -6,12 +6,13 @@
  */
 
 #include "SkPictureRecord.h"
-#include "SkTSearch.h"
-#include "SkPixelRef.h"
-#include "SkRRect.h"
 #include "SkBBoxHierarchy.h"
 #include "SkDevice.h"
+#include "SkPatchUtils.h"
 #include "SkPictureStateTree.h"
+#include "SkPixelRef.h"
+#include "SkRRect.h"
+#include "SkTSearch.h"
 
 #define HEAP_BLOCK_SIZE 4096
 
@@ -1283,14 +1284,46 @@
     this->validate(initialOffset, size);
 }
 
-void SkPictureRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
-    // op + paint index + patch 12 control points + patch 4 colors
-    size_t size = 2 * kUInt32Size + SkPatch::kNumCtrlPts * sizeof(SkPoint) +
-                    SkPatch::kNumColors * sizeof(SkColor);
+void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                                  const SkPoint texCoords[4], SkXfermode* xmode,
+                                  const SkPaint& paint) {
+    // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
+    size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
+    uint32_t flag = 0;
+    if (NULL != colors) {
+        flag |= DRAW_VERTICES_HAS_COLORS;
+        size += SkPatchUtils::kNumCorners * sizeof(SkColor);
+    }
+    if (NULL != texCoords) {
+        flag |= DRAW_VERTICES_HAS_TEXS;
+        size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
+    }
+    if (NULL != xmode) {
+        SkXfermode::Mode mode;
+        if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
+            flag |= DRAW_VERTICES_HAS_XFER;
+            size += kUInt32Size;
+        }
+    }
+    
     size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
     SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
     this->addPaint(paint);
-    this->addPatch(patch);
+    this->addPatch(cubics);
+    this->addInt(flag);
+    
+    // write optional parameters
+    if (NULL != colors) {
+        fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
+    }
+    if (NULL != texCoords) {
+        fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
+    }
+    if (flag & DRAW_VERTICES_HAS_XFER) {
+        SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
+        xmode->asMode(&mode);
+        this->addInt(mode);
+    }
     this->validate(initialOffset, size);
 }
 
@@ -1420,8 +1453,8 @@
     this->addInt(this->addPathToHeap(path));
 }
 
-void SkPictureRecord::addPatch(const SkPatch& patch) {
-    fWriter.writePatch(patch);
+void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
+    fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
 }
 
 void SkPictureRecord::addPicture(const SkPicture* picture) {
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index d0c099e..8fd40bc 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -58,7 +58,6 @@
                           const SkColor colors[], SkXfermode*,
                           const uint16_t indices[], int indexCount,
                               const SkPaint&) SK_OVERRIDE;
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
     virtual void drawData(const void*, size_t) SK_OVERRIDE;
     virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
     virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
@@ -170,7 +169,7 @@
     const SkFlatData* addPaint(const SkPaint& paint) { return this->addPaintPtr(&paint); }
     const SkFlatData* addPaintPtr(const SkPaint* paint);
     void addFlatPaint(const SkFlatData* flatPaint);
-    void addPatch(const SkPatch& patch);
+    void addPatch(const SkPoint cubics[12]);
     void addPath(const SkPath& path);
     void addPicture(const SkPicture* picture);
     void addPoint(const SkPoint& point);
@@ -214,6 +213,10 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
+    
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) SK_OVERRIDE;
 
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index 27f2d2b..4358786 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -148,10 +148,6 @@
     fReader.readRegion(region);
 }
 
-void SkReadBuffer::readPatch(SkPatch* patch) {
-    fReader.readPatch(patch);
-}
-
 void SkReadBuffer::readPath(SkPath* path) {
     fReader.readPath(path);
 }
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 0e2a470..8be9e00 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -84,7 +84,7 @@
 DRAW(DrawOval, drawOval(r.oval, r.paint));
 DRAW(DrawPaint, drawPaint(r.paint));
 DRAW(DrawPath, drawPath(r.path, r.paint));
-DRAW(DrawPatch, drawPatch(r.patch, r.paint));
+DRAW(DrawPatch, drawPatch(r.cubics, r.colors, r.texCoords, r.xmode.get(), r.paint));
 DRAW(DrawPicture, drawPicture(r.picture, r.matrix, r.paint));
 DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
 DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 6b3eac9..327a97a 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkRecorder.h"
+#include "SkPatchUtils.h"
 #include "SkPicture.h"
 
 // SkCanvas will fail in mysterious ways if it doesn't know the real width and height.
@@ -206,8 +207,13 @@
                          indexCount);
 }
 
-void SkRecorder::drawPatch(const SkPatch& patch, const SkPaint& paint) {
-    APPEND(DrawPatch, delay_copy(paint), delay_copy(patch));
+void SkRecorder::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) {
+    APPEND(DrawPatch, delay_copy(paint),
+           cubics ? this->copy(cubics, SkPatchUtils::kNumCtrlPts) : NULL,
+           colors ? this->copy(colors, SkPatchUtils::kNumCorners) : NULL,
+           texCoords ? this->copy(texCoords, SkPatchUtils::kNumCorners) : NULL,
+           xmode);
 }
 
 void SkRecorder::willSave() {
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index be89248..2c7234a 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -61,7 +61,6 @@
                       const uint16_t indices[],
                       int indexCount,
                       const SkPaint& paint) SK_OVERRIDE;
-    void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
 
     void willSave() SK_OVERRIDE;
     SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SkCanvas::SaveFlags) SK_OVERRIDE;
@@ -90,6 +89,10 @@
                           const SkPath& path,
                           const SkMatrix* matrix,
                           const SkPaint& paint) SK_OVERRIDE;
+    void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                     const SkPoint texCoords[4], SkXfermode* xmode,
+                     const SkPaint& paint) SK_OVERRIDE;
+    
     void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) SK_OVERRIDE;
     void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) SK_OVERRIDE;
     void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) SK_OVERRIDE;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 6aefd19..1efdf28 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -232,7 +232,7 @@
 RECORD2(DrawOval, SkPaint, paint, SkRect, oval);
 RECORD1(DrawPaint, SkPaint, paint);
 RECORD2(DrawPath, SkPaint, paint, SkPath, path);
-RECORD2(DrawPatch, SkPaint, paint, SkPatch, patch);
+//RECORD2(DrawPatch, SkPaint, paint, SkPatch, patch);
 RECORD3(DrawPicture, Optional<SkPaint>, paint, SkPictureBox, picture, Optional<SkMatrix>, matrix);
 RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, size_t, count, SkPoint*, pts);
 RECORD4(DrawPosText, SkPaint, paint,
@@ -291,6 +291,24 @@
     PODArray<uint16_t> indices;
     int indexCount;
 };
+    
+struct DrawPatch {
+    static const Type kType = DrawPatch_Type;
+    
+    DrawPatch(const SkPaint& paint, SkPoint cubics[12], SkColor colors[4],
+              SkPoint texCoords[4], SkXfermode* xmode)
+    : paint(paint)
+    , cubics(cubics)
+    , colors(colors)
+    , texCoords(texCoords)
+    , xmode(SkSafeRef(xmode)) { }
+    
+    SkPaint paint;
+    PODArray<SkPoint> cubics;
+    PODArray<SkColor> colors;
+    PODArray<SkPoint> texCoords;
+    SkAutoTUnref<SkXfermode> xmode;
+};
 
 #undef RECORD0
 #undef RECORD1
diff --git a/src/core/SkValidatingReadBuffer.cpp b/src/core/SkValidatingReadBuffer.cpp
index 8202149..037a994 100644
--- a/src/core/SkValidatingReadBuffer.cpp
+++ b/src/core/SkValidatingReadBuffer.cpp
@@ -171,17 +171,6 @@
     }
 }
 
-void SkValidatingReadBuffer::readPatch(SkPatch* patch) {
-    size_t size = 0;
-    if (!fError) {
-        size = patch->readFromMemory(fReader.peek(), fReader.available());
-        this->validate((SkAlign4(size) == size) && (0 != size));
-    }
-    if (!fError) {
-        (void)this->skip(size);
-    }
-}
-
 bool SkValidatingReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
     const uint32_t count = this->getArrayCount();
     this->validate(size == count);
diff --git a/src/core/SkValidatingReadBuffer.h b/src/core/SkValidatingReadBuffer.h
index 8850a07..5cf3abe 100644
--- a/src/core/SkValidatingReadBuffer.h
+++ b/src/core/SkValidatingReadBuffer.h
@@ -46,7 +46,6 @@
     virtual void readIRect(SkIRect* rect) SK_OVERRIDE;
     virtual void readRect(SkRect* rect) SK_OVERRIDE;
     virtual void readRegion(SkRegion* region) SK_OVERRIDE;
-    virtual void readPatch(SkPatch* patch) SK_OVERRIDE;
     virtual void readPath(SkPath* path) SK_OVERRIDE;
 
     // binary data and arrays
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 35b0a94..35de638 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -21,6 +21,7 @@
 #include "SkImageFilter.h"
 #include "SkMaskFilter.h"
 #include "SkReadBuffer.h"
+#include "SkPatchUtils.h"
 #include "SkPathEffect.h"
 #include "SkRasterizer.h"
 #include "SkRRect.h"
@@ -406,10 +407,29 @@
 
 static void drawPatch_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
-    SkPatch patch;
-    reader->readPatch(&patch);
+    
+    unsigned flags = DrawOp_unpackFlags(op32);
+    
+    const SkPoint* cubics = skip<SkPoint>(reader, SkPatchUtils::kNumCtrlPts);
+    
+    const SkColor* colors = NULL;
+    if (flags & kDrawVertices_HasColors_DrawOpFlag) {
+        colors = skip<SkColor>(reader, SkPatchUtils::kNumCorners);
+    }
+    const SkPoint* texCoords = NULL;
+    if (flags & kDrawVertices_HasTexs_DrawOpFlag) {
+        texCoords = skip<SkPoint>(reader, SkPatchUtils::kNumCorners);
+    }
+    SkAutoTUnref<SkXfermode> xfer;
+    if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
+        int mode = reader->readInt();
+        if (mode < 0 || mode > SkXfermode::kLastMode) {
+            mode = SkXfermode::kModulate_Mode;
+        }
+        xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
+    }
     if (state->shouldDraw()) {
-        canvas->drawPatch(patch, state->paint());
+        canvas->drawPatch(cubics, colors, texCoords, xfer, state->paint());
     }
 }
 
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index d796e8a..94a30a3 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -19,6 +19,7 @@
 #include "SkMaskFilter.h"
 #include "SkWriteBuffer.h"
 #include "SkPaint.h"
+#include "SkPatchUtils.h"
 #include "SkPathEffect.h"
 #include "SkPictureFlat.h"
 #include "SkRasterizer.h"
@@ -254,7 +255,6 @@
                           const SkColor colors[], SkXfermode*,
                           const uint16_t indices[], int indexCount,
                               const SkPaint&) SK_OVERRIDE;
-    virtual void drawPatch(const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE;
     virtual void drawData(const void*, size_t) SK_OVERRIDE;
     virtual void beginCommentGroup(const char* description) SK_OVERRIDE;
     virtual void addComment(const char* kywd, const char* value) SK_OVERRIDE;
@@ -283,7 +283,9 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
-
+    virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                             const SkPoint texCoords[4], SkXfermode* xmode,
+                             const SkPaint& paint) SK_OVERRIDE;
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
@@ -1003,12 +1005,48 @@
     }
 }
 
-void SkGPipeCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkGPipeCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                                const SkPoint texCoords[4], SkXfermode* xmode,
+                                const SkPaint& paint) {
     NOTIFY_SETUP(this);
+    
+    size_t size = SkPatchUtils::kNumCtrlPts * sizeof(SkPoint);
+    unsigned flags = 0;
+    if (NULL != colors) {
+        flags |= kDrawVertices_HasColors_DrawOpFlag;
+        size += SkPatchUtils::kNumCorners * sizeof(SkColor);
+    }
+    if (NULL != texCoords) {
+        flags |= kDrawVertices_HasTexs_DrawOpFlag;
+        size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
+    }
+    if (NULL != xmode) {
+        SkXfermode::Mode mode;
+        if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
+            flags |= kDrawVertices_HasXfermode_DrawOpFlag;
+            size += sizeof(int32_t);
+        }
+    }
+    
     this->writePaint(paint);
-    if (this->needOpBytes(patch.writeToMemory(NULL))) {
-        this->writeOp(kDrawPatch_DrawOp);
-        fWriter.writePatch(patch);
+    if (this->needOpBytes(size)) {
+        this->writeOp(kDrawPatch_DrawOp, flags, 0);
+        
+        fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
+        
+        if (NULL != colors) {
+            fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
+        }
+        
+        if (NULL != texCoords) {
+            fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
+        }
+        
+        if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
+            SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
+            SkAssertResult(xmode->asMode(&mode));
+            fWriter.write32(mode);
+        }
     }
 }
 
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 128f8a5..de3958a 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -224,7 +224,9 @@
                                 SkXfermode* xmode, const uint16_t indices[],
                                 int indexCount, const SkPaint& paint) SK_OVERRIDE
         {SkASSERT(0);}
-    virtual void drawPatch(const SkDraw&, const SkPatch& patch, const SkPaint& paint) SK_OVERRIDE
+    virtual void drawPatch(const SkDraw&, const SkPoint cubics[12], const SkColor colors[4],
+                           const SkPoint texCoords[4], SkXfermode* xmode,
+                           const SkPaint& paint) SK_OVERRIDE
         {SkASSERT(0);}
     virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y,
                             const SkPaint&) SK_OVERRIDE
@@ -917,9 +919,11 @@
     this->recordedDrawCommand();
 }
 
-void SkDeferredCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkDeferredCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                                   const SkPoint texCoords[4], SkXfermode* xmode,
+                                   const SkPaint& paint) {
     AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
-    this->drawingCanvas()->drawPatch(patch, paint);
+    this->drawingCanvas()->drawPatch(cubics, colors, texCoords, xmode, paint);
     this->recordedDrawCommand();
 }
 
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index 946aaa3..661f0d8 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -9,6 +9,7 @@
 #include "SkDumpCanvas.h"
 
 #ifdef SK_DEVELOPER
+#include "SkPatchUtils.h"
 #include "SkPicture.h"
 #include "SkPixelRef.h"
 #include "SkRRect.h"
@@ -443,17 +444,24 @@
                SkScalarToFloat(vertices[0].fY));
 }
 
-void SkDumpCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
-    const SkPoint* points = patch.getControlPoints();
-    const SkColor* color = patch.getColors();
+void SkDumpCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                               const SkPoint texCoords[4], SkXfermode* xmode,
+                               const SkPaint& paint) {
     //dumps corner points and colors in clockwise order starting on upper-left corner
     this->dump(kDrawPatch_Verb, &paint, "drawPatch(Vertices{[%f, %f], [%f, %f], [%f, %f], [%f, %f]}\
-              | Colors{[0x%x], [0x%x], [0x%x], [0x%x]})",
-              points[SkPatch::kTopP0_CubicCtrlPts].fX, points[SkPatch::kTopP0_CubicCtrlPts].fY,
-              points[SkPatch::kTopP3_CubicCtrlPts].fX, points[SkPatch::kTopP3_CubicCtrlPts].fY,
-              points[SkPatch::kBottomP3_CubicCtrlPts].fX,points[SkPatch::kBottomP3_CubicCtrlPts].fY,
-              points[SkPatch::kBottomP0_CubicCtrlPts].fX,points[SkPatch::kBottomP0_CubicCtrlPts].fY,
-              color[0], color[1], color[2], color[3]);
+              | Colors{[0x%x], [0x%x], [0x%x], [0x%x]} | TexCoords{[%f,%f], [%f,%f], [%f,%f], \
+               [%f,%f]})",
+              cubics[SkPatchUtils::kTopP0_CubicCtrlPts].fX,
+              cubics[SkPatchUtils::kTopP0_CubicCtrlPts].fY,
+              cubics[SkPatchUtils::kTopP3_CubicCtrlPts].fX,
+              cubics[SkPatchUtils::kTopP3_CubicCtrlPts].fY,
+              cubics[SkPatchUtils::kBottomP3_CubicCtrlPts].fX,
+              cubics[SkPatchUtils::kBottomP3_CubicCtrlPts].fY,
+              cubics[SkPatchUtils::kBottomP0_CubicCtrlPts].fX,
+              cubics[SkPatchUtils::kBottomP0_CubicCtrlPts].fY,
+              colors[0], colors[1], colors[2], colors[3],
+              texCoords[0].x(), texCoords[0].y(), texCoords[1].x(), texCoords[1].y(),
+              texCoords[2].x(), texCoords[2].y(), texCoords[3].x(), texCoords[3].y());
 }
 
 void SkDumpCanvas::drawData(const void* data, size_t length) {
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index d02835a..d436bd4 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -285,10 +285,12 @@
     }
 }
 
-void SkNWayCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+void SkNWayCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                               const SkPoint texCoords[4], SkXfermode* xmode,
+                               const SkPaint& paint) {
     Iter iter(fList);
     while (iter.next()) {
-        iter->drawPatch(patch, paint);
+        iter->drawPatch(cubics, colors, texCoords, xmode, paint);
     }
 }
 
diff --git a/src/utils/SkPatchUtils.cpp b/src/utils/SkPatchUtils.cpp
index ab15290..d120195 100644
--- a/src/utils/SkPatchUtils.cpp
+++ b/src/utils/SkPatchUtils.cpp
@@ -7,8 +7,121 @@
 
 #include "SkPatchUtils.h"
 
+#include "SkColorPriv.h"
+#include "SkGeometry.h"
+
+/**
+ * Evaluator to sample the values of a cubic bezier using forward differences.
+ * Forward differences is a method for evaluating a nth degree polynomial at a uniform step by only
+ * adding precalculated values.
+ * For a linear example we have the function f(t) = m*t+b, then the value of that function at t+h
+ * would be f(t+h) = m*(t+h)+b. If we want to know the uniform step that we must add to the first
+ * evaluation f(t) then we need to substract f(t+h) - f(t) = m*t + m*h + b - m*t + b = mh. After
+ * obtaining this value (mh) we could just add this constant step to our first sampled point
+ * to compute the next one.
+ *
+ * For the cubic case the first difference gives as a result a quadratic polynomial to which we can
+ * apply again forward differences and get linear function to which we can apply again forward
+ * differences to get a constant difference. This is why we keep an array of size 4, the 0th
+ * position keeps the sampled value while the next ones keep the quadratic, linear and constant
+ * difference values.
+ */
+
+class FwDCubicEvaluator {
+    
+public:
+    FwDCubicEvaluator()
+    : fMax(0)
+    , fCurrent(0)
+    , fDivisions(0) {
+        memset(fPoints, 0, 4 * sizeof(SkPoint));
+        memset(fPoints, 0, 4 * sizeof(SkPoint));
+        memset(fPoints, 0, 4 * sizeof(SkPoint));
+    }
+    
+    /**
+     * Receives the 4 control points of the cubic bezier.
+     */
+    FwDCubicEvaluator(SkPoint a, SkPoint b, SkPoint c, SkPoint d) {
+        fPoints[0] = a;
+        fPoints[1] = b;
+        fPoints[2] = c;
+        fPoints[3] = d;
+        
+        SkScalar cx[4], cy[4];
+        SkGetCubicCoeff(fPoints, cx, cy);
+        fCoefs[0].set(cx[0], cy[0]);
+        fCoefs[1].set(cx[1], cy[1]);
+        fCoefs[2].set(cx[2], cy[2]);
+        fCoefs[3].set(cx[3], cy[3]);
+        
+        this->restart(1);
+    }
+    
+    explicit FwDCubicEvaluator(const SkPoint points[4])  {
+        memcpy(fPoints, points, 4 * sizeof(SkPoint));
+        
+        SkScalar cx[4], cy[4];
+        SkGetCubicCoeff(fPoints, cx, cy);
+        fCoefs[0].set(cx[0], cy[0]);
+        fCoefs[1].set(cx[1], cy[1]);
+        fCoefs[2].set(cx[2], cy[2]);
+        fCoefs[3].set(cx[3], cy[3]);
+        
+        this->restart(1);
+    }
+    
+    /**
+     * Restarts the forward differences evaluator to the first value of t = 0.
+     */
+    void restart(int divisions)  {
+        fDivisions = divisions;
+        SkScalar h  = 1.f / fDivisions;
+        fCurrent    = 0;
+        fMax        = fDivisions + 1;
+        fFwDiff[0]  = fCoefs[3];
+        SkScalar h2 = h * h;
+        SkScalar h3 = h2 * h;
+        
+        fFwDiff[3].set(6.f * fCoefs[0].x() * h3, 6.f * fCoefs[0].y() * h3); //6ah^3
+        fFwDiff[2].set(fFwDiff[3].x() + 2.f * fCoefs[1].x() * h2, //6ah^3 + 2bh^2
+                       fFwDiff[3].y() + 2.f * fCoefs[1].y() * h2);
+        fFwDiff[1].set(fCoefs[0].x() * h3 + fCoefs[1].x() * h2 + fCoefs[2].x() * h,//ah^3 + bh^2 +ch
+                       fCoefs[0].y() * h3 + fCoefs[1].y() * h2 + fCoefs[2].y() * h);
+    }
+    
+    /**
+     * Check if the evaluator is still within the range of 0<=t<=1
+     */
+    bool done() const {
+        return fCurrent > fMax;
+    }
+    
+    /**
+     * Call next to obtain the SkPoint sampled and move to the next one.
+     */
+    SkPoint next() {
+        SkPoint point = fFwDiff[0];
+        fFwDiff[0]    += fFwDiff[1];
+        fFwDiff[1]    += fFwDiff[2];
+        fFwDiff[2]    += fFwDiff[3];
+        fCurrent++;
+        return point;
+    }
+    
+    const SkPoint* getCtrlPoints() const {
+        return fPoints;
+    }
+    
+private:
+    int fMax, fCurrent, fDivisions;
+    SkPoint fFwDiff[4], fCoefs[4], fPoints[4];
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
 // size in pixels of each partition per axis, adjust this knob
-static const int kPartitionSize = 15;
+static const int kPartitionSize = 10;
 
 /**
  * Calculate the approximate arc length given a bezier curve's control points.
@@ -24,32 +137,188 @@
     return arcLength;
 }
 
-SkISize SkPatchUtils::GetLevelOfDetail(const SkPatch& patch, const SkMatrix* matrix) {
-    
-    SkPoint mapPts[12];
-    matrix->mapPoints(mapPts, patch.getControlPoints(), 12);
+static SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01,
+                      SkScalar c11) {
+    SkScalar a = c00 * (1.f - tx) + c10 * tx;
+    SkScalar b = c01 * (1.f - tx) + c11 * tx;
+    return a * (1.f - ty) + b * ty;
+}
+
+SkISize SkPatchUtils::GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix) {
     
     // Approximate length of each cubic.
-    SkPoint pts[4];
-    patch.getTopPoints(pts);
-    matrix->mapPoints(pts, 4);
-    SkScalar topLength = approx_arc_length(pts, 4);
+    SkPoint pts[kNumPtsCubic];
+    SkPatchUtils::getTopCubic(cubics, pts);
+    matrix->mapPoints(pts, kNumPtsCubic);
+    SkScalar topLength = approx_arc_length(pts, kNumPtsCubic);
     
-    patch.getBottomPoints(pts);
-    matrix->mapPoints(pts, 4);
-    SkScalar bottomLength = approx_arc_length(pts, 4);
+    SkPatchUtils::getBottomCubic(cubics, pts);
+    matrix->mapPoints(pts, kNumPtsCubic);
+    SkScalar bottomLength = approx_arc_length(pts, kNumPtsCubic);
     
-    patch.getLeftPoints(pts);
-    matrix->mapPoints(pts, 4);
-    SkScalar leftLength = approx_arc_length(pts, 4);
+    SkPatchUtils::getLeftCubic(cubics, pts);
+    matrix->mapPoints(pts, kNumPtsCubic);
+    SkScalar leftLength = approx_arc_length(pts, kNumPtsCubic);
     
-    patch.getRightPoints(pts);
-    matrix->mapPoints(pts, 4);
-    SkScalar rightLength = approx_arc_length(pts, 4);
+    SkPatchUtils::getRightCubic(cubics, pts);
+    matrix->mapPoints(pts, kNumPtsCubic);
+    SkScalar rightLength = approx_arc_length(pts, kNumPtsCubic);
     
     // Level of detail per axis, based on the larger side between top and bottom or left and right
     int lodX = static_cast<int>(SkMaxScalar(topLength, bottomLength) / kPartitionSize);
     int lodY = static_cast<int>(SkMaxScalar(leftLength, rightLength) / kPartitionSize);
     
-    return SkISize::Make(SkMax32(4, lodX), SkMax32(4, lodY));
+    return SkISize::Make(SkMax32(8, lodX), SkMax32(8, lodY));
+}
+
+void SkPatchUtils::getTopCubic(const SkPoint cubics[12], SkPoint points[4]) {
+    points[0] = cubics[kTopP0_CubicCtrlPts];
+    points[1] = cubics[kTopP1_CubicCtrlPts];
+    points[2] = cubics[kTopP2_CubicCtrlPts];
+    points[3] = cubics[kTopP3_CubicCtrlPts];
+}
+
+void SkPatchUtils::getBottomCubic(const SkPoint cubics[12], SkPoint points[4]) {
+    points[0] = cubics[kBottomP0_CubicCtrlPts];
+    points[1] = cubics[kBottomP1_CubicCtrlPts];
+    points[2] = cubics[kBottomP2_CubicCtrlPts];
+    points[3] = cubics[kBottomP3_CubicCtrlPts];
+}
+
+void SkPatchUtils::getLeftCubic(const SkPoint cubics[12], SkPoint points[4]) {
+    points[0] = cubics[kLeftP0_CubicCtrlPts];
+    points[1] = cubics[kLeftP1_CubicCtrlPts];
+    points[2] = cubics[kLeftP2_CubicCtrlPts];
+    points[3] = cubics[kLeftP3_CubicCtrlPts];
+}
+
+void SkPatchUtils::getRightCubic(const SkPoint cubics[12], SkPoint points[4]) {
+    points[0] = cubics[kRightP0_CubicCtrlPts];
+    points[1] = cubics[kRightP1_CubicCtrlPts];
+    points[2] = cubics[kRightP2_CubicCtrlPts];
+    points[3] = cubics[kRightP3_CubicCtrlPts];
+}
+
+bool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12],
+                   const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) {
+    if (lodX < 1 || lodY < 1 || NULL == cubics || NULL == data) {
+        return false;
+    }
+    
+    // number of indices is limited by size of uint16_t, so we clamp it to avoid overflow
+    data->fVertexCount = SkMin32((lodX + 1) * (lodY + 1), 65536);
+    lodX  = SkMin32(lodX, 255);
+    lodY  = SkMin32(lodY, 255);
+    data->fIndexCount = lodX * lodY * 6;
+    
+    data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount);
+    data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
+    
+    // if colors is not null then create array for colors
+    SkPMColor colorsPM[kNumCorners];
+    if (NULL != colors) {
+        // premultiply colors to avoid color bleeding.
+        for (int i = 0; i < kNumCorners; i++) {
+            colorsPM[i] = SkPreMultiplyColor(colors[i]);
+        }
+        data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount);
+    }
+    
+    // if texture coordinates are not null then create array for them
+    if (NULL != texCoords) {
+        data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
+    }
+    
+    SkPoint pts[kNumPtsCubic];
+    SkPatchUtils::getBottomCubic(cubics, pts);
+    FwDCubicEvaluator fBottom(pts);
+    SkPatchUtils::getTopCubic(cubics, pts);
+    FwDCubicEvaluator fTop(pts);
+    SkPatchUtils::getLeftCubic(cubics, pts);
+    FwDCubicEvaluator fLeft(pts);
+    SkPatchUtils::getRightCubic(cubics, pts);
+    FwDCubicEvaluator fRight(pts);
+    
+    fBottom.restart(lodX);
+    fTop.restart(lodX);
+    
+    SkScalar u = 0.0f;
+    int stride = lodY + 1;
+    for (int x = 0; x <= lodX; x++) {
+        SkPoint bottom = fBottom.next(), top = fTop.next();
+        fLeft.restart(lodY);
+        fRight.restart(lodY);
+        SkScalar v = 0.f;
+        for (int y = 0; y <= lodY; y++) {
+            int dataIndex = x * (lodY + 1) + y;
+            
+            SkPoint left = fLeft.next(), right = fRight.next();
+            
+            SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(),
+                                       (1.0f - v) * top.y() + v * bottom.y());
+            SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(),
+                                       (1.0f - u) * left.y() + u * right.y());
+            SkPoint s2 = SkPoint::Make(
+                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x()
+                                                     + u * fTop.getCtrlPoints()[3].x())
+                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x()
+                                              + u * fBottom.getCtrlPoints()[3].x()),
+                                       (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y()
+                                                     + u * fTop.getCtrlPoints()[3].y())
+                                       + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y()
+                                              + u * fBottom.getCtrlPoints()[3].y()));
+            data->fPoints[dataIndex] = s0 + s1 - s2;
+            
+            if (NULL != colors) {
+                uint8_t a = uint8_t(bilerp(u, v,
+                                   SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])),
+                                   SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])),
+                                   SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])),
+                                   SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner]))));
+                uint8_t r = uint8_t(bilerp(u, v,
+                                   SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])),
+                                   SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])),
+                                   SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])),
+                                   SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner]))));
+                uint8_t g = uint8_t(bilerp(u, v,
+                                   SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])),
+                                   SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])),
+                                   SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])),
+                                   SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner]))));
+                uint8_t b = uint8_t(bilerp(u, v,
+                                   SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])),
+                                   SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])),
+                                   SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])),
+                                   SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner]))));
+                data->fColors[dataIndex] = SkPackARGB32(a,r,g,b);
+            }
+            
+            if (NULL != texCoords) {
+                data->fTexCoords[dataIndex] = SkPoint::Make(
+                                            bilerp(u, v, texCoords[kTopLeft_Corner].x(),
+                                                   texCoords[kTopRight_Corner].x(),
+                                                   texCoords[kBottomLeft_Corner].x(),
+                                                   texCoords[kBottomRight_Corner].x()),
+                                            bilerp(u, v, texCoords[kTopLeft_Corner].y(),
+                                                   texCoords[kTopRight_Corner].y(),
+                                                   texCoords[kBottomLeft_Corner].y(),
+                                                   texCoords[kBottomRight_Corner].y()));
+                
+            }
+            
+            if(x < lodX && y < lodY) {
+                int i = 6 * (x * lodY + y);
+                data->fIndices[i] = x * stride + y;
+                data->fIndices[i + 1] = x * stride + 1 + y;
+                data->fIndices[i + 2] = (x + 1) * stride + 1 + y;
+                data->fIndices[i + 3] = data->fIndices[i];
+                data->fIndices[i + 4] = data->fIndices[i + 2];
+                data->fIndices[i + 5] = (x + 1) * stride + y;
+            }
+            v = SkScalarClampMax(v + 1.f / lodY, 1);
+        }
+        u = SkScalarClampMax(u + 1.f / lodX, 1);
+    }
+    return true;
+
 }
diff --git a/src/utils/SkPatchUtils.h b/src/utils/SkPatchUtils.h
index f2e3b43..879053a 100644
--- a/src/utils/SkPatchUtils.h
+++ b/src/utils/SkPatchUtils.h
@@ -8,16 +8,114 @@
 #ifndef SkPatchUtils_DEFINED
 #define SkPatchUtils_DEFINED
 
-#include "SkPatch.h"
+#include "SkColorPriv.h"
 #include "SkMatrix.h"
 
 class SK_API SkPatchUtils {
-
+    
 public:
     /**
+     * Structure that holds the vertex data related to the tessellation of a patch. It is passed
+     * as a parameter to the function getVertexData which sets the points, colors and texture
+     * coordinates of the vertices and the indices for them to be drawn as triangles.
+     */
+    struct VertexData {
+        int fVertexCount, fIndexCount;
+        SkPoint* fPoints;
+        SkPoint* fTexCoords;
+        uint32_t* fColors;
+        uint16_t* fIndices;
+        
+        VertexData()
+        : fVertexCount(0)
+        , fIndexCount(0)
+        , fPoints(NULL)
+        , fTexCoords(NULL)
+        , fColors(NULL)
+        , fIndices(NULL) { }
+        
+        ~VertexData() {
+            SkDELETE_ARRAY(fPoints);
+            SkDELETE_ARRAY(fTexCoords);
+            SkDELETE_ARRAY(fColors);
+            SkDELETE_ARRAY(fIndices);
+        }
+    };
+    
+    // Enums for control points based on the order specified in the constructor (clockwise).
+    enum CubicCtrlPts {
+        kTopP0_CubicCtrlPts = 0,
+        kTopP1_CubicCtrlPts = 1,
+        kTopP2_CubicCtrlPts = 2,
+        kTopP3_CubicCtrlPts = 3,
+        
+        kRightP0_CubicCtrlPts = 3,
+        kRightP1_CubicCtrlPts = 4,
+        kRightP2_CubicCtrlPts = 5,
+        kRightP3_CubicCtrlPts = 6,
+        
+        kBottomP0_CubicCtrlPts = 9,
+        kBottomP1_CubicCtrlPts = 8,
+        kBottomP2_CubicCtrlPts = 7,
+        kBottomP3_CubicCtrlPts = 6,
+        
+        kLeftP0_CubicCtrlPts = 0,
+        kLeftP1_CubicCtrlPts = 11,
+        kLeftP2_CubicCtrlPts = 10,
+        kLeftP3_CubicCtrlPts = 9,
+    };
+    
+    // Enum for corner also clockwise.
+    enum Corner {
+        kTopLeft_Corner = 0,
+        kTopRight_Corner,
+        kBottomRight_Corner,
+        kBottomLeft_Corner
+    };
+    
+    enum {
+        kNumCtrlPts = 12,
+        kNumCorners = 4,
+        kNumPtsCubic = 4
+    };
+    
+    /**
      * Method that calculates a level of detail (number of subdivisions) for a patch in both axis. 
      */
-    static SkISize GetLevelOfDetail(const SkPatch& patch, const SkMatrix* matrix);
+    static SkISize GetLevelOfDetail(const SkPoint cubics[12], const SkMatrix* matrix);
+    
+    /**
+     * Get the points corresponding to the top cubic of cubics.
+     */
+    static void getTopCubic(const SkPoint cubics[12], SkPoint points[4]);
+    
+    /**
+     * Get the points corresponding to the bottom cubic of cubics.
+     */
+    static void getBottomCubic(const SkPoint cubics[12], SkPoint points[4]);
+    
+    /**
+     * Get the points corresponding to the left cubic of cubics.
+     */
+    static void getLeftCubic(const SkPoint cubics[12], SkPoint points[4]);
+    
+    /**
+     * Get the points corresponding to the right cubic of cubics.
+     */
+    static void getRightCubic(const SkPoint cubics[12], SkPoint points[4]);
+    
+    /**
+     * Function that evaluates the coons patch interpolation.
+     * data refers to the pointer of the PatchData struct in which the tessellation data is set.
+     * cubics refers to the points of the cubics.
+     * lod refers the level of detail for each axis.
+     * colors refers to the corner colors that will be bilerp across the patch (optional parameter)
+     * texCoords refers to the corner texture coordinates that will be bilerp across the patch 
+        (optional parameter)
+     */
+    static bool getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12],
+                              const SkColor colors[4], const SkPoint texCoords[4],
+                              int lodX, int lodY);
 };
 
 #endif
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index 773fd20..c15acaa 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -150,8 +150,10 @@
                                      xmode, indices, indexCount, paint);
 }
 
-void SkProxyCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
-    fProxy->drawPatch(patch, paint);
+void SkProxyCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+                                const SkPoint texCoords[4], SkXfermode* xmode,
+                                const SkPaint& paint) {
+    fProxy->drawPatch(cubics, colors, texCoords, xmode, paint);
 }
 
 void SkProxyCanvas::drawData(const void* data, size_t length) {