Stopped skipping tests in dm of SkPatch by implementing the
corresponding drawPath calls on classes that derive from SkCanvas.

BUG=skia:
R=egdaniel@google.com, bsalomon@google.com, mtklein@google.com, robertphillips@google.com

Author: dandov@google.com

Review URL: https://codereview.chromium.org/429343004
diff --git a/gm/patch.cpp b/gm/patch.cpp
index 5658ef6..3f1e079 100644
--- a/gm/patch.cpp
+++ b/gm/patch.cpp
@@ -16,61 +16,47 @@
 #include "GrTest.h"
 #include "SkPatch.h"
 
-static void draw_control_points(SkCanvas* canvas, SkPatch& patch, SkPaint& paint) {
+static void draw_control_points(SkCanvas* canvas, const SkPatch& patch) {
     //draw control points
-    SkPaint copy(paint);
-    SkPoint bottom[4];
+    SkPaint paint;
+    SkPoint bottom[SkPatch::kNumPtsCubic];
     patch.getBottomPoints(bottom);
-    SkPoint top[4];
+    SkPoint top[SkPatch::kNumPtsCubic];
     patch.getTopPoints(top);
-    SkPoint left[4];
+    SkPoint left[SkPatch::kNumPtsCubic];
     patch.getLeftPoints(left);
-    SkPoint right[4];
+    SkPoint right[SkPatch::kNumPtsCubic];
     patch.getRightPoints(right);
 
-    copy.setColor(SK_ColorBLACK);
-    copy.setStrokeWidth(0.5);
+    paint.setColor(SK_ColorBLACK);
+    paint.setStrokeWidth(0.5);
     SkPoint corners[4] = { bottom[0], bottom[3], top[0], top[3] };
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, copy);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, bottom+1, copy);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 4, top, copy);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 4, left, copy);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 4, right, copy);
+    canvas->drawPoints(SkCanvas::kLines_PointMode, 4, bottom, 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, copy);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, left+1, copy);
-    canvas->drawPoints(SkCanvas::kLines_PointMode, 2, right+1, copy);
+    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);
 
-    copy.setStrokeWidth(2);
+    paint.setStrokeWidth(2);
 
-    copy.setColor(SK_ColorRED);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, copy);
+    paint.setColor(SK_ColorRED);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, paint);
 
-    copy.setColor(SK_ColorBLUE);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom+1, copy);
+    paint.setColor(SK_ColorBLUE);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom+1, paint);
 
-    copy.setColor(SK_ColorCYAN);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top+1, copy);
+    paint.setColor(SK_ColorCYAN);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top+1, paint);
 
-    copy.setColor(SK_ColorYELLOW);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left+1, copy);
+    paint.setColor(SK_ColorYELLOW);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left+1, paint);
 
-    copy.setColor(SK_ColorGREEN);
-    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right+1, copy);
-}
-
-static void draw_random_patch(SkPoint points[12], SkColor colors[4], SkCanvas* canvas,
-                              SkPaint& paint, SkRandom* rnd) {
-    SkPoint ptsCpy[12];
-    memcpy(ptsCpy, points, 12 * sizeof(SkPoint));
-    for (int i = 0; i < 5; i++) {
-        int index = rnd->nextRangeU(0, 11);
-        SkScalar dx = rnd->nextRangeScalar(-50, 50), dy = rnd->nextRangeScalar(-50, 50);
-        ptsCpy[index].offset(dx, dy);
-    }
-    SkPatch patch(ptsCpy, colors);
-    canvas->drawPatch(patch, paint);
-    draw_control_points(canvas, patch, paint);
+    paint.setColor(SK_ColorGREEN);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right+1, paint);
 }
 
 namespace skiagm {
@@ -94,40 +80,51 @@
     }
 
     virtual uint32_t onGetFlags() const SK_OVERRIDE {
-        return kSkipTiled_Flag | kSkipPipe_Flag | kSkipPicture_Flag;
+        return kSkipTiled_Flag;
     }
     
     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
         
         SkPaint paint;
-        SkColor colors[4] = {
+        
+        // The order of the colors and points is clockwise starting at upper-left corner.
+        SkColor colors[SkPatch::kNumColors] = {
             SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN
         };
-        SkPoint points[12] = {
+        SkPoint points[SkPatch::kNumCtrlPts] = {
+            //top points
             {50,50},{75,20},{125,80}, {150,50},
-            {120,75},{180,125},{150,150},
-            {125,120},{75,180},{50,150},
+            //right points
+            {120,75},{180,125},
+            //bottom points
+            {150,150},{125,120},{75,180},{50,150},
+            //left points
             {20,125},{80,75}
         };
         
-        SkRandom rnd;
-        SkScalar scale = 0.5f;
+        SkPatch patch(points, colors);
+        static const SkScalar kScale = 0.5f;
+        canvas->translate(100, 100);
         canvas->save();
         for (SkScalar x = 0; x < 4; x++) {
             canvas->save();
-            canvas->scale(scale * (x + 1), scale * (x + 1));
+            canvas->scale(kScale * (x + 1), kScale * (x + 1));
             canvas->translate(x * 100, 0);
-            draw_random_patch(points, colors, canvas, paint, &rnd);
+            canvas->drawPatch(patch, paint);
+            draw_control_points(canvas, patch);
             canvas->restore();
         }
+        
         canvas->translate(0, 270);
-        SkScalar skew = 0.1f;
+        
+        static const SkScalar kSkew = 0.2f;
         for (SkScalar x = 0; x < 4; x++) {
             canvas->save();
-            canvas->scale(scale * (x + 1), scale * (x + 1));
-            canvas->skew(skew * (x + 1), skew * (x + 1));
+            canvas->scale(kScale * (x + 1), kScale * (x + 1));
             canvas->translate(x * 100, 0);
-            draw_random_patch(points, colors, canvas, paint, &rnd);
+            canvas->skew(kSkew * (x + 1), kSkew * (x + 1));
+            canvas->drawPatch(patch, paint);
+            draw_control_points(canvas, patch);
             canvas->restore();
         }
         canvas->restore();
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 5c4db20..f74ebb7 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1008,6 +1008,13 @@
                               const uint16_t indices[], int indexCount,
                               const SkPaint& paint);
     
+    /** 
+     
+     Draw a SkPatch
+     
+     @param patch specifies the 4 bounding cubic bezier curves of a patch.
+     @param paint Specifies the shader/texture if present.
+     */
     virtual void drawPatch(const SkPatch& patch, const SkPaint& paint);
 
     /** Send a blob of data to the canvas.
diff --git a/include/core/SkPatch.h b/include/core/SkPatch.h
index 3e06c3f..698b1cb 100644
--- a/include/core/SkPatch.h
+++ b/include/core/SkPatch.h
@@ -77,6 +77,12 @@
         kBottomLeft_CornerColors
     };
     
+    enum {
+        kNumCtrlPts = 12,
+        kNumColors = 4,
+        kNumPtsCubic = 4
+    };
+    
     /**
      * Points are in the following order:
      *              (top curve)
@@ -86,7 +92,8 @@
      *                9 8 7 6
      *              (bottom curve)
      */
-    SkPatch(SkPoint points[12], SkColor colors[4]);
+    SkPatch() { }
+    SkPatch(const SkPoint points[12], const SkColor colors[4]);
 
     /**
      * Function that evaluates the coons patch interpolation.
@@ -138,9 +145,38 @@
         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[12];
-    SkColor fCornerColors[4];
+    SkPoint fCtrlPoints[kNumCtrlPts];
+    SkColor fCornerColors[kNumColors];
 };
 
 #endif
diff --git a/include/core/SkReadBuffer.h b/include/core/SkReadBuffer.h
index 2beb7ac..e4f33af 100644
--- a/include/core/SkReadBuffer.h
+++ b/include/core/SkReadBuffer.h
@@ -108,6 +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 51e28ef..3ee63be 100644
--- a/include/core/SkReader32.h
+++ b/include/core/SkReader32.h
@@ -15,6 +15,7 @@
 #include "SkRegion.h"
 #include "SkRRect.h"
 #include "SkScalar.h"
+#include "SkPatch.h"
 
 class SkString;
 
@@ -105,21 +106,25 @@
     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 readObjectFromMemory(path);
+        return this->readObjectFromMemory(path);
     }
 
     bool readMatrix(SkMatrix* matrix) {
-        return readObjectFromMemory(matrix);
+        return this->readObjectFromMemory(matrix);
     }
 
     bool readRRect(SkRRect* rrect) {
-        return readObjectFromMemory(rrect);
+        return this->readObjectFromMemory(rrect);
     }
 
     bool readRegion(SkRegion* rgn) {
-        return readObjectFromMemory(rgn);
+        return this->readObjectFromMemory(rgn);
     }
 
     /**
diff --git a/include/core/SkWriter32.h b/include/core/SkWriter32.h
index fd24ba9..737ffd5 100644
--- a/include/core/SkWriter32.h
+++ b/include/core/SkWriter32.h
@@ -12,6 +12,7 @@
 
 #include "SkData.h"
 #include "SkMatrix.h"
+#include "SkPatch.h"
 #include "SkPath.h"
 #include "SkPoint.h"
 #include "SkRRect.h"
@@ -137,6 +138,12 @@
     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/SkDumpCanvas.h b/include/utils/SkDumpCanvas.h
index 91d698f..53b9755 100644
--- a/include/utils/SkDumpCanvas.h
+++ b/include/utils/SkDumpCanvas.h
@@ -46,6 +46,7 @@
         kDrawText_Verb,
         kDrawPicture_Verb,
         kDrawVertices_Verb,
+        kDrawPatch_Verb,
         kDrawData_Verb,
 
         kBeginCommentGroup_Verb,
@@ -95,6 +96,7 @@
                               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;
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index aabf274..a4bfa88 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -48,6 +48,7 @@
                               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;
diff --git a/include/utils/SkProxyCanvas.h b/include/utils/SkProxyCanvas.h
index 6055db9..d31806f 100644
--- a/include/utils/SkProxyCanvas.h
+++ b/include/utils/SkProxyCanvas.h
@@ -47,6 +47,7 @@
                               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;
diff --git a/src/core/SkBBoxRecord.cpp b/src/core/SkBBoxRecord.cpp
index 448e8f6..802eb66 100644
--- a/src/core/SkBBoxRecord.cpp
+++ b/src/core/SkBBoxRecord.cpp
@@ -284,6 +284,15 @@
     }
 }
 
+void SkBBoxRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+    const SkPoint* points = patch.getControlPoints();
+    SkRect bbox;
+    bbox.set(points, SkPatch::kNumCtrlPts);
+    if (this->transformBounds(bbox, &paint)) {
+        INHERITED::drawPatch(patch, paint);
+    }
+}
+
 void SkBBoxRecord::onDrawPicture(const SkPicture* picture) {
     if (picture->width() > 0 && picture->height() > 0 &&
         this->transformBounds(SkRect::MakeWH(picture->width(), picture->height()), NULL)) {
diff --git a/src/core/SkBBoxRecord.h b/src/core/SkBBoxRecord.h
index a6edc98..d10626f 100644
--- a/src/core/SkBBoxRecord.h
+++ b/src/core/SkBBoxRecord.h
@@ -55,6 +55,7 @@
                               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;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 3320d18..757e711 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2258,7 +2258,7 @@
     // 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(), 12);
+    bounds.set(patch.getControlPoints(), SkPatch::kNumCtrlPts);
     if (this->quickReject(bounds)) {
         return;
     }
diff --git a/src/core/SkPatch.cpp b/src/core/SkPatch.cpp
index cc967d5..4cca2ba 100644
--- a/src/core/SkPatch.cpp
+++ b/src/core/SkPatch.cpp
@@ -9,6 +9,7 @@
 
 #include "SkGeometry.h"
 #include "SkColorPriv.h"
+#include "SkBuffer.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -117,18 +118,12 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-SkPatch::SkPatch(SkPoint points[12], SkColor colors[4]) {
-        
-    for (int i = 0; i < 12; i++) {
-        fCtrlPoints[i] = points[i];
-    }
-    for (int i = 0; i < 4; i++) {
-        fCornerColors[i] = colors[i];
-    }
-    
+SkPatch::SkPatch(const SkPoint points[12], const SkColor colors[4]) {
+    this->reset(points, colors);
 }
 
-uint8_t bilinear(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01, SkScalar c11) {
+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);
@@ -141,8 +136,8 @@
     }
     
     // premultiply colors to avoid color bleeding. 
-    SkPMColor colors[4];
-    for (int i = 0; i < 4; i++) {
+    SkPMColor colors[SkPatch::kNumColors];
+    for (int i = 0; i < SkPatch::kNumColors; i++) {
         colors[i] = SkPreMultiplyColor(fCornerColors[i]);
     }
     
@@ -157,7 +152,7 @@
     data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount);
     data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount);
     
-    SkPoint pts[4];
+    SkPoint pts[SkPatch::kNumPtsCubic];
     this->getBottomPoints(pts);
     FwDCubicEvaluator fBottom(pts);
     this->getTopPoints(pts);
@@ -197,22 +192,22 @@
                                         + u * fBottom.getCtrlPoints()[3].y()));
             data->fPoints[dataIndex] = s0 + s1 - s2;
 
-            uint8_t a = bilinear(u, v, 
+            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 = bilinear(u, v, 
+            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 = bilinear(u, v, 
+            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 = bilinear(u, v, 
+            uint8_t b = bilerp(u, v, 
                             SkScalar(SkColorGetB(colors[kTopLeft_CornerColors])),
                             SkScalar(SkColorGetB(colors[kTopRight_CornerColors])),
                             SkScalar(SkColorGetB(colors[kBottomLeft_CornerColors])),
@@ -236,3 +231,32 @@
     }
     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/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 5d1a6b5..2be929b 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -67,8 +67,10 @@
     DRAW_DRRECT,
     PUSH_CULL,
     POP_CULL,
+    
+    DRAW_PATCH, // could not add in aphabetical order
 
-    LAST_DRAWTYPE_ENUM = POP_CULL
+    LAST_DRAWTYPE_ENUM = DRAW_PATCH
 };
 
 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index d16a635..59abe7c 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -306,6 +306,12 @@
         case DRAW_PAINT:
             canvas->drawPaint(*fPictureData->getPaint(reader));
             break;
+        case DRAW_PATCH: {
+            const SkPaint& paint = *fPictureData->getPaint(reader);
+            SkPatch patch;
+            reader->readPatch(&patch);
+            canvas->drawPatch(patch, paint);
+        } break;
         case DRAW_PATH: {
             const SkPaint& paint = *fPictureData->getPaint(reader);
             canvas->drawPath(fPictureData->getPath(reader), paint);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index ab4c3fa..72c537b 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -122,6 +122,7 @@
         1,  // DRAWDRRECT - right after op code
         0,  // PUSH_CULL - no paint
         0,  // POP_CULL - no paint
+        1,  // DRAW_PATCH - right after op code
     };
 
     SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
@@ -1480,6 +1481,21 @@
     this->validate(initialOffset, size);
 }
 
+void SkPictureRecord::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
+    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
+#endif
+    
+    // op + paint index + patch 12 control points + patch 4 colors
+    size_t size = 2 * kUInt32Size + SkPatch::kNumCtrlPts * sizeof(SkPoint) +
+                    SkPatch::kNumColors * sizeof(SkColor);
+    size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
+    SkASSERT(initialOffset+getPaintOffset(DRAW_PATCH, size) == fWriter.bytesWritten());
+    this->addPaint(paint);
+    this->addPatch(patch);
+    this->validate(initialOffset, size);
+}
+
 void SkPictureRecord::drawData(const void* data, size_t length) {
 
 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
@@ -1613,6 +1629,10 @@
     this->addInt(this->addPathToHeap(path));
 }
 
+void SkPictureRecord::addPatch(const SkPatch& patch) {
+    fWriter.writePatch(patch);
+}
+
 void SkPictureRecord::addPicture(const SkPicture* picture) {
     int index = fPictureRefs.find(picture);
     if (index < 0) {    // not found
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index a1b52fb..140558d 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -61,6 +61,7 @@
                           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;
@@ -177,6 +178,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 addPath(const SkPath& path);
     void addPicture(const SkPicture* picture);
     void addPoint(const SkPoint& point);
diff --git a/src/core/SkReadBuffer.cpp b/src/core/SkReadBuffer.cpp
index 4358786..27f2d2b 100644
--- a/src/core/SkReadBuffer.cpp
+++ b/src/core/SkReadBuffer.cpp
@@ -148,6 +148,10 @@
     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 89efb8e..ac46319 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -63,6 +63,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(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
 DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
 DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint));
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 4c02a35..255eb39 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -206,6 +206,10 @@
                          indexCount);
 }
 
+void SkRecorder::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+    APPEND(DrawPatch, delay_copy(paint), delay_copy(patch));
+}
+
 void SkRecorder::willSave() {
     APPEND(Save);
     INHERITED(willSave);
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 0eb11d7..6eba19e 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -61,6 +61,7 @@
                       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;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 02cfc64..e6d98f7 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -45,6 +45,7 @@
     M(DrawOval)                                                     \
     M(DrawPaint)                                                    \
     M(DrawPath)                                                     \
+    M(DrawPatch)                                                    \
     M(DrawPoints)                                                   \
     M(DrawPosText)                                                  \
     M(DrawPosTextH)                                                 \
@@ -217,6 +218,7 @@
 RECORD2(DrawOval, SkPaint, paint, SkRect, oval);
 RECORD1(DrawPaint, SkPaint, paint);
 RECORD2(DrawPath, SkPaint, paint, SkPath, path);
+RECORD2(DrawPatch, SkPaint, paint, SkPatch, patch);
 RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, size_t, count, SkPoint*, pts);
 RECORD4(DrawPosText, SkPaint, paint,
                      PODArray<char>, text,
diff --git a/src/core/SkValidatingReadBuffer.cpp b/src/core/SkValidatingReadBuffer.cpp
index 037a994..8202149 100644
--- a/src/core/SkValidatingReadBuffer.cpp
+++ b/src/core/SkValidatingReadBuffer.cpp
@@ -171,6 +171,17 @@
     }
 }
 
+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 5cf3abe..8850a07 100644
--- a/src/core/SkValidatingReadBuffer.h
+++ b/src/core/SkValidatingReadBuffer.h
@@ -46,6 +46,7 @@
     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/SkGPipePriv.h b/src/pipe/SkGPipePriv.h
index 58cafe8..821da0f 100644
--- a/src/pipe/SkGPipePriv.h
+++ b/src/pipe/SkGPipePriv.h
@@ -48,6 +48,7 @@
     kDrawDRRect_DrawOp,
     kDrawOval_DrawOp,
     kDrawPaint_DrawOp,
+    kDrawPatch_DrawOp,
     kDrawPath_DrawOp,
     kDrawPicture_DrawOp,
     kDrawPoints_DrawOp,
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 9047e82..35b0a94 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -404,6 +404,15 @@
     }
 }
 
+static void drawPatch_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
+                         SkGPipeState* state) {
+    SkPatch patch;
+    reader->readPatch(&patch);
+    if (state->shouldDraw()) {
+        canvas->drawPatch(patch, state->paint());
+    }
+}
+
 static void drawPath_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                         SkGPipeState* state) {
     SkPath path;
@@ -775,6 +784,7 @@
     drawDRRect_rp,
     drawOval_rp,
     drawPaint_rp,
+    drawPatch_rp,
     drawPath_rp,
     drawPicture_rp,
     drawPoints_rp,
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 46e4260f..186b66c 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -254,6 +254,7 @@
                           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;
@@ -997,6 +998,15 @@
     }
 }
 
+void SkGPipeCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+    NOTIFY_SETUP(this);
+    this->writePaint(paint);
+    if (this->needOpBytes(patch.writeToMemory(NULL))) {
+        this->writeOp(kDrawPatch_DrawOp);
+        fWriter.writePatch(patch);
+    }
+}
+
 void SkGPipeCanvas::drawData(const void* ptr, size_t size) {
     if (size && ptr) {
         NOTIFY_SETUP(this);
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 2820bac..17a1f6c 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -917,7 +917,9 @@
 }
 
 void SkDeferredCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
-    //TODO
+    AutoImmediateDrawIfNeeded autoDraw(*this, &paint);
+    this->drawingCanvas()->drawPatch(patch, paint);
+    this->recordedDrawCommand();
 }
 
 SkDrawFilter* SkDeferredCanvas::setDrawFilter(SkDrawFilter* filter) {
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index b12928f..3c683e6 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -442,6 +442,19 @@
                SkScalarToFloat(vertices[0].fY));
 }
 
+void SkDumpCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+    const SkPoint* points = patch.getControlPoints();
+    const SkColor* color = patch.getColors();
+    //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]);
+}
+
 void SkDumpCanvas::drawData(const void* data, size_t length) {
 //    this->dump(kDrawData_Verb, NULL, "drawData(%d)", length);
     this->dump(kDrawData_Verb, NULL, "drawData(%d) %.*s", length,
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index 11e4a65..b33c99e 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -284,6 +284,13 @@
     }
 }
 
+void SkNWayCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+    Iter iter(fList);
+    while (iter.next()) {
+        iter->drawPatch(patch, paint);
+    }
+}
+
 void SkNWayCanvas::drawData(const void* data, size_t length) {
     Iter iter(fList);
     while (iter.next()) {
diff --git a/src/utils/SkPatchUtils.cpp b/src/utils/SkPatchUtils.cpp
index 7dd0a09..ab15290 100644
--- a/src/utils/SkPatchUtils.cpp
+++ b/src/utils/SkPatchUtils.cpp
@@ -7,10 +7,8 @@
 
 #include "SkPatchUtils.h"
 
-#include "SkGeometry.h"
-
 // size in pixels of each partition per axis, adjust this knob
-static const int kPartitionSize = 30;
+static const int kPartitionSize = 15;
 
 /**
  * Calculate the approximate arc length given a bezier curve's control points.
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index 3aa459c..1029f40 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -149,6 +149,10 @@
                                      xmode, indices, indexCount, paint);
 }
 
+void SkProxyCanvas::drawPatch(const SkPatch& patch, const SkPaint& paint) {
+    fProxy->drawPatch(patch, paint);
+}
+
 void SkProxyCanvas::drawData(const void* data, size_t length) {
     fProxy->drawData(data, length);
 }