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/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