Proposal for the mesh gradient interface. Implemented as a grid of
patches and uses 4 private arrays to store the values of the control points and
colors. When it needs a patch at a certain position of the grid it just
builds it using the corresponding values of the array and the
grid coordinates provided. Details on implementation are documented in the corresponding classes' comments.

Also added a gm for mesh gradients.

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

Author: dandov@google.com

Review URL: https://codereview.chromium.org/451723003
diff --git a/gm/patch.cpp b/gm/patch.cpp
index d4fe4ff..2579993 100644
--- a/gm/patch.cpp
+++ b/gm/patch.cpp
@@ -87,9 +87,9 @@
     virtual uint32_t onGetFlags() const SK_OVERRIDE {
         return kSkipTiled_Flag;
     }
-    
+
     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
-        
+
         SkPaint paint;
         
         // The order of the colors and points is clockwise starting at upper-left corner.
diff --git a/gm/patchgrid.cpp b/gm/patchgrid.cpp
new file mode 100644
index 0000000..79baf94
--- /dev/null
+++ b/gm/patchgrid.cpp
@@ -0,0 +1,165 @@
+
+/*
+ * 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 "gm.h"
+#include "SkPatchGrid.h"
+
+static void draw_control_points(SkCanvas* canvas, const SkPoint cubics[12]) {
+    //draw control points
+    SkPaint paint;
+    SkPoint bottom[4];
+    SkPatchUtils::getBottomCubic(cubics, bottom);
+    SkPoint top[4];
+    SkPatchUtils::getTopCubic(cubics, top);
+    SkPoint left[4];
+    SkPatchUtils::getLeftCubic(cubics, left);
+    SkPoint right[4];
+    SkPatchUtils::getRightCubic(cubics, right);
+
+    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, 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);
+
+    paint.setStrokeWidth(2);
+
+    paint.setColor(SK_ColorRED);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, corners, paint);
+
+    paint.setColor(SK_ColorBLUE);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, bottom+1, paint);
+
+    paint.setColor(SK_ColorCYAN);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, top+1, paint);
+
+    paint.setColor(SK_ColorYELLOW);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, left+1, paint);
+
+    paint.setColor(SK_ColorGREEN);
+    canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, right+1, paint);
+}
+
+namespace skiagm {
+/**
+ * This GM draws a grid of patches, it only uses colors so it could be considered a mesh gradient.
+ */
+class SkPatchGridGM : public GM {
+    
+public:
+    SkPatchGridGM() {
+        this->setBGColor(0xFFFFFFFF);
+    }
+
+protected:
+    virtual SkString onShortName() SK_OVERRIDE {
+        return SkString("patch_grid");
+    }
+
+    virtual SkISize onISize() SK_OVERRIDE {
+        return SkISize::Make(800, 800);
+    }
+
+    virtual uint32_t onGetFlags() const SK_OVERRIDE {
+        return kSkipTiled_Flag;
+    }
+
+    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+
+        SkPaint paint;
+        
+        SkPoint vertices[4][5] = {
+            {{50,50}, {150,50}, {250,50},{350,50},{450,50}},
+            {{50,150}, {120,120}, {250,150},{350,150},{450,150}},
+            {{50,250}, {150,250}, {250,250},{350,250},{450,250}},
+            {{100,300}, {150,350}, {250,350},{350,350},{450,350}}
+        };
+        
+        SkColor cornerColors[4][5] = {
+            {SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE},
+            {SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED},
+            {SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE},
+            {SK_ColorRED, SK_ColorBLUE, SK_ColorRED, SK_ColorBLUE, SK_ColorRED},
+        };
+        
+        SkPoint hrzCtrl[4][8] = {
+            {{75,30},{125,45},{175,70},{225,20},{275,50},{325,50},{375,5},{425,90}},
+            {{75,150},{125,150},{175,150},{225,150},{275,150},{325,150},{375,150},{425,150}},
+            {{75,250},{125,250},{175,250},{225,250},{275,200},{325,150},{375,250},{425,250}},
+            {{75,350},{125,350},{175,350},{225,350},{275,350},{325,350},{375,350},{425,350}}
+        };
+        
+        SkPoint vrtCtrl[6][5] = {
+            {{50,75},{150,75},{250,75},{350,75},{450,75}},
+            {{50,125},{150,125},{250,125},{350,125},{450,125}},
+            {{50,175},{150,175},{220,225},{350,175},{470,225}},
+            {{50,225},{150,225},{220,175},{350,225},{470,155}},
+            {{50,275},{150,275},{250,275},{350,275},{400,305}},
+            {{50,325},{150,325},{250,325},{350,325},{450,325}}
+        };
+        
+        static const int kRows = 3;
+        static const int kCols = 4;
+        
+        canvas->scale(3, 3);
+        SkPatchGrid grid(kRows, kCols, SkPatchGrid::kColors_VertexType, NULL);
+        for (int i = 0; i < kRows; i++) {
+            for (int j = 0; j < kCols; j++) {
+                SkPoint points[12];
+                
+                //set corners
+                points[SkPatchUtils::kTopP0_CubicCtrlPts] = vertices[i][j];
+                points[SkPatchUtils::kTopP3_CubicCtrlPts] = vertices[i][j + 1];
+                points[SkPatchUtils::kBottomP0_CubicCtrlPts] = vertices[i + 1][j];
+                points[SkPatchUtils::kBottomP3_CubicCtrlPts] = vertices[i + 1][j + 1];
+                
+                points[SkPatchUtils::kTopP1_CubicCtrlPts] = hrzCtrl[i][j * 2];
+                points[SkPatchUtils::kTopP2_CubicCtrlPts] = hrzCtrl[i][j * 2 + 1];
+                points[SkPatchUtils::kBottomP1_CubicCtrlPts] = hrzCtrl[i + 1][j * 2];
+                points[SkPatchUtils::kBottomP2_CubicCtrlPts] = hrzCtrl[i + 1][j * 2 + 1];
+                
+                points[SkPatchUtils::kLeftP1_CubicCtrlPts] = vrtCtrl[i * 2][j];
+                points[SkPatchUtils::kLeftP2_CubicCtrlPts] = vrtCtrl[i * 2 + 1][j];
+                points[SkPatchUtils::kRightP1_CubicCtrlPts] = vrtCtrl[i * 2][j + 1];
+                points[SkPatchUtils::kRightP2_CubicCtrlPts] = vrtCtrl[i * 2 + 1][j + 1];
+                
+                SkColor colors[4];
+                colors[0] = cornerColors[i][j];
+                colors[1] = cornerColors[i][j + 1];
+                colors[3] = cornerColors[i + 1][j];
+                colors[2] = cornerColors[i + 1][j + 1];
+                
+                grid.setPatch(j, i, points, colors, NULL);
+            }
+        }
+        
+        grid.draw(canvas, paint);
+        SkISize dims = grid.getDimensions();
+        for (int y = 0; y < dims.height(); y++) {
+            for (int x = 0; x < dims.width(); x++) {
+                SkPoint cubics[12];
+                grid.getPatch(x, y, cubics, NULL, NULL);
+                draw_control_points(canvas, cubics);
+            }
+        }
+    }
+
+private:
+    typedef GM INHERITED;
+};
+
+DEF_GM(return SkNEW(SkPatchGridGM); )
+
+}
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index e1cb1a6..c1f527f 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -127,6 +127,7 @@
         '../gm/optimizations.cpp',
         '../gm/ovals.cpp',
         '../gm/patch.cpp',
+        '../gm/patchgrid.cpp',
         '../gm/patheffects.cpp',
         '../gm/pathfill.cpp',
         '../gm/pathinterior.cpp',
diff --git a/gyp/utils.gypi b/gyp/utils.gypi
index b033573..9156b84 100644
--- a/gyp/utils.gypi
+++ b/gyp/utils.gypi
@@ -78,6 +78,8 @@
         '<(skia_src_path)/utils/SkParseColor.cpp',
         '<(skia_src_path)/utils/SkParsePath.cpp',
         '<(skia_src_path)/utils/SkPictureUtils.cpp',
+        '<(skia_src_path)/utils/SkPatchGrid.cpp',
+        '<(skia_src_path)/utils/SkPatchGrid.h',
         '<(skia_src_path)/utils/SkPatchUtils.cpp',
         '<(skia_src_path)/utils/SkPatchUtils.h',
         '<(skia_src_path)/utils/SkPathUtils.cpp',
diff --git a/src/utils/SkPatchGrid.cpp b/src/utils/SkPatchGrid.cpp
new file mode 100644
index 0000000..b1fea57
--- /dev/null
+++ b/src/utils/SkPatchGrid.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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 "SkPatchGrid.h"
+#include "SkPatchUtils.h"
+
+SkPatchGrid::SkPatchGrid(int rows, int cols, VertexType flags, SkXfermode* xfer)
+    : fRows(0)
+    , fCols(0)
+    , fModeFlags(kNone_VertexType)
+    , fCornerPts(NULL)
+    , fCornerColors(NULL)
+    , fTexCoords(NULL)
+    , fHrzCtrlPts(NULL)
+    , fVrtCtrlPts(NULL)
+    , fXferMode(NULL) {
+        this->reset(rows, cols, flags, xfer);
+}
+
+SkPatchGrid::~SkPatchGrid() {
+    SkDELETE_ARRAY(fCornerPts);
+    SkDELETE_ARRAY(fCornerColors);
+    SkDELETE_ARRAY(fTexCoords);
+    SkDELETE_ARRAY(fHrzCtrlPts);
+    SkDELETE_ARRAY(fVrtCtrlPts);
+}
+
+bool SkPatchGrid::setPatch(int x, int y, const SkPoint cubics[12], const SkColor colors[4],
+                           const SkPoint texCoords[4]) {
+    // Check for the passed paramaters to be within the range of the grid dimensions and a valid
+    // pointer for the cubics' control points.
+    if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) {
+        return false;
+    }
+    
+    // setup corners and colors
+    int cornerPos = y * (fCols + 1) + x;
+    fCornerPts[cornerPos] = cubics[SkPatchUtils::kTopP0_CubicCtrlPts];
+    fCornerPts[cornerPos + 1] = cubics[SkPatchUtils::kTopP3_CubicCtrlPts];
+    fCornerPts[cornerPos + (fCols + 1)] = cubics[SkPatchUtils::kBottomP0_CubicCtrlPts];
+    fCornerPts[cornerPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kBottomP3_CubicCtrlPts];
+    
+    // set horizontal control points
+    int hrzPos = y * (fCols * 2) + (x * 2);
+    fHrzCtrlPts[hrzPos] = cubics[SkPatchUtils::kTopP1_CubicCtrlPts];
+    fHrzCtrlPts[hrzPos + 1] = cubics[SkPatchUtils::kTopP2_CubicCtrlPts];
+    fHrzCtrlPts[hrzPos + (fCols * 2)] = cubics[SkPatchUtils::kBottomP1_CubicCtrlPts];
+    fHrzCtrlPts[hrzPos + (fCols * 2) + 1] = cubics[SkPatchUtils::kBottomP2_CubicCtrlPts];
+    
+    // set vertical control points
+    int vrtPos = (y*2) * (fCols + 1) + x;
+    fVrtCtrlPts[vrtPos] = cubics[SkPatchUtils::kLeftP1_CubicCtrlPts];
+    fVrtCtrlPts[vrtPos + 1] = cubics[SkPatchUtils::kRightP1_CubicCtrlPts];
+    fVrtCtrlPts[vrtPos + (fCols + 1)] = cubics[SkPatchUtils::kLeftP2_CubicCtrlPts];
+    fVrtCtrlPts[vrtPos + (fCols + 1) + 1] = cubics[SkPatchUtils::kRightP2_CubicCtrlPts];
+    
+    // set optional values (colors and texture coordinates)
+    if ((fModeFlags & kColors_VertexType)  && NULL != colors) {
+        fCornerColors[cornerPos] = colors[0];
+        fCornerColors[cornerPos + 1] = colors[1];
+        fCornerColors[cornerPos + (fCols + 1)] = colors[3];
+        fCornerColors[cornerPos + (fCols + 1) + 1] = colors[2];
+    }
+    
+    if ((fModeFlags & kTexs_VertexType) && NULL != texCoords) {
+        fTexCoords[cornerPos] = texCoords[0];
+        fTexCoords[cornerPos + 1] = texCoords[1];
+        fTexCoords[cornerPos + (fCols + 1)] = texCoords[3];
+        fTexCoords[cornerPos + (fCols + 1) + 1] = texCoords[2];
+    }
+    
+    return true;
+}
+
+bool SkPatchGrid::getPatch(int x, int y, SkPoint cubics[12], SkColor colors[4],
+                           SkPoint texCoords[4]) const {
+    
+    if (x < 0 || y < 0 || x > fCols - 1 || y > fRows - 1 || NULL == cubics) {
+        return false;
+    }
+    
+    // set the patch by building the array of points and colors with the corresponding values.
+    int cornerPos = y * (fCols + 1) + x;
+    cubics[SkPatchUtils::kTopP0_CubicCtrlPts] = fCornerPts[cornerPos];
+    cubics[SkPatchUtils::kTopP3_CubicCtrlPts] = fCornerPts[cornerPos + 1];
+    cubics[SkPatchUtils::kBottomP0_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1)];
+    cubics[SkPatchUtils::kBottomP3_CubicCtrlPts] = fCornerPts[cornerPos + (fCols + 1) + 1];
+    
+    int hrzPos = y * (fCols * 2) + (x * 2);
+    cubics[SkPatchUtils::kTopP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos];
+    cubics[SkPatchUtils::kTopP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + 1];
+    cubics[SkPatchUtils::kBottomP1_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2)];
+    cubics[SkPatchUtils::kBottomP2_CubicCtrlPts] = fHrzCtrlPts[hrzPos + (fCols * 2) + 1];
+    
+    int vrtPos = (y*2) * (fCols + 1) + x;
+    cubics[SkPatchUtils::kLeftP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos];
+    cubics[SkPatchUtils::kRightP1_CubicCtrlPts] = fVrtCtrlPts[vrtPos + 1];
+    cubics[SkPatchUtils::kLeftP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1)];
+    cubics[SkPatchUtils::kRightP2_CubicCtrlPts] = fVrtCtrlPts[vrtPos + (fCols + 1) + 1];
+    
+    if ((fModeFlags & kColors_VertexType)  && NULL != colors) {
+        colors[0] = fCornerColors[cornerPos];
+        colors[1] = fCornerColors[cornerPos + 1];
+        colors[3] = fCornerColors[cornerPos + (fCols + 1)];
+        colors[2] = fCornerColors[cornerPos + (fCols + 1) + 1];
+    }
+    
+    if ((fModeFlags & kTexs_VertexType)  && NULL != texCoords) {
+        texCoords[0] = fTexCoords[cornerPos];
+        texCoords[1] = fTexCoords[cornerPos + 1];
+        texCoords[3] = fTexCoords[cornerPos + (fCols + 1)];
+        texCoords[2] = fTexCoords[cornerPos + (fCols + 1) + 1];
+    }
+    
+    return true;
+}
+
+void SkPatchGrid::reset(int rows, int cols, VertexType flags, SkXfermode* xMode) {
+    SkDELETE_ARRAY(fCornerPts);
+    SkDELETE_ARRAY(fCornerColors);
+    SkDELETE_ARRAY(fTexCoords);
+    SkDELETE_ARRAY(fHrzCtrlPts);
+    SkDELETE_ARRAY(fVrtCtrlPts);
+    
+    fCols = cols;
+    fRows = rows;
+    fModeFlags = flags;
+    fXferMode = xMode;
+    
+    fCornerPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
+    fHrzCtrlPts = SkNEW_ARRAY(SkPoint, (fRows + 1) * fCols * 2);
+    fVrtCtrlPts = SkNEW_ARRAY(SkPoint, fRows * 2 * (fCols + 1));
+    memset(fCornerPts, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint));
+    memset(fHrzCtrlPts, 0, (fRows + 1) * fCols * 2 * sizeof(SkPoint));
+    memset(fVrtCtrlPts, 0, fRows * 2 * (fCols + 1) * sizeof(SkPoint));
+    
+    if (fModeFlags & kColors_VertexType) {
+        fCornerColors = SkNEW_ARRAY(SkColor, (fRows + 1) * (fCols + 1));
+        memset(fCornerColors, 0, (fRows + 1) * (fCols + 1) * sizeof(SkColor));
+    }
+    
+    if (fModeFlags & kTexs_VertexType) {
+        fTexCoords = SkNEW_ARRAY(SkPoint, (fRows + 1) * (fCols + 1));
+        memset(fTexCoords, 0, (fRows + 1) * (fCols + 1) * sizeof(SkPoint));
+    }
+}
+
+void SkPatchGrid::draw(SkCanvas* canvas, SkPaint& paint) {
+    int* maxCols = SkNEW_ARRAY(int, fCols);
+    int* maxRows = SkNEW_ARRAY(int, fRows);
+    memset(maxCols, 0, fCols * sizeof(int));
+    memset(maxRows, 0, fRows * sizeof(int));
+    
+    // Get the maximum level of detail per axis for each row and column
+    for (int y = 0; y < fRows; y++) {
+        for (int x = 0; x < fCols; x++) {
+            SkPoint cubics[12];
+            this->getPatch(x, y, cubics, NULL, NULL);
+            SkMatrix matrix = canvas->getTotalMatrix();
+            SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
+            maxCols[x] = SkMax32(maxCols[x], lod.width());
+            maxRows[y] = SkMax32(maxRows[y], lod.height());
+        }
+    }
+    // Draw the patches by generating their geometry with the maximum level of detail per axis.
+    for (int x = 0; x < fCols; x++) {
+        for (int y = 0; y < fRows; y++) {
+            SkPoint cubics[12];
+            SkPoint texCoords[4];
+            SkColor colors[4];
+            this->getPatch(x, y, cubics, colors, texCoords);
+            SkPatchUtils::VertexData data;
+            SkPatchUtils::getVertexData(&data, cubics,
+                                        fModeFlags & kColors_VertexType ? colors : NULL,
+                                        fModeFlags & kTexs_VertexType ? texCoords : NULL,
+                                        maxCols[x], maxRows[y]);
+            canvas->drawVertices(SkCanvas::kTriangles_VertexMode, data.fVertexCount,
+                                 data.fPoints, data.fTexCoords, data.fColors, fXferMode,
+                                 data.fIndices, data.fIndexCount, paint);
+        }
+    }
+    SkDELETE_ARRAY(maxCols);
+    SkDELETE_ARRAY(maxRows);
+}
diff --git a/src/utils/SkPatchGrid.h b/src/utils/SkPatchGrid.h
new file mode 100644
index 0000000..cf90098
--- /dev/null
+++ b/src/utils/SkPatchGrid.h
@@ -0,0 +1,144 @@
+/*
+ * 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 SkPatchGrid_DEFINED
+#define SkPatchGrid_DEFINED
+
+#include "SkCanvas.h"
+#include "SkPatchUtils.h"
+#include "SkXfermode.h"
+
+/**
+ * Class that represents a grid of patches. Adjacent patches share their corners and a color is 
+ * specified at each one of them. The colors are bilinearly interpolated across the patch.
+ *
+ * This implementation defines a bidimensional array of patches. There are 3 arrays to store the 
+ * control points of the patches to avoid storing repeated data since there are several points
+ * shared between adjacent patches. 
+ *
+ * The array fCornerPts stores the corner control points of the patches.
+ * The array fHrzPts holds the intermidiate control points of the top and bottom curves of a patch.
+ * The array fVrtPts holds the intermidiate control points of the left and right curves of a patch.
+ * The array fCornerColors holds the corner colors in the same format as fCornerPts.
+ * The array fTexCoords holds the texture coordinates in the same format as fCornerpts.
+ *
+ *               fCornerPts               fHrzPts                  fVrtPts
+ *             --------------       -------------------         --------------
+ *            | C0 | C1 | C2 |     | H0 | H1 | H2 | H3 |       | V0 | V1 | V2 |
+ *             --------------       ------------------         ---------------
+ *            | C3 | C4 | C5 |     | H4 | H5 | H6 | H7 |       | V4 | V5 | V6 |
+ *             --------------       -------------------         --------------
+ *            | C6 | C7 | C8 |     | H8 | H9 | H10| H11|       | V6 | V7 | V8 |
+ *             --------------       -------------------         --------------
+ *                                                             | V9 | V10| V11|
+ *                                                              --------------
+ *
+ * With the above configuration we would have a 2x2 grid of patches:
+ *               H0     H1 H2   H3
+ *              /        \/      \
+ *              C0-------C1-------C2
+ *             /|        |        |\
+ *           v0 |        v1       | v2
+ *           v3 |        V4       | v5
+ *             \|        |        |/
+ *              C3-H4-H5-C4-H6-H7-C5
+ *             /|        |        |\
+ *           v6 |        v7       | v8
+ *           v9 |        v10      | v11
+ *             \|        |        |/
+ *              C6-------C7-------C8
+ *               \      / \      /
+ *                H8   H9  H10  H11
+ *
+ * When trying to get a patch at a certain position it justs builds it with the corresponding 
+ * points.
+ * When adding a patch it tries to add the points at their corresponding position trying to comply
+ * with the adjacent points or overwriting them.
+ * 
+ * Based the idea on the SVG2 spec for mesh gradients in which a grid of patches is build as in the
+ * the following example:
+ * <meshGradient x="100" y="100">
+ *      <meshRow>
+ *          <meshPatch>
+ *              <stop .../>
+ *              Up to four stops in first patch. See details below.
+ *          </meshPatch>
+ *          <meshPatch>
+ *              Any number of meshPatches in row.
+ *          </meshPatch>
+ *      </meshRow>
+ *      <meshRow>
+ *          Any number of meshRows, each with the same number of meshPatches as in the first row.
+ *      </meshRow>
+ * </meshGradient>
+ */
+class SkPatchGrid {
+    
+public:
+    
+    enum VertexType {
+        kNone_VertexType = 0X00,
+        kColors_VertexType = 0x01,
+        kTexs_VertexType = 0x02,
+        kColorsAndTexs_VertexType = 0x03
+    };
+    
+    SkPatchGrid(int rows = 0, int cols = 0, VertexType flags = kNone_VertexType,
+                SkXfermode* xfer = NULL);
+    
+    ~SkPatchGrid();
+    
+    /**
+     * Add a patch at location (x,y) overwriting the previous patch and shared points so they 
+     * mantain C0 connectivity.
+     * The control points must be passed in a clockwise order starting at the top left corner.
+     * The colors and texCoords are the values at the corners of the patch which will be bilerp 
+     * across it, they must also be in counterclockwise order starting at the top left corner.
+     */
+    bool setPatch(int x, int y, const SkPoint cubics[12], const SkColor colors[4],
+                  const SkPoint texCoords[4]);
+    
+    /**
+     * Get patch at location (x,y). If cubics, colors or texCoords is not NULL it sets patch's
+     * array with its corresponding values.
+     * The function returns false if the cubics parameter is NULL or if the (x,y) coordinates are 
+     * not within the range of the grid.
+     */
+    bool getPatch(int x, int y, SkPoint cubics[12], SkColor colors[4], SkPoint texCoords[4]) const;
+    
+    /**
+     * Resets the grid of patches to contain rows and cols of patches.
+     */
+    void reset(int rows, int cols, VertexType flags, SkXfermode* xMode);
+    
+    /**
+     * Draws the grid of patches. The patches are drawn starting at patch (0,0) drawing columns, so 
+     * for a 2x2 grid the order would be (0,0)->(0,1)->(1,0)->(1,1). The order follows the order 
+     * of the parametric coordinates of the coons patch.
+     */
+    void draw(SkCanvas* canvas, SkPaint& paint);
+    
+    /**
+     * Get the dimensions of the grid of patches.
+     */
+    SkISize getDimensions() const {
+        return SkISize::Make(fCols, fRows);
+    }
+    
+private:
+    int fRows, fCols;
+    VertexType fModeFlags;
+    SkPoint* fCornerPts;
+    SkColor* fCornerColors;
+    SkPoint* fTexCoords;
+    SkPoint* fHrzCtrlPts;
+    SkPoint* fVrtCtrlPts;
+    SkXfermode* fXferMode;
+};
+
+
+#endif