de-Sk tools/debugger
Change-Id: I489a54860139d1820471aa0330b29a8ae9eca31e
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/202316
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/tools/debugger/DrawCommand.cpp b/tools/debugger/DrawCommand.cpp
new file mode 100644
index 0000000..df04b0e
--- /dev/null
+++ b/tools/debugger/DrawCommand.cpp
@@ -0,0 +1,2116 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "DrawCommand.h"
+
+#include <algorithm>
+#include "JsonWriteBuffer.h"
+#include "SkAutoMalloc.h"
+#include "SkCanvasPriv.h"
+#include "SkClipOpPriv.h"
+#include "SkColorFilter.h"
+#include "SkDashPathEffect.h"
+#include "SkDrawable.h"
+#include "SkImageFilter.h"
+#include "SkLatticeIter.h"
+#include "SkMaskFilterBase.h"
+#include "SkPaintDefaults.h"
+#include "SkPathEffect.h"
+#include "SkPicture.h"
+#include "SkPngEncoder.h"
+#include "SkReadBuffer.h"
+#include "SkRectPriv.h"
+#include "SkShadowFlags.h"
+#include "SkTHash.h"
+#include "SkTextBlobPriv.h"
+#include "SkTypeface.h"
+#include "SkWriteBuffer.h"
+
+#define SKDEBUGCANVAS_ATTRIBUTE_COMMAND "command"
+#define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE "visible"
+#define SKDEBUGCANVAS_ATTRIBUTE_MATRIX "matrix"
+#define SKDEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS "drawDepthTranslation"
+#define SKDEBUGCANVAS_ATTRIBUTE_COORDS "coords"
+#define SKDEBUGCANVAS_ATTRIBUTE_EDGING "edging"
+#define SKDEBUGCANVAS_ATTRIBUTE_HINTING "hinting"
+#define SKDEBUGCANVAS_ATTRIBUTE_BOUNDS "bounds"
+#define SKDEBUGCANVAS_ATTRIBUTE_PAINT "paint"
+#define SKDEBUGCANVAS_ATTRIBUTE_OUTER "outer"
+#define SKDEBUGCANVAS_ATTRIBUTE_INNER "inner"
+#define SKDEBUGCANVAS_ATTRIBUTE_MODE "mode"
+#define SKDEBUGCANVAS_ATTRIBUTE_POINTS "points"
+#define SKDEBUGCANVAS_ATTRIBUTE_PATH "path"
+#define SKDEBUGCANVAS_ATTRIBUTE_TEXT "text"
+#define SKDEBUGCANVAS_ATTRIBUTE_COLOR "color"
+#define SKDEBUGCANVAS_ATTRIBUTE_ALPHA "alpha"
+#define SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE "blendMode"
+#define SKDEBUGCANVAS_ATTRIBUTE_STYLE "style"
+#define SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH "strokeWidth"
+#define SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER "strokeMiter"
+#define SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN "strokeJoin"
+#define SKDEBUGCANVAS_ATTRIBUTE_CAP "cap"
+#define SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS "antiAlias"
+#define SKDEBUGCANVAS_ATTRIBUTE_DITHER "dither"
+#define SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT "fakeBoldText"
+#define SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT "linearText"
+#define SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT "subpixelText"
+#define SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT "devKernText"
+#define SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT "lcdRenderText"
+#define SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT "embeddedBitmapText"
+#define SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING "forceAutoHinting"
+#define SKDEBUGCANVAS_ATTRIBUTE_REGION "region"
+#define SKDEBUGCANVAS_ATTRIBUTE_REGIONOP "op"
+#define SKDEBUGCANVAS_ATTRIBUTE_EDGESTYLE "edgeStyle"
+#define SKDEBUGCANVAS_ATTRIBUTE_DEVICEREGION "deviceRegion"
+#define SKDEBUGCANVAS_ATTRIBUTE_BLUR "blur"
+#define SKDEBUGCANVAS_ATTRIBUTE_SIGMA "sigma"
+#define SKDEBUGCANVAS_ATTRIBUTE_QUALITY "quality"
+#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE "textSize"
+#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX "textScaleX"
+#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX "textSkewX"
+#define SKDEBUGCANVAS_ATTRIBUTE_DASHING "dashing"
+#define SKDEBUGCANVAS_ATTRIBUTE_INTERVALS "intervals"
+#define SKDEBUGCANVAS_ATTRIBUTE_PHASE "phase"
+#define SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE "fillType"
+#define SKDEBUGCANVAS_ATTRIBUTE_VERBS "verbs"
+#define SKDEBUGCANVAS_ATTRIBUTE_NAME "name"
+#define SKDEBUGCANVAS_ATTRIBUTE_DATA "data"
+#define SKDEBUGCANVAS_ATTRIBUTE_VALUES "values"
+#define SKDEBUGCANVAS_ATTRIBUTE_SHADER "shader"
+#define SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT "pathEffect"
+#define SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER "maskFilter"
+#define SKDEBUGCANVAS_ATTRIBUTE_XFERMODE "xfermode"
+#define SKDEBUGCANVAS_ATTRIBUTE_LOOPER "looper"
+#define SKDEBUGCANVAS_ATTRIBUTE_BACKDROP "backdrop"
+#define SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER "colorfilter"
+#define SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER "imagefilter"
+#define SKDEBUGCANVAS_ATTRIBUTE_IMAGE "image"
+#define SKDEBUGCANVAS_ATTRIBUTE_BITMAP "bitmap"
+#define SKDEBUGCANVAS_ATTRIBUTE_SRC "src"
+#define SKDEBUGCANVAS_ATTRIBUTE_DST "dst"
+#define SKDEBUGCANVAS_ATTRIBUTE_CENTER "center"
+#define SKDEBUGCANVAS_ATTRIBUTE_STRICT "strict"
+#define SKDEBUGCANVAS_ATTRIBUTE_DESCRIPTION "description"
+#define SKDEBUGCANVAS_ATTRIBUTE_X "x"
+#define SKDEBUGCANVAS_ATTRIBUTE_Y "y"
+#define SKDEBUGCANVAS_ATTRIBUTE_RUNS "runs"
+#define SKDEBUGCANVAS_ATTRIBUTE_POSITIONS "positions"
+#define SKDEBUGCANVAS_ATTRIBUTE_GLYPHS "glyphs"
+#define SKDEBUGCANVAS_ATTRIBUTE_FONT "font"
+#define SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE "typeface"
+#define SKDEBUGCANVAS_ATTRIBUTE_CUBICS "cubics"
+#define SKDEBUGCANVAS_ATTRIBUTE_COLORS "colors"
+#define SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS "textureCoords"
+#define SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY "filterQuality"
+#define SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE "startAngle"
+#define SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE "sweepAngle"
+#define SKDEBUGCANVAS_ATTRIBUTE_USECENTER "useCenter"
+#define SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC "shortDesc"
+#define SKDEBUGCANVAS_ATTRIBUTE_UNIQUE_ID "uniqueID"
+#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_ATTRIBUTE_ZPLANE "zPlane"
+#define SKDEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION "lightPositions"
+#define SKDEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR "ambientColor"
+#define SKDEBUGCANVAS_ATTRIBUTE_SPOTCOLOR "spotColor"
+#define SKDEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS "lightRadius"
+
+#define SKDEBUGCANVAS_VERB_MOVE "move"
+#define SKDEBUGCANVAS_VERB_LINE "line"
+#define SKDEBUGCANVAS_VERB_QUAD "quad"
+#define SKDEBUGCANVAS_VERB_CUBIC "cubic"
+#define SKDEBUGCANVAS_VERB_CONIC "conic"
+#define SKDEBUGCANVAS_VERB_CLOSE "close"
+
+#define SKDEBUGCANVAS_STYLE_FILL "fill"
+#define SKDEBUGCANVAS_STYLE_STROKE "stroke"
+#define SKDEBUGCANVAS_STYLE_STROKEANDFILL "strokeAndFill"
+
+#define SKDEBUGCANVAS_POINTMODE_POINTS "points"
+#define SKDEBUGCANVAS_POINTMODE_LINES "lines"
+#define SKDEBUGCANVAS_POINTMODE_POLYGON "polygon"
+
+#define SKDEBUGCANVAS_REGIONOP_DIFFERENCE "difference"
+#define SKDEBUGCANVAS_REGIONOP_INTERSECT "intersect"
+#define SKDEBUGCANVAS_REGIONOP_UNION "union"
+#define SKDEBUGCANVAS_REGIONOP_XOR "xor"
+#define SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE "reverseDifference"
+#define SKDEBUGCANVAS_REGIONOP_REPLACE "replace"
+
+#define SKDEBUGCANVAS_BLURSTYLE_NORMAL "normal"
+#define SKDEBUGCANVAS_BLURSTYLE_SOLID "solid"
+#define SKDEBUGCANVAS_BLURSTYLE_OUTER "outer"
+#define SKDEBUGCANVAS_BLURSTYLE_INNER "inner"
+
+#define SKDEBUGCANVAS_BLURQUALITY_LOW "low"
+#define SKDEBUGCANVAS_BLURQUALITY_HIGH "high"
+
+#define SKDEBUGCANVAS_FILLTYPE_WINDING "winding"
+#define SKDEBUGCANVAS_FILLTYPE_EVENODD "evenOdd"
+#define SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING "inverseWinding"
+#define SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD "inverseEvenOdd"
+
+#define SKDEBUGCANVAS_CAP_BUTT "butt"
+#define SKDEBUGCANVAS_CAP_ROUND "round"
+#define SKDEBUGCANVAS_CAP_SQUARE "square"
+
+#define SKDEBUGCANVAS_MITER_JOIN "miter"
+#define SKDEBUGCANVAS_ROUND_JOIN "round"
+#define SKDEBUGCANVAS_BEVEL_JOIN "bevel"
+
+#define SKDEBUGCANVAS_COLORTYPE_ARGB4444 "ARGB4444"
+#define SKDEBUGCANVAS_COLORTYPE_RGBA8888 "RGBA8888"
+#define SKDEBUGCANVAS_COLORTYPE_BGRA8888 "BGRA8888"
+#define SKDEBUGCANVAS_COLORTYPE_565 "565"
+#define SKDEBUGCANVAS_COLORTYPE_GRAY8 "Gray8"
+#define SKDEBUGCANVAS_COLORTYPE_INDEX8 "Index8"
+#define SKDEBUGCANVAS_COLORTYPE_ALPHA8 "Alpha8"
+
+#define SKDEBUGCANVAS_ALPHATYPE_OPAQUE "opaque"
+#define SKDEBUGCANVAS_ALPHATYPE_PREMUL "premul"
+#define SKDEBUGCANVAS_ALPHATYPE_UNPREMUL "unpremul"
+#define SKDEBUGCANVAS_ALPHATYPE_UNKNOWN "unknown"
+
+#define SKDEBUGCANVAS_FILTERQUALITY_NONE "none"
+#define SKDEBUGCANVAS_FILTERQUALITY_LOW "low"
+#define SKDEBUGCANVAS_FILTERQUALITY_MEDIUM "medium"
+#define SKDEBUGCANVAS_FILTERQUALITY_HIGH "high"
+
+#define SKDEBUGCANVAS_HINTING_NONE "none"
+#define SKDEBUGCANVAS_HINTING_SLIGHT "slight"
+#define SKDEBUGCANVAS_HINTING_NORMAL "normal"
+#define SKDEBUGCANVAS_HINTING_FULL "full"
+
+#define SKDEBUGCANVAS_EDGING_ALIAS "alias"
+#define SKDEBUGCANVAS_EDGING_ANTIALIAS "antialias"
+#define SKDEBUGCANVAS_EDGING_SUBPIXELANTIALIAS "subpixelantialias"
+
+#define SKDEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC "transparentOccluder"
+#define SKDEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY "geometricOnly"
+
+static SkString* str_append(SkString* str, const SkRect& r) {
+ str->appendf(" [%g %g %g %g]", r.left(), r.top(), r.right(), r.bottom());
+ return str;
+}
+
+DrawCommand::DrawCommand(OpType type) : fOpType(type), fVisible(true) {}
+
+const char* DrawCommand::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";
+ case kClipRRect_OpType: return "ClipRRect";
+ case kConcat_OpType: return "Concat";
+ case kDrawAnnotation_OpType: return "DrawAnnotation";
+ case kDrawBitmap_OpType: return "DrawBitmap";
+ case kDrawBitmapLattice_OpType: return "DrawBitmapLattice";
+ case kDrawBitmapNine_OpType: return "DrawBitmapNine";
+ case kDrawBitmapRect_OpType: return "DrawBitmapRect";
+ 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 kDrawRect_OpType: return "DrawRect";
+ case kDrawRRect_OpType: return "DrawRRect";
+ case kDrawRegion_OpType: return "DrawRegion";
+ case kDrawShadow_OpType: return "DrawShadow";
+ case kDrawTextBlob_OpType: return "DrawTextBlob";
+ case kDrawVertices_OpType: return "DrawVertices";
+ case kDrawAtlas_OpType: return "DrawAtlas";
+ case kDrawDrawable_OpType: return "DrawDrawable";
+ case kDrawEdgeAAQuad_OpType: return "DrawEdgeAAQuad";
+ case kDrawEdgeAAImageSet_OpType: return "DrawEdgeAAImageSet";
+ case kEndDrawPicture_OpType: return "EndDrawPicture";
+ case kRestore_OpType: return "Restore";
+ case kSave_OpType: return "Save";
+ case kSaveLayer_OpType: return "SaveLayer";
+ case kSetMatrix_OpType: return "SetMatrix";
+ default:
+ SkDebugf("OpType error 0x%08x\n", type);
+ SkASSERT(0);
+ break;
+ }
+ SkDEBUGFAIL("DrawType UNUSED\n");
+ return nullptr;
+}
+
+void DrawCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_COMMAND, this->GetCommandString(fOpType));
+ writer.appendBool(SKDEBUGCANVAS_ATTRIBUTE_VISIBLE, this->isVisible());
+}
+
+namespace {
+
+void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) {
+ const SkISize& size = canvas->getBaseLayerSize();
+
+ static const SkScalar kInsetFrac = 0.9f; // Leave a border around object
+
+ canvas->translate(size.fWidth / 2.0f, size.fHeight / 2.0f);
+ if (bounds.width() > bounds.height()) {
+ canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.width()),
+ SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.width()));
+ } else {
+ canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.height()),
+ SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.height()));
+ }
+ canvas->translate(-bounds.centerX(), -bounds.centerY());
+}
+
+void render_path(SkCanvas* canvas, const SkPath& path) {
+ canvas->clear(0xFFFFFFFF);
+
+ const SkRect& bounds = path.getBounds();
+ if (bounds.isEmpty()) {
+ return;
+ }
+
+ SkAutoCanvasRestore acr(canvas, true);
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ 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::Make(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();
+
+ SkScalar xScale = SkIntToScalar(size.fWidth - 2) / input.width();
+ SkScalar yScale = SkIntToScalar(size.fHeight - 2) / input.height();
+
+ if (input.width() > input.height()) {
+ yScale *= input.height() / (float)input.width();
+ } else {
+ xScale *= input.width() / (float)input.height();
+ }
+
+ SkRect dst = SkRect::MakeXYWH(
+ SK_Scalar1, SK_Scalar1, xScale * input.width(), yScale * input.height());
+
+ static const int kNumBlocks = 8;
+
+ canvas->clear(0xFFFFFFFF);
+ SkISize block = {canvas->imageInfo().width() / kNumBlocks,
+ canvas->imageInfo().height() / kNumBlocks};
+ for (int y = 0; y < kNumBlocks; ++y) {
+ for (int x = 0; x < kNumBlocks; ++x) {
+ SkPaint paint;
+ paint.setColor((x + y) % 2 ? SK_ColorLTGRAY : SK_ColorDKGRAY);
+ SkRect r = SkRect::MakeXYWH(SkIntToScalar(x * block.width()),
+ SkIntToScalar(y * block.height()),
+ SkIntToScalar(block.width()),
+ SkIntToScalar(block.height()));
+ canvas->drawRect(r, paint);
+ }
+ }
+
+ canvas->drawBitmapRect(input, dst, nullptr);
+
+ if (srcRect) {
+ SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
+ srcRect->fTop * yScale + SK_Scalar1,
+ srcRect->fRight * xScale + SK_Scalar1,
+ srcRect->fBottom * yScale + SK_Scalar1);
+ SkPaint p;
+ p.setColor(SK_ColorRED);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawRect(r, p);
+ }
+}
+
+void render_rrect(SkCanvas* canvas, const SkRRect& rrect) {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ const SkRect& bounds = rrect.getBounds();
+
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawRRect(rrect, p);
+ canvas->restore();
+}
+
+void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ const SkRect& bounds = outer.getBounds();
+
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawDRRect(outer, inner, p);
+ canvas->restore();
+}
+
+void render_shadow(SkCanvas* canvas, const SkPath& path, SkDrawShadowRec rec) {
+ canvas->clear(0xFFFFFFFF);
+
+ const SkRect& bounds = path.getBounds();
+ if (bounds.isEmpty()) {
+ return;
+ }
+
+ SkAutoCanvasRestore acr(canvas, true);
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ rec.fAmbientColor = SK_ColorBLACK;
+ rec.fSpotColor = SK_ColorBLACK;
+ canvas->private_draw_shadow_rec(path, rec);
+}
+
+static const char* const gBlendModeMap[] = {
+ "clear", "src", "dst", "srcOver", "dstOver", "srcIn", "dstIn",
+ "srcOut", "dstOut", "srcATop", "dstATop", "xor", "plus", "modulate",
+
+ "screen",
+
+ "overlay", "darken", "lighten", "colorDodge", "colorBurn", "hardLight", "softLight",
+ "difference", "exclusion", "multiply",
+
+ "hue", "saturation", "color", "luminosity",
+};
+
+static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLastMode) + 1,
+ "blendMode mismatch");
+static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLuminosity) + 1,
+ "blendMode mismatch");
+
+void apply_paint_blend_mode(const SkPaint& paint, SkJSONWriter& writer) {
+ const auto mode = paint.getBlendMode();
+ if (mode != SkBlendMode::kSrcOver) {
+ SkASSERT(static_cast<size_t>(mode) < SK_ARRAY_COUNT(gBlendModeMap));
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE,
+ gBlendModeMap[static_cast<size_t>(mode)]);
+ }
+}
+
+}; // namespace
+
+void DrawCommand::MakeJsonColor(SkJSONWriter& writer, const SkColor color) {
+ writer.beginArray(nullptr, false);
+ writer.appendS32(SkColorGetA(color));
+ writer.appendS32(SkColorGetR(color));
+ writer.appendS32(SkColorGetG(color));
+ writer.appendS32(SkColorGetB(color));
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonColor4f(SkJSONWriter& writer, const SkColor4f& color) {
+ writer.beginArray(nullptr, false);
+ writer.appendFloat(color.fA);
+ writer.appendFloat(color.fR);
+ writer.appendFloat(color.fG);
+ writer.appendFloat(color.fB);
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, const SkPoint& point) {
+ writer.beginArray(nullptr, false);
+ writer.appendFloat(point.x());
+ writer.appendFloat(point.y());
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, SkScalar x, SkScalar y) {
+ writer.beginArray(nullptr, false);
+ writer.appendFloat(x);
+ writer.appendFloat(y);
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonPoint3(SkJSONWriter& writer, const SkPoint3& point) {
+ writer.beginArray(nullptr, false);
+ writer.appendFloat(point.x());
+ writer.appendFloat(point.y());
+ writer.appendFloat(point.z());
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonRect(SkJSONWriter& writer, const SkRect& rect) {
+ writer.beginArray(nullptr, false);
+ writer.appendFloat(rect.left());
+ writer.appendFloat(rect.top());
+ writer.appendFloat(rect.right());
+ writer.appendFloat(rect.bottom());
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonIRect(SkJSONWriter& writer, const SkIRect& rect) {
+ writer.beginArray(nullptr, false);
+ writer.appendS32(rect.left());
+ writer.appendS32(rect.top());
+ writer.appendS32(rect.right());
+ writer.appendS32(rect.bottom());
+ writer.endArray();
+}
+
+static void make_json_rrect(SkJSONWriter& writer, const SkRRect& rrect) {
+ writer.beginArray(nullptr, false);
+ DrawCommand::MakeJsonRect(writer, rrect.rect());
+ DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperLeft_Corner));
+ DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperRight_Corner));
+ DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerRight_Corner));
+ DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerLeft_Corner));
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonMatrix(SkJSONWriter& writer, const SkMatrix& matrix) {
+ writer.beginArray();
+ for (int r = 0; r < 3; ++r) {
+ writer.beginArray(nullptr, false);
+ for (int c = 0; c < 3; ++c) {
+ writer.appendFloat(matrix[r * 3 + c]);
+ }
+ writer.endArray();
+ }
+ writer.endArray();
+}
+
+void DrawCommand::MakeJsonPath(SkJSONWriter& writer, const SkPath& path) {
+ writer.beginObject();
+ switch (path.getFillType()) {
+ case SkPath::kWinding_FillType:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE, SKDEBUGCANVAS_FILLTYPE_WINDING);
+ break;
+ case SkPath::kEvenOdd_FillType:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE, SKDEBUGCANVAS_FILLTYPE_EVENODD);
+ break;
+ case SkPath::kInverseWinding_FillType:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE,
+ SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING);
+ break;
+ case SkPath::kInverseEvenOdd_FillType:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE,
+ SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD);
+ break;
+ }
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_VERBS);
+ SkPath::Iter iter(path, false);
+ SkPoint pts[4];
+ SkPath::Verb verb;
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ if (verb == SkPath::kClose_Verb) {
+ writer.appendString(SKDEBUGCANVAS_VERB_CLOSE);
+ continue;
+ }
+ writer.beginObject(); // verb
+ switch (verb) {
+ case SkPath::kLine_Verb: {
+ writer.appendName(SKDEBUGCANVAS_VERB_LINE);
+ MakeJsonPoint(writer, pts[1]);
+ break;
+ }
+ case SkPath::kQuad_Verb: {
+ writer.beginArray(SKDEBUGCANVAS_VERB_QUAD);
+ MakeJsonPoint(writer, pts[1]);
+ MakeJsonPoint(writer, pts[2]);
+ writer.endArray(); // quad coords
+ break;
+ }
+ case SkPath::kCubic_Verb: {
+ writer.beginArray(SKDEBUGCANVAS_VERB_CUBIC);
+ MakeJsonPoint(writer, pts[1]);
+ MakeJsonPoint(writer, pts[2]);
+ MakeJsonPoint(writer, pts[3]);
+ writer.endArray(); // cubic coords
+ break;
+ }
+ case SkPath::kConic_Verb: {
+ writer.beginArray(SKDEBUGCANVAS_VERB_CONIC);
+ MakeJsonPoint(writer, pts[1]);
+ MakeJsonPoint(writer, pts[2]);
+ writer.appendFloat(iter.conicWeight());
+ writer.endArray(); // conic coords
+ break;
+ }
+ case SkPath::kMove_Verb: {
+ writer.appendName(SKDEBUGCANVAS_VERB_MOVE);
+ MakeJsonPoint(writer, pts[0]);
+ break;
+ }
+ case SkPath::kClose_Verb:
+ case SkPath::kDone_Verb:
+ // Unreachable
+ break;
+ }
+ writer.endObject(); // verb
+ }
+ writer.endArray(); // verbs
+ writer.endObject(); // path
+}
+
+void DrawCommand::MakeJsonRegion(SkJSONWriter& writer, const SkRegion& region) {
+ // TODO: Actually serialize the rectangles, rather than just devolving to path
+ SkPath path;
+ region.getBoundaryPath(&path);
+ MakeJsonPath(writer, path);
+}
+
+static const char* regionop_name(SkClipOp op) {
+ switch (op) {
+ case kDifference_SkClipOp: return SKDEBUGCANVAS_REGIONOP_DIFFERENCE;
+ case kIntersect_SkClipOp: return SKDEBUGCANVAS_REGIONOP_INTERSECT;
+ case kUnion_SkClipOp: return SKDEBUGCANVAS_REGIONOP_UNION;
+ case kXOR_SkClipOp: return SKDEBUGCANVAS_REGIONOP_XOR;
+ case kReverseDifference_SkClipOp: return SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE;
+ case kReplace_SkClipOp: return SKDEBUGCANVAS_REGIONOP_REPLACE;
+ default: SkASSERT(false); return "<invalid region op>";
+ }
+}
+
+static const char* pointmode_name(SkCanvas::PointMode mode) {
+ switch (mode) {
+ case SkCanvas::kPoints_PointMode: return SKDEBUGCANVAS_POINTMODE_POINTS;
+ case SkCanvas::kLines_PointMode: return SKDEBUGCANVAS_POINTMODE_LINES;
+ case SkCanvas::kPolygon_PointMode: return SKDEBUGCANVAS_POINTMODE_POLYGON;
+ default: SkASSERT(false); return "<invalid point mode>";
+ }
+}
+
+static void store_scalar(SkJSONWriter& writer,
+ const char* key,
+ SkScalar value,
+ SkScalar defaultValue) {
+ if (value != defaultValue) {
+ writer.appendFloat(key, value);
+ }
+}
+
+static void store_bool(SkJSONWriter& writer, const char* key, bool value, bool defaultValue) {
+ if (value != defaultValue) {
+ writer.appendBool(key, value);
+ }
+}
+
+static SkString encode_data(const void* bytes,
+ size_t count,
+ const char* contentType,
+ UrlDataManager& urlDataManager) {
+ sk_sp<SkData> data(SkData::MakeWithCopy(bytes, count));
+ return urlDataManager.addData(data.get(), contentType);
+}
+
+void DrawCommand::flatten(const SkFlattenable* flattenable,
+ SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) {
+ SkBinaryWriteBuffer buffer;
+ flattenable->flatten(buffer);
+ void* data = sk_malloc_throw(buffer.bytesWritten());
+ buffer.writeToMemory(data);
+ SkString url =
+ encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_NAME, flattenable->getTypeName());
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
+
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_VALUES);
+ JsonWriteBuffer jsonBuffer(&writer, &urlDataManager);
+ flattenable->flatten(jsonBuffer);
+ writer.endObject(); // values
+
+ sk_free(data);
+}
+
+void DrawCommand::WritePNG(SkBitmap bitmap, SkWStream& out) {
+ SkPixmap pm;
+ SkAssertResult(bitmap.peekPixels(&pm));
+
+ SkPngEncoder::Options options;
+ options.fZLibLevel = 1;
+ options.fFilterFlags = SkPngEncoder::FilterFlag::kNone;
+ SkPngEncoder::Encode(&out, pm, options);
+}
+
+bool DrawCommand::flatten(const SkImage& image,
+ SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) {
+ size_t rowBytes = 4 * image.width();
+ SkAutoMalloc buffer(rowBytes * image.height());
+ SkImageInfo dstInfo =
+ SkImageInfo::Make(image.width(), image.height(), kN32_SkColorType, kPremul_SkAlphaType);
+ if (!image.readPixels(dstInfo, buffer.get(), rowBytes, 0, 0)) {
+ SkDebugf("readPixels failed\n");
+ return false;
+ }
+
+ SkBitmap bm;
+ bm.installPixels(dstInfo, buffer.get(), rowBytes);
+
+ SkDynamicMemoryWStream out;
+ DrawCommand::WritePNG(bm, out);
+ sk_sp<SkData> encoded = out.detachAsData();
+ SkString url = encode_data(encoded->data(), encoded->size(), "image/png", urlDataManager);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
+ return true;
+}
+
+static const char* color_type_name(SkColorType colorType) {
+ switch (colorType) {
+ case kARGB_4444_SkColorType: return SKDEBUGCANVAS_COLORTYPE_ARGB4444;
+ case kRGBA_8888_SkColorType: return SKDEBUGCANVAS_COLORTYPE_RGBA8888;
+ case kBGRA_8888_SkColorType: return SKDEBUGCANVAS_COLORTYPE_BGRA8888;
+ case kRGB_565_SkColorType: return SKDEBUGCANVAS_COLORTYPE_565;
+ case kGray_8_SkColorType: return SKDEBUGCANVAS_COLORTYPE_GRAY8;
+ case kAlpha_8_SkColorType: return SKDEBUGCANVAS_COLORTYPE_ALPHA8;
+ default: SkASSERT(false); return SKDEBUGCANVAS_COLORTYPE_RGBA8888;
+ }
+}
+
+static const char* alpha_type_name(SkAlphaType alphaType) {
+ switch (alphaType) {
+ case kOpaque_SkAlphaType: return SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
+ case kPremul_SkAlphaType: return SKDEBUGCANVAS_ALPHATYPE_PREMUL;
+ case kUnpremul_SkAlphaType: return SKDEBUGCANVAS_ALPHATYPE_UNPREMUL;
+ default: SkASSERT(false); return SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
+ }
+}
+
+bool DrawCommand::flatten(const SkBitmap& bitmap,
+ SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) {
+ sk_sp<SkImage> image(SkImage::MakeFromBitmap(bitmap));
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_COLOR, color_type_name(bitmap.colorType()));
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_ALPHA, alpha_type_name(bitmap.alphaType()));
+ bool success = flatten(*image, writer, urlDataManager);
+ return success;
+}
+
+static void apply_font_hinting(const SkFont& font, SkJSONWriter& writer) {
+ SkFontHinting hinting = font.getHinting();
+ if (hinting != SkPaintDefaults_Hinting) {
+ switch (hinting) {
+ case kNo_SkFontHinting:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_HINTING, SKDEBUGCANVAS_HINTING_NONE);
+ break;
+ case kSlight_SkFontHinting:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_HINTING, SKDEBUGCANVAS_HINTING_SLIGHT);
+ break;
+ case kNormal_SkFontHinting:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_HINTING, SKDEBUGCANVAS_HINTING_NORMAL);
+ break;
+ case kFull_SkFontHinting:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_HINTING, SKDEBUGCANVAS_HINTING_FULL);
+ break;
+ }
+ }
+}
+
+static void apply_font_edging(const SkFont& font, SkJSONWriter& writer) {
+ switch (font.getEdging()) {
+ case SkFont::Edging::kAlias:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_EDGING, SKDEBUGCANVAS_EDGING_ALIAS);
+ break;
+ case SkFont::Edging::kAntiAlias:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_EDGING, SKDEBUGCANVAS_EDGING_ANTIALIAS);
+ break;
+ case SkFont::Edging::kSubpixelAntiAlias:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_EDGING,
+ SKDEBUGCANVAS_EDGING_SUBPIXELANTIALIAS);
+ break;
+ }
+}
+
+static void apply_paint_color(const SkPaint& paint, SkJSONWriter& writer) {
+ SkColor color = paint.getColor();
+ if (color != SK_ColorBLACK) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COLOR);
+ DrawCommand::MakeJsonColor(writer, color);
+ }
+}
+
+static void apply_paint_style(const SkPaint& paint, SkJSONWriter& writer) {
+ SkPaint::Style style = paint.getStyle();
+ if (style != SkPaint::kFill_Style) {
+ switch (style) {
+ case SkPaint::kStroke_Style: {
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STYLE, SKDEBUGCANVAS_STYLE_STROKE);
+ break;
+ }
+ case SkPaint::kStrokeAndFill_Style: {
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STYLE,
+ SKDEBUGCANVAS_STYLE_STROKEANDFILL);
+ break;
+ }
+ default: SkASSERT(false);
+ }
+ }
+}
+
+static void apply_paint_cap(const SkPaint& paint, SkJSONWriter& writer) {
+ SkPaint::Cap cap = paint.getStrokeCap();
+ if (cap != SkPaint::kDefault_Cap) {
+ switch (cap) {
+ case SkPaint::kButt_Cap:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_CAP, SKDEBUGCANVAS_CAP_BUTT);
+ break;
+ case SkPaint::kRound_Cap:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_CAP, SKDEBUGCANVAS_CAP_ROUND);
+ break;
+ case SkPaint::kSquare_Cap:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_CAP, SKDEBUGCANVAS_CAP_SQUARE);
+ break;
+ default: SkASSERT(false);
+ }
+ }
+}
+
+static void apply_paint_join(const SkPaint& paint, SkJSONWriter& writer) {
+ SkPaint::Join join = paint.getStrokeJoin();
+ if (join != SkPaint::kDefault_Join) {
+ switch (join) {
+ case SkPaint::kMiter_Join:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN, SKDEBUGCANVAS_MITER_JOIN);
+ break;
+ case SkPaint::kRound_Join:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN, SKDEBUGCANVAS_ROUND_JOIN);
+ break;
+ case SkPaint::kBevel_Join:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN, SKDEBUGCANVAS_BEVEL_JOIN);
+ break;
+ default: SkASSERT(false);
+ }
+ }
+}
+
+static void apply_paint_filterquality(const SkPaint& paint, SkJSONWriter& writer) {
+ SkFilterQuality quality = paint.getFilterQuality();
+ switch (quality) {
+ case kNone_SkFilterQuality: break;
+ case kLow_SkFilterQuality:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY,
+ SKDEBUGCANVAS_FILTERQUALITY_LOW);
+ break;
+ case kMedium_SkFilterQuality:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY,
+ SKDEBUGCANVAS_FILTERQUALITY_MEDIUM);
+ break;
+ case kHigh_SkFilterQuality:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY,
+ SKDEBUGCANVAS_FILTERQUALITY_HIGH);
+ break;
+ }
+}
+
+static void apply_paint_maskfilter(const SkPaint& paint,
+ SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) {
+ SkMaskFilter* maskFilter = paint.getMaskFilter();
+ if (maskFilter != nullptr) {
+ SkMaskFilterBase::BlurRec blurRec;
+ if (as_MFB(maskFilter)->asABlur(&blurRec)) {
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_BLUR);
+ writer.appendFloat(SKDEBUGCANVAS_ATTRIBUTE_SIGMA, blurRec.fSigma);
+ switch (blurRec.fStyle) {
+ case SkBlurStyle::kNormal_SkBlurStyle:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STYLE,
+ SKDEBUGCANVAS_BLURSTYLE_NORMAL);
+ break;
+ case SkBlurStyle::kSolid_SkBlurStyle:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STYLE,
+ SKDEBUGCANVAS_BLURSTYLE_SOLID);
+ break;
+ case SkBlurStyle::kOuter_SkBlurStyle:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STYLE,
+ SKDEBUGCANVAS_BLURSTYLE_OUTER);
+ break;
+ case SkBlurStyle::kInner_SkBlurStyle:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_STYLE,
+ SKDEBUGCANVAS_BLURSTYLE_INNER);
+ break;
+ default: SkASSERT(false);
+ }
+ writer.endObject(); // blur
+ } else {
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER);
+ DrawCommand::flatten(maskFilter, writer, urlDataManager);
+ writer.endObject(); // maskFilter
+ }
+ }
+}
+
+static void apply_paint_patheffect(const SkPaint& paint,
+ SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) {
+ SkPathEffect* pathEffect = paint.getPathEffect();
+ if (pathEffect != nullptr) {
+ SkPathEffect::DashInfo dashInfo;
+ SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo);
+ if (dashType == SkPathEffect::kDash_DashType) {
+ dashInfo.fIntervals = (SkScalar*)sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar));
+ pathEffect->asADash(&dashInfo);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_DASHING);
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_INTERVALS, false);
+ for (int32_t i = 0; i < dashInfo.fCount; i++) {
+ writer.appendFloat(dashInfo.fIntervals[i]);
+ }
+ writer.endArray(); // intervals
+ sk_free(dashInfo.fIntervals);
+ writer.appendFloat(SKDEBUGCANVAS_ATTRIBUTE_PHASE, dashInfo.fPhase);
+ writer.endObject(); // dashing
+ } else {
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT);
+ DrawCommand::flatten(pathEffect, writer, urlDataManager);
+ writer.endObject(); // pathEffect
+ }
+ }
+}
+
+static void apply_font_typeface(const SkFont& font,
+ SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) {
+ SkTypeface* typeface = font.getTypefaceOrDefault();
+ if (typeface != nullptr) {
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE);
+ SkDynamicMemoryWStream buffer;
+ typeface->serialize(&buffer);
+ void* data = sk_malloc_throw(buffer.bytesWritten());
+ buffer.copyTo(data);
+ SkString url = encode_data(
+ data, buffer.bytesWritten(), "application/octet-stream", urlDataManager);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
+ sk_free(data);
+ writer.endObject();
+ }
+}
+
+static void apply_flattenable(const char* key,
+ SkFlattenable* flattenable,
+ SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) {
+ if (flattenable != nullptr) {
+ writer.beginObject(key);
+ DrawCommand::flatten(flattenable, writer, urlDataManager);
+ writer.endObject();
+ }
+}
+
+void DrawCommand::MakeJsonPaint(SkJSONWriter& writer,
+ const SkPaint& paint,
+ UrlDataManager& urlDataManager) {
+ writer.beginObject();
+ store_scalar(writer, SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f);
+ store_scalar(writer,
+ SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER,
+ paint.getStrokeMiter(),
+ SkPaintDefaults_MiterLimit);
+ store_bool(writer, SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false);
+ store_bool(writer, SKDEBUGCANVAS_ATTRIBUTE_DITHER, paint.isDither(), false);
+
+ apply_paint_color(paint, writer);
+ apply_paint_style(paint, writer);
+ apply_paint_blend_mode(paint, writer);
+ apply_paint_cap(paint, writer);
+ apply_paint_join(paint, writer);
+ apply_paint_filterquality(paint, writer);
+ apply_paint_patheffect(paint, writer, urlDataManager);
+ apply_paint_maskfilter(paint, writer, urlDataManager);
+ apply_flattenable(SKDEBUGCANVAS_ATTRIBUTE_SHADER, paint.getShader(), writer, urlDataManager);
+ apply_flattenable(SKDEBUGCANVAS_ATTRIBUTE_LOOPER, paint.getLooper(), writer, urlDataManager);
+ apply_flattenable(
+ SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER, paint.getImageFilter(), writer, urlDataManager);
+ apply_flattenable(
+ SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER, paint.getColorFilter(), writer, urlDataManager);
+ writer.endObject(); // paint
+}
+
+static void MakeJsonFont(const SkFont& font, SkJSONWriter& writer, UrlDataManager& urlDataManager) {
+ writer.beginObject();
+ store_bool(writer, SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT, font.isEmbolden(), false);
+ store_bool(writer, SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT, font.isLinearMetrics(), false);
+ store_bool(writer, SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT, font.isSubpixel(), false);
+ store_bool(writer, SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT, font.isEmbeddedBitmaps(), false);
+ store_bool(writer, SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING, font.isForceAutoHinting(), false);
+
+ store_scalar(
+ writer, SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE, font.getSize(), SkPaintDefaults_TextSize);
+ store_scalar(writer, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getScaleX(), SK_Scalar1);
+ store_scalar(writer, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getSkewX(), 0.0f);
+ apply_font_edging(font, writer);
+ apply_font_hinting(font, writer);
+ apply_font_typeface(font, writer, urlDataManager);
+ writer.endObject(); // font
+}
+
+void DrawCommand::MakeJsonLattice(SkJSONWriter& writer, const SkCanvas::Lattice& lattice) {
+ writer.beginObject();
+ writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT, lattice.fXCount);
+ writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT, lattice.fYCount);
+ if (nullptr != lattice.fBounds) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_BOUNDS);
+ MakeJsonIRect(writer, *lattice.fBounds);
+ }
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS);
+ for (int i = 0; i < lattice.fXCount; i++) {
+ writer.appendS32(lattice.fXDivs[i]);
+ }
+ writer.endArray(); // xdivs
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS);
+ for (int i = 0; i < lattice.fYCount; i++) {
+ writer.appendS32(lattice.fYDivs[i]);
+ }
+ writer.endArray(); // ydivs
+ if (nullptr != lattice.fRectTypes) {
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS);
+ int flagCount = 0;
+ for (int row = 0; row < lattice.fYCount + 1; row++) {
+ writer.beginArray();
+ for (int column = 0; column < lattice.fXCount + 1; column++) {
+ writer.appendS32(lattice.fRectTypes[flagCount++]);
+ }
+ writer.endArray(); // row
+ }
+ writer.endArray();
+ }
+ writer.endObject();
+}
+
+SkClearCommand::SkClearCommand(SkColor color) : INHERITED(kClear_OpType) { fColor = color; }
+
+void SkClearCommand::execute(SkCanvas* canvas) const { canvas->clear(fColor); }
+
+void SkClearCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COLOR);
+ MakeJsonColor(writer, fColor);
+}
+
+SkClipPathCommand::SkClipPathCommand(const SkPath& path, SkClipOp op, bool doAA)
+ : INHERITED(kClipPath_OpType) {
+ fPath = path;
+ fOp = op;
+ fDoAA = doAA;
+}
+
+void SkClipPathCommand::execute(SkCanvas* canvas) const { canvas->clipPath(fPath, fOp, fDoAA); }
+
+bool SkClipPathCommand::render(SkCanvas* canvas) const {
+ render_path(canvas, fPath);
+ return true;
+}
+
+void SkClipPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PATH);
+ MakeJsonPath(writer, fPath);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+ writer.appendBool(SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
+}
+
+SkClipRegionCommand::SkClipRegionCommand(const SkRegion& region, SkClipOp op)
+ : INHERITED(kClipRegion_OpType) {
+ fRegion = region;
+ fOp = op;
+}
+
+void SkClipRegionCommand::execute(SkCanvas* canvas) const { canvas->clipRegion(fRegion, fOp); }
+
+void SkClipRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_REGION);
+ MakeJsonRegion(writer, fRegion);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+}
+
+SkClipRectCommand::SkClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA)
+ : INHERITED(kClipRect_OpType) {
+ fRect = rect;
+ fOp = op;
+ fDoAA = doAA;
+}
+
+void SkClipRectCommand::execute(SkCanvas* canvas) const { canvas->clipRect(fRect, fOp, fDoAA); }
+
+void SkClipRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonRect(writer, fRect);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+ writer.appendBool(SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
+
+ SkString desc;
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fRect)->c_str());
+}
+
+SkClipRRectCommand::SkClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA)
+ : INHERITED(kClipRRect_OpType) {
+ fRRect = rrect;
+ fOp = op;
+ fDoAA = doAA;
+}
+
+void SkClipRRectCommand::execute(SkCanvas* canvas) const { canvas->clipRRect(fRRect, fOp, fDoAA); }
+
+bool SkClipRRectCommand::render(SkCanvas* canvas) const {
+ render_rrect(canvas, fRRect);
+ return true;
+}
+
+void SkClipRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ make_json_rrect(writer, fRRect);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
+ writer.appendBool(SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
+}
+
+SkConcatCommand::SkConcatCommand(const SkMatrix& matrix) : INHERITED(kConcat_OpType) {
+ fMatrix = matrix;
+}
+
+void SkConcatCommand::execute(SkCanvas* canvas) const { canvas->concat(fMatrix); }
+
+void SkConcatCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_MATRIX);
+ MakeJsonMatrix(writer, fMatrix);
+}
+
+////
+
+SkDrawAnnotationCommand::SkDrawAnnotationCommand(const SkRect& rect,
+ const char key[],
+ sk_sp<SkData> value)
+ : INHERITED(kDrawAnnotation_OpType), fRect(rect), fKey(key), fValue(std::move(value)) {}
+
+void SkDrawAnnotationCommand::execute(SkCanvas* canvas) const {
+ canvas->drawAnnotation(fRect, fKey.c_str(), fValue);
+}
+
+void SkDrawAnnotationCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonRect(writer, fRect);
+ writer.appendString("key", fKey.c_str());
+ if (fValue.get()) {
+ // TODO: dump out the "value"
+ }
+
+ SkString desc;
+ str_append(&desc, fRect)->appendf(" %s", fKey.c_str());
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, desc.c_str());
+}
+
+////
+
+SkDrawBitmapCommand::SkDrawBitmapCommand(const SkBitmap& bitmap,
+ SkScalar left,
+ SkScalar top,
+ const SkPaint* paint)
+ : INHERITED(kDrawBitmap_OpType), fBitmap(bitmap), fLeft(left), fTop(top), fPaint(paint) {}
+
+void SkDrawBitmapCommand::execute(SkCanvas* canvas) const {
+ canvas->drawBitmap(fBitmap, fLeft, fTop, fPaint.getMaybeNull());
+}
+
+bool SkDrawBitmapCommand::render(SkCanvas* canvas) const {
+ render_bitmap(canvas, fBitmap);
+ return true;
+}
+
+void SkDrawBitmapCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_BITMAP);
+ flatten(fBitmap, writer, urlDataManager);
+ writer.endObject();
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonPoint(writer, fLeft, fTop);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+}
+
+SkDrawBitmapLatticeCommand::SkDrawBitmapLatticeCommand(const SkBitmap& bitmap,
+ const SkCanvas::Lattice& lattice,
+ const SkRect& dst,
+ const SkPaint* paint)
+ : INHERITED(kDrawBitmapLattice_OpType)
+ , fBitmap(bitmap)
+ , fLattice(lattice)
+ , fDst(dst)
+ , fPaint(paint) {}
+
+void SkDrawBitmapLatticeCommand::execute(SkCanvas* canvas) const {
+ canvas->drawBitmapLattice(fBitmap, fLattice, fDst, fPaint.getMaybeNull());
+}
+
+bool SkDrawBitmapLatticeCommand::render(SkCanvas* canvas) const {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clear(0xFFFFFFFF);
+
+ xlate_and_scale_to_bounds(canvas, fDst);
+
+ this->execute(canvas);
+ return true;
+}
+
+void SkDrawBitmapLatticeCommand::toJSON(SkJSONWriter& writer,
+ UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_BITMAP);
+ flatten(fBitmap, writer, urlDataManager);
+ writer.endObject(); // bitmap
+
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_LATTICE);
+ MakeJsonLattice(writer, fLattice);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_DST);
+ MakeJsonRect(writer, fDst);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+
+ SkString desc;
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+SkDrawBitmapNineCommand::SkDrawBitmapNineCommand(const SkBitmap& bitmap,
+ const SkIRect& center,
+ const SkRect& dst,
+ const SkPaint* paint)
+ : INHERITED(kDrawBitmapNine_OpType)
+ , fBitmap(bitmap)
+ , fCenter(center)
+ , fDst(dst)
+ , fPaint(paint) {}
+
+void SkDrawBitmapNineCommand::execute(SkCanvas* canvas) const {
+ canvas->drawBitmapNine(fBitmap, fCenter, fDst, fPaint.getMaybeNull());
+}
+
+bool SkDrawBitmapNineCommand::render(SkCanvas* canvas) const {
+ SkRect tmp = SkRect::Make(fCenter);
+ render_bitmap(canvas, fBitmap, &tmp);
+ return true;
+}
+
+void SkDrawBitmapNineCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_BITMAP);
+ flatten(fBitmap, writer, urlDataManager);
+ writer.endObject(); // bitmap
+
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_CENTER);
+ MakeJsonIRect(writer, fCenter);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_DST);
+ MakeJsonRect(writer, fDst);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+}
+
+SkDrawBitmapRectCommand::SkDrawBitmapRectCommand(const SkBitmap& bitmap,
+ const SkRect* src,
+ const SkRect& dst,
+ const SkPaint* paint,
+ SkCanvas::SrcRectConstraint constraint)
+ : INHERITED(kDrawBitmapRect_OpType)
+ , fBitmap(bitmap)
+ , fSrc(src)
+ , fDst(dst)
+ , fPaint(paint)
+ , fConstraint(constraint) {}
+
+void SkDrawBitmapRectCommand::execute(SkCanvas* canvas) const {
+ canvas->legacy_drawBitmapRect(
+ fBitmap, fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), fConstraint);
+}
+
+bool SkDrawBitmapRectCommand::render(SkCanvas* canvas) const {
+ render_bitmap(canvas, fBitmap, fSrc.getMaybeNull());
+ return true;
+}
+
+void SkDrawBitmapRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_BITMAP);
+ flatten(fBitmap, writer, urlDataManager);
+ writer.endObject(); // bitmap
+
+ if (fSrc.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_SRC);
+ MakeJsonRect(writer, *fSrc);
+ }
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_DST);
+ MakeJsonRect(writer, fDst);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+ if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
+ writer.appendBool(SKDEBUGCANVAS_ATTRIBUTE_STRICT, true);
+ }
+
+ SkString desc;
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+SkDrawImageCommand::SkDrawImageCommand(const SkImage* image,
+ SkScalar left,
+ SkScalar top,
+ const SkPaint* paint)
+ : INHERITED(kDrawImage_OpType)
+ , fImage(SkRef(image))
+ , fLeft(left)
+ , fTop(top)
+ , fPaint(paint) {}
+
+void SkDrawImageCommand::execute(SkCanvas* canvas) const {
+ canvas->drawImage(fImage.get(), fLeft, fTop, fPaint.getMaybeNull());
+}
+
+bool SkDrawImageCommand::render(SkCanvas* canvas) const {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clear(0xFFFFFFFF);
+
+ xlate_and_scale_to_bounds(
+ canvas,
+ SkRect::MakeXYWH(
+ fLeft, fTop, SkIntToScalar(fImage->width()), SkIntToScalar(fImage->height())));
+ this->execute(canvas);
+ return true;
+}
+
+void SkDrawImageCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_IMAGE);
+ flatten(*fImage, writer, urlDataManager);
+ writer.endObject(); // image
+
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonPoint(writer, fLeft, fTop);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+
+ writer.appendU32(SKDEBUGCANVAS_ATTRIBUTE_UNIQUE_ID, fImage->uniqueID());
+ writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_WIDTH, fImage->width());
+ writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_HEIGHT, fImage->height());
+ switch (fImage->alphaType()) {
+ case kOpaque_SkAlphaType:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_ALPHA, SKDEBUGCANVAS_ALPHATYPE_OPAQUE);
+ break;
+ case kPremul_SkAlphaType:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_ALPHA, SKDEBUGCANVAS_ALPHATYPE_PREMUL);
+ break;
+ case kUnpremul_SkAlphaType:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_ALPHA, SKDEBUGCANVAS_ALPHATYPE_UNPREMUL);
+ break;
+ default:
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_ALPHA, SKDEBUGCANVAS_ALPHATYPE_UNKNOWN);
+ break;
+ }
+}
+
+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)
+ , fPaint(paint) {}
+
+void SkDrawImageLatticeCommand::execute(SkCanvas* canvas) const {
+ canvas->drawImageLattice(fImage.get(), fLattice, fDst, fPaint.getMaybeNull());
+}
+
+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;
+}
+
+void SkDrawImageLatticeCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_IMAGE);
+ flatten(*fImage, writer, urlDataManager);
+ writer.endObject(); // image
+
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_LATTICE);
+ MakeJsonLattice(writer, fLattice);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_DST);
+ MakeJsonRect(writer, fDst);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+
+ SkString desc;
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+SkDrawImageRectCommand::SkDrawImageRectCommand(const SkImage* image,
+ const SkRect* src,
+ const SkRect& dst,
+ const SkPaint* paint,
+ SkCanvas::SrcRectConstraint constraint)
+ : INHERITED(kDrawImageRect_OpType)
+ , fImage(SkRef(image))
+ , fSrc(src)
+ , fDst(dst)
+ , fPaint(paint)
+ , fConstraint(constraint) {}
+
+void SkDrawImageRectCommand::execute(SkCanvas* canvas) const {
+ canvas->legacy_drawImageRect(
+ fImage.get(), fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), fConstraint);
+}
+
+bool SkDrawImageRectCommand::render(SkCanvas* canvas) const {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clear(0xFFFFFFFF);
+
+ xlate_and_scale_to_bounds(canvas, fDst);
+
+ this->execute(canvas);
+ return true;
+}
+
+void SkDrawImageRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_IMAGE);
+ flatten(*fImage, writer, urlDataManager);
+ writer.endObject(); // image
+
+ if (fSrc.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_SRC);
+ MakeJsonRect(writer, *fSrc);
+ }
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_DST);
+ MakeJsonRect(writer, fDst);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+ if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
+ writer.appendBool(SKDEBUGCANVAS_ATTRIBUTE_STRICT, true);
+ }
+
+ SkString desc;
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
+}
+
+SkDrawImageNineCommand::SkDrawImageNineCommand(const SkImage* image,
+ const SkIRect& center,
+ const SkRect& dst,
+ const SkPaint* paint)
+ : INHERITED(kDrawImageNine_OpType)
+ , fImage(SkRef(image))
+ , fCenter(center)
+ , fDst(dst)
+ , fPaint(paint) {}
+
+void SkDrawImageNineCommand::execute(SkCanvas* canvas) const {
+ canvas->drawImageNine(fImage.get(), fCenter, fDst, fPaint.getMaybeNull());
+}
+
+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;
+}
+
+void SkDrawImageNineCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_IMAGE);
+ flatten(*fImage, writer, urlDataManager);
+ writer.endObject(); // image
+
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_CENTER);
+ MakeJsonIRect(writer, fCenter);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_DST);
+ MakeJsonRect(writer, fDst);
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+}
+
+SkDrawOvalCommand::SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint)
+ : INHERITED(kDrawOval_OpType) {
+ fOval = oval;
+ fPaint = paint;
+}
+
+void SkDrawOvalCommand::execute(SkCanvas* canvas) const { canvas->drawOval(fOval, fPaint); }
+
+bool SkDrawOvalCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ xlate_and_scale_to_bounds(canvas, fOval);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawOval(fOval, p);
+ canvas->restore();
+
+ return true;
+}
+
+void SkDrawOvalCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonRect(writer, fOval);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkDrawArcCommand::SkDrawArcCommand(const SkRect& oval,
+ SkScalar startAngle,
+ SkScalar sweepAngle,
+ bool useCenter,
+ const SkPaint& paint)
+ : INHERITED(kDrawArc_OpType) {
+ fOval = oval;
+ fStartAngle = startAngle;
+ fSweepAngle = sweepAngle;
+ fUseCenter = useCenter;
+ fPaint = paint;
+}
+
+void SkDrawArcCommand::execute(SkCanvas* canvas) const {
+ canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, fPaint);
+}
+
+bool SkDrawArcCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ xlate_and_scale_to_bounds(canvas, fOval);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, p);
+ canvas->restore();
+
+ return true;
+}
+
+void SkDrawArcCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonRect(writer, fOval);
+ writer.appendFloat(SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE, fStartAngle);
+ writer.appendFloat(SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE, fSweepAngle);
+ writer.appendBool(SKDEBUGCANVAS_ATTRIBUTE_USECENTER, fUseCenter);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkDrawPaintCommand::SkDrawPaintCommand(const SkPaint& paint) : INHERITED(kDrawPaint_OpType) {
+ fPaint = paint;
+}
+
+void SkDrawPaintCommand::execute(SkCanvas* canvas) const { canvas->drawPaint(fPaint); }
+
+bool SkDrawPaintCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->drawPaint(fPaint);
+ return true;
+}
+
+void SkDrawPaintCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkDrawPathCommand::SkDrawPathCommand(const SkPath& path, const SkPaint& paint)
+ : INHERITED(kDrawPath_OpType) {
+ fPath = path;
+ fPaint = paint;
+}
+
+void SkDrawPathCommand::execute(SkCanvas* canvas) const { canvas->drawPath(fPath, fPaint); }
+
+bool SkDrawPathCommand::render(SkCanvas* canvas) const {
+ render_path(canvas, fPath);
+ return true;
+}
+
+void SkDrawPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PATH);
+ MakeJsonPath(writer, fPath);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkDrawRegionCommand::SkDrawRegionCommand(const SkRegion& region, const SkPaint& paint)
+ : INHERITED(kDrawRegion_OpType) {
+ fRegion = region;
+ fPaint = paint;
+}
+
+void SkDrawRegionCommand::execute(SkCanvas* canvas) const { canvas->drawRegion(fRegion, fPaint); }
+
+bool SkDrawRegionCommand::render(SkCanvas* canvas) const {
+ render_region(canvas, fRegion);
+ return true;
+}
+
+void SkDrawRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_REGION);
+ MakeJsonRegion(writer, fRegion);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkBeginDrawPictureCommand::SkBeginDrawPictureCommand(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint)
+ : INHERITED(kBeginDrawPicture_OpType)
+ , fPicture(SkRef(picture))
+ , fMatrix(matrix)
+ , fPaint(paint) {}
+
+void SkBeginDrawPictureCommand::execute(SkCanvas* canvas) const {
+ if (fPaint.isValid()) {
+ SkRect bounds = fPicture->cullRect();
+ if (fMatrix.isValid()) {
+ fMatrix->mapRect(&bounds);
+ }
+ canvas->saveLayer(&bounds, fPaint.get());
+ }
+
+ if (fMatrix.isValid()) {
+ if (!fPaint.isValid()) {
+ canvas->save();
+ }
+ canvas->concat(*fMatrix);
+ }
+}
+
+bool SkBeginDrawPictureCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ xlate_and_scale_to_bounds(canvas, fPicture->cullRect());
+
+ canvas->drawPicture(fPicture.get());
+
+ canvas->restore();
+
+ return true;
+}
+
+SkEndDrawPictureCommand::SkEndDrawPictureCommand(bool restore)
+ : INHERITED(kEndDrawPicture_OpType), fRestore(restore) {}
+
+void SkEndDrawPictureCommand::execute(SkCanvas* canvas) const {
+ if (fRestore) {
+ canvas->restore();
+ }
+}
+
+SkDrawPointsCommand::SkDrawPointsCommand(SkCanvas::PointMode mode,
+ size_t count,
+ const SkPoint pts[],
+ const SkPaint& paint)
+ : INHERITED(kDrawPoints_OpType), fMode(mode), fPts(pts, count), fPaint(paint) {}
+
+void SkDrawPointsCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPoints(fMode, fPts.count(), fPts.begin(), fPaint);
+}
+
+bool SkDrawPointsCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ SkRect bounds;
+
+ bounds.setEmpty();
+ for (int i = 0; i < fPts.count(); ++i) {
+ SkRectPriv::GrowToInclude(&bounds, fPts[i]);
+ }
+
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawPoints(fMode, fPts.count(), fPts.begin(), p);
+ canvas->restore();
+
+ return true;
+}
+
+void SkDrawPointsCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_MODE, pointmode_name(fMode));
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_POINTS);
+ for (int i = 0; i < fPts.count(); i++) {
+ MakeJsonPoint(writer, fPts[i]);
+ }
+ writer.endArray(); // points
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkDrawTextBlobCommand::SkDrawTextBlobCommand(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint)
+ : INHERITED(kDrawTextBlob_OpType)
+ , fBlob(std::move(blob))
+ , fXPos(x)
+ , fYPos(y)
+ , fPaint(paint) {}
+
+void SkDrawTextBlobCommand::execute(SkCanvas* canvas) const {
+ canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
+}
+
+bool SkDrawTextBlobCommand::render(SkCanvas* canvas) const {
+ canvas->clear(SK_ColorWHITE);
+ canvas->save();
+
+ SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos);
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
+
+ canvas->restore();
+
+ return true;
+}
+
+void SkDrawTextBlobCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_RUNS);
+ SkTextBlobRunIterator iter(fBlob.get());
+ while (!iter.done()) {
+ writer.beginObject(); // run
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_GLYPHS);
+ for (uint32_t i = 0; i < iter.glyphCount(); i++) {
+ writer.appendU32(iter.glyphs()[i]);
+ }
+ writer.endArray(); // glyphs
+ if (iter.positioning() != SkTextBlobRunIterator::kDefault_Positioning) {
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_POSITIONS);
+ const SkScalar* iterPositions = iter.pos();
+ for (uint32_t i = 0; i < iter.glyphCount(); i++) {
+ switch (iter.positioning()) {
+ case SkTextBlobRunIterator::kFull_Positioning:
+ MakeJsonPoint(writer, iterPositions[i * 2], iterPositions[i * 2 + 1]);
+ break;
+ case SkTextBlobRunIterator::kHorizontal_Positioning:
+ writer.appendFloat(iterPositions[i]);
+ break;
+ case SkTextBlobRunIterator::kDefault_Positioning: break;
+ case SkTextBlobRunIterator::kRSXform_Positioning:
+ // TODO_RSXFORM_BLOB
+ break;
+ }
+ }
+ writer.endArray(); // positions
+ }
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_FONT);
+ MakeJsonFont(iter.font(), writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonPoint(writer, iter.offset());
+
+ writer.endObject(); // run
+ iter.next();
+ }
+ writer.endArray(); // runs
+ writer.appendFloat(SKDEBUGCANVAS_ATTRIBUTE_X, fXPos);
+ writer.appendFloat(SKDEBUGCANVAS_ATTRIBUTE_Y, fYPos);
+ SkRect bounds = fBlob->bounds();
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonRect(writer, bounds);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+
+ SkString desc;
+ // make the bounds local by applying the x,y
+ bounds.offset(fXPos, fYPos);
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, bounds)->c_str());
+}
+
+SkDrawPatchCommand::SkDrawPatchCommand(const SkPoint cubics[12],
+ const SkColor colors[4],
+ const SkPoint texCoords[4],
+ SkBlendMode bmode,
+ const SkPaint& paint)
+ : INHERITED(kDrawPatch_OpType), fBlendMode(bmode) {
+ memcpy(fCubics, cubics, sizeof(fCubics));
+ if (colors != nullptr) {
+ memcpy(fColors, colors, sizeof(fColors));
+ fColorsPtr = fColors;
+ } else {
+ fColorsPtr = nullptr;
+ }
+ if (texCoords != nullptr) {
+ memcpy(fTexCoords, texCoords, sizeof(fTexCoords));
+ fTexCoordsPtr = fTexCoords;
+ } else {
+ fTexCoordsPtr = nullptr;
+ }
+ fPaint = paint;
+}
+
+void SkDrawPatchCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fBlendMode, fPaint);
+}
+
+void SkDrawPatchCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_CUBICS);
+ for (int i = 0; i < 12; i++) {
+ MakeJsonPoint(writer, fCubics[i]);
+ }
+ writer.endArray(); // cubics
+ if (fColorsPtr != nullptr) {
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_COLORS);
+ for (int i = 0; i < 4; i++) {
+ MakeJsonColor(writer, fColorsPtr[i]);
+ }
+ writer.endArray(); // colors
+ }
+ if (fTexCoordsPtr != nullptr) {
+ writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS);
+ for (int i = 0; i < 4; i++) {
+ MakeJsonPoint(writer, fTexCoords[i]);
+ }
+ writer.endArray(); // texCoords
+ }
+ // fBlendMode
+}
+
+SkDrawRectCommand::SkDrawRectCommand(const SkRect& rect, const SkPaint& paint)
+ : INHERITED(kDrawRect_OpType) {
+ fRect = rect;
+ fPaint = paint;
+}
+
+void SkDrawRectCommand::execute(SkCanvas* canvas) const { canvas->drawRect(fRect, fPaint); }
+
+void SkDrawRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ MakeJsonRect(writer, fRect);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+
+ SkString desc;
+ writer.appendString(SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fRect)->c_str());
+}
+
+SkDrawRRectCommand::SkDrawRRectCommand(const SkRRect& rrect, const SkPaint& paint)
+ : INHERITED(kDrawRRect_OpType) {
+ fRRect = rrect;
+ fPaint = paint;
+}
+
+void SkDrawRRectCommand::execute(SkCanvas* canvas) const { canvas->drawRRect(fRRect, fPaint); }
+
+bool SkDrawRRectCommand::render(SkCanvas* canvas) const {
+ render_rrect(canvas, fRRect);
+ return true;
+}
+
+void SkDrawRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_COORDS);
+ make_json_rrect(writer, fRRect);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkDrawDRRectCommand::SkDrawDRRectCommand(const SkRRect& outer,
+ const SkRRect& inner,
+ const SkPaint& paint)
+ : INHERITED(kDrawDRRect_OpType) {
+ fOuter = outer;
+ fInner = inner;
+ fPaint = paint;
+}
+
+void SkDrawDRRectCommand::execute(SkCanvas* canvas) const {
+ canvas->drawDRRect(fOuter, fInner, fPaint);
+}
+
+bool SkDrawDRRectCommand::render(SkCanvas* canvas) const {
+ render_drrect(canvas, fOuter, fInner);
+ return true;
+}
+
+void SkDrawDRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_OUTER);
+ make_json_rrect(writer, fOuter);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_INNER);
+ make_json_rrect(writer, fInner);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, fPaint, urlDataManager);
+}
+
+SkDrawShadowCommand::SkDrawShadowCommand(const SkPath& path, const SkDrawShadowRec& rec)
+ : INHERITED(kDrawShadow_OpType) {
+ fPath = path;
+ fShadowRec = rec;
+}
+
+void SkDrawShadowCommand::execute(SkCanvas* canvas) const {
+ canvas->private_draw_shadow_rec(fPath, fShadowRec);
+}
+
+bool SkDrawShadowCommand::render(SkCanvas* canvas) const {
+ render_shadow(canvas, fPath, fShadowRec);
+ return true;
+}
+
+void SkDrawShadowCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+
+ bool geometricOnly = SkToBool(fShadowRec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+ bool transparentOccluder =
+ SkToBool(fShadowRec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
+
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PATH);
+ MakeJsonPath(writer, fPath);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_ZPLANE);
+ MakeJsonPoint3(writer, fShadowRec.fZPlaneParams);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION);
+ MakeJsonPoint3(writer, fShadowRec.fLightPos);
+ writer.appendFloat(SKDEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS, fShadowRec.fLightRadius);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR);
+ MakeJsonColor(writer, fShadowRec.fAmbientColor);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_SPOTCOLOR);
+ MakeJsonColor(writer, fShadowRec.fSpotColor);
+ store_bool(writer, SKDEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC, transparentOccluder, false);
+ store_bool(writer, SKDEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY, geometricOnly, false);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkDrawEdgeAAQuadCommand::SkDrawEdgeAAQuadCommand(const SkRect& rect,
+ const SkPoint clip[],
+ SkCanvas::QuadAAFlags aa,
+ SkColor color,
+ SkBlendMode mode)
+ : INHERITED(kDrawEdgeAAQuad_OpType)
+ , fRect(rect)
+ , fHasClip(clip != nullptr)
+ , fAA(aa)
+ , fColor(color)
+ , fMode(mode) {
+ if (clip) {
+ for (int i = 0; i < 4; ++i) {
+ fClip[i] = clip[i];
+ }
+ }
+}
+
+void SkDrawEdgeAAQuadCommand::execute(SkCanvas* canvas) const {
+ canvas->experimental_DrawEdgeAAQuad(fRect, fHasClip ? fClip : nullptr, fAA, fColor, fMode);
+}
+
+SkDrawEdgeAAImageSetCommand::SkDrawEdgeAAImageSetCommand(const SkCanvas::ImageSetEntry set[],
+ int count,
+ const SkPoint dstClips[],
+ const SkMatrix preViewMatrices[],
+ const SkPaint* paint,
+ SkCanvas::SrcRectConstraint constraint)
+ : INHERITED(kDrawEdgeAAImageSet_OpType)
+ , fSet(count)
+ , fCount(count)
+ , fPaint(paint)
+ , fConstraint(constraint) {
+ int totalDstClipCount, totalMatrixCount;
+ SkCanvasPriv::GetDstClipAndMatrixCounts(set, count, &totalDstClipCount, &totalMatrixCount);
+
+ std::copy_n(set, count, fSet.get());
+ fDstClips.reset(totalDstClipCount);
+ std::copy_n(dstClips, totalDstClipCount, fDstClips.get());
+ fPreViewMatrices.reset(totalMatrixCount);
+ std::copy_n(preViewMatrices, totalMatrixCount, fPreViewMatrices.get());
+}
+
+void SkDrawEdgeAAImageSetCommand::execute(SkCanvas* canvas) const {
+ canvas->experimental_DrawEdgeAAImageSet(fSet.get(),
+ fCount,
+ fDstClips.get(),
+ fPreViewMatrices.get(),
+ fPaint.getMaybeNull(),
+ fConstraint);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkDrawDrawableCommand::SkDrawDrawableCommand(SkDrawable* drawable, const SkMatrix* matrix)
+ : INHERITED(kDrawDrawable_OpType), fDrawable(SkRef(drawable)), fMatrix(matrix) {}
+
+void SkDrawDrawableCommand::execute(SkCanvas* canvas) const {
+ canvas->drawDrawable(fDrawable.get(), fMatrix.getMaybeNull());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkDrawVerticesCommand::SkDrawVerticesCommand(sk_sp<SkVertices> vertices,
+ SkBlendMode bmode,
+ const SkPaint& paint)
+ : INHERITED(kDrawVertices_OpType)
+ , fVertices(std::move(vertices))
+ , fBlendMode(bmode)
+ , fPaint(paint) {}
+
+void SkDrawVerticesCommand::execute(SkCanvas* canvas) const {
+ canvas->drawVertices(fVertices, fBlendMode, fPaint);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkDrawAtlasCommand::SkDrawAtlasCommand(const SkImage* image,
+ const SkRSXform xform[],
+ const SkRect tex[],
+ const SkColor colors[],
+ int count,
+ SkBlendMode bmode,
+ const SkRect* cull,
+ const SkPaint* paint)
+ : INHERITED(kDrawAtlas_OpType)
+ , fImage(SkRef(image))
+ , fXform(xform, count)
+ , fTex(tex, count)
+ , fColors(colors, colors ? count : 0)
+ , fBlendMode(bmode)
+ , fCull(cull)
+ , fPaint(paint) {}
+
+void SkDrawAtlasCommand::execute(SkCanvas* canvas) const {
+ canvas->drawAtlas(fImage.get(),
+ fXform.begin(),
+ fTex.begin(),
+ fColors.isEmpty() ? nullptr : fColors.begin(),
+ fXform.count(),
+ fBlendMode,
+ fCull.getMaybeNull(),
+ fPaint.getMaybeNull());
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+SkRestoreCommand::SkRestoreCommand() : INHERITED(kRestore_OpType) {}
+
+void SkRestoreCommand::execute(SkCanvas* canvas) const { canvas->restore(); }
+
+SkSaveCommand::SkSaveCommand() : INHERITED(kSave_OpType) {}
+
+void SkSaveCommand::execute(SkCanvas* canvas) const { canvas->save(); }
+
+SkSaveLayerCommand::SkSaveLayerCommand(const SkCanvas::SaveLayerRec& rec)
+ : INHERITED(kSaveLayer_OpType)
+ , fBounds(rec.fBounds)
+ , fPaint(rec.fPaint)
+ , fBackdrop(SkSafeRef(rec.fBackdrop))
+ , fSaveLayerFlags(rec.fSaveLayerFlags) {}
+
+void SkSaveLayerCommand::execute(SkCanvas* canvas) const {
+ canvas->saveLayer(
+ SkCanvas::SaveLayerRec(fBounds.getMaybeNull(), fPaint.getMaybeNull(), fSaveLayerFlags));
+}
+
+void SkSaveLayerCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ if (fBounds.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_BOUNDS);
+ MakeJsonRect(writer, *fBounds);
+ }
+ if (fPaint.isValid()) {
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_PAINT);
+ MakeJsonPaint(writer, *fPaint, urlDataManager);
+ }
+ if (fBackdrop != nullptr) {
+ writer.beginObject(SKDEBUGCANVAS_ATTRIBUTE_BACKDROP);
+ flatten(fBackdrop.get(), writer, urlDataManager);
+ writer.endObject(); // backdrop
+ }
+ if (fSaveLayerFlags != 0) {
+ SkDebugf("unsupported: saveLayer flags\n");
+ SkASSERT(false);
+ }
+}
+
+SkSetMatrixCommand::SkSetMatrixCommand(const SkMatrix& matrix) : INHERITED(kSetMatrix_OpType) {
+ fMatrix = matrix;
+}
+
+void SkSetMatrixCommand::execute(SkCanvas* canvas) const { canvas->setMatrix(fMatrix); }
+
+void SkSetMatrixCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
+ INHERITED::toJSON(writer, urlDataManager);
+ writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_MATRIX);
+ MakeJsonMatrix(writer, fMatrix);
+}