1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tools/debugger/DrawCommand.h"
9 
10 #include <algorithm>
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkDrawable.h"
13 #include "include/core/SkImageFilter.h"
14 #include "include/core/SkPathEffect.h"
15 #include "include/core/SkPicture.h"
16 #include "include/core/SkTypeface.h"
17 #include "include/effects/SkDashPathEffect.h"
18 #include "include/encode/SkPngEncoder.h"
19 #include "include/private/SkShadowFlags.h"
20 #include "include/private/SkTHash.h"
21 #include "src/core/SkAutoMalloc.h"
22 #include "src/core/SkCanvasPriv.h"
23 #include "src/core/SkClipOpPriv.h"
24 #include "src/core/SkLatticeIter.h"
25 #include "src/core/SkMaskFilterBase.h"
26 #include "src/core/SkPaintDefaults.h"
27 #include "src/core/SkReadBuffer.h"
28 #include "src/core/SkRectPriv.h"
29 #include "src/core/SkTextBlobPriv.h"
30 #include "src/core/SkWriteBuffer.h"
31 #include "tools/debugger/DebugLayerManager.h"
32 #include "tools/debugger/JsonWriteBuffer.h"
33 
34 #define DEBUGCANVAS_ATTRIBUTE_COMMAND "command"
35 #define DEBUGCANVAS_ATTRIBUTE_VISIBLE "visible"
36 #define DEBUGCANVAS_ATTRIBUTE_MATRIX "matrix"
37 #define DEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS "drawDepthTranslation"
38 #define DEBUGCANVAS_ATTRIBUTE_COORDS "coords"
39 #define DEBUGCANVAS_ATTRIBUTE_EDGING "edging"
40 #define DEBUGCANVAS_ATTRIBUTE_HINTING "hinting"
41 #define DEBUGCANVAS_ATTRIBUTE_BOUNDS "bounds"
42 #define DEBUGCANVAS_ATTRIBUTE_PAINT "paint"
43 #define DEBUGCANVAS_ATTRIBUTE_OUTER "outer"
44 #define DEBUGCANVAS_ATTRIBUTE_INNER "inner"
45 #define DEBUGCANVAS_ATTRIBUTE_MODE "mode"
46 #define DEBUGCANVAS_ATTRIBUTE_POINTS "points"
47 #define DEBUGCANVAS_ATTRIBUTE_PATH "path"
48 #define DEBUGCANVAS_ATTRIBUTE_TEXT "text"
49 #define DEBUGCANVAS_ATTRIBUTE_COLOR "color"
50 #define DEBUGCANVAS_ATTRIBUTE_ALPHA "alpha"
51 #define DEBUGCANVAS_ATTRIBUTE_BLENDMODE "blendMode"
52 #define DEBUGCANVAS_ATTRIBUTE_STYLE "style"
53 #define DEBUGCANVAS_ATTRIBUTE_STROKEWIDTH "strokeWidth"
54 #define DEBUGCANVAS_ATTRIBUTE_STROKEMITER "strokeMiter"
55 #define DEBUGCANVAS_ATTRIBUTE_STROKEJOIN "strokeJoin"
56 #define DEBUGCANVAS_ATTRIBUTE_CAP "cap"
57 #define DEBUGCANVAS_ATTRIBUTE_ANTIALIAS "antiAlias"
58 #define DEBUGCANVAS_ATTRIBUTE_DITHER "dither"
59 #define DEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT "fakeBoldText"
60 #define DEBUGCANVAS_ATTRIBUTE_LINEARTEXT "linearText"
61 #define DEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT "subpixelText"
62 #define DEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT "devKernText"
63 #define DEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT "lcdRenderText"
64 #define DEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT "embeddedBitmapText"
65 #define DEBUGCANVAS_ATTRIBUTE_AUTOHINTING "forceAutoHinting"
66 #define DEBUGCANVAS_ATTRIBUTE_REGION "region"
67 #define DEBUGCANVAS_ATTRIBUTE_REGIONOP "op"
68 #define DEBUGCANVAS_ATTRIBUTE_EDGESTYLE "edgeStyle"
69 #define DEBUGCANVAS_ATTRIBUTE_DEVICEREGION "deviceRegion"
70 #define DEBUGCANVAS_ATTRIBUTE_BLUR "blur"
71 #define DEBUGCANVAS_ATTRIBUTE_SIGMA "sigma"
72 #define DEBUGCANVAS_ATTRIBUTE_QUALITY "quality"
73 #define DEBUGCANVAS_ATTRIBUTE_TEXTSIZE "textSize"
74 #define DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX "textScaleX"
75 #define DEBUGCANVAS_ATTRIBUTE_TEXTSKEWX "textSkewX"
76 #define DEBUGCANVAS_ATTRIBUTE_DASHING "dashing"
77 #define DEBUGCANVAS_ATTRIBUTE_INTERVALS "intervals"
78 #define DEBUGCANVAS_ATTRIBUTE_PHASE "phase"
79 #define DEBUGCANVAS_ATTRIBUTE_FILLTYPE "fillType"
80 #define DEBUGCANVAS_ATTRIBUTE_VERBS "verbs"
81 #define DEBUGCANVAS_ATTRIBUTE_NAME "name"
82 #define DEBUGCANVAS_ATTRIBUTE_DATA "data"
83 #define DEBUGCANVAS_ATTRIBUTE_VALUES "values"
84 #define DEBUGCANVAS_ATTRIBUTE_SHADER "shader"
85 #define DEBUGCANVAS_ATTRIBUTE_PATHEFFECT "pathEffect"
86 #define DEBUGCANVAS_ATTRIBUTE_MASKFILTER "maskFilter"
87 #define DEBUGCANVAS_ATTRIBUTE_XFERMODE "xfermode"
88 #define DEBUGCANVAS_ATTRIBUTE_BACKDROP "backdrop"
89 #define DEBUGCANVAS_ATTRIBUTE_COLORFILTER "colorfilter"
90 #define DEBUGCANVAS_ATTRIBUTE_IMAGEFILTER "imagefilter"
91 #define DEBUGCANVAS_ATTRIBUTE_IMAGE "image"
92 #define DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX "imageIndex"
93 #define DEBUGCANVAS_ATTRIBUTE_BITMAP "bitmap"
94 #define DEBUGCANVAS_ATTRIBUTE_SRC "src"
95 #define DEBUGCANVAS_ATTRIBUTE_DST "dst"
96 #define DEBUGCANVAS_ATTRIBUTE_CENTER "center"
97 #define DEBUGCANVAS_ATTRIBUTE_STRICT "strict"
98 #define DEBUGCANVAS_ATTRIBUTE_DESCRIPTION "description"
99 #define DEBUGCANVAS_ATTRIBUTE_X "x"
100 #define DEBUGCANVAS_ATTRIBUTE_Y "y"
101 #define DEBUGCANVAS_ATTRIBUTE_RUNS "runs"
102 #define DEBUGCANVAS_ATTRIBUTE_POSITIONS "positions"
103 #define DEBUGCANVAS_ATTRIBUTE_GLYPHS "glyphs"
104 #define DEBUGCANVAS_ATTRIBUTE_FONT "font"
105 #define DEBUGCANVAS_ATTRIBUTE_TYPEFACE "typeface"
106 #define DEBUGCANVAS_ATTRIBUTE_CUBICS "cubics"
107 #define DEBUGCANVAS_ATTRIBUTE_COLORS "colors"
108 #define DEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS "textureCoords"
109 #define DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY "filterQuality"
110 #define DEBUGCANVAS_ATTRIBUTE_STARTANGLE "startAngle"
111 #define DEBUGCANVAS_ATTRIBUTE_SWEEPANGLE "sweepAngle"
112 #define DEBUGCANVAS_ATTRIBUTE_USECENTER "useCenter"
113 #define DEBUGCANVAS_ATTRIBUTE_SHORTDESC "shortDesc"
114 #define DEBUGCANVAS_ATTRIBUTE_UNIQUE_ID "uniqueID"
115 #define DEBUGCANVAS_ATTRIBUTE_WIDTH "width"
116 #define DEBUGCANVAS_ATTRIBUTE_HEIGHT "height"
117 #define DEBUGCANVAS_ATTRIBUTE_ALPHA "alpha"
118 #define DEBUGCANVAS_ATTRIBUTE_LATTICE "lattice"
119 #define DEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT "xCount"
120 #define DEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT "yCount"
121 #define DEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS "xDivs"
122 #define DEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS "yDivs"
123 #define DEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS "flags"
124 #define DEBUGCANVAS_ATTRIBUTE_ZPLANE "zPlane"
125 #define DEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION "lightPositions"
126 #define DEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR "ambientColor"
127 #define DEBUGCANVAS_ATTRIBUTE_SPOTCOLOR "spotColor"
128 #define DEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS "lightRadius"
129 #define DEBUGCANVAS_ATTRIBUTE_LAYERNODEID "layerNodeId"
130 
131 #define DEBUGCANVAS_VERB_MOVE "move"
132 #define DEBUGCANVAS_VERB_LINE "line"
133 #define DEBUGCANVAS_VERB_QUAD "quad"
134 #define DEBUGCANVAS_VERB_CUBIC "cubic"
135 #define DEBUGCANVAS_VERB_CONIC "conic"
136 #define DEBUGCANVAS_VERB_CLOSE "close"
137 
138 #define DEBUGCANVAS_STYLE_FILL "fill"
139 #define DEBUGCANVAS_STYLE_STROKE "stroke"
140 #define DEBUGCANVAS_STYLE_STROKEANDFILL "strokeAndFill"
141 
142 #define DEBUGCANVAS_POINTMODE_POINTS "points"
143 #define DEBUGCANVAS_POINTMODE_LINES "lines"
144 #define DEBUGCANVAS_POINTMODE_POLYGON "polygon"
145 
146 #define DEBUGCANVAS_REGIONOP_DIFFERENCE "difference"
147 #define DEBUGCANVAS_REGIONOP_INTERSECT "intersect"
148 #define DEBUGCANVAS_REGIONOP_UNION "union"
149 #define DEBUGCANVAS_REGIONOP_XOR "xor"
150 #define DEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE "reverseDifference"
151 #define DEBUGCANVAS_REGIONOP_REPLACE "replace"
152 
153 #define DEBUGCANVAS_BLURSTYLE_NORMAL "normal"
154 #define DEBUGCANVAS_BLURSTYLE_SOLID "solid"
155 #define DEBUGCANVAS_BLURSTYLE_OUTER "outer"
156 #define DEBUGCANVAS_BLURSTYLE_INNER "inner"
157 
158 #define DEBUGCANVAS_BLURQUALITY_LOW "low"
159 #define DEBUGCANVAS_BLURQUALITY_HIGH "high"
160 
161 #define DEBUGCANVAS_FILLTYPE_WINDING "winding"
162 #define DEBUGCANVAS_FILLTYPE_EVENODD "evenOdd"
163 #define DEBUGCANVAS_FILLTYPE_INVERSEWINDING "inverseWinding"
164 #define DEBUGCANVAS_FILLTYPE_INVERSEEVENODD "inverseEvenOdd"
165 
166 #define DEBUGCANVAS_CAP_BUTT "butt"
167 #define DEBUGCANVAS_CAP_ROUND "round"
168 #define DEBUGCANVAS_CAP_SQUARE "square"
169 
170 #define DEBUGCANVAS_MITER_JOIN "miter"
171 #define DEBUGCANVAS_ROUND_JOIN "round"
172 #define DEBUGCANVAS_BEVEL_JOIN "bevel"
173 
174 #define DEBUGCANVAS_COLORTYPE_ARGB4444 "ARGB4444"
175 #define DEBUGCANVAS_COLORTYPE_RGBA8888 "RGBA8888"
176 #define DEBUGCANVAS_COLORTYPE_BGRA8888 "BGRA8888"
177 #define DEBUGCANVAS_COLORTYPE_565 "565"
178 #define DEBUGCANVAS_COLORTYPE_GRAY8 "Gray8"
179 #define DEBUGCANVAS_COLORTYPE_INDEX8 "Index8"
180 #define DEBUGCANVAS_COLORTYPE_ALPHA8 "Alpha8"
181 
182 #define DEBUGCANVAS_ALPHATYPE_OPAQUE "opaque"
183 #define DEBUGCANVAS_ALPHATYPE_PREMUL "premul"
184 #define DEBUGCANVAS_ALPHATYPE_UNPREMUL "unpremul"
185 #define DEBUGCANVAS_ALPHATYPE_UNKNOWN "unknown"
186 
187 #define DEBUGCANVAS_FILTERQUALITY_NONE "none"
188 #define DEBUGCANVAS_FILTERQUALITY_LOW "low"
189 #define DEBUGCANVAS_FILTERQUALITY_MEDIUM "medium"
190 #define DEBUGCANVAS_FILTERQUALITY_HIGH "high"
191 
192 #define DEBUGCANVAS_HINTING_NONE "none"
193 #define DEBUGCANVAS_HINTING_SLIGHT "slight"
194 #define DEBUGCANVAS_HINTING_NORMAL "normal"
195 #define DEBUGCANVAS_HINTING_FULL "full"
196 
197 #define DEBUGCANVAS_EDGING_ALIAS "alias"
198 #define DEBUGCANVAS_EDGING_ANTIALIAS "antialias"
199 #define DEBUGCANVAS_EDGING_SUBPIXELANTIALIAS "subpixelantialias"
200 
201 #define DEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC "transparentOccluder"
202 #define DEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY "geometricOnly"
203 
str_append(SkString * str,const SkRect & r)204 static SkString* str_append(SkString* str, const SkRect& r) {
205     str->appendf(" [%g %g %g %g]", r.left(), r.top(), r.right(), r.bottom());
206     return str;
207 }
208 
DrawCommand(OpType type)209 DrawCommand::DrawCommand(OpType type) : fOpType(type), fVisible(true) {}
210 
GetCommandString(OpType type)211 const char* DrawCommand::GetCommandString(OpType type) {
212     switch (type) {
213         case kBeginDrawPicture_OpType: return "BeginDrawPicture";
214         case kClear_OpType: return "DrawClear";
215         case kClipPath_OpType: return "ClipPath";
216         case kClipRegion_OpType: return "ClipRegion";
217         case kClipRect_OpType: return "ClipRect";
218         case kClipRRect_OpType: return "ClipRRect";
219         case kConcat_OpType: return "Concat";
220         case kDrawAnnotation_OpType: return "DrawAnnotation";
221         case kDrawBitmap_OpType: return "DrawBitmap";
222         case kDrawBitmapRect_OpType: return "DrawBitmapRect";
223         case kDrawDRRect_OpType: return "DrawDRRect";
224         case kDrawImage_OpType: return "DrawImage";
225         case kDrawImageLattice_OpType: return "DrawImageLattice";
226         case kDrawImageNine_OpType: return "DrawImageNine";
227         case kDrawImageRect_OpType: return "DrawImageRect";
228         case kDrawImageRectLayer_OpType: return "DrawImageRectLayer";
229         case kDrawOval_OpType: return "DrawOval";
230         case kDrawPaint_OpType: return "DrawPaint";
231         case kDrawPatch_OpType: return "DrawPatch";
232         case kDrawPath_OpType: return "DrawPath";
233         case kDrawArc_OpType: return "DrawArc";
234         case kDrawPoints_OpType: return "DrawPoints";
235         case kDrawRect_OpType: return "DrawRect";
236         case kDrawRRect_OpType: return "DrawRRect";
237         case kDrawRegion_OpType: return "DrawRegion";
238         case kDrawShadow_OpType: return "DrawShadow";
239         case kDrawTextBlob_OpType: return "DrawTextBlob";
240         case kDrawVertices_OpType: return "DrawVertices";
241         case kDrawAtlas_OpType: return "DrawAtlas";
242         case kDrawDrawable_OpType: return "DrawDrawable";
243         case kDrawEdgeAAQuad_OpType: return "DrawEdgeAAQuad";
244         case kDrawEdgeAAImageSet_OpType: return "DrawEdgeAAImageSet";
245         case kEndDrawPicture_OpType: return "EndDrawPicture";
246         case kRestore_OpType: return "Restore";
247         case kSave_OpType: return "Save";
248         case kSaveLayer_OpType: return "SaveLayer";
249         case kSetMatrix_OpType: return "SetMatrix";
250         default:
251             SkDebugf("OpType error 0x%08x\n", type);
252             SkASSERT(0);
253             break;
254     }
255     SkDEBUGFAIL("DrawType UNUSED\n");
256     return nullptr;
257 }
258 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const259 void DrawCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
260     writer.appendString(DEBUGCANVAS_ATTRIBUTE_COMMAND, this->GetCommandString(fOpType));
261     writer.appendBool(DEBUGCANVAS_ATTRIBUTE_VISIBLE, this->isVisible());
262 }
263 
264 namespace {
265 
xlate_and_scale_to_bounds(SkCanvas * canvas,const SkRect & bounds)266 void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) {
267     const SkISize& size = canvas->getBaseLayerSize();
268 
269     static const SkScalar kInsetFrac = 0.9f;  // Leave a border around object
270 
271     canvas->translate(size.fWidth / 2.0f, size.fHeight / 2.0f);
272     if (bounds.width() > bounds.height()) {
273         canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.width()),
274                       SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.width()));
275     } else {
276         canvas->scale(SkDoubleToScalar((kInsetFrac * size.fWidth) / bounds.height()),
277                       SkDoubleToScalar((kInsetFrac * size.fHeight) / bounds.height()));
278     }
279     canvas->translate(-bounds.centerX(), -bounds.centerY());
280 }
281 
render_path(SkCanvas * canvas,const SkPath & path)282 void render_path(SkCanvas* canvas, const SkPath& path) {
283     canvas->clear(0xFFFFFFFF);
284 
285     const SkRect& bounds = path.getBounds();
286     if (bounds.isEmpty()) {
287         return;
288     }
289 
290     SkAutoCanvasRestore acr(canvas, true);
291     xlate_and_scale_to_bounds(canvas, bounds);
292 
293     SkPaint p;
294     p.setColor(SK_ColorBLACK);
295     p.setStyle(SkPaint::kStroke_Style);
296 
297     canvas->drawPath(path, p);
298 }
299 
render_region(SkCanvas * canvas,const SkRegion & region)300 void render_region(SkCanvas* canvas, const SkRegion& region) {
301     canvas->clear(0xFFFFFFFF);
302 
303     const SkIRect& bounds = region.getBounds();
304     if (bounds.isEmpty()) {
305         return;
306     }
307 
308     SkAutoCanvasRestore acr(canvas, true);
309     xlate_and_scale_to_bounds(canvas, SkRect::Make(bounds));
310 
311     SkPaint p;
312     p.setColor(SK_ColorBLACK);
313     p.setStyle(SkPaint::kStroke_Style);
314 
315     canvas->drawRegion(region, p);
316 }
317 
render_rrect(SkCanvas * canvas,const SkRRect & rrect)318 void render_rrect(SkCanvas* canvas, const SkRRect& rrect) {
319     canvas->clear(0xFFFFFFFF);
320     canvas->save();
321 
322     const SkRect& bounds = rrect.getBounds();
323 
324     xlate_and_scale_to_bounds(canvas, bounds);
325 
326     SkPaint p;
327     p.setColor(SK_ColorBLACK);
328     p.setStyle(SkPaint::kStroke_Style);
329 
330     canvas->drawRRect(rrect, p);
331     canvas->restore();
332 }
333 
render_drrect(SkCanvas * canvas,const SkRRect & outer,const SkRRect & inner)334 void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) {
335     canvas->clear(0xFFFFFFFF);
336     canvas->save();
337 
338     const SkRect& bounds = outer.getBounds();
339 
340     xlate_and_scale_to_bounds(canvas, bounds);
341 
342     SkPaint p;
343     p.setColor(SK_ColorBLACK);
344     p.setStyle(SkPaint::kStroke_Style);
345 
346     canvas->drawDRRect(outer, inner, p);
347     canvas->restore();
348 }
349 
render_shadow(SkCanvas * canvas,const SkPath & path,SkDrawShadowRec rec)350 void render_shadow(SkCanvas* canvas, const SkPath& path, SkDrawShadowRec rec) {
351     canvas->clear(0xFFFFFFFF);
352 
353     const SkRect& bounds = path.getBounds();
354     if (bounds.isEmpty()) {
355         return;
356     }
357 
358     SkAutoCanvasRestore acr(canvas, true);
359     xlate_and_scale_to_bounds(canvas, bounds);
360 
361     rec.fAmbientColor = SK_ColorBLACK;
362     rec.fSpotColor    = SK_ColorBLACK;
363     canvas->private_draw_shadow_rec(path, rec);
364 }
365 
366 static const char* const gBlendModeMap[] = {
367         "clear",      "src",        "dst",      "srcOver",    "dstOver",   "srcIn",     "dstIn",
368         "srcOut",     "dstOut",     "srcATop",  "dstATop",    "xor",       "plus",      "modulate",
369 
370         "screen",
371 
372         "overlay",    "darken",     "lighten",  "colorDodge", "colorBurn", "hardLight", "softLight",
373         "difference", "exclusion",  "multiply",
374 
375         "hue",        "saturation", "color",    "luminosity",
376 };
377 
378 static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLastMode) + 1,
379               "blendMode mismatch");
380 static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLuminosity) + 1,
381               "blendMode mismatch");
382 
apply_paint_blend_mode(const SkPaint & paint,SkJSONWriter & writer)383 void apply_paint_blend_mode(const SkPaint& paint, SkJSONWriter& writer) {
384     const auto mode = paint.getBlendMode();
385     if (mode != SkBlendMode::kSrcOver) {
386         SkASSERT(static_cast<size_t>(mode) < SK_ARRAY_COUNT(gBlendModeMap));
387         writer.appendString(DEBUGCANVAS_ATTRIBUTE_BLENDMODE,
388                             gBlendModeMap[static_cast<size_t>(mode)]);
389     }
390 }
391 
392 };  // namespace
393 
MakeJsonColor(SkJSONWriter & writer,const SkColor color)394 void DrawCommand::MakeJsonColor(SkJSONWriter& writer, const SkColor color) {
395     writer.beginArray(nullptr, false);
396     writer.appendS32(SkColorGetA(color));
397     writer.appendS32(SkColorGetR(color));
398     writer.appendS32(SkColorGetG(color));
399     writer.appendS32(SkColorGetB(color));
400     writer.endArray();
401 }
402 
MakeJsonColor4f(SkJSONWriter & writer,const SkColor4f & color)403 void DrawCommand::MakeJsonColor4f(SkJSONWriter& writer, const SkColor4f& color) {
404     writer.beginArray(nullptr, false);
405     writer.appendFloat(color.fA);
406     writer.appendFloat(color.fR);
407     writer.appendFloat(color.fG);
408     writer.appendFloat(color.fB);
409     writer.endArray();
410 }
411 
MakeJsonPoint(SkJSONWriter & writer,const SkPoint & point)412 void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, const SkPoint& point) {
413     writer.beginArray(nullptr, false);
414     writer.appendFloat(point.x());
415     writer.appendFloat(point.y());
416     writer.endArray();
417 }
418 
MakeJsonPoint(SkJSONWriter & writer,SkScalar x,SkScalar y)419 void DrawCommand::MakeJsonPoint(SkJSONWriter& writer, SkScalar x, SkScalar y) {
420     writer.beginArray(nullptr, false);
421     writer.appendFloat(x);
422     writer.appendFloat(y);
423     writer.endArray();
424 }
425 
MakeJsonPoint3(SkJSONWriter & writer,const SkPoint3 & point)426 void DrawCommand::MakeJsonPoint3(SkJSONWriter& writer, const SkPoint3& point) {
427     writer.beginArray(nullptr, false);
428     writer.appendFloat(point.x());
429     writer.appendFloat(point.y());
430     writer.appendFloat(point.z());
431     writer.endArray();
432 }
433 
MakeJsonRect(SkJSONWriter & writer,const SkRect & rect)434 void DrawCommand::MakeJsonRect(SkJSONWriter& writer, const SkRect& rect) {
435     writer.beginArray(nullptr, false);
436     writer.appendFloat(rect.left());
437     writer.appendFloat(rect.top());
438     writer.appendFloat(rect.right());
439     writer.appendFloat(rect.bottom());
440     writer.endArray();
441 }
442 
MakeJsonIRect(SkJSONWriter & writer,const SkIRect & rect)443 void DrawCommand::MakeJsonIRect(SkJSONWriter& writer, const SkIRect& rect) {
444     writer.beginArray(nullptr, false);
445     writer.appendS32(rect.left());
446     writer.appendS32(rect.top());
447     writer.appendS32(rect.right());
448     writer.appendS32(rect.bottom());
449     writer.endArray();
450 }
451 
make_json_rrect(SkJSONWriter & writer,const SkRRect & rrect)452 static void make_json_rrect(SkJSONWriter& writer, const SkRRect& rrect) {
453     writer.beginArray(nullptr, false);
454     DrawCommand::MakeJsonRect(writer, rrect.rect());
455     DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperLeft_Corner));
456     DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kUpperRight_Corner));
457     DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerRight_Corner));
458     DrawCommand::MakeJsonPoint(writer, rrect.radii(SkRRect::kLowerLeft_Corner));
459     writer.endArray();
460 }
461 
MakeJsonMatrix(SkJSONWriter & writer,const SkMatrix & matrix)462 void DrawCommand::MakeJsonMatrix(SkJSONWriter& writer, const SkMatrix& matrix) {
463     writer.beginArray();
464     for (int r = 0; r < 3; ++r) {
465         writer.beginArray(nullptr, false);
466         for (int c = 0; c < 3; ++c) {
467             writer.appendFloat(matrix[r * 3 + c]);
468         }
469         writer.endArray();
470     }
471     writer.endArray();
472 }
473 
MakeJsonPath(SkJSONWriter & writer,const SkPath & path)474 void DrawCommand::MakeJsonPath(SkJSONWriter& writer, const SkPath& path) {
475     writer.beginObject();
476     switch (path.getFillType()) {
477         case SkPathFillType::kWinding:
478             writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, DEBUGCANVAS_FILLTYPE_WINDING);
479             break;
480         case SkPathFillType::kEvenOdd:
481             writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE, DEBUGCANVAS_FILLTYPE_EVENODD);
482             break;
483         case SkPathFillType::kInverseWinding:
484             writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE,
485                                 DEBUGCANVAS_FILLTYPE_INVERSEWINDING);
486             break;
487         case SkPathFillType::kInverseEvenOdd:
488             writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILLTYPE,
489                                 DEBUGCANVAS_FILLTYPE_INVERSEEVENODD);
490             break;
491     }
492     writer.beginArray(DEBUGCANVAS_ATTRIBUTE_VERBS);
493     SkPath::Iter iter(path, false);
494     SkPoint      pts[4];
495     SkPath::Verb verb;
496     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
497         if (verb == SkPath::kClose_Verb) {
498             writer.appendString(DEBUGCANVAS_VERB_CLOSE);
499             continue;
500         }
501         writer.beginObject();  // verb
502         switch (verb) {
503             case SkPath::kLine_Verb: {
504                 writer.appendName(DEBUGCANVAS_VERB_LINE);
505                 MakeJsonPoint(writer, pts[1]);
506                 break;
507             }
508             case SkPath::kQuad_Verb: {
509                 writer.beginArray(DEBUGCANVAS_VERB_QUAD);
510                 MakeJsonPoint(writer, pts[1]);
511                 MakeJsonPoint(writer, pts[2]);
512                 writer.endArray();  // quad coords
513                 break;
514             }
515             case SkPath::kCubic_Verb: {
516                 writer.beginArray(DEBUGCANVAS_VERB_CUBIC);
517                 MakeJsonPoint(writer, pts[1]);
518                 MakeJsonPoint(writer, pts[2]);
519                 MakeJsonPoint(writer, pts[3]);
520                 writer.endArray();  // cubic coords
521                 break;
522             }
523             case SkPath::kConic_Verb: {
524                 writer.beginArray(DEBUGCANVAS_VERB_CONIC);
525                 MakeJsonPoint(writer, pts[1]);
526                 MakeJsonPoint(writer, pts[2]);
527                 writer.appendFloat(iter.conicWeight());
528                 writer.endArray();  // conic coords
529                 break;
530             }
531             case SkPath::kMove_Verb: {
532                 writer.appendName(DEBUGCANVAS_VERB_MOVE);
533                 MakeJsonPoint(writer, pts[0]);
534                 break;
535             }
536             case SkPath::kClose_Verb:
537             case SkPath::kDone_Verb:
538                 // Unreachable
539                 break;
540         }
541         writer.endObject();  // verb
542     }
543     writer.endArray();   // verbs
544     writer.endObject();  // path
545 }
546 
MakeJsonRegion(SkJSONWriter & writer,const SkRegion & region)547 void DrawCommand::MakeJsonRegion(SkJSONWriter& writer, const SkRegion& region) {
548     // TODO: Actually serialize the rectangles, rather than just devolving to path
549     SkPath path;
550     region.getBoundaryPath(&path);
551     MakeJsonPath(writer, path);
552 }
553 
regionop_name(SkClipOp op)554 static const char* regionop_name(SkClipOp op) {
555     switch (op) {
556         case kDifference_SkClipOp: return DEBUGCANVAS_REGIONOP_DIFFERENCE;
557         case kIntersect_SkClipOp: return DEBUGCANVAS_REGIONOP_INTERSECT;
558         case kUnion_SkClipOp: return DEBUGCANVAS_REGIONOP_UNION;
559         case kXOR_SkClipOp: return DEBUGCANVAS_REGIONOP_XOR;
560         case kReverseDifference_SkClipOp: return DEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE;
561         case kReplace_SkClipOp: return DEBUGCANVAS_REGIONOP_REPLACE;
562         default: SkASSERT(false); return "<invalid region op>";
563     }
564 }
565 
pointmode_name(SkCanvas::PointMode mode)566 static const char* pointmode_name(SkCanvas::PointMode mode) {
567     switch (mode) {
568         case SkCanvas::kPoints_PointMode: return DEBUGCANVAS_POINTMODE_POINTS;
569         case SkCanvas::kLines_PointMode: return DEBUGCANVAS_POINTMODE_LINES;
570         case SkCanvas::kPolygon_PointMode: return DEBUGCANVAS_POINTMODE_POLYGON;
571         default: SkASSERT(false); return "<invalid point mode>";
572     }
573 }
574 
store_scalar(SkJSONWriter & writer,const char * key,SkScalar value,SkScalar defaultValue)575 static void store_scalar(SkJSONWriter& writer,
576                          const char*   key,
577                          SkScalar      value,
578                          SkScalar      defaultValue) {
579     if (value != defaultValue) {
580         writer.appendFloat(key, value);
581     }
582 }
583 
store_bool(SkJSONWriter & writer,const char * key,bool value,bool defaultValue)584 static void store_bool(SkJSONWriter& writer, const char* key, bool value, bool defaultValue) {
585     if (value != defaultValue) {
586         writer.appendBool(key, value);
587     }
588 }
589 
encode_data(const void * bytes,size_t count,const char * contentType,UrlDataManager & urlDataManager)590 static SkString encode_data(const void*     bytes,
591                             size_t          count,
592                             const char*     contentType,
593                             UrlDataManager& urlDataManager) {
594     sk_sp<SkData> data(SkData::MakeWithCopy(bytes, count));
595     return urlDataManager.addData(data.get(), contentType);
596 }
597 
flatten(const SkFlattenable * flattenable,SkJSONWriter & writer,UrlDataManager & urlDataManager)598 void DrawCommand::flatten(const SkFlattenable* flattenable,
599                           SkJSONWriter&        writer,
600                           UrlDataManager&      urlDataManager) {
601     SkBinaryWriteBuffer buffer;
602     flattenable->flatten(buffer);
603     void* data = sk_malloc_throw(buffer.bytesWritten());
604     buffer.writeToMemory(data);
605     SkString url =
606             encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager);
607     writer.appendString(DEBUGCANVAS_ATTRIBUTE_NAME, flattenable->getTypeName());
608     writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
609 
610     writer.beginObject(DEBUGCANVAS_ATTRIBUTE_VALUES);
611     JsonWriteBuffer jsonBuffer(&writer, &urlDataManager);
612     flattenable->flatten(jsonBuffer);
613     writer.endObject();  // values
614 
615     sk_free(data);
616 }
617 
WritePNG(SkBitmap bitmap,SkWStream & out)618 void DrawCommand::WritePNG(SkBitmap bitmap, SkWStream& out) {
619     SkPixmap pm;
620     SkAssertResult(bitmap.peekPixels(&pm));
621 
622     SkPngEncoder::Options options;
623     options.fZLibLevel   = 1;
624     options.fFilterFlags = SkPngEncoder::FilterFlag::kNone;
625     SkPngEncoder::Encode(&out, pm, options);
626 }
627 
flatten(const SkImage & image,SkJSONWriter & writer,UrlDataManager & urlDataManager)628 bool DrawCommand::flatten(const SkImage&  image,
629                           SkJSONWriter&   writer,
630                           UrlDataManager& urlDataManager) {
631     size_t       rowBytes = 4 * image.width();
632     SkAutoMalloc buffer(rowBytes * image.height());
633     SkImageInfo  dstInfo =
634             SkImageInfo::Make(image.dimensions(), kN32_SkColorType, kPremul_SkAlphaType);
635     if (!image.readPixels(dstInfo, buffer.get(), rowBytes, 0, 0)) {
636         SkDebugf("readPixels failed\n");
637         return false;
638     }
639 
640     SkBitmap bm;
641     bm.installPixels(dstInfo, buffer.get(), rowBytes);
642 
643     SkDynamicMemoryWStream out;
644     DrawCommand::WritePNG(bm, out);
645     sk_sp<SkData> encoded = out.detachAsData();
646     SkString      url = encode_data(encoded->data(), encoded->size(), "image/png", urlDataManager);
647     writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
648     return true;
649 }
650 
color_type_name(SkColorType colorType)651 static const char* color_type_name(SkColorType colorType) {
652     switch (colorType) {
653         case kARGB_4444_SkColorType: return DEBUGCANVAS_COLORTYPE_ARGB4444;
654         case kRGBA_8888_SkColorType: return DEBUGCANVAS_COLORTYPE_RGBA8888;
655         case kBGRA_8888_SkColorType: return DEBUGCANVAS_COLORTYPE_BGRA8888;
656         case kRGB_565_SkColorType: return DEBUGCANVAS_COLORTYPE_565;
657         case kGray_8_SkColorType: return DEBUGCANVAS_COLORTYPE_GRAY8;
658         case kAlpha_8_SkColorType: return DEBUGCANVAS_COLORTYPE_ALPHA8;
659         default: SkASSERT(false); return DEBUGCANVAS_COLORTYPE_RGBA8888;
660     }
661 }
662 
alpha_type_name(SkAlphaType alphaType)663 static const char* alpha_type_name(SkAlphaType alphaType) {
664     switch (alphaType) {
665         case kOpaque_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_OPAQUE;
666         case kPremul_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_PREMUL;
667         case kUnpremul_SkAlphaType: return DEBUGCANVAS_ALPHATYPE_UNPREMUL;
668         default: SkASSERT(false); return DEBUGCANVAS_ALPHATYPE_OPAQUE;
669     }
670 }
671 
flatten(const SkBitmap & bitmap,SkJSONWriter & writer,UrlDataManager & urlDataManager)672 bool DrawCommand::flatten(const SkBitmap& bitmap,
673                           SkJSONWriter&   writer,
674                           UrlDataManager& urlDataManager) {
675     sk_sp<SkImage> image(SkImage::MakeFromBitmap(bitmap));
676     writer.appendString(DEBUGCANVAS_ATTRIBUTE_COLOR, color_type_name(bitmap.colorType()));
677     writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, alpha_type_name(bitmap.alphaType()));
678     bool success = flatten(*image, writer, urlDataManager);
679     return success;
680 }
681 
apply_font_hinting(const SkFont & font,SkJSONWriter & writer)682 static void apply_font_hinting(const SkFont& font, SkJSONWriter& writer) {
683     SkFontHinting hinting = font.getHinting();
684     if (hinting != SkPaintDefaults_Hinting) {
685         switch (hinting) {
686             case SkFontHinting::kNone:
687                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_NONE);
688                 break;
689             case SkFontHinting::kSlight:
690                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_SLIGHT);
691                 break;
692             case SkFontHinting::kNormal:
693                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_NORMAL);
694                 break;
695             case SkFontHinting::kFull:
696                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_HINTING, DEBUGCANVAS_HINTING_FULL);
697                 break;
698         }
699     }
700 }
701 
apply_font_edging(const SkFont & font,SkJSONWriter & writer)702 static void apply_font_edging(const SkFont& font, SkJSONWriter& writer) {
703     switch (font.getEdging()) {
704         case SkFont::Edging::kAlias:
705             writer.appendString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_ALIAS);
706             break;
707         case SkFont::Edging::kAntiAlias:
708             writer.appendString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_ANTIALIAS);
709             break;
710         case SkFont::Edging::kSubpixelAntiAlias:
711             writer.appendString(DEBUGCANVAS_ATTRIBUTE_EDGING, DEBUGCANVAS_EDGING_SUBPIXELANTIALIAS);
712             break;
713     }
714 }
715 
apply_paint_color(const SkPaint & paint,SkJSONWriter & writer)716 static void apply_paint_color(const SkPaint& paint, SkJSONWriter& writer) {
717     SkColor color = paint.getColor();
718     if (color != SK_ColorBLACK) {
719         writer.appendName(DEBUGCANVAS_ATTRIBUTE_COLOR);
720         DrawCommand::MakeJsonColor(writer, color);
721     }
722 }
723 
apply_paint_style(const SkPaint & paint,SkJSONWriter & writer)724 static void apply_paint_style(const SkPaint& paint, SkJSONWriter& writer) {
725     SkPaint::Style style = paint.getStyle();
726     if (style != SkPaint::kFill_Style) {
727         switch (style) {
728             case SkPaint::kStroke_Style: {
729                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_STYLE_STROKE);
730                 break;
731             }
732             case SkPaint::kStrokeAndFill_Style: {
733                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_STYLE_STROKEANDFILL);
734                 break;
735             }
736             default: SkASSERT(false);
737         }
738     }
739 }
740 
apply_paint_cap(const SkPaint & paint,SkJSONWriter & writer)741 static void apply_paint_cap(const SkPaint& paint, SkJSONWriter& writer) {
742     SkPaint::Cap cap = paint.getStrokeCap();
743     if (cap != SkPaint::kDefault_Cap) {
744         switch (cap) {
745             case SkPaint::kButt_Cap:
746                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_BUTT);
747                 break;
748             case SkPaint::kRound_Cap:
749                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_ROUND);
750                 break;
751             case SkPaint::kSquare_Cap:
752                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_CAP, DEBUGCANVAS_CAP_SQUARE);
753                 break;
754             default: SkASSERT(false);
755         }
756     }
757 }
758 
apply_paint_join(const SkPaint & paint,SkJSONWriter & writer)759 static void apply_paint_join(const SkPaint& paint, SkJSONWriter& writer) {
760     SkPaint::Join join = paint.getStrokeJoin();
761     if (join != SkPaint::kDefault_Join) {
762         switch (join) {
763             case SkPaint::kMiter_Join:
764                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_MITER_JOIN);
765                 break;
766             case SkPaint::kRound_Join:
767                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_ROUND_JOIN);
768                 break;
769             case SkPaint::kBevel_Join:
770                 writer.appendString(DEBUGCANVAS_ATTRIBUTE_STROKEJOIN, DEBUGCANVAS_BEVEL_JOIN);
771                 break;
772             default: SkASSERT(false);
773         }
774     }
775 }
776 
apply_paint_filterquality(const SkPaint & paint,SkJSONWriter & writer)777 static void apply_paint_filterquality(const SkPaint& paint, SkJSONWriter& writer) {
778     SkFilterQuality quality = paint.getFilterQuality();
779     switch (quality) {
780         case kNone_SkFilterQuality: break;
781         case kLow_SkFilterQuality:
782             writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY, DEBUGCANVAS_FILTERQUALITY_LOW);
783             break;
784         case kMedium_SkFilterQuality:
785             writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY,
786                                 DEBUGCANVAS_FILTERQUALITY_MEDIUM);
787             break;
788         case kHigh_SkFilterQuality:
789             writer.appendString(DEBUGCANVAS_ATTRIBUTE_FILTERQUALITY,
790                                 DEBUGCANVAS_FILTERQUALITY_HIGH);
791             break;
792     }
793 }
794 
apply_paint_maskfilter(const SkPaint & paint,SkJSONWriter & writer,UrlDataManager & urlDataManager)795 static void apply_paint_maskfilter(const SkPaint&  paint,
796                                    SkJSONWriter&   writer,
797                                    UrlDataManager& urlDataManager) {
798     SkMaskFilter* maskFilter = paint.getMaskFilter();
799     if (maskFilter != nullptr) {
800         SkMaskFilterBase::BlurRec blurRec;
801         if (as_MFB(maskFilter)->asABlur(&blurRec)) {
802             writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BLUR);
803             writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_SIGMA, blurRec.fSigma);
804             switch (blurRec.fStyle) {
805                 case SkBlurStyle::kNormal_SkBlurStyle:
806                     writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_NORMAL);
807                     break;
808                 case SkBlurStyle::kSolid_SkBlurStyle:
809                     writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_SOLID);
810                     break;
811                 case SkBlurStyle::kOuter_SkBlurStyle:
812                     writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_OUTER);
813                     break;
814                 case SkBlurStyle::kInner_SkBlurStyle:
815                     writer.appendString(DEBUGCANVAS_ATTRIBUTE_STYLE, DEBUGCANVAS_BLURSTYLE_INNER);
816                     break;
817                 default: SkASSERT(false);
818             }
819             writer.endObject();  // blur
820         } else {
821             writer.beginObject(DEBUGCANVAS_ATTRIBUTE_MASKFILTER);
822             DrawCommand::flatten(maskFilter, writer, urlDataManager);
823             writer.endObject();  // maskFilter
824         }
825     }
826 }
827 
apply_paint_patheffect(const SkPaint & paint,SkJSONWriter & writer,UrlDataManager & urlDataManager)828 static void apply_paint_patheffect(const SkPaint&  paint,
829                                    SkJSONWriter&   writer,
830                                    UrlDataManager& urlDataManager) {
831     SkPathEffect* pathEffect = paint.getPathEffect();
832     if (pathEffect != nullptr) {
833         SkPathEffect::DashInfo dashInfo;
834         SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo);
835         if (dashType == SkPathEffect::kDash_DashType) {
836             dashInfo.fIntervals = (SkScalar*)sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar));
837             pathEffect->asADash(&dashInfo);
838             writer.beginObject(DEBUGCANVAS_ATTRIBUTE_DASHING);
839             writer.beginArray(DEBUGCANVAS_ATTRIBUTE_INTERVALS, false);
840             for (int32_t i = 0; i < dashInfo.fCount; i++) {
841                 writer.appendFloat(dashInfo.fIntervals[i]);
842             }
843             writer.endArray();  // intervals
844             sk_free(dashInfo.fIntervals);
845             writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_PHASE, dashInfo.fPhase);
846             writer.endObject();  // dashing
847         } else {
848             writer.beginObject(DEBUGCANVAS_ATTRIBUTE_PATHEFFECT);
849             DrawCommand::flatten(pathEffect, writer, urlDataManager);
850             writer.endObject();  // pathEffect
851         }
852     }
853 }
854 
apply_font_typeface(const SkFont & font,SkJSONWriter & writer,UrlDataManager & urlDataManager)855 static void apply_font_typeface(const SkFont&   font,
856                                 SkJSONWriter&   writer,
857                                 UrlDataManager& urlDataManager) {
858     SkTypeface* typeface = font.getTypefaceOrDefault();
859     if (typeface != nullptr) {
860         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_TYPEFACE);
861         SkDynamicMemoryWStream buffer;
862         typeface->serialize(&buffer);
863         void* data = sk_malloc_throw(buffer.bytesWritten());
864         buffer.copyTo(data);
865         SkString url = encode_data(
866                 data, buffer.bytesWritten(), "application/octet-stream", urlDataManager);
867         writer.appendString(DEBUGCANVAS_ATTRIBUTE_DATA, url.c_str());
868         sk_free(data);
869         writer.endObject();
870     }
871 }
872 
apply_flattenable(const char * key,SkFlattenable * flattenable,SkJSONWriter & writer,UrlDataManager & urlDataManager)873 static void apply_flattenable(const char*     key,
874                               SkFlattenable*  flattenable,
875                               SkJSONWriter&   writer,
876                               UrlDataManager& urlDataManager) {
877     if (flattenable != nullptr) {
878         writer.beginObject(key);
879         DrawCommand::flatten(flattenable, writer, urlDataManager);
880         writer.endObject();
881     }
882 }
883 
MakeJsonPaint(SkJSONWriter & writer,const SkPaint & paint,UrlDataManager & urlDataManager)884 void DrawCommand::MakeJsonPaint(SkJSONWriter&   writer,
885                                 const SkPaint&  paint,
886                                 UrlDataManager& urlDataManager) {
887     writer.beginObject();
888     store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f);
889     store_scalar(writer,
890                  DEBUGCANVAS_ATTRIBUTE_STROKEMITER,
891                  paint.getStrokeMiter(),
892                  SkPaintDefaults_MiterLimit);
893     store_bool(writer, DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false);
894     store_bool(writer, DEBUGCANVAS_ATTRIBUTE_DITHER, paint.isDither(), false);
895 
896     apply_paint_color(paint, writer);
897     apply_paint_style(paint, writer);
898     apply_paint_blend_mode(paint, writer);
899     apply_paint_cap(paint, writer);
900     apply_paint_join(paint, writer);
901     apply_paint_filterquality(paint, writer);
902     apply_paint_patheffect(paint, writer, urlDataManager);
903     apply_paint_maskfilter(paint, writer, urlDataManager);
904     apply_flattenable(DEBUGCANVAS_ATTRIBUTE_SHADER, paint.getShader(), writer, urlDataManager);
905     apply_flattenable(
906             DEBUGCANVAS_ATTRIBUTE_IMAGEFILTER, paint.getImageFilter(), writer, urlDataManager);
907     apply_flattenable(
908             DEBUGCANVAS_ATTRIBUTE_COLORFILTER, paint.getColorFilter(), writer, urlDataManager);
909     writer.endObject();  // paint
910 }
911 
MakeJsonFont(const SkFont & font,SkJSONWriter & writer,UrlDataManager & urlDataManager)912 static void MakeJsonFont(const SkFont& font, SkJSONWriter& writer, UrlDataManager& urlDataManager) {
913     writer.beginObject();
914     store_bool(writer, DEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT, font.isEmbolden(), false);
915     store_bool(writer, DEBUGCANVAS_ATTRIBUTE_LINEARTEXT, font.isLinearMetrics(), false);
916     store_bool(writer, DEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT, font.isSubpixel(), false);
917     store_bool(writer, DEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT, font.isEmbeddedBitmaps(), false);
918     store_bool(writer, DEBUGCANVAS_ATTRIBUTE_AUTOHINTING, font.isForceAutoHinting(), false);
919 
920     store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSIZE, font.getSize(), SkPaintDefaults_TextSize);
921     store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getScaleX(), SK_Scalar1);
922     store_scalar(writer, DEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, font.getSkewX(), 0.0f);
923     apply_font_edging(font, writer);
924     apply_font_hinting(font, writer);
925     apply_font_typeface(font, writer, urlDataManager);
926     writer.endObject();  // font
927 }
928 
MakeJsonLattice(SkJSONWriter & writer,const SkCanvas::Lattice & lattice)929 void DrawCommand::MakeJsonLattice(SkJSONWriter& writer, const SkCanvas::Lattice& lattice) {
930     writer.beginObject();
931     writer.appendS32(DEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT, lattice.fXCount);
932     writer.appendS32(DEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT, lattice.fYCount);
933     if (nullptr != lattice.fBounds) {
934         writer.appendName(DEBUGCANVAS_ATTRIBUTE_BOUNDS);
935         MakeJsonIRect(writer, *lattice.fBounds);
936     }
937     writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS);
938     for (int i = 0; i < lattice.fXCount; i++) {
939         writer.appendS32(lattice.fXDivs[i]);
940     }
941     writer.endArray();  // xdivs
942     writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS);
943     for (int i = 0; i < lattice.fYCount; i++) {
944         writer.appendS32(lattice.fYDivs[i]);
945     }
946     writer.endArray();  // ydivs
947     if (nullptr != lattice.fRectTypes) {
948         writer.beginArray(DEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS);
949         int flagCount = 0;
950         for (int row = 0; row < lattice.fYCount + 1; row++) {
951             writer.beginArray();
952             for (int column = 0; column < lattice.fXCount + 1; column++) {
953                 writer.appendS32(lattice.fRectTypes[flagCount++]);
954             }
955             writer.endArray();  // row
956         }
957         writer.endArray();
958     }
959     writer.endObject();
960 }
961 
ClearCommand(SkColor color)962 ClearCommand::ClearCommand(SkColor color) : INHERITED(kClear_OpType) { fColor = color; }
963 
execute(SkCanvas * canvas) const964 void ClearCommand::execute(SkCanvas* canvas) const { canvas->clear(fColor); }
965 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const966 void ClearCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
967     INHERITED::toJSON(writer, urlDataManager);
968     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COLOR);
969     MakeJsonColor(writer, fColor);
970 }
971 
ClipPathCommand(const SkPath & path,SkClipOp op,bool doAA)972 ClipPathCommand::ClipPathCommand(const SkPath& path, SkClipOp op, bool doAA)
973         : INHERITED(kClipPath_OpType) {
974     fPath = path;
975     fOp   = op;
976     fDoAA = doAA;
977 }
978 
execute(SkCanvas * canvas) const979 void ClipPathCommand::execute(SkCanvas* canvas) const { canvas->clipPath(fPath, fOp, fDoAA); }
980 
render(SkCanvas * canvas) const981 bool ClipPathCommand::render(SkCanvas* canvas) const {
982     render_path(canvas, fPath);
983     return true;
984 }
985 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const986 void ClipPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
987     INHERITED::toJSON(writer, urlDataManager);
988     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH);
989     MakeJsonPath(writer, fPath);
990     writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
991     writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
992 }
993 
ClipRegionCommand(const SkRegion & region,SkClipOp op)994 ClipRegionCommand::ClipRegionCommand(const SkRegion& region, SkClipOp op)
995         : INHERITED(kClipRegion_OpType) {
996     fRegion = region;
997     fOp     = op;
998 }
999 
execute(SkCanvas * canvas) const1000 void ClipRegionCommand::execute(SkCanvas* canvas) const { canvas->clipRegion(fRegion, fOp); }
1001 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1002 void ClipRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1003     INHERITED::toJSON(writer, urlDataManager);
1004     writer.appendName(DEBUGCANVAS_ATTRIBUTE_REGION);
1005     MakeJsonRegion(writer, fRegion);
1006     writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
1007 }
1008 
ClipRectCommand(const SkRect & rect,SkClipOp op,bool doAA)1009 ClipRectCommand::ClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA)
1010         : INHERITED(kClipRect_OpType) {
1011     fRect = rect;
1012     fOp   = op;
1013     fDoAA = doAA;
1014 }
1015 
execute(SkCanvas * canvas) const1016 void ClipRectCommand::execute(SkCanvas* canvas) const { canvas->clipRect(fRect, fOp, fDoAA); }
1017 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1018 void ClipRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1019     INHERITED::toJSON(writer, urlDataManager);
1020     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1021     MakeJsonRect(writer, fRect);
1022     writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
1023     writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
1024 
1025     SkString desc;
1026     writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fRect)->c_str());
1027 }
1028 
ClipRRectCommand(const SkRRect & rrect,SkClipOp op,bool doAA)1029 ClipRRectCommand::ClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA)
1030         : INHERITED(kClipRRect_OpType) {
1031     fRRect = rrect;
1032     fOp    = op;
1033     fDoAA  = doAA;
1034 }
1035 
execute(SkCanvas * canvas) const1036 void ClipRRectCommand::execute(SkCanvas* canvas) const { canvas->clipRRect(fRRect, fOp, fDoAA); }
1037 
render(SkCanvas * canvas) const1038 bool ClipRRectCommand::render(SkCanvas* canvas) const {
1039     render_rrect(canvas, fRRect);
1040     return true;
1041 }
1042 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1043 void ClipRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1044     INHERITED::toJSON(writer, urlDataManager);
1045     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1046     make_json_rrect(writer, fRRect);
1047     writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
1048     writer.appendBool(DEBUGCANVAS_ATTRIBUTE_ANTIALIAS, fDoAA);
1049 }
1050 
ClipShaderCommand(sk_sp<SkShader> cs,SkClipOp op)1051 ClipShaderCommand::ClipShaderCommand(sk_sp<SkShader> cs, SkClipOp op)
1052         : INHERITED(kClipShader_OpType) {
1053     fShader = cs;
1054     fOp     = op;
1055 }
1056 
execute(SkCanvas * canvas) const1057 void ClipShaderCommand::execute(SkCanvas* canvas) const { canvas->clipShader(fShader, fOp); }
1058 
render(SkCanvas * canvas) const1059 bool ClipShaderCommand::render(SkCanvas* canvas) const {
1060     SkPaint paint;
1061     paint.setShader(fShader);
1062     canvas->drawPaint(paint);
1063     return true;
1064 }
1065 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1066 void ClipShaderCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1067     INHERITED::toJSON(writer, urlDataManager);
1068     apply_flattenable(DEBUGCANVAS_ATTRIBUTE_SHADER, fShader.get(), writer, urlDataManager);
1069     writer.appendString(DEBUGCANVAS_ATTRIBUTE_REGIONOP, regionop_name(fOp));
1070 }
1071 
ConcatCommand(const SkMatrix & matrix)1072 ConcatCommand::ConcatCommand(const SkMatrix& matrix) : INHERITED(kConcat_OpType) {
1073     fMatrix = matrix;
1074 }
1075 
execute(SkCanvas * canvas) const1076 void ConcatCommand::execute(SkCanvas* canvas) const { canvas->concat(fMatrix); }
1077 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1078 void ConcatCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1079     INHERITED::toJSON(writer, urlDataManager);
1080     writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX);
1081     MakeJsonMatrix(writer, fMatrix);
1082 }
1083 
1084 ////
1085 
DrawAnnotationCommand(const SkRect & rect,const char key[],sk_sp<SkData> value)1086 DrawAnnotationCommand::DrawAnnotationCommand(const SkRect& rect,
1087                                              const char    key[],
1088                                              sk_sp<SkData> value)
1089         : INHERITED(kDrawAnnotation_OpType), fRect(rect), fKey(key), fValue(std::move(value)) {}
1090 
execute(SkCanvas * canvas) const1091 void DrawAnnotationCommand::execute(SkCanvas* canvas) const {
1092     canvas->drawAnnotation(fRect, fKey.c_str(), fValue);
1093 }
1094 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1095 void DrawAnnotationCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1096     INHERITED::toJSON(writer, urlDataManager);
1097 
1098     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1099     MakeJsonRect(writer, fRect);
1100     writer.appendString("key", fKey.c_str());
1101     if (fValue.get()) {
1102         // TODO: dump out the "value"
1103     }
1104 
1105     SkString desc;
1106     str_append(&desc, fRect)->appendf(" %s", fKey.c_str());
1107     writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, desc.c_str());
1108 }
1109 
1110 ////
1111 
DrawImageCommand(const SkImage * image,SkScalar left,SkScalar top,const SkPaint * paint)1112 DrawImageCommand::DrawImageCommand(const SkImage* image,
1113                                    SkScalar       left,
1114                                    SkScalar       top,
1115                                    const SkPaint* paint)
1116         : INHERITED(kDrawImage_OpType)
1117         , fImage(SkRef(image))
1118         , fLeft(left)
1119         , fTop(top)
1120         , fPaint(paint) {}
1121 
execute(SkCanvas * canvas) const1122 void DrawImageCommand::execute(SkCanvas* canvas) const {
1123     canvas->drawImage(fImage.get(), fLeft, fTop, fPaint.getMaybeNull());
1124 }
1125 
render(SkCanvas * canvas) const1126 bool DrawImageCommand::render(SkCanvas* canvas) const {
1127     SkAutoCanvasRestore acr(canvas, true);
1128     canvas->clear(0xFFFFFFFF);
1129 
1130     xlate_and_scale_to_bounds(
1131             canvas,
1132             SkRect::MakeXYWH(
1133                     fLeft, fTop, SkIntToScalar(fImage->width()), SkIntToScalar(fImage->height())));
1134     this->execute(canvas);
1135     return true;
1136 }
1137 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1138 void DrawImageCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1139     INHERITED::toJSON(writer, urlDataManager);
1140 
1141 
1142     if (urlDataManager.hasImageIndex()) {
1143         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
1144         writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
1145     } else {
1146         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
1147         flatten(*fImage, writer, urlDataManager);
1148         writer.endObject();  // image
1149     }
1150 
1151     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1152     MakeJsonPoint(writer, fLeft, fTop);
1153     if (fPaint.isValid()) {
1154         writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1155         MakeJsonPaint(writer, *fPaint, urlDataManager);
1156     }
1157 
1158     writer.appendU32(DEBUGCANVAS_ATTRIBUTE_UNIQUE_ID, fImage->uniqueID());
1159     writer.appendS32(DEBUGCANVAS_ATTRIBUTE_WIDTH, fImage->width());
1160     writer.appendS32(DEBUGCANVAS_ATTRIBUTE_HEIGHT, fImage->height());
1161     switch (fImage->alphaType()) {
1162         case kOpaque_SkAlphaType:
1163             writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_OPAQUE);
1164             break;
1165         case kPremul_SkAlphaType:
1166             writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_PREMUL);
1167             break;
1168         case kUnpremul_SkAlphaType:
1169             writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_UNPREMUL);
1170             break;
1171         default:
1172             writer.appendString(DEBUGCANVAS_ATTRIBUTE_ALPHA, DEBUGCANVAS_ALPHATYPE_UNKNOWN);
1173             break;
1174     }
1175 }
1176 
DrawImageLatticeCommand(const SkImage * image,const SkCanvas::Lattice & lattice,const SkRect & dst,const SkPaint * paint)1177 DrawImageLatticeCommand::DrawImageLatticeCommand(const SkImage*           image,
1178                                                  const SkCanvas::Lattice& lattice,
1179                                                  const SkRect&            dst,
1180                                                  const SkPaint*           paint)
1181         : INHERITED(kDrawImageLattice_OpType)
1182         , fImage(SkRef(image))
1183         , fLattice(lattice)
1184         , fDst(dst)
1185         , fPaint(paint) {}
1186 
execute(SkCanvas * canvas) const1187 void DrawImageLatticeCommand::execute(SkCanvas* canvas) const {
1188     canvas->drawImageLattice(fImage.get(), fLattice, fDst, fPaint.getMaybeNull());
1189 }
1190 
render(SkCanvas * canvas) const1191 bool DrawImageLatticeCommand::render(SkCanvas* canvas) const {
1192     SkAutoCanvasRestore acr(canvas, true);
1193     canvas->clear(0xFFFFFFFF);
1194 
1195     xlate_and_scale_to_bounds(canvas, fDst);
1196 
1197     this->execute(canvas);
1198     return true;
1199 }
1200 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1201 void DrawImageLatticeCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1202     INHERITED::toJSON(writer, urlDataManager);
1203     if (urlDataManager.hasImageIndex()) {
1204         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
1205         writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
1206     } else {
1207         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
1208         flatten(*fImage, writer, urlDataManager);
1209         writer.endObject();  // image
1210     }
1211 
1212     writer.appendName(DEBUGCANVAS_ATTRIBUTE_LATTICE);
1213     MakeJsonLattice(writer, fLattice);
1214     writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
1215     MakeJsonRect(writer, fDst);
1216     if (fPaint.isValid()) {
1217         writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1218         MakeJsonPaint(writer, *fPaint, urlDataManager);
1219     }
1220 
1221     SkString desc;
1222     writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
1223 }
1224 
DrawImageRectCommand(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)1225 DrawImageRectCommand::DrawImageRectCommand(const SkImage*              image,
1226                                            const SkRect*               src,
1227                                            const SkRect&               dst,
1228                                            const SkPaint*              paint,
1229                                            SkCanvas::SrcRectConstraint constraint)
1230         : INHERITED(kDrawImageRect_OpType)
1231         , fImage(SkRef(image))
1232         , fSrc(src)
1233         , fDst(dst)
1234         , fPaint(paint)
1235         , fConstraint(constraint) {}
1236 
execute(SkCanvas * canvas) const1237 void DrawImageRectCommand::execute(SkCanvas* canvas) const {
1238     canvas->legacy_drawImageRect(
1239             fImage.get(), fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), fConstraint);
1240 }
1241 
render(SkCanvas * canvas) const1242 bool DrawImageRectCommand::render(SkCanvas* canvas) const {
1243     SkAutoCanvasRestore acr(canvas, true);
1244     canvas->clear(0xFFFFFFFF);
1245 
1246     xlate_and_scale_to_bounds(canvas, fDst);
1247 
1248     this->execute(canvas);
1249     return true;
1250 }
1251 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1252 void DrawImageRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1253     INHERITED::toJSON(writer, urlDataManager);
1254     if (urlDataManager.hasImageIndex()) {
1255         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
1256         writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
1257     } else {
1258         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
1259         flatten(*fImage, writer, urlDataManager);
1260         writer.endObject();  // image
1261     }
1262 
1263     if (fSrc.isValid()) {
1264         writer.appendName(DEBUGCANVAS_ATTRIBUTE_SRC);
1265         MakeJsonRect(writer, *fSrc);
1266     }
1267     writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
1268     MakeJsonRect(writer, fDst);
1269     if (fPaint.isValid()) {
1270         writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1271         MakeJsonPaint(writer, *fPaint, urlDataManager);
1272     }
1273     if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
1274         writer.appendBool(DEBUGCANVAS_ATTRIBUTE_STRICT, true);
1275     }
1276 
1277     SkString desc;
1278     writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
1279 }
1280 
DrawImageRectLayerCommand(DebugLayerManager * layerManager,const int nodeId,const int frame,const SkRect * src,const SkRect & dst,const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)1281 DrawImageRectLayerCommand::DrawImageRectLayerCommand(DebugLayerManager*    layerManager,
1282                                                      const int                   nodeId,
1283                                                      const int                   frame,
1284                                                      const SkRect*               src,
1285                                                      const SkRect&               dst,
1286                                                      const SkPaint*              paint,
1287                                                      SkCanvas::SrcRectConstraint constraint)
1288         : INHERITED(kDrawImageRectLayer_OpType)
1289         , fLayerManager(layerManager)
1290         , fNodeId(nodeId)
1291         , fFrame(frame)
1292         , fSrc(src)
1293         , fDst(dst)
1294         , fPaint(paint)
1295         , fConstraint(constraint) {}
1296 
execute(SkCanvas * canvas) const1297 void DrawImageRectLayerCommand::execute(SkCanvas* canvas) const {
1298     sk_sp<SkImage> snapshot = fLayerManager->getLayerAsImage(fNodeId, fFrame);
1299     canvas->legacy_drawImageRect(
1300             snapshot.get(), fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), fConstraint);
1301 }
1302 
render(SkCanvas * canvas) const1303 bool DrawImageRectLayerCommand::render(SkCanvas* canvas) const {
1304     SkAutoCanvasRestore acr(canvas, true);
1305     canvas->clear(0xFFFFFFFF);
1306 
1307     xlate_and_scale_to_bounds(canvas, fDst);
1308 
1309     this->execute(canvas);
1310     return true;
1311 }
1312 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1313 void DrawImageRectLayerCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1314     INHERITED::toJSON(writer, urlDataManager);
1315 
1316     // Don't append an image attribute here, the image can be rendered in as many different ways
1317     // as there are commands in the layer, at least. the urlDataManager would save each one under
1318     // a different URL.
1319     // Append the node id, and the layer inspector of the debugger will know what to do with it.
1320     writer.appendS64(DEBUGCANVAS_ATTRIBUTE_LAYERNODEID, fNodeId);
1321 
1322     if (fSrc.isValid()) {
1323         writer.appendName(DEBUGCANVAS_ATTRIBUTE_SRC);
1324         MakeJsonRect(writer, *fSrc);
1325     }
1326     writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
1327     MakeJsonRect(writer, fDst);
1328     if (fPaint.isValid()) {
1329         writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1330         MakeJsonPaint(writer, *fPaint, urlDataManager);
1331     }
1332     if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
1333         writer.appendBool(DEBUGCANVAS_ATTRIBUTE_STRICT, true);
1334     }
1335 
1336     SkString desc;
1337     writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fDst)->c_str());
1338 }
1339 
DrawImageNineCommand(const SkImage * image,const SkIRect & center,const SkRect & dst,const SkPaint * paint)1340 DrawImageNineCommand::DrawImageNineCommand(const SkImage* image,
1341                                            const SkIRect& center,
1342                                            const SkRect&  dst,
1343                                            const SkPaint* paint)
1344         : INHERITED(kDrawImageNine_OpType)
1345         , fImage(SkRef(image))
1346         , fCenter(center)
1347         , fDst(dst)
1348         , fPaint(paint) {}
1349 
execute(SkCanvas * canvas) const1350 void DrawImageNineCommand::execute(SkCanvas* canvas) const {
1351     canvas->drawImageNine(fImage.get(), fCenter, fDst, fPaint.getMaybeNull());
1352 }
1353 
render(SkCanvas * canvas) const1354 bool DrawImageNineCommand::render(SkCanvas* canvas) const {
1355     SkAutoCanvasRestore acr(canvas, true);
1356     canvas->clear(0xFFFFFFFF);
1357 
1358     xlate_and_scale_to_bounds(canvas, fDst);
1359 
1360     this->execute(canvas);
1361     return true;
1362 }
1363 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1364 void DrawImageNineCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1365     INHERITED::toJSON(writer, urlDataManager);
1366     if (urlDataManager.hasImageIndex()) {
1367         writer.appendName(DEBUGCANVAS_ATTRIBUTE_IMAGE_INDEX);
1368         writer.appendU64((uint64_t)urlDataManager.lookupImage(fImage.get()));
1369     } else {
1370         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_IMAGE);
1371         flatten(*fImage, writer, urlDataManager);
1372         writer.endObject();  // image
1373     }
1374 
1375     writer.appendName(DEBUGCANVAS_ATTRIBUTE_CENTER);
1376     MakeJsonIRect(writer, fCenter);
1377     writer.appendName(DEBUGCANVAS_ATTRIBUTE_DST);
1378     MakeJsonRect(writer, fDst);
1379     if (fPaint.isValid()) {
1380         writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1381         MakeJsonPaint(writer, *fPaint, urlDataManager);
1382     }
1383 }
1384 
DrawOvalCommand(const SkRect & oval,const SkPaint & paint)1385 DrawOvalCommand::DrawOvalCommand(const SkRect& oval, const SkPaint& paint)
1386         : INHERITED(kDrawOval_OpType) {
1387     fOval  = oval;
1388     fPaint = paint;
1389 }
1390 
execute(SkCanvas * canvas) const1391 void DrawOvalCommand::execute(SkCanvas* canvas) const { canvas->drawOval(fOval, fPaint); }
1392 
render(SkCanvas * canvas) const1393 bool DrawOvalCommand::render(SkCanvas* canvas) const {
1394     canvas->clear(0xFFFFFFFF);
1395     canvas->save();
1396 
1397     xlate_and_scale_to_bounds(canvas, fOval);
1398 
1399     SkPaint p;
1400     p.setColor(SK_ColorBLACK);
1401     p.setStyle(SkPaint::kStroke_Style);
1402 
1403     canvas->drawOval(fOval, p);
1404     canvas->restore();
1405 
1406     return true;
1407 }
1408 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1409 void DrawOvalCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1410     INHERITED::toJSON(writer, urlDataManager);
1411     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1412     MakeJsonRect(writer, fOval);
1413     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1414     MakeJsonPaint(writer, fPaint, urlDataManager);
1415 }
1416 
DrawArcCommand(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)1417 DrawArcCommand::DrawArcCommand(const SkRect&  oval,
1418                                SkScalar       startAngle,
1419                                SkScalar       sweepAngle,
1420                                bool           useCenter,
1421                                const SkPaint& paint)
1422         : INHERITED(kDrawArc_OpType) {
1423     fOval       = oval;
1424     fStartAngle = startAngle;
1425     fSweepAngle = sweepAngle;
1426     fUseCenter  = useCenter;
1427     fPaint      = paint;
1428 }
1429 
execute(SkCanvas * canvas) const1430 void DrawArcCommand::execute(SkCanvas* canvas) const {
1431     canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, fPaint);
1432 }
1433 
render(SkCanvas * canvas) const1434 bool DrawArcCommand::render(SkCanvas* canvas) const {
1435     canvas->clear(0xFFFFFFFF);
1436     canvas->save();
1437 
1438     xlate_and_scale_to_bounds(canvas, fOval);
1439 
1440     SkPaint p;
1441     p.setColor(SK_ColorBLACK);
1442     p.setStyle(SkPaint::kStroke_Style);
1443 
1444     canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, p);
1445     canvas->restore();
1446 
1447     return true;
1448 }
1449 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1450 void DrawArcCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1451     INHERITED::toJSON(writer, urlDataManager);
1452     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1453     MakeJsonRect(writer, fOval);
1454     writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_STARTANGLE, fStartAngle);
1455     writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_SWEEPANGLE, fSweepAngle);
1456     writer.appendBool(DEBUGCANVAS_ATTRIBUTE_USECENTER, fUseCenter);
1457     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1458     MakeJsonPaint(writer, fPaint, urlDataManager);
1459 }
1460 
DrawPaintCommand(const SkPaint & paint)1461 DrawPaintCommand::DrawPaintCommand(const SkPaint& paint) : INHERITED(kDrawPaint_OpType) {
1462     fPaint = paint;
1463 }
1464 
execute(SkCanvas * canvas) const1465 void DrawPaintCommand::execute(SkCanvas* canvas) const { canvas->drawPaint(fPaint); }
1466 
render(SkCanvas * canvas) const1467 bool DrawPaintCommand::render(SkCanvas* canvas) const {
1468     canvas->clear(0xFFFFFFFF);
1469     canvas->drawPaint(fPaint);
1470     return true;
1471 }
1472 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1473 void DrawPaintCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1474     INHERITED::toJSON(writer, urlDataManager);
1475     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1476     MakeJsonPaint(writer, fPaint, urlDataManager);
1477 }
1478 
DrawBehindCommand(const SkPaint & paint)1479 DrawBehindCommand::DrawBehindCommand(const SkPaint& paint) : INHERITED(kDrawPaint_OpType) {
1480     fPaint = paint;
1481 }
1482 
execute(SkCanvas * canvas) const1483 void DrawBehindCommand::execute(SkCanvas* canvas) const {
1484     SkCanvasPriv::DrawBehind(canvas, fPaint);
1485 }
1486 
render(SkCanvas * canvas) const1487 bool DrawBehindCommand::render(SkCanvas* canvas) const {
1488     canvas->clear(0xFFFFFFFF);
1489     SkCanvasPriv::DrawBehind(canvas, fPaint);
1490     return true;
1491 }
1492 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1493 void DrawBehindCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1494     INHERITED::toJSON(writer, urlDataManager);
1495     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1496     MakeJsonPaint(writer, fPaint, urlDataManager);
1497 }
1498 
DrawPathCommand(const SkPath & path,const SkPaint & paint)1499 DrawPathCommand::DrawPathCommand(const SkPath& path, const SkPaint& paint)
1500         : INHERITED(kDrawPath_OpType) {
1501     fPath  = path;
1502     fPaint = paint;
1503 }
1504 
execute(SkCanvas * canvas) const1505 void DrawPathCommand::execute(SkCanvas* canvas) const { canvas->drawPath(fPath, fPaint); }
1506 
render(SkCanvas * canvas) const1507 bool DrawPathCommand::render(SkCanvas* canvas) const {
1508     render_path(canvas, fPath);
1509     return true;
1510 }
1511 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1512 void DrawPathCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1513     INHERITED::toJSON(writer, urlDataManager);
1514     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH);
1515     MakeJsonPath(writer, fPath);
1516     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1517     MakeJsonPaint(writer, fPaint, urlDataManager);
1518 }
1519 
DrawRegionCommand(const SkRegion & region,const SkPaint & paint)1520 DrawRegionCommand::DrawRegionCommand(const SkRegion& region, const SkPaint& paint)
1521         : INHERITED(kDrawRegion_OpType) {
1522     fRegion = region;
1523     fPaint  = paint;
1524 }
1525 
execute(SkCanvas * canvas) const1526 void DrawRegionCommand::execute(SkCanvas* canvas) const { canvas->drawRegion(fRegion, fPaint); }
1527 
render(SkCanvas * canvas) const1528 bool DrawRegionCommand::render(SkCanvas* canvas) const {
1529     render_region(canvas, fRegion);
1530     return true;
1531 }
1532 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1533 void DrawRegionCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1534     INHERITED::toJSON(writer, urlDataManager);
1535     writer.appendName(DEBUGCANVAS_ATTRIBUTE_REGION);
1536     MakeJsonRegion(writer, fRegion);
1537     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1538     MakeJsonPaint(writer, fPaint, urlDataManager);
1539 }
1540 
BeginDrawPictureCommand(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)1541 BeginDrawPictureCommand::BeginDrawPictureCommand(const SkPicture* picture,
1542                                                  const SkMatrix*  matrix,
1543                                                  const SkPaint*   paint)
1544         : INHERITED(kBeginDrawPicture_OpType)
1545         , fPicture(SkRef(picture))
1546         , fMatrix(matrix)
1547         , fPaint(paint) {}
1548 
execute(SkCanvas * canvas) const1549 void BeginDrawPictureCommand::execute(SkCanvas* canvas) const {
1550     if (fPaint.isValid()) {
1551         SkRect bounds = fPicture->cullRect();
1552         if (fMatrix.isValid()) {
1553             fMatrix->mapRect(&bounds);
1554         }
1555         canvas->saveLayer(&bounds, fPaint.get());
1556     }
1557 
1558     if (fMatrix.isValid()) {
1559         if (!fPaint.isValid()) {
1560             canvas->save();
1561         }
1562         canvas->concat(*fMatrix);
1563     }
1564 }
1565 
render(SkCanvas * canvas) const1566 bool BeginDrawPictureCommand::render(SkCanvas* canvas) const {
1567     canvas->clear(0xFFFFFFFF);
1568     canvas->save();
1569 
1570     xlate_and_scale_to_bounds(canvas, fPicture->cullRect());
1571 
1572     canvas->drawPicture(fPicture.get());
1573 
1574     canvas->restore();
1575 
1576     return true;
1577 }
1578 
EndDrawPictureCommand(bool restore)1579 EndDrawPictureCommand::EndDrawPictureCommand(bool restore)
1580         : INHERITED(kEndDrawPicture_OpType), fRestore(restore) {}
1581 
execute(SkCanvas * canvas) const1582 void EndDrawPictureCommand::execute(SkCanvas* canvas) const {
1583     if (fRestore) {
1584         canvas->restore();
1585     }
1586 }
1587 
DrawPointsCommand(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)1588 DrawPointsCommand::DrawPointsCommand(SkCanvas::PointMode mode,
1589                                      size_t              count,
1590                                      const SkPoint       pts[],
1591                                      const SkPaint&      paint)
1592         : INHERITED(kDrawPoints_OpType), fMode(mode), fPts(pts, count), fPaint(paint) {}
1593 
execute(SkCanvas * canvas) const1594 void DrawPointsCommand::execute(SkCanvas* canvas) const {
1595     canvas->drawPoints(fMode, fPts.count(), fPts.begin(), fPaint);
1596 }
1597 
render(SkCanvas * canvas) const1598 bool DrawPointsCommand::render(SkCanvas* canvas) const {
1599     canvas->clear(0xFFFFFFFF);
1600     canvas->save();
1601 
1602     SkRect bounds;
1603 
1604     bounds.setEmpty();
1605     for (int i = 0; i < fPts.count(); ++i) {
1606         SkRectPriv::GrowToInclude(&bounds, fPts[i]);
1607     }
1608 
1609     xlate_and_scale_to_bounds(canvas, bounds);
1610 
1611     SkPaint p;
1612     p.setColor(SK_ColorBLACK);
1613     p.setStyle(SkPaint::kStroke_Style);
1614 
1615     canvas->drawPoints(fMode, fPts.count(), fPts.begin(), p);
1616     canvas->restore();
1617 
1618     return true;
1619 }
1620 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1621 void DrawPointsCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1622     INHERITED::toJSON(writer, urlDataManager);
1623     writer.appendString(DEBUGCANVAS_ATTRIBUTE_MODE, pointmode_name(fMode));
1624     writer.beginArray(DEBUGCANVAS_ATTRIBUTE_POINTS);
1625     for (int i = 0; i < fPts.count(); i++) {
1626         MakeJsonPoint(writer, fPts[i]);
1627     }
1628     writer.endArray();  // points
1629     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1630     MakeJsonPaint(writer, fPaint, urlDataManager);
1631 }
1632 
DrawTextBlobCommand(sk_sp<SkTextBlob> blob,SkScalar x,SkScalar y,const SkPaint & paint)1633 DrawTextBlobCommand::DrawTextBlobCommand(sk_sp<SkTextBlob> blob,
1634                                          SkScalar          x,
1635                                          SkScalar          y,
1636                                          const SkPaint&    paint)
1637         : INHERITED(kDrawTextBlob_OpType)
1638         , fBlob(std::move(blob))
1639         , fXPos(x)
1640         , fYPos(y)
1641         , fPaint(paint) {}
1642 
execute(SkCanvas * canvas) const1643 void DrawTextBlobCommand::execute(SkCanvas* canvas) const {
1644     canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
1645 }
1646 
render(SkCanvas * canvas) const1647 bool DrawTextBlobCommand::render(SkCanvas* canvas) const {
1648     canvas->clear(SK_ColorWHITE);
1649     canvas->save();
1650 
1651     SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos);
1652     xlate_and_scale_to_bounds(canvas, bounds);
1653 
1654     canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
1655 
1656     canvas->restore();
1657 
1658     return true;
1659 }
1660 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1661 void DrawTextBlobCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1662     INHERITED::toJSON(writer, urlDataManager);
1663     writer.beginArray(DEBUGCANVAS_ATTRIBUTE_RUNS);
1664     SkTextBlobRunIterator iter(fBlob.get());
1665     while (!iter.done()) {
1666         writer.beginObject();  // run
1667         writer.beginArray(DEBUGCANVAS_ATTRIBUTE_GLYPHS);
1668         for (uint32_t i = 0; i < iter.glyphCount(); i++) {
1669             writer.appendU32(iter.glyphs()[i]);
1670         }
1671         writer.endArray();  // glyphs
1672         if (iter.positioning() != SkTextBlobRunIterator::kDefault_Positioning) {
1673             writer.beginArray(DEBUGCANVAS_ATTRIBUTE_POSITIONS);
1674             const SkScalar* iterPositions = iter.pos();
1675             for (uint32_t i = 0; i < iter.glyphCount(); i++) {
1676                 switch (iter.positioning()) {
1677                     case SkTextBlobRunIterator::kFull_Positioning:
1678                         MakeJsonPoint(writer, iterPositions[i * 2], iterPositions[i * 2 + 1]);
1679                         break;
1680                     case SkTextBlobRunIterator::kHorizontal_Positioning:
1681                         writer.appendFloat(iterPositions[i]);
1682                         break;
1683                     case SkTextBlobRunIterator::kDefault_Positioning: break;
1684                     case SkTextBlobRunIterator::kRSXform_Positioning:
1685                         // TODO_RSXFORM_BLOB
1686                         break;
1687                 }
1688             }
1689             writer.endArray();  // positions
1690         }
1691         writer.appendName(DEBUGCANVAS_ATTRIBUTE_FONT);
1692         MakeJsonFont(iter.font(), writer, urlDataManager);
1693         writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1694         MakeJsonPoint(writer, iter.offset());
1695 
1696         writer.endObject();  // run
1697         iter.next();
1698     }
1699     writer.endArray();  // runs
1700     writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_X, fXPos);
1701     writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_Y, fYPos);
1702     SkRect bounds = fBlob->bounds();
1703     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1704     MakeJsonRect(writer, bounds);
1705     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1706     MakeJsonPaint(writer, fPaint, urlDataManager);
1707 
1708     SkString desc;
1709     // make the bounds local by applying the x,y
1710     bounds.offset(fXPos, fYPos);
1711     writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, bounds)->c_str());
1712 }
1713 
DrawPatchCommand(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)1714 DrawPatchCommand::DrawPatchCommand(const SkPoint  cubics[12],
1715                                    const SkColor  colors[4],
1716                                    const SkPoint  texCoords[4],
1717                                    SkBlendMode    bmode,
1718                                    const SkPaint& paint)
1719         : INHERITED(kDrawPatch_OpType), fBlendMode(bmode) {
1720     memcpy(fCubics, cubics, sizeof(fCubics));
1721     if (colors != nullptr) {
1722         memcpy(fColors, colors, sizeof(fColors));
1723         fColorsPtr = fColors;
1724     } else {
1725         fColorsPtr = nullptr;
1726     }
1727     if (texCoords != nullptr) {
1728         memcpy(fTexCoords, texCoords, sizeof(fTexCoords));
1729         fTexCoordsPtr = fTexCoords;
1730     } else {
1731         fTexCoordsPtr = nullptr;
1732     }
1733     fPaint = paint;
1734 }
1735 
execute(SkCanvas * canvas) const1736 void DrawPatchCommand::execute(SkCanvas* canvas) const {
1737     canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fBlendMode, fPaint);
1738 }
1739 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1740 void DrawPatchCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1741     INHERITED::toJSON(writer, urlDataManager);
1742     writer.beginArray(DEBUGCANVAS_ATTRIBUTE_CUBICS);
1743     for (int i = 0; i < 12; i++) {
1744         MakeJsonPoint(writer, fCubics[i]);
1745     }
1746     writer.endArray();  // cubics
1747     if (fColorsPtr != nullptr) {
1748         writer.beginArray(DEBUGCANVAS_ATTRIBUTE_COLORS);
1749         for (int i = 0; i < 4; i++) {
1750             MakeJsonColor(writer, fColorsPtr[i]);
1751         }
1752         writer.endArray();  // colors
1753     }
1754     if (fTexCoordsPtr != nullptr) {
1755         writer.beginArray(DEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS);
1756         for (int i = 0; i < 4; i++) {
1757             MakeJsonPoint(writer, fTexCoords[i]);
1758         }
1759         writer.endArray();  // texCoords
1760     }
1761     // fBlendMode
1762 }
1763 
DrawRectCommand(const SkRect & rect,const SkPaint & paint)1764 DrawRectCommand::DrawRectCommand(const SkRect& rect, const SkPaint& paint)
1765         : INHERITED(kDrawRect_OpType) {
1766     fRect  = rect;
1767     fPaint = paint;
1768 }
1769 
execute(SkCanvas * canvas) const1770 void DrawRectCommand::execute(SkCanvas* canvas) const { canvas->drawRect(fRect, fPaint); }
1771 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1772 void DrawRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1773     INHERITED::toJSON(writer, urlDataManager);
1774     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1775     MakeJsonRect(writer, fRect);
1776     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1777     MakeJsonPaint(writer, fPaint, urlDataManager);
1778 
1779     SkString desc;
1780     writer.appendString(DEBUGCANVAS_ATTRIBUTE_SHORTDESC, str_append(&desc, fRect)->c_str());
1781 }
1782 
DrawRRectCommand(const SkRRect & rrect,const SkPaint & paint)1783 DrawRRectCommand::DrawRRectCommand(const SkRRect& rrect, const SkPaint& paint)
1784         : INHERITED(kDrawRRect_OpType) {
1785     fRRect = rrect;
1786     fPaint = paint;
1787 }
1788 
execute(SkCanvas * canvas) const1789 void DrawRRectCommand::execute(SkCanvas* canvas) const { canvas->drawRRect(fRRect, fPaint); }
1790 
render(SkCanvas * canvas) const1791 bool DrawRRectCommand::render(SkCanvas* canvas) const {
1792     render_rrect(canvas, fRRect);
1793     return true;
1794 }
1795 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1796 void DrawRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1797     INHERITED::toJSON(writer, urlDataManager);
1798     writer.appendName(DEBUGCANVAS_ATTRIBUTE_COORDS);
1799     make_json_rrect(writer, fRRect);
1800     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1801     MakeJsonPaint(writer, fPaint, urlDataManager);
1802 }
1803 
DrawDRRectCommand(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1804 DrawDRRectCommand::DrawDRRectCommand(const SkRRect& outer,
1805                                      const SkRRect& inner,
1806                                      const SkPaint& paint)
1807         : INHERITED(kDrawDRRect_OpType) {
1808     fOuter = outer;
1809     fInner = inner;
1810     fPaint = paint;
1811 }
1812 
execute(SkCanvas * canvas) const1813 void DrawDRRectCommand::execute(SkCanvas* canvas) const {
1814     canvas->drawDRRect(fOuter, fInner, fPaint);
1815 }
1816 
render(SkCanvas * canvas) const1817 bool DrawDRRectCommand::render(SkCanvas* canvas) const {
1818     render_drrect(canvas, fOuter, fInner);
1819     return true;
1820 }
1821 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1822 void DrawDRRectCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1823     INHERITED::toJSON(writer, urlDataManager);
1824     writer.appendName(DEBUGCANVAS_ATTRIBUTE_OUTER);
1825     make_json_rrect(writer, fOuter);
1826     writer.appendName(DEBUGCANVAS_ATTRIBUTE_INNER);
1827     make_json_rrect(writer, fInner);
1828     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
1829     MakeJsonPaint(writer, fPaint, urlDataManager);
1830 }
1831 
DrawShadowCommand(const SkPath & path,const SkDrawShadowRec & rec)1832 DrawShadowCommand::DrawShadowCommand(const SkPath& path, const SkDrawShadowRec& rec)
1833         : INHERITED(kDrawShadow_OpType) {
1834     fPath      = path;
1835     fShadowRec = rec;
1836 }
1837 
execute(SkCanvas * canvas) const1838 void DrawShadowCommand::execute(SkCanvas* canvas) const {
1839     canvas->private_draw_shadow_rec(fPath, fShadowRec);
1840 }
1841 
render(SkCanvas * canvas) const1842 bool DrawShadowCommand::render(SkCanvas* canvas) const {
1843     render_shadow(canvas, fPath, fShadowRec);
1844     return true;
1845 }
1846 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1847 void DrawShadowCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1848     INHERITED::toJSON(writer, urlDataManager);
1849 
1850     bool geometricOnly = SkToBool(fShadowRec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1851     bool transparentOccluder =
1852             SkToBool(fShadowRec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1853 
1854     writer.appendName(DEBUGCANVAS_ATTRIBUTE_PATH);
1855     MakeJsonPath(writer, fPath);
1856     writer.appendName(DEBUGCANVAS_ATTRIBUTE_ZPLANE);
1857     MakeJsonPoint3(writer, fShadowRec.fZPlaneParams);
1858     writer.appendName(DEBUGCANVAS_ATTRIBUTE_LIGHTPOSITION);
1859     MakeJsonPoint3(writer, fShadowRec.fLightPos);
1860     writer.appendFloat(DEBUGCANVAS_ATTRIBUTE_LIGHTRADIUS, fShadowRec.fLightRadius);
1861     writer.appendName(DEBUGCANVAS_ATTRIBUTE_AMBIENTCOLOR);
1862     MakeJsonColor(writer, fShadowRec.fAmbientColor);
1863     writer.appendName(DEBUGCANVAS_ATTRIBUTE_SPOTCOLOR);
1864     MakeJsonColor(writer, fShadowRec.fSpotColor);
1865     store_bool(writer, DEBUGCANVAS_SHADOWFLAG_TRANSPARENT_OCC, transparentOccluder, false);
1866     store_bool(writer, DEBUGCANVAS_SHADOWFLAG_GEOMETRIC_ONLY, geometricOnly, false);
1867 }
1868 
1869 ///////////////////////////////////////////////////////////////////////////////////////////////////
1870 
DrawEdgeAAQuadCommand(const SkRect & rect,const SkPoint clip[],SkCanvas::QuadAAFlags aa,const SkColor4f & color,SkBlendMode mode)1871 DrawEdgeAAQuadCommand::DrawEdgeAAQuadCommand(const SkRect&         rect,
1872                                              const SkPoint         clip[],
1873                                              SkCanvas::QuadAAFlags aa,
1874                                              const SkColor4f&      color,
1875                                              SkBlendMode           mode)
1876         : INHERITED(kDrawEdgeAAQuad_OpType)
1877         , fRect(rect)
1878         , fHasClip(clip != nullptr)
1879         , fAA(aa)
1880         , fColor(color)
1881         , fMode(mode) {
1882     if (clip) {
1883         for (int i = 0; i < 4; ++i) {
1884             fClip[i] = clip[i];
1885         }
1886     }
1887 }
1888 
execute(SkCanvas * canvas) const1889 void DrawEdgeAAQuadCommand::execute(SkCanvas* canvas) const {
1890     canvas->experimental_DrawEdgeAAQuad(fRect, fHasClip ? fClip : nullptr, fAA, fColor, fMode);
1891 }
1892 
DrawEdgeAAImageSetCommand(const SkCanvas::ImageSetEntry set[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)1893 DrawEdgeAAImageSetCommand::DrawEdgeAAImageSetCommand(const SkCanvas::ImageSetEntry set[],
1894                                                      int                           count,
1895                                                      const SkPoint                 dstClips[],
1896                                                      const SkMatrix              preViewMatrices[],
1897                                                      const SkPaint*              paint,
1898                                                      SkCanvas::SrcRectConstraint constraint)
1899         : INHERITED(kDrawEdgeAAImageSet_OpType)
1900         , fSet(count)
1901         , fCount(count)
1902         , fPaint(paint)
1903         , fConstraint(constraint) {
1904     int totalDstClipCount, totalMatrixCount;
1905     SkCanvasPriv::GetDstClipAndMatrixCounts(set, count, &totalDstClipCount, &totalMatrixCount);
1906 
1907     std::copy_n(set, count, fSet.get());
1908     fDstClips.reset(totalDstClipCount);
1909     std::copy_n(dstClips, totalDstClipCount, fDstClips.get());
1910     fPreViewMatrices.reset(totalMatrixCount);
1911     std::copy_n(preViewMatrices, totalMatrixCount, fPreViewMatrices.get());
1912 }
1913 
execute(SkCanvas * canvas) const1914 void DrawEdgeAAImageSetCommand::execute(SkCanvas* canvas) const {
1915     canvas->experimental_DrawEdgeAAImageSet(fSet.get(),
1916                                             fCount,
1917                                             fDstClips.get(),
1918                                             fPreViewMatrices.get(),
1919                                             fPaint.getMaybeNull(),
1920                                             fConstraint);
1921 }
1922 
1923 ///////////////////////////////////////////////////////////////////////////////////////////////////
1924 
DrawDrawableCommand(SkDrawable * drawable,const SkMatrix * matrix)1925 DrawDrawableCommand::DrawDrawableCommand(SkDrawable* drawable, const SkMatrix* matrix)
1926         : INHERITED(kDrawDrawable_OpType), fDrawable(SkRef(drawable)), fMatrix(matrix) {}
1927 
execute(SkCanvas * canvas) const1928 void DrawDrawableCommand::execute(SkCanvas* canvas) const {
1929     canvas->drawDrawable(fDrawable.get(), fMatrix.getMaybeNull());
1930 }
1931 
1932 ///////////////////////////////////////////////////////////////////////////////////////////////////
1933 
DrawVerticesCommand(sk_sp<SkVertices> vertices,SkBlendMode bmode,const SkPaint & paint)1934 DrawVerticesCommand::DrawVerticesCommand(sk_sp<SkVertices> vertices,
1935                                          SkBlendMode       bmode,
1936                                          const SkPaint&    paint)
1937         : INHERITED(kDrawVertices_OpType)
1938         , fVertices(std::move(vertices))
1939         , fBlendMode(bmode)
1940         , fPaint(paint) {}
1941 
execute(SkCanvas * canvas) const1942 void DrawVerticesCommand::execute(SkCanvas* canvas) const {
1943     canvas->drawVertices(fVertices, fBlendMode, fPaint);
1944 }
1945 
1946 ///////////////////////////////////////////////////////////////////////////////////////////////////
1947 
DrawAtlasCommand(const SkImage * image,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode bmode,const SkRect * cull,const SkPaint * paint)1948 DrawAtlasCommand::DrawAtlasCommand(const SkImage*  image,
1949                                    const SkRSXform xform[],
1950                                    const SkRect    tex[],
1951                                    const SkColor   colors[],
1952                                    int             count,
1953                                    SkBlendMode     bmode,
1954                                    const SkRect*   cull,
1955                                    const SkPaint*  paint)
1956         : INHERITED(kDrawAtlas_OpType)
1957         , fImage(SkRef(image))
1958         , fXform(xform, count)
1959         , fTex(tex, count)
1960         , fColors(colors, colors ? count : 0)
1961         , fBlendMode(bmode)
1962         , fCull(cull)
1963         , fPaint(paint) {}
1964 
execute(SkCanvas * canvas) const1965 void DrawAtlasCommand::execute(SkCanvas* canvas) const {
1966     canvas->drawAtlas(fImage.get(),
1967                       fXform.begin(),
1968                       fTex.begin(),
1969                       fColors.isEmpty() ? nullptr : fColors.begin(),
1970                       fXform.count(),
1971                       fBlendMode,
1972                       fCull.getMaybeNull(),
1973                       fPaint.getMaybeNull());
1974 }
1975 
1976 ///////////////////////////////////////////////////////////////////////////////////////////////////
1977 
RestoreCommand()1978 RestoreCommand::RestoreCommand() : INHERITED(kRestore_OpType) {}
1979 
execute(SkCanvas * canvas) const1980 void RestoreCommand::execute(SkCanvas* canvas) const { canvas->restore(); }
1981 
SaveCommand()1982 SaveCommand::SaveCommand() : INHERITED(kSave_OpType) {}
1983 
execute(SkCanvas * canvas) const1984 void SaveCommand::execute(SkCanvas* canvas) const { canvas->save(); }
1985 
SaveLayerCommand(const SkCanvas::SaveLayerRec & rec)1986 SaveLayerCommand::SaveLayerCommand(const SkCanvas::SaveLayerRec& rec)
1987         : INHERITED(kSaveLayer_OpType)
1988         , fBounds(rec.fBounds)
1989         , fPaint(rec.fPaint)
1990         , fBackdrop(SkSafeRef(rec.fBackdrop))
1991         , fSaveLayerFlags(rec.fSaveLayerFlags) {}
1992 
execute(SkCanvas * canvas) const1993 void SaveLayerCommand::execute(SkCanvas* canvas) const {
1994     canvas->saveLayer(
1995             SkCanvas::SaveLayerRec(fBounds.getMaybeNull(), fPaint.getMaybeNull(), fSaveLayerFlags));
1996 }
1997 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const1998 void SaveLayerCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
1999     INHERITED::toJSON(writer, urlDataManager);
2000     if (fBounds.isValid()) {
2001         writer.appendName(DEBUGCANVAS_ATTRIBUTE_BOUNDS);
2002         MakeJsonRect(writer, *fBounds);
2003     }
2004     if (fPaint.isValid()) {
2005         writer.appendName(DEBUGCANVAS_ATTRIBUTE_PAINT);
2006         MakeJsonPaint(writer, *fPaint, urlDataManager);
2007     }
2008     if (fBackdrop != nullptr) {
2009         writer.beginObject(DEBUGCANVAS_ATTRIBUTE_BACKDROP);
2010         flatten(fBackdrop.get(), writer, urlDataManager);
2011         writer.endObject();  // backdrop
2012     }
2013     if (fSaveLayerFlags != 0) {
2014         SkDebugf("unsupported: saveLayer flags\n");
2015         SkASSERT(false);
2016     }
2017 }
2018 
SetMatrixCommand(const SkMatrix & matrix)2019 SetMatrixCommand::SetMatrixCommand(const SkMatrix& matrix) : INHERITED(kSetMatrix_OpType) {
2020     fMatrix = matrix;
2021 }
2022 
execute(SkCanvas * canvas) const2023 void SetMatrixCommand::execute(SkCanvas* canvas) const { canvas->setMatrix(fMatrix); }
2024 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager) const2025 void SetMatrixCommand::toJSON(SkJSONWriter& writer, UrlDataManager& urlDataManager) const {
2026     INHERITED::toJSON(writer, urlDataManager);
2027     writer.appendName(DEBUGCANVAS_ATTRIBUTE_MATRIX);
2028     MakeJsonMatrix(writer, fMatrix);
2029 }
2030