Implement a fast path for solid color lattice rectangle

Add a flag that hints, which lattice rectangles are solid colors.
Draw solid rectangles and 1x1 rectangles with drawRect.

Test: Measured performance of a ninepatch drawn by HWUI
Bug: b/69796044
Change-Id: Ib3b00ca608da42fa9f2d2038cc126a978421ec7c
Reviewed-on: https://skia-review.googlesource.com/79821
Commit-Queue: Stan Iliev <stani@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
diff --git a/bench/DrawLatticeBench.cpp b/bench/DrawLatticeBench.cpp
index 7a8cdf3..fbab2f7 100644
--- a/bench/DrawLatticeBench.cpp
+++ b/bench/DrawLatticeBench.cpp
@@ -22,8 +22,9 @@
         fLattice.fXCount = xCount;
         fLattice.fYDivs = yDivs;
         fLattice.fYCount = yCount;
-        fLattice.fFlags = nullptr;
+        fLattice.fRectTypes = nullptr;
         fLattice.fBounds = nullptr;
+        fLattice.fColors = nullptr;
 
         fName = SkStringPrintf("DrawLattice_%s", desc);
     }
diff --git a/fuzz/FuzzCanvas.cpp b/fuzz/FuzzCanvas.cpp
index 618f7ac..74b2467 100644
--- a/fuzz/FuzzCanvas.cpp
+++ b/fuzz/FuzzCanvas.cpp
@@ -1548,7 +1548,7 @@
                 }
                 constexpr int kMax = 6;
                 int xDivs[kMax], yDivs[kMax];
-                SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr};
+                SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr, nullptr};
                 fuzz->nextRange(&lattice.fXCount, 2, kMax);
                 fuzz->nextRange(&lattice.fYCount, 2, kMax);
                 fuzz->nextN(xDivs, lattice.fXCount);
@@ -1566,7 +1566,7 @@
                 }
                 constexpr int kMax = 6;
                 int xDivs[kMax], yDivs[kMax];
-                SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr};
+                SkCanvas::Lattice lattice{xDivs, yDivs, nullptr, 0, 0, nullptr, nullptr};
                 fuzz->nextRange(&lattice.fXCount, 2, kMax);
                 fuzz->nextRange(&lattice.fYCount, 2, kMax);
                 fuzz->nextN(xDivs, lattice.fXCount);
diff --git a/gm/lattice.cpp b/gm/lattice.cpp
index 55759d0..d5e2b45 100644
--- a/gm/lattice.cpp
+++ b/gm/lattice.cpp
@@ -124,7 +124,8 @@
         lattice.fXDivs = xDivs + 1;
         lattice.fYCount = 4;
         lattice.fYDivs = yDivs + 1;
-        lattice.fFlags = nullptr;
+        lattice.fRectTypes = nullptr;
+        lattice.fColors = nullptr;
 
         SkIRect bounds = SkIRect::MakeLTRB(padLeft, padTop,
                                            image->width() - padRight, image->height() - padBottom);
@@ -140,6 +141,19 @@
             }
         }
 
+        // Provide hints about 3 solid color rects. These colors match
+        // what was already in the bitmap.
+        int fixedColorX[3] = {2, 4, 1};
+        int fixedColorY[3] = {1, 1, 2};
+        SkColor fixedColor[3] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
+        const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType,
+                                                   kUnpremul_SkAlphaType);
+        for (int rectNum = 0; rectNum < 3; rectNum++) {
+            int srcX = xDivs[fixedColorX[rectNum]-1];
+            int srcY = yDivs[fixedColorY[rectNum]-1];
+            image->readPixels(info, &fixedColor[rectNum], 4, srcX, srcY);
+        }
+
         // Include the degenerate first div.  While normally the first patch is "scalable",
         // this will mean that the first non-degenerate patch is "fixed".
         lattice.fXCount = 5;
@@ -148,13 +162,26 @@
         lattice.fYDivs = yDivs;
 
         // Let's skip a few rects.
-        SkCanvas::Lattice::Flags flags[36];
-        sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::Flags));
-        flags[4] = SkCanvas::Lattice::kTransparent_Flags;
-        flags[9] = SkCanvas::Lattice::kTransparent_Flags;
-        flags[12] = SkCanvas::Lattice::kTransparent_Flags;
-        flags[19] = SkCanvas::Lattice::kTransparent_Flags;
-        lattice.fFlags = flags;
+        SkCanvas::Lattice::RectType flags[36];
+        sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::RectType));
+        flags[4] = SkCanvas::Lattice::kTransparent;
+        flags[9] = SkCanvas::Lattice::kTransparent;
+        flags[12] = SkCanvas::Lattice::kTransparent;
+        flags[19] = SkCanvas::Lattice::kTransparent;
+        for (int rectNum = 0; rectNum < 3; rectNum++) {
+            flags[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
+                   = SkCanvas::Lattice::kFixedColor;
+        }
+        lattice.fRectTypes = flags;
+
+        SkColor colors[36];
+        sk_bzero(colors, 36 * sizeof(SkColor));
+        for (int rectNum = 0; rectNum < 3; rectNum++) {
+            colors[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
+                   = fixedColor[rectNum];
+        }
+
+        lattice.fColors = colors;
 
         canvas->translate(400, 0);
         for (int iy = 0; iy < 2; ++iy) {
@@ -179,3 +206,140 @@
     typedef skiagm::GM INHERITED;
 };
 DEF_GM( return new LatticeGM; )
+
+
+// LatticeGM2 exercises code paths that draw fixed color and 1x1 rectangles.
+class LatticeGM2 : public skiagm::GM {
+public:
+    LatticeGM2() {}
+    SkString onShortName() override {
+        return SkString("lattice2");
+    }
+
+    SkISize onISize() override {
+        return SkISize::Make(800, 800);
+    }
+
+    sk_sp<SkImage> makeImage(SkCanvas* root, int padLeft, int padTop, int padRight, int padBottom) {
+        const int kSize = 80;
+        auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
+        SkCanvas* canvas = surface->getCanvas();;
+        SkPaint paint;
+        paint.setAntiAlias(false);
+        SkRect r;
+
+        //first line
+        r.setXYWH(0, 0, 4, 1);  //4x1 green rect
+        paint.setColor(0xFF00FF00);
+        canvas->drawRect(r, paint);
+
+        r.setXYWH(4, 0, 1, 1); //1x1 blue pixel -> draws as rectangle
+        paint.setColor(0xFF0000FF);
+        canvas->drawRect(r, paint);
+
+        r.setXYWH(5, 0, kSize-5, 1); //the rest of the line is red
+        paint.setColor(0xFFFF0000);
+        canvas->drawRect(r, paint);
+
+
+        //second line -> draws as fixed color rectangles
+        r.setXYWH(0, 1, 4, 1);  //4x1 red rect
+        paint.setColor(0xFFFF0000);
+        canvas->drawRect(r, paint);
+
+        r.setXYWH(4, 1, 1, 1); //1x1 blue pixel with alpha
+        paint.setColor(0x880000FF);
+        canvas->drawRect(r, paint);
+
+        r.setXYWH(5, 1, kSize-5, 1); //the rest of the line is green
+        paint.setColor(0xFF00FF00);
+        canvas->drawRect(r, paint);
+
+
+        //third line - does not draw, because it is transparent
+        r.setXYWH(0, 2, 4, kSize-2);  //4x78 green rect
+        paint.setColor(0xFF00FF00);
+        canvas->drawRect(r, paint);
+
+        r.setXYWH(4, 2, 1, kSize-2); //1x78 red pixel with alpha
+        paint.setColor(0x88FF0000);
+        canvas->drawRect(r, paint);
+
+        r.setXYWH(5, 2, kSize-5, kSize-2); //the rest of the image is blue
+        paint.setColor(0xFF0000FF);
+        canvas->drawRect(r, paint);
+
+        return surface->makeImageSnapshot();
+    }
+
+    void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom,
+                      SkPaint& paint) {
+        int xDivs[2] = {4, 5};
+        int yDivs[2] = {1, 2};
+
+        canvas->save();
+
+        sk_sp<SkImage> image = makeImage(canvas, padLeft, padTop, padRight, padBottom);
+
+        canvas->drawImage(image, 10, 10, nullptr);
+
+        SkCanvas::Lattice lattice;
+        lattice.fXCount = 2;
+        lattice.fXDivs = xDivs;
+        lattice.fYCount = 2;
+        lattice.fYDivs = yDivs;
+        lattice.fBounds = nullptr;
+
+        SkCanvas::Lattice::RectType flags[9];
+        sk_bzero(flags, 9 * sizeof(SkCanvas::Lattice::RectType));
+        flags[3] = SkCanvas::Lattice::kFixedColor;
+        flags[4] = SkCanvas::Lattice::kFixedColor;
+        flags[5] = SkCanvas::Lattice::kFixedColor;
+
+        flags[6] = SkCanvas::Lattice::kTransparent;
+        flags[7] = SkCanvas::Lattice::kTransparent;
+        flags[8] = SkCanvas::Lattice::kTransparent;
+        lattice.fRectTypes = flags;
+
+        SkColor colors[9] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK,
+                             0xFFFF0000, 0x880000FF, 0xFF00FF00,
+                             SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
+        lattice.fColors = colors;
+        paint.setColor(0xFFFFFFFF);
+        canvas->drawImageLattice(image.get(), lattice,
+                                 SkRect::MakeXYWH(100, 100, 200, 200), &paint);
+
+        //draw the same content with alpha
+        canvas->translate(400, 0);
+        paint.setColor(0x80000FFF);
+        canvas->drawImageLattice(image.get(), lattice,
+                                 SkRect::MakeXYWH(100, 100, 200, 200), &paint);
+
+        canvas->restore();
+    }
+
+    void onDraw(SkCanvas* canvas) override {
+
+        //draw a rectangle in the background with transparent pixels
+        SkPaint paint;
+        paint.setColor(0x7F123456);
+        paint.setBlendMode(SkBlendMode::kSrc);
+        canvas->drawRect( SkRect::MakeXYWH(300, 0, 300, 800), paint);
+
+        //draw image lattice with kSrcOver blending
+        paint.setBlendMode(SkBlendMode::kSrcOver);
+        this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
+
+        //draw image lattice with kSrcATop blending
+        canvas->translate(0.0f, 400.0f);
+        paint.setBlendMode(SkBlendMode::kSrcATop);
+        this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
+    }
+
+private:
+    typedef skiagm::GM INHERITED;
+};
+DEF_GM( return new LatticeGM2; )
+
+
+
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 15ee872..f5f32f8 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1760,12 +1760,19 @@
     */
     struct Lattice {
 
-        /** \enum SkCanvas::Lattice::Flags
-            Optional setting per rectangular grid entry to make it transparent.
+        /** \enum SkCanvas::Lattice::RectType
+            Optional setting per rectangular grid entry.
         */
-        enum Flags : uint8_t {
+        enum RectType : uint8_t {
+            kDefault = 0,
+
             /** Set to skip lattice rectangle by making it transparent. */
-            kTransparent_Flags = 1 << 0,
+            kTransparent,
+
+            /** The lattice rectangle is a fixed color. The color value is stored
+                in fColors.
+            */
+            kFixedColor,
         };
 
         /** Array of x-coordinates that divide the bitmap vertically.
@@ -1784,13 +1791,13 @@
         */
         const int*     fYDivs;
 
-        /** Optional array of flags, one per rectangular grid entry:
+        /** Optional array of rectangle types, one per rectangular grid entry:
             array length must be (fXCount + 1) * (fYCount + 1).
 
             Array entries correspond to the rectangular grid entries, ascending
             left to right and then top to bottom.
         */
-        const Flags*   fFlags;
+        const RectType* fRectTypes;
 
         /** Number of entries in fXDivs array; one less than the number of
             horizontal divisions.
@@ -1807,6 +1814,15 @@
         */
         const SkIRect* fBounds;
 
+
+        /** Optional array of colors, one per rectangular grid entry:
+            array length must be (fXCount + 1) * (fYCount + 1).
+
+            Array entries correspond to the rectangular grid entries, ascending
+            left to right and then top to bottom.
+        */
+        const SkColor* fColors;
+
     };
 
     /** Draw SkBitmap bitmap stretched proportionally to fit into SkRect dst.
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 5d5c9da..8513672 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -223,8 +223,24 @@
     SkLatticeIter iter(lattice, dst);
 
     SkRect srcR, dstR;
-    while (iter.next(&srcR, &dstR)) {
-        this->drawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint);
+    SkColor c;
+    bool isFixedColor = false;
+    const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
+
+    while (iter.next(&srcR, &dstR, &isFixedColor, &c)) {
+          if (isFixedColor || (srcR.width() <= 1.0f && srcR.height() <= 1.0f &&
+                               image->readPixels(info, &c, 4, srcR.fLeft, srcR.fTop))) {
+              // Fast draw with drawRect, if this is a patch containing a single color
+              // or if this is a patch containing a single pixel.
+              if (0 != c || !paint.isSrcOver()) {
+                   SkPaint paintCopy(paint);
+                   int alpha = SkAlphaMul(SkColorGetA(c), SkAlpha255To256(paint.getAlpha()));
+                   paintCopy.setColor(SkColorSetA(c, alpha));
+                   this->drawRect(dstR, paintCopy);
+              }
+        } else {
+            this->drawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint);
+        }
     }
 }
 
diff --git a/src/core/SkLatticeIter.cpp b/src/core/SkLatticeIter.cpp
index 9b2a279..551982e 100644
--- a/src/core/SkLatticeIter.cpp
+++ b/src/core/SkLatticeIter.cpp
@@ -166,16 +166,19 @@
     fNumRectsInLattice = (xCount + 1) * (yCount + 1);
     fNumRectsToDraw = fNumRectsInLattice;
 
-    if (lattice.fFlags) {
-        fFlags.push_back_n(fNumRectsInLattice);
+    if (lattice.fRectTypes) {
+        fRectTypes.push_back_n(fNumRectsInLattice);
+        fColors.push_back_n(fNumRectsInLattice);
 
-        const SkCanvas::Lattice::Flags* flags = lattice.fFlags;
+        const SkCanvas::Lattice::RectType* flags = lattice.fRectTypes;
+        const SkColor* colors = lattice.fColors;
 
         bool hasPadRow = (yCount != origYCount);
         bool hasPadCol = (xCount != origXCount);
         if (hasPadRow) {
             // The first row of rects are all empty, skip the first row of flags.
             flags += origXCount + 1;
+            colors += origXCount + 1;
         }
 
         int i = 0;
@@ -184,17 +187,20 @@
                 if (0 == x && hasPadCol) {
                     // The first column of rects are all empty.  Skip a rect.
                     flags++;
+                    colors++;
                     continue;
                 }
 
-                fFlags[i] = *flags;
+                fRectTypes[i] = *flags;
+                fColors[i] = *colors;
                 flags++;
+                colors++;
                 i++;
             }
         }
 
-        for (int j = 0; j < fFlags.count(); j++) {
-            if (SkCanvas::Lattice::kTransparent_Flags == fFlags[j]) {
+        for (int j = 0; j < fRectTypes.count(); j++) {
+            if (SkCanvas::Lattice::kTransparent == fRectTypes[j]) {
                 fNumRectsToDraw--;
             }
         }
@@ -248,7 +254,7 @@
     fNumRectsToDraw = 9;
 }
 
-bool SkLatticeIter::next(SkRect* src, SkRect* dst) {
+bool SkLatticeIter::next(SkRect* src, SkRect* dst, bool* isFixedColor, SkColor* fixedColor) {
     int currRect = fCurrX + fCurrY * (fSrcX.count() - 1);
     if (currRect == fNumRectsInLattice) {
         return false;
@@ -264,12 +270,20 @@
         fCurrY += 1;
     }
 
-    if (fFlags.count() > 0 && SkToBool(SkCanvas::Lattice::kTransparent_Flags & fFlags[currRect])) {
-        return this->next(src, dst);
+    if (fRectTypes.count() > 0
+        && SkToBool(SkCanvas::Lattice::kTransparent == fRectTypes[currRect])) {
+        return this->next(src, dst, isFixedColor, fixedColor);
     }
 
     src->set(fSrcX[x], fSrcY[y], fSrcX[x + 1], fSrcY[y + 1]);
     dst->set(fDstX[x], fDstY[y], fDstX[x + 1], fDstY[y + 1]);
+    if (isFixedColor && fixedColor) {
+        *isFixedColor = fRectTypes.count() > 0
+                     && SkToBool(SkCanvas::Lattice::kFixedColor == fRectTypes[currRect]);
+        if (*isFixedColor) {
+            *fixedColor = fColors[currRect];
+        }
+    }
     return true;
 }
 
diff --git a/src/core/SkLatticeIter.h b/src/core/SkLatticeIter.h
index aad3982..08cdd5a 100644
--- a/src/core/SkLatticeIter.h
+++ b/src/core/SkLatticeIter.h
@@ -30,9 +30,12 @@
     SkLatticeIter(int imageWidth, int imageHeight, const SkIRect& center, const SkRect& dst);
 
     /**
-     *  While it returns true, use src/dst to draw the image/bitmap
+     *  While it returns true, use src/dst to draw the image/bitmap. Optional parameters
+     *  isFixedColor and fixedColor specify if the rectangle is filled with a fixed color.
+     *  If (*isFixedColor) is true, then (*fixedColor) contains the rectangle color.
      */
-    bool next(SkRect* src, SkRect* dst);
+    bool next(SkRect* src, SkRect* dst, bool* isFixedColor = nullptr,
+              SkColor* fixedColor = nullptr);
 
     /**
      *  Apply a matrix to the dst points.
@@ -51,7 +54,8 @@
     SkTArray<SkScalar> fSrcY;
     SkTArray<SkScalar> fDstX;
     SkTArray<SkScalar> fDstY;
-    SkTArray<SkCanvas::Lattice::Flags> fFlags;
+    SkTArray<SkCanvas::Lattice::RectType> fRectTypes;
+    SkTArray<SkColor> fColors;
 
     int  fCurrX;
     int  fCurrY;
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp
index ab5cce3..ed23acf 100644
--- a/src/core/SkLiteDL.cpp
+++ b/src/core/SkLiteDL.cpp
@@ -330,9 +330,13 @@
         void draw(SkCanvas* c, const SkMatrix&) const {
             auto xdivs = pod<int>(this, 0),
                  ydivs = pod<int>(this, xs*sizeof(int));
+            auto colors = (0 == fs) ? nullptr :
+                          pod<SkColor>(this, (xs+ys)*sizeof(int));
             auto flags = (0 == fs) ? nullptr :
-                                     pod<SkCanvas::Lattice::Flags>(this, (xs+ys)*sizeof(int));
-            c->drawImageLattice(image.get(), {xdivs, ydivs, flags, xs, ys, &src}, dst, &paint);
+                         pod<SkCanvas::Lattice::RectType>(this, (xs+ys)*sizeof(int)+
+                                                          fs*sizeof(SkColor));
+            c->drawImageLattice(image.get(), {xdivs, ydivs, flags, xs, ys, &src, colors}, dst,
+                                &paint);
         }
     };
 
@@ -619,14 +623,16 @@
 void SkLiteDL::drawImageLattice(sk_sp<const SkImage> image, const SkCanvas::Lattice& lattice,
                                 const SkRect& dst, const SkPaint* paint) {
     int xs = lattice.fXCount, ys = lattice.fYCount;
-    int fs = lattice.fFlags ? (xs + 1) * (ys + 1) : 0;
-    size_t bytes = (xs + ys) * sizeof(int) + fs * sizeof(SkCanvas::Lattice::Flags);
+    int fs = lattice.fRectTypes ? (xs + 1) * (ys + 1) : 0;
+    size_t bytes = (xs + ys) * sizeof(int) + fs * sizeof(SkCanvas::Lattice::RectType)
+                   + fs * sizeof(SkColor);
     SkASSERT(lattice.fBounds);
     void* pod = this->push<DrawImageLattice>(bytes, std::move(image), xs, ys, fs, *lattice.fBounds,
                                              dst, paint);
     copy_v(pod, lattice.fXDivs, xs,
                 lattice.fYDivs, ys,
-                lattice.fFlags, fs);
+                lattice.fColors, fs,
+                lattice.fRectTypes, fs);
 }
 
 void SkLiteDL::drawText(const void* text, size_t bytes,
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index f9f390e..071e6b3 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -351,8 +351,11 @@
             lattice.fYCount = reader->readInt();
             lattice.fYDivs = (const int*) reader->skip(lattice.fYCount * sizeof(int32_t));
             int flagCount = reader->readInt();
-            lattice.fFlags = (0 == flagCount) ? nullptr : (const SkCanvas::Lattice::Flags*)
-                    reader->skip(SkAlign4(flagCount * sizeof(SkCanvas::Lattice::Flags)));
+            lattice.fRectTypes = (0 == flagCount) ? nullptr :
+                    (const SkCanvas::Lattice::RectType*)
+                    reader->skip(SkAlign4(flagCount * sizeof(SkCanvas::Lattice::RectType)));
+            lattice.fColors = (0 == flagCount) ? nullptr : (const SkColor*)
+                    reader->skip(SkAlign4(flagCount * sizeof(SkColor)));
             SkIRect src;
             reader->readIRect(&src);
             lattice.fBounds = &src;
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 3700e3b..8a7b5cf 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -550,9 +550,12 @@
 void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
                                          const SkRect& dst, const SkPaint* paint) {
     // xCount + xDivs + yCount+ yDivs
-    int flagCount = (nullptr == lattice.fFlags) ? 0 : (lattice.fXCount + 1) * (lattice.fYCount + 1);
+    int flagCount = (nullptr == lattice.fRectTypes) ? 0 :
+                                                      (lattice.fXCount + 1) * (lattice.fYCount + 1);
     size_t latticeSize = (1 + lattice.fXCount + 1 + lattice.fYCount + 1) * kUInt32Size +
-                         SkAlign4(flagCount * sizeof(SkCanvas::Lattice::Flags)) + sizeof(SkIRect);
+                         SkAlign4(flagCount * sizeof(SkCanvas::Lattice::RectType)) +
+                         SkAlign4(flagCount * sizeof(SkColor)) +
+                         sizeof(SkIRect);
 
     // op + paint index + image index + lattice + dst rect
     size_t size = 3 * kUInt32Size + latticeSize + sizeof(dst);
@@ -564,7 +567,8 @@
     this->addInt(lattice.fYCount);
     fWriter.writePad(lattice.fYDivs, lattice.fYCount * kUInt32Size);
     this->addInt(flagCount);
-    fWriter.writePad(lattice.fFlags, flagCount * sizeof(SkCanvas::Lattice::Flags));
+    fWriter.writePad(lattice.fRectTypes, flagCount * sizeof(SkCanvas::Lattice::RectType));
+    fWriter.writePad(lattice.fColors, flagCount * sizeof(SkColor));
     SkASSERT(lattice.fBounds);
     this->addIRect(*lattice.fBounds);
     this->addRect(dst);
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 56bde16..89eb8a7 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -101,7 +101,8 @@
     lattice.fXDivs = r.xDivs;
     lattice.fYCount = r.yCount;
     lattice.fYDivs = r.yDivs;
-    lattice.fFlags = (0 == r.flagCount) ? nullptr : r.flags;
+    lattice.fRectTypes = (0 == r.flagCount) ? nullptr : r.flags;
+    lattice.fColors = (0 == r.flagCount) ? nullptr : r.colors;
     lattice.fBounds = &r.src;
     fCanvas->drawImageLattice(r.image.get(), lattice, r.dst, r.paint);
 }
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 3d53e93..9374b60 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -238,12 +238,13 @@
 
 void SkRecorder::onDrawImageLattice(const SkImage* image, const Lattice& lattice, const SkRect& dst,
                                     const SkPaint* paint) {
-    int flagCount = lattice.fFlags ? (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0;
+    int flagCount = lattice.fRectTypes ? (lattice.fXCount + 1) * (lattice.fYCount + 1) : 0;
     SkASSERT(lattice.fBounds);
     APPEND(DrawImageLattice, this->copy(paint), sk_ref_sp(image),
            lattice.fXCount, this->copy(lattice.fXDivs, lattice.fXCount),
            lattice.fYCount, this->copy(lattice.fYDivs, lattice.fYCount),
-           flagCount, this->copy(lattice.fFlags, flagCount), *lattice.fBounds, dst);
+           flagCount, this->copy(lattice.fRectTypes, flagCount),
+           this->copy(lattice.fColors, flagCount), *lattice.fBounds, dst);
 }
 
 void SkRecorder::onDrawText(const void* text, size_t byteLength,
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index bbac445..f1e70b6 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -256,7 +256,8 @@
         int yCount;
         PODArray<int> yDivs;
         int flagCount;
-        PODArray<SkCanvas::Lattice::Flags> flags;
+        PODArray<SkCanvas::Lattice::RectType> flags;
+        PODArray<SkColor> colors;
         SkIRect src;
         SkRect dst);
 RECORD(DrawImageRect, kDraw_Tag|kHasImage_Tag|kHasPaint_Tag,
diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp
index d91151c..7438eb2 100644
--- a/src/gpu/ops/GrLatticeOp.cpp
+++ b/src/gpu/ops/GrLatticeOp.cpp
@@ -244,7 +244,8 @@
     // edge of the image subset, respectively.
     std::unique_ptr<int[]> xdivs;
     std::unique_ptr<int[]> ydivs;
-    std::unique_ptr<SkCanvas::Lattice::Flags[]> flags;
+    std::unique_ptr<SkCanvas::Lattice::RectType[]> flags;
+    std::unique_ptr<SkColor[]> colors;
     SkIRect subset;
     do {
         imgW = random->nextRangeU(1, 1000);
@@ -271,14 +272,17 @@
         bool hasFlags = random->nextBool();
         if (hasFlags) {
             int n = (lattice.fXCount + 1) * (lattice.fYCount + 1);
-            flags.reset(new SkCanvas::Lattice::Flags[n]);
+            flags.reset(new SkCanvas::Lattice::RectType[n]);
+            colors.reset(new SkColor[n]);
             for (int i = 0; i < n; ++i) {
-                flags[i] = random->nextBool() ? SkCanvas::Lattice::kTransparent_Flags
-                                              : (SkCanvas::Lattice::Flags)0;
+                flags[i] = random->nextBool() ? SkCanvas::Lattice::kTransparent
+                                              : SkCanvas::Lattice::kDefault;
             }
-            lattice.fFlags = flags.get();
+            lattice.fRectTypes = flags.get();
+            lattice.fColors = colors.get();
         } else {
-            lattice.fFlags = nullptr;
+            lattice.fRectTypes = nullptr;
+            lattice.fColors = nullptr;
         }
     } while (!SkLatticeIter::Valid(imgW, imgH, lattice));
 
diff --git a/src/pipe/SkPipeCanvas.cpp b/src/pipe/SkPipeCanvas.cpp
index b9fcd2d..d53e40d 100644
--- a/src/pipe/SkPipeCanvas.cpp
+++ b/src/pipe/SkPipeCanvas.cpp
@@ -556,7 +556,7 @@
     if (paint) {
         extra |= kHasPaint_DrawImageLatticeMask;
     }
-    if (lattice.fFlags) {
+    if (lattice.fRectTypes) {
         extra |= kHasFlags_DrawImageLatticeMask;
     }
     if (lattice.fXCount >= kCount_DrawImageLatticeMask) {
@@ -583,10 +583,11 @@
     // so we can store them smaller.
     writer.write(lattice.fXDivs, lattice.fXCount * sizeof(int32_t));
     writer.write(lattice.fYDivs, lattice.fYCount * sizeof(int32_t));
-    if (lattice.fFlags) {
+    if (lattice.fRectTypes) {
         int32_t count = (lattice.fXCount + 1) * (lattice.fYCount + 1);
         SkASSERT(count > 0);
-        write_pad(&writer, lattice.fFlags, count);
+        write_pad(&writer, lattice.fRectTypes, count);
+        write_pad(&writer, lattice.fColors, count*sizeof(SkColor));
     }
     SkASSERT(lattice.fBounds);
     writer.write(&lattice.fBounds, sizeof(*lattice.fBounds));
diff --git a/src/pipe/SkPipeReader.cpp b/src/pipe/SkPipeReader.cpp
index 593c8b3..3afb22e 100644
--- a/src/pipe/SkPipeReader.cpp
+++ b/src/pipe/SkPipeReader.cpp
@@ -560,9 +560,11 @@
     if (packedVerb & kHasFlags_DrawImageLatticeMask) {
         int32_t count = (lattice.fXCount + 1) * (lattice.fYCount + 1);
         SkASSERT(count > 0);
-        lattice.fFlags = skip<SkCanvas::Lattice::Flags>(reader, SkAlign4(count));
+        lattice.fRectTypes = skip<SkCanvas::Lattice::RectType>(reader, SkAlign4(count));
+        lattice.fColors = skip<SkColor>(reader, SkAlign4(count));
     } else {
-        lattice.fFlags = nullptr;
+        lattice.fRectTypes = nullptr;
+        lattice.fColors = nullptr;
     }
     lattice.fBounds = skip<SkIRect>(reader);
     const SkRect* dst = skip<SkRect>(reader);
diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp
index 5f4316f..0c0d7ac 100644
--- a/tools/debugger/SkDrawCommand.cpp
+++ b/tools/debugger/SkDrawCommand.cpp
@@ -1272,13 +1272,13 @@
         YDivs.append(Json::Value(lattice.fYDivs[i]));
     }
     result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS] = YDivs;
-    if (nullptr != lattice.fFlags) {
+    if (nullptr != lattice.fRectTypes) {
         Json::Value flags(Json::arrayValue);
         int flagCount = 0;
         for (int row = 0; row < lattice.fYCount+1; row++) {
             Json::Value flagsRow(Json::arrayValue);
             for (int column = 0; column < lattice.fXCount+1; column++) {
-                flagsRow.append(Json::Value(lattice.fFlags[flagCount++]));
+                flagsRow.append(Json::Value(lattice.fRectTypes[flagCount++]));
             }
             flags.append(flagsRow);
         }