Fix several bugs in SkDebugCanvas/SkDrawCommand

This adds drawImageNine and drawRegion support, actually
serializes regions (badly) for clipRegion, and fixes bugs
in quite a few other draw commands (wrong op type, missing
factory registration, JSON attribute mismatch, etc...)

There are still some other draw virtuals missing, but even
getting Lattice to round-trip through JSON is going to be
a bunch of new code, and I didn't want to combine too much
new code with the fixes for existing bugs.

Change-Id: I13749a2d21f4a5ca5f5948b60fc11185bc46645f
Reviewed-on: https://skia-review.googlesource.com/113707
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp
index d2dddb8..8644025 100644
--- a/tools/debugger/SkDebugCanvas.cpp
+++ b/tools/debugger/SkDebugCanvas.cpp
@@ -509,6 +509,11 @@
     this->addDrawCommand(new SkDrawImageRectCommand(image, src, dst, paint, constraint));
 }
 
+void SkDebugCanvas::onDrawImageNine(const SkImage* image, const SkIRect& center,
+                                    const SkRect& dst, const SkPaint* paint) {
+    this->addDrawCommand(new SkDrawImageNineCommand(image, center, dst, paint));
+}
+
 void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
     this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
 }
@@ -526,6 +531,10 @@
     this->addDrawCommand(new SkDrawPathCommand(path, paint));
 }
 
+void SkDebugCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
+    this->addDrawCommand(new SkDrawRegionCommand(region, paint));
+}
+
 void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
                                   const SkMatrix* matrix,
                                   const SkPaint* paint) {
diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h
index 634d5b4..45266d3 100644
--- a/tools/debugger/SkDebugCanvas.h
+++ b/tools/debugger/SkDebugCanvas.h
@@ -206,6 +206,7 @@
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
     void onDrawPath(const SkPath&, const SkPaint&) override;
+    void onDrawRegion(const SkRegion&, const SkPaint&) override;
     void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
     void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
                           SrcRectConstraint) override;
@@ -216,6 +217,8 @@
                          const SkPaint*, SrcRectConstraint) override;
     void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
                           const SkPaint*) override;
+    void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
+                         const SkPaint*) override;
     void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp
index 5766689..7138596 100644
--- a/tools/debugger/SkDrawCommand.cpp
+++ b/tools/debugger/SkDrawCommand.cpp
@@ -214,6 +214,7 @@
 const char* SkDrawCommand::GetCommandString(OpType type) {
     switch (type) {
         case kBeginDrawPicture_OpType: return "BeginDrawPicture";
+        case kClear_OpType: return "DrawClear";
         case kClipPath_OpType: return "ClipPath";
         case kClipRegion_OpType: return "ClipRegion";
         case kClipRect_OpType: return "ClipRect";
@@ -223,20 +224,22 @@
         case kDrawBitmap_OpType: return "DrawBitmap";
         case kDrawBitmapNine_OpType: return "DrawBitmapNine";
         case kDrawBitmapRect_OpType: return "DrawBitmapRect";
-        case kDrawClear_OpType: return "DrawClear";
         case kDrawDRRect_OpType: return "DrawDRRect";
         case kDrawImage_OpType: return "DrawImage";
         case kDrawImageLattice_OpType: return "DrawImageLattice";
+        case kDrawImageNine_OpType: return "DrawImageNine";
         case kDrawImageRect_OpType: return "DrawImageRect";
         case kDrawOval_OpType: return "DrawOval";
         case kDrawPaint_OpType: return "DrawPaint";
         case kDrawPatch_OpType: return "DrawPatch";
         case kDrawPath_OpType: return "DrawPath";
+        case kDrawArc_OpType: return "DrawArc";
         case kDrawPoints_OpType: return "DrawPoints";
         case kDrawPosText_OpType: return "DrawPosText";
         case kDrawPosTextH_OpType: return "DrawPosTextH";
         case kDrawRect_OpType: return "DrawRect";
         case kDrawRRect_OpType: return "DrawRRect";
+        case kDrawRegion_OpType: return "DrawRegion";
         case kDrawText_OpType: return "DrawText";
         case kDrawTextBlob_OpType: return "DrawTextBlob";
         case kDrawTextOnPath_OpType: return "DrawTextOnPath";
@@ -275,6 +278,7 @@
     if (!initialized) {
         initialized = true;
         INSTALL_FACTORY(Restore);
+        INSTALL_FACTORY(Clear);
         INSTALL_FACTORY(ClipPath);
         INSTALL_FACTORY(ClipRegion);
         INSTALL_FACTORY(ClipRect);
@@ -282,14 +286,18 @@
         INSTALL_FACTORY(Concat);
         INSTALL_FACTORY(DrawAnnotation);
         INSTALL_FACTORY(DrawBitmap);
-        INSTALL_FACTORY(DrawBitmapRect);
         INSTALL_FACTORY(DrawBitmapNine);
+        INSTALL_FACTORY(DrawBitmapRect);
         INSTALL_FACTORY(DrawImage);
+        INSTALL_FACTORY(DrawImageLattice);
+        INSTALL_FACTORY(DrawImageNine);
         INSTALL_FACTORY(DrawImageRect);
         INSTALL_FACTORY(DrawOval);
+        INSTALL_FACTORY(DrawArc);
         INSTALL_FACTORY(DrawPaint);
         INSTALL_FACTORY(DrawPath);
         INSTALL_FACTORY(DrawPoints);
+        INSTALL_FACTORY(DrawRegion);
         INSTALL_FACTORY(DrawText);
         INSTALL_FACTORY(DrawPosText);
         INSTALL_FACTORY(DrawPosTextH);
@@ -351,6 +359,24 @@
     canvas->drawPath(path, p);
 }
 
+void render_region(SkCanvas* canvas, const SkRegion& region) {
+    canvas->clear(0xFFFFFFFF);
+
+    const SkIRect& bounds = region.getBounds();
+    if (bounds.isEmpty()) {
+        return;
+    }
+
+    SkAutoCanvasRestore acr(canvas, true);
+    xlate_and_scale_to_bounds(canvas, SkRect::MakeFromIRect(bounds));
+
+    SkPaint p;
+    p.setColor(SK_ColorBLACK);
+    p.setStyle(SkPaint::kStroke_Style);
+
+    canvas->drawRegion(region, p);
+}
+
 void render_bitmap(SkCanvas* canvas, const SkBitmap& input, const SkRect* srcRect = nullptr) {
     const SkISize& size = canvas->getBaseLayerSize();
 
@@ -657,7 +683,10 @@
 }
 
 Json::Value SkDrawCommand::MakeJsonRegion(const SkRegion& region) {
-    return Json::Value("<unimplemented>");
+    // TODO: Actually serialize the rectangles, rather than just devolving to path
+    SkPath path;
+    region.getBoundaryPath(&path);
+    return MakeJsonPath(path);
 }
 
 static Json::Value make_json_regionop(SkClipOp op) {
@@ -1753,6 +1782,12 @@
     }
 }
 
+static void extract_json_region(Json::Value& region, SkRegion* result) {
+    SkPath path;
+    extract_json_path(region, &path);
+    result->setPath(path, SkRegion(path.getBounds().roundOut()));
+}
+
 SkClipOp get_json_clipop(Json::Value& jsonOp) {
     const char* op = jsonOp.asCString();
     if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_DIFFERENCE)) {
@@ -1777,7 +1812,7 @@
     return kIntersect_SkClipOp;
 }
 
-SkClearCommand::SkClearCommand(SkColor color) : INHERITED(kDrawClear_OpType) {
+SkClearCommand::SkClearCommand(SkColor color) : INHERITED(kClear_OpType) {
     fColor = color;
     fInfo.push(SkObjectParser::CustomTextToString("No Parameters"));
 }
@@ -1855,8 +1890,10 @@
 
 SkClipRegionCommand* SkClipRegionCommand::fromJSON(Json::Value& command,
                                                    UrlDataManager& urlDataManager) {
-    SkASSERT(false);
-    return nullptr;
+    SkRegion region;
+    extract_json_region(command[SKDEBUGCANVAS_ATTRIBUTE_REGION], &region);
+    return new SkClipRegionCommand(region,
+                                   get_json_clipop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]));
 }
 
 SkClipRectCommand::SkClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA)
@@ -2366,7 +2403,7 @@
     Json::Value result = INHERITED::toJSON(urlDataManager);
     Json::Value encoded;
     if (flatten(*fImage.get(), &encoded, urlDataManager)) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
+        result[SKDEBUGCANVAS_ATTRIBUTE_IMAGE] = encoded;
         result[SKDEBUGCANVAS_ATTRIBUTE_LATTICE] = MakeJsonLattice(fLattice);
         result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
         if (fPaint.isValid()) {
@@ -2380,6 +2417,12 @@
     return result;
 }
 
+SkDrawImageLatticeCommand* SkDrawImageLatticeCommand::fromJSON(Json::Value& command,
+                                                               UrlDataManager& urlDataManager) {
+    SkDEBUGFAIL("Not implemented yet.");
+    return nullptr;
+}
+
 SkDrawImageRectCommand::SkDrawImageRectCommand(const SkImage* image, const SkRect* src,
                                                const SkRect& dst, const SkPaint* paint,
                                                SkCanvas::SrcRectConstraint constraint)
@@ -2426,7 +2469,7 @@
     Json::Value result = INHERITED::toJSON(urlDataManager);
     Json::Value encoded;
     if (flatten(*fImage.get(), &encoded, urlDataManager)) {
-        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
+        result[SKDEBUGCANVAS_ATTRIBUTE_IMAGE] = encoded;
         if (fSrc.isValid()) {
             result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = MakeJsonRect(*fSrc.get());
         }
@@ -2484,6 +2527,77 @@
     return result;
 }
 
+SkDrawImageNineCommand::SkDrawImageNineCommand(const SkImage* image, const SkIRect& center,
+                                               const SkRect& dst, const SkPaint* paint)
+        : INHERITED(kDrawImageNine_OpType)
+        , fImage(SkRef(image))
+        , fCenter(center)
+        , fDst(dst) {
+    if (paint) {
+        fPaint = *paint;
+        fPaintPtr = &fPaint;
+    } else {
+        fPaintPtr = nullptr;
+    }
+
+    fInfo.push(SkObjectParser::ImageToString(image));
+    fInfo.push(SkObjectParser::IRectToString(center));
+    fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
+    if (paint) {
+        fInfo.push(SkObjectParser::PaintToString(*paint));
+    }
+}
+
+void SkDrawImageNineCommand::execute(SkCanvas* canvas) const {
+    canvas->drawImageNine(fImage.get(), fCenter, fDst, fPaintPtr);
+}
+
+bool SkDrawImageNineCommand::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 SkDrawImageNineCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
+    Json::Value encoded;
+    if (flatten(*fImage.get(), &encoded, urlDataManager)) {
+        result[SKDEBUGCANVAS_ATTRIBUTE_IMAGE] = encoded;
+        result[SKDEBUGCANVAS_ATTRIBUTE_CENTER] = MakeJsonIRect(fCenter);
+        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
+        if (fPaintPtr != nullptr) {
+            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr, urlDataManager);
+        }
+    }
+    return result;
+}
+
+SkDrawImageNineCommand* SkDrawImageNineCommand::fromJSON(Json::Value& command,
+                                                         UrlDataManager& urlDataManager) {
+    sk_sp<SkImage> image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager);
+    if (image == nullptr) {
+        return nullptr;
+    }
+    SkIRect center;
+    extract_json_irect(command[SKDEBUGCANVAS_ATTRIBUTE_CENTER], &center);
+    SkRect dst;
+    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst);
+    SkPaint* paintPtr;
+    SkPaint paint;
+    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
+        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
+        paintPtr = &paint;
+    } else {
+        paintPtr = nullptr;
+    }
+    SkDrawImageNineCommand* result = new SkDrawImageNineCommand(image.get(), center, dst, paintPtr);
+    return result;
+}
+
 SkDrawOvalCommand::SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint)
     : INHERITED(kDrawOval_OpType) {
     fOval = oval;
@@ -2531,7 +2645,7 @@
 
 SkDrawArcCommand::SkDrawArcCommand(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
                                    bool useCenter, const SkPaint& paint)
-        : INHERITED(kDrawOval_OpType) {
+        : INHERITED(kDrawArc_OpType) {
     fOval = oval;
     fStartAngle = startAngle;
     fSweepAngle = sweepAngle;
@@ -2651,6 +2765,40 @@
     return new SkDrawPathCommand(path, paint);
 }
 
+SkDrawRegionCommand::SkDrawRegionCommand(const SkRegion& region, const SkPaint& paint)
+    : INHERITED(kDrawRegion_OpType) {
+    fRegion = region;
+    fPaint = paint;
+
+    fInfo.push(SkObjectParser::RegionToString(region));
+    fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawRegionCommand::execute(SkCanvas* canvas) const {
+    canvas->drawRegion(fRegion, fPaint);
+}
+
+bool SkDrawRegionCommand::render(SkCanvas* canvas) const {
+    render_region(canvas, fRegion);
+    return true;
+}
+
+Json::Value SkDrawRegionCommand::toJSON(UrlDataManager& urlDataManager) const {
+    Json::Value result = INHERITED::toJSON(urlDataManager);
+    result[SKDEBUGCANVAS_ATTRIBUTE_REGION] = MakeJsonRegion(fRegion);
+    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
+    return result;
+}
+
+SkDrawRegionCommand* SkDrawRegionCommand::fromJSON(Json::Value& command,
+                                                   UrlDataManager& urlDataManager) {
+    SkRegion region;
+    extract_json_region(command[SKDEBUGCANVAS_ATTRIBUTE_REGION], &region);
+    SkPaint paint;
+    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
+    return new SkDrawRegionCommand(region, paint);
+}
+
 SkBeginDrawPictureCommand::SkBeginDrawPictureCommand(const SkPicture* picture,
                                                      const SkMatrix* matrix,
                                                      const SkPaint* paint)
diff --git a/tools/debugger/SkDrawCommand.h b/tools/debugger/SkDrawCommand.h
index 654cbdd..d2eee9b 100644
--- a/tools/debugger/SkDrawCommand.h
+++ b/tools/debugger/SkDrawCommand.h
@@ -26,6 +26,7 @@
 public:
     enum OpType {
         kBeginDrawPicture_OpType,
+        kClear_OpType,
         kClipPath_OpType,
         kClipRegion_OpType,
         kClipRect_OpType,
@@ -35,12 +36,13 @@
         kDrawBitmap_OpType,
         kDrawBitmapNine_OpType,
         kDrawBitmapRect_OpType,
-        kDrawClear_OpType,
         kDrawDRRect_OpType,
         kDrawImage_OpType,
         kDrawImageLattice_OpType,
+        kDrawImageNine_OpType,
         kDrawImageRect_OpType,
         kDrawOval_OpType,
+        kDrawArc_OpType,
         kDrawPaint_OpType,
         kDrawPatch_OpType,
         kDrawPath_OpType,
@@ -49,6 +51,7 @@
         kDrawPosTextH_OpType,
         kDrawRect_OpType,
         kDrawRRect_OpType,
+        kDrawRegion_OpType,
         kDrawText_OpType,
         kDrawTextBlob_OpType,
         kDrawTextOnPath_OpType,
@@ -374,6 +377,8 @@
     void execute(SkCanvas* canvas) const override;
     bool render(SkCanvas* canvas) const override;
     Json::Value toJSON(UrlDataManager& urlDataManager) const override;
+    static SkDrawImageLatticeCommand* fromJSON(Json::Value& command,
+                                               UrlDataManager& urlDataManager);
 
 private:
     sk_sp<const SkImage>        fImage;
@@ -384,6 +389,25 @@
     typedef SkDrawCommand INHERITED;
 };
 
+class SkDrawImageNineCommand : public SkDrawCommand {
+public:
+    SkDrawImageNineCommand(const SkImage* image, const SkIRect& center,
+                           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;
+    static SkDrawImageNineCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
+
+private:
+    sk_sp<const SkImage> fImage;
+    SkIRect              fCenter;
+    SkRect               fDst;
+    SkPaint              fPaint;
+    SkPaint*             fPaintPtr;
+
+    typedef SkDrawCommand INHERITED;
+};
+
 class SkDrawImageRectCommand : public SkDrawCommand {
 public:
     SkDrawImageRectCommand(const SkImage* image, const SkRect* src, const SkRect& dst,
@@ -514,6 +538,21 @@
     typedef SkDrawCommand INHERITED;
 };
 
+class SkDrawRegionCommand : public SkDrawCommand {
+public:
+    SkDrawRegionCommand(const SkRegion& region, const SkPaint& paint);
+    void execute(SkCanvas* canvas) const override;
+    bool render(SkCanvas* canvas) const override;
+    Json::Value toJSON(UrlDataManager& urlDataManager) const override;
+    static SkDrawRegionCommand* fromJSON(Json::Value& command, UrlDataManager& urlDataManager);
+
+private:
+    SkRegion fRegion;
+    SkPaint  fPaint;
+
+    typedef SkDrawCommand INHERITED;
+};
+
 class SkDrawTextCommand : public SkDrawCommand {
 public:
     SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y,