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