Add support for drawImageLattice in SKIA debugger

Add support in SKIA debugger for SkCanvas.drawImageLattice calls.

Test: Tested with an SKP from android settings app.
Change-Id: I3f39f353dca8a3a2854241e7ef995d4d8c635f3e
Reviewed-on: https://skia-review.googlesource.com/6882
Commit-Queue: Stan Iliev <stani@google.com>
Reviewed-by: Joe Gregorio <jcgregorio@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp
index 0a28bdc..04e8341 100644
--- a/tools/debugger/SkDebugCanvas.cpp
+++ b/tools/debugger/SkDebugCanvas.cpp
@@ -562,6 +562,11 @@
     this->addDrawCommand(new SkDrawImageCommand(image, left, top, paint));
 }
 
+void SkDebugCanvas::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
+                                       const SkRect& dst, const SkPaint* paint) {
+    this->addDrawCommand(new SkDrawImageLatticeCommand(image, lattice, dst, paint));
+}
+
 void SkDebugCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
                                     const SkPaint* paint, SrcRectConstraint constraint) {
     this->addDrawCommand(new SkDrawImageRectCommand(image, src, dst, paint, constraint));
diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h
index 312141b..4a81e26 100644
--- a/tools/debugger/SkDebugCanvas.h
+++ b/tools/debugger/SkDebugCanvas.h
@@ -242,6 +242,8 @@
     void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
                           SrcRectConstraint) override;
     void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
+    void onDrawImageLattice(const SkImage* image, const Lattice& lattice,
+                            const SkRect& dst, const SkPaint* paint) override;
     void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
                          const SkPaint*, SrcRectConstraint) override;
     void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp
index 6dea988..3bb1b90 100644
--- a/tools/debugger/SkDrawCommand.cpp
+++ b/tools/debugger/SkDrawCommand.cpp
@@ -28,6 +28,7 @@
 #include "SkWriteBuffer.h"
 #include "picture_utils.h"
 #include "SkClipOpPriv.h"
+#include <SkLatticeIter.h>
 
 #define SKDEBUGCANVAS_ATTRIBUTE_COMMAND           "command"
 #define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE           "visible"
@@ -105,6 +106,12 @@
 #define SKDEBUGCANVAS_ATTRIBUTE_WIDTH             "width"
 #define SKDEBUGCANVAS_ATTRIBUTE_HEIGHT            "height"
 #define SKDEBUGCANVAS_ATTRIBUTE_ALPHA             "alpha"
+#define SKDEBUGCANVAS_ATTRIBUTE_LATTICE           "lattice"
+#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT     "xCount"
+#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT     "yCount"
+#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS      "xDivs"
+#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS      "yDivs"
+#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS      "flags"
 
 #define SKDEBUGCANVAS_VERB_MOVE                   "move"
 #define SKDEBUGCANVAS_VERB_LINE                   "line"
@@ -210,6 +217,7 @@
         case kDrawClear_OpType: return "DrawClear";
         case kDrawDRRect_OpType: return "DrawDRRect";
         case kDrawImage_OpType: return "DrawImage";
+        case kDrawImageLattice_OpType: return "DrawImageLattice";
         case kDrawImageRect_OpType: return "DrawImageRect";
         case kDrawOval_OpType: return "DrawOval";
         case kDrawPaint_OpType: return "DrawPaint";
@@ -1178,6 +1186,38 @@
     return result;
 }
 
+Json::Value SkDrawCommand::MakeJsonLattice(const SkCanvas::Lattice& lattice) {
+    Json::Value result(Json::objectValue);
+    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT] = Json::Value(lattice.fXCount);
+    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT] = Json::Value(lattice.fYCount);
+    if (nullptr != lattice.fBounds) {
+        result[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS] = MakeJsonIRect(*lattice.fBounds);
+    }
+    Json::Value XDivs(Json::arrayValue);
+    for (int i = 0; i < lattice.fXCount; i++) {
+        XDivs.append(Json::Value(lattice.fXDivs[i]));
+    }
+    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS] = XDivs;
+    Json::Value YDivs(Json::arrayValue);
+    for (int i = 0; i < lattice.fYCount; i++) {
+        YDivs.append(Json::Value(lattice.fYDivs[i]));
+    }
+    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS] = YDivs;
+    if (nullptr != lattice.fFlags) {
+        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++]));
+            }
+            flags.append(flagsRow);
+        }
+        result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS] = flags;
+    }
+    return result;
+}
+
 static SkPoint get_json_point(Json::Value point) {
     return SkPoint::Make(point[0].asFloat(), point[1].asFloat());
 }
@@ -2167,6 +2207,60 @@
     return result;
 }
 
+SkDrawImageLatticeCommand::SkDrawImageLatticeCommand(const SkImage* image,
+                                                     const SkCanvas::Lattice& lattice,
+                                                     const SkRect& dst, const SkPaint* paint)
+    : INHERITED(kDrawImageLattice_OpType)
+    , fImage(SkRef(image))
+    , fLattice(lattice)
+    , fDst(dst) {
+
+      fInfo.push(SkObjectParser::ImageToString(image));
+      fInfo.push(SkObjectParser::LatticeToString(lattice));
+      fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
+      if (paint) {
+          fPaint.set(*paint);
+          fInfo.push(SkObjectParser::PaintToString(*paint));
+      }
+}
+
+void SkDrawImageLatticeCommand::execute(SkCanvas* canvas) const {
+    SkLatticeIter iter(fLattice, fDst);
+    SkRect srcR, dstR;
+    while (iter.next(&srcR, &dstR)) {
+        canvas->legacy_drawImageRect(fImage.get(), &srcR, dstR,
+                                     fPaint.getMaybeNull(), SkCanvas::kStrict_SrcRectConstraint);
+    }
+}
+
+bool SkDrawImageLatticeCommand::render(SkCanvas* canvas) const {
+    SkAutoCanvasRestore acr(canvas, true);
+    canvas->clear(0xFFFFFFFF);
+
+    xlate_and_scale_to_bounds(canvas, fDst);
+
+    this->execute(canvas);
+    return true;
+}
+
+Json::Value SkDrawImageLatticeCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
+    Json::Value encoded;
+    if (flatten(*fImage.get(), &encoded, urlDataManager)) {
+        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
+        result[SKDEBUGCANVAS_ATTRIBUTE_LATTICE] = MakeJsonLattice(fLattice);
+        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
+        if (fPaint.isValid()) {
+            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaint.get(), urlDataManager);
+        }
+    }
+
+    SkString desc;
+    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fDst)->c_str());
+
+    return result;
+}
+
 SkDrawImageRectCommand::SkDrawImageRectCommand(const SkImage* image, const SkRect* src,
                                                const SkRect& dst, const SkPaint* paint,
                                                SkCanvas::SrcRectConstraint constraint)
diff --git a/tools/debugger/SkDrawCommand.h b/tools/debugger/SkDrawCommand.h
index 880c2aa..266fc99 100644
--- a/tools/debugger/SkDrawCommand.h
+++ b/tools/debugger/SkDrawCommand.h
@@ -35,6 +35,7 @@
         kDrawClear_OpType,
         kDrawDRRect_OpType,
         kDrawImage_OpType,
+        kDrawImageLattice_OpType,
         kDrawImageRect_OpType,
         kDrawOval_OpType,
         kDrawPaint_OpType,
@@ -131,6 +132,7 @@
     static Json::Value MakeJsonPath(const SkPath& path);
     static Json::Value MakeJsonRegion(const SkRegion& region);
     static Json::Value MakeJsonPaint(const SkPaint& paint, UrlDataManager& urlDataManager);
+    static Json::Value MakeJsonLattice(const SkCanvas::Lattice& lattice);
 
     static void flatten(const SkFlattenable* flattenable, Json::Value* target,
                         UrlDataManager& urlDataManager);
@@ -364,6 +366,23 @@
     typedef SkDrawCommand INHERITED;
 };
 
+class SkDrawImageLatticeCommand : public SkDrawCommand {
+public:
+    SkDrawImageLatticeCommand(const SkImage* image, const SkCanvas::Lattice& lattice,
+                              const SkRect& dst, const SkPaint* paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
+
+private:
+    sk_sp<const SkImage>        fImage;
+    SkCanvas::Lattice           fLattice;
+    SkRect                      fDst;
+    SkTLazy<SkPaint>            fPaint;
+
+    typedef SkDrawCommand INHERITED;
+};
+
 class SkDrawImageRectCommand : public SkDrawCommand {
 public:
     SkDrawImageRectCommand(const SkImage* image, const SkRect* src, const SkRect& dst,
diff --git a/tools/debugger/SkObjectParser.cpp b/tools/debugger/SkObjectParser.cpp
index e89e8c5..227532a 100644
--- a/tools/debugger/SkObjectParser.cpp
+++ b/tools/debugger/SkObjectParser.cpp
@@ -404,3 +404,20 @@
 
     return decodedText;
 }
+
+SkString* SkObjectParser::LatticeToString(const SkCanvas::Lattice& lattice) {
+    SkString* mLattice = new SkString;
+    mLattice->append("Lattice: ");
+    mLattice->append("(X: ");
+    mLattice->appendS32(lattice.fXCount);
+    mLattice->append(", Y:");
+    mLattice->appendS32(lattice.fYCount);
+    mLattice->append(", Bounds:");
+    if (nullptr != lattice.fBounds) {
+        mLattice->append(*IRectToString(*lattice.fBounds));
+    } else {
+        mLattice->append("null");
+    }
+    mLattice->append(")");
+    return mLattice;
+}
diff --git a/tools/debugger/SkObjectParser.h b/tools/debugger/SkObjectParser.h
index 4805179..2532c5c 100644
--- a/tools/debugger/SkObjectParser.h
+++ b/tools/debugger/SkObjectParser.h
@@ -129,6 +129,12 @@
      */
     static SkString* TextToString(const void* text, size_t byteLength,
                                   SkPaint::TextEncoding encoding);
+
+    /**
+        Returns a string representation of the SkCanvas::Lattice.
+        @param lattice  SkCanvas::Lattice
+     */
+    static SkString* LatticeToString(const SkCanvas::Lattice& lattice);
 };
 
 #endif