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 "SkDrawCommand.h"
9
10#include "png.h"
11
12#include "SkAutoMalloc.h"
13#include "SkBlurMaskFilter.h"
14#include "SkColorFilter.h"
15#include "SkDashPathEffect.h"
16#include "SkImageFilter.h"
17#include "SkJsonWriteBuffer.h"
18#include "SkMaskFilterBase.h"
19#include "SkObjectParser.h"
20#include "SkPaintDefaults.h"
21#include "SkPathEffect.h"
22#include "SkPicture.h"
23#include "SkReadBuffer.h"
24#include "SkRectPriv.h"
25#include "SkTextBlob.h"
26#include "SkTextBlobRunIterator.h"
27#include "SkTHash.h"
28#include "SkTypeface.h"
29#include "SkWriteBuffer.h"
30#include "picture_utils.h"
31#include "SkClipOpPriv.h"
32#include <SkLatticeIter.h>
33
34#define SKDEBUGCANVAS_ATTRIBUTE_COMMAND           "command"
35#define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE           "visible"
36#define SKDEBUGCANVAS_ATTRIBUTE_MATRIX            "matrix"
37#define SKDEBUGCANVAS_ATTRIBUTE_DRAWDEPTHTRANS    "drawDepthTranslation"
38#define SKDEBUGCANVAS_ATTRIBUTE_COORDS            "coords"
39#define SKDEBUGCANVAS_ATTRIBUTE_HINTING           "hinting"
40#define SKDEBUGCANVAS_ATTRIBUTE_BOUNDS            "bounds"
41#define SKDEBUGCANVAS_ATTRIBUTE_PAINT             "paint"
42#define SKDEBUGCANVAS_ATTRIBUTE_OUTER             "outer"
43#define SKDEBUGCANVAS_ATTRIBUTE_INNER             "inner"
44#define SKDEBUGCANVAS_ATTRIBUTE_MODE              "mode"
45#define SKDEBUGCANVAS_ATTRIBUTE_POINTS            "points"
46#define SKDEBUGCANVAS_ATTRIBUTE_PATH              "path"
47#define SKDEBUGCANVAS_ATTRIBUTE_TEXT              "text"
48#define SKDEBUGCANVAS_ATTRIBUTE_COLOR             "color"
49#define SKDEBUGCANVAS_ATTRIBUTE_ALPHA             "alpha"
50#define SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE         "blendMode"
51#define SKDEBUGCANVAS_ATTRIBUTE_STYLE             "style"
52#define SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH       "strokeWidth"
53#define SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER       "strokeMiter"
54#define SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN        "strokeJoin"
55#define SKDEBUGCANVAS_ATTRIBUTE_CAP               "cap"
56#define SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS         "antiAlias"
57#define SKDEBUGCANVAS_ATTRIBUTE_DITHER            "dither"
58#define SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT      "fakeBoldText"
59#define SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT        "linearText"
60#define SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT      "subpixelText"
61#define SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT       "devKernText"
62#define SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT     "lcdRenderText"
63#define SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT "embeddedBitmapText"
64#define SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING       "forceAutoHinting"
65#define SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT      "verticalText"
66#define SKDEBUGCANVAS_ATTRIBUTE_REGION            "region"
67#define SKDEBUGCANVAS_ATTRIBUTE_REGIONOP          "op"
68#define SKDEBUGCANVAS_ATTRIBUTE_EDGESTYLE         "edgeStyle"
69#define SKDEBUGCANVAS_ATTRIBUTE_DEVICEREGION      "deviceRegion"
70#define SKDEBUGCANVAS_ATTRIBUTE_BLUR              "blur"
71#define SKDEBUGCANVAS_ATTRIBUTE_SIGMA             "sigma"
72#define SKDEBUGCANVAS_ATTRIBUTE_QUALITY           "quality"
73#define SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN         "textAlign"
74#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE          "textSize"
75#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX        "textScaleX"
76#define SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX         "textSkewX"
77#define SKDEBUGCANVAS_ATTRIBUTE_DASHING           "dashing"
78#define SKDEBUGCANVAS_ATTRIBUTE_INTERVALS         "intervals"
79#define SKDEBUGCANVAS_ATTRIBUTE_PHASE             "phase"
80#define SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE          "fillType"
81#define SKDEBUGCANVAS_ATTRIBUTE_VERBS             "verbs"
82#define SKDEBUGCANVAS_ATTRIBUTE_NAME              "name"
83#define SKDEBUGCANVAS_ATTRIBUTE_DATA              "data"
84#define SKDEBUGCANVAS_ATTRIBUTE_VALUES            "values"
85#define SKDEBUGCANVAS_ATTRIBUTE_SHADER            "shader"
86#define SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT        "pathEffect"
87#define SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER        "maskFilter"
88#define SKDEBUGCANVAS_ATTRIBUTE_XFERMODE          "xfermode"
89#define SKDEBUGCANVAS_ATTRIBUTE_LOOPER            "looper"
90#define SKDEBUGCANVAS_ATTRIBUTE_BACKDROP          "backdrop"
91#define SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER       "colorfilter"
92#define SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER       "imagefilter"
93#define SKDEBUGCANVAS_ATTRIBUTE_IMAGE             "image"
94#define SKDEBUGCANVAS_ATTRIBUTE_BITMAP            "bitmap"
95#define SKDEBUGCANVAS_ATTRIBUTE_SRC               "src"
96#define SKDEBUGCANVAS_ATTRIBUTE_DST               "dst"
97#define SKDEBUGCANVAS_ATTRIBUTE_CENTER            "center"
98#define SKDEBUGCANVAS_ATTRIBUTE_STRICT            "strict"
99#define SKDEBUGCANVAS_ATTRIBUTE_DESCRIPTION       "description"
100#define SKDEBUGCANVAS_ATTRIBUTE_X                 "x"
101#define SKDEBUGCANVAS_ATTRIBUTE_Y                 "y"
102#define SKDEBUGCANVAS_ATTRIBUTE_RUNS              "runs"
103#define SKDEBUGCANVAS_ATTRIBUTE_POSITIONS         "positions"
104#define SKDEBUGCANVAS_ATTRIBUTE_GLYPHS            "glyphs"
105#define SKDEBUGCANVAS_ATTRIBUTE_FONT              "font"
106#define SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE          "typeface"
107#define SKDEBUGCANVAS_ATTRIBUTE_CUBICS            "cubics"
108#define SKDEBUGCANVAS_ATTRIBUTE_COLORS            "colors"
109#define SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS     "textureCoords"
110#define SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY     "filterQuality"
111#define SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE        "startAngle"
112#define SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE        "sweepAngle"
113#define SKDEBUGCANVAS_ATTRIBUTE_USECENTER         "useCenter"
114#define SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC         "shortDesc"
115#define SKDEBUGCANVAS_ATTRIBUTE_UNIQUE_ID         "uniqueID"
116#define SKDEBUGCANVAS_ATTRIBUTE_WIDTH             "width"
117#define SKDEBUGCANVAS_ATTRIBUTE_HEIGHT            "height"
118#define SKDEBUGCANVAS_ATTRIBUTE_ALPHA             "alpha"
119#define SKDEBUGCANVAS_ATTRIBUTE_LATTICE           "lattice"
120#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT     "xCount"
121#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT     "yCount"
122#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS      "xDivs"
123#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS      "yDivs"
124#define SKDEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS      "flags"
125
126#define SKDEBUGCANVAS_VERB_MOVE                   "move"
127#define SKDEBUGCANVAS_VERB_LINE                   "line"
128#define SKDEBUGCANVAS_VERB_QUAD                   "quad"
129#define SKDEBUGCANVAS_VERB_CUBIC                  "cubic"
130#define SKDEBUGCANVAS_VERB_CONIC                  "conic"
131#define SKDEBUGCANVAS_VERB_CLOSE                  "close"
132
133#define SKDEBUGCANVAS_STYLE_FILL                  "fill"
134#define SKDEBUGCANVAS_STYLE_STROKE                "stroke"
135#define SKDEBUGCANVAS_STYLE_STROKEANDFILL         "strokeAndFill"
136
137#define SKDEBUGCANVAS_POINTMODE_POINTS            "points"
138#define SKDEBUGCANVAS_POINTMODE_LINES             "lines"
139#define SKDEBUGCANVAS_POINTMODE_POLYGON           "polygon"
140
141#define SKDEBUGCANVAS_REGIONOP_DIFFERENCE         "difference"
142#define SKDEBUGCANVAS_REGIONOP_INTERSECT          "intersect"
143#define SKDEBUGCANVAS_REGIONOP_UNION              "union"
144#define SKDEBUGCANVAS_REGIONOP_XOR                "xor"
145#define SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE "reverseDifference"
146#define SKDEBUGCANVAS_REGIONOP_REPLACE            "replace"
147
148#define SKDEBUGCANVAS_BLURSTYLE_NORMAL            "normal"
149#define SKDEBUGCANVAS_BLURSTYLE_SOLID             "solid"
150#define SKDEBUGCANVAS_BLURSTYLE_OUTER             "outer"
151#define SKDEBUGCANVAS_BLURSTYLE_INNER             "inner"
152
153#define SKDEBUGCANVAS_BLURQUALITY_LOW             "low"
154#define SKDEBUGCANVAS_BLURQUALITY_HIGH            "high"
155
156#define SKDEBUGCANVAS_ALIGN_LEFT                  "left"
157#define SKDEBUGCANVAS_ALIGN_CENTER                "center"
158#define SKDEBUGCANVAS_ALIGN_RIGHT                 "right"
159
160#define SKDEBUGCANVAS_FILLTYPE_WINDING            "winding"
161#define SKDEBUGCANVAS_FILLTYPE_EVENODD            "evenOdd"
162#define SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING     "inverseWinding"
163#define SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD     "inverseEvenOdd"
164
165#define SKDEBUGCANVAS_CAP_BUTT                    "butt"
166#define SKDEBUGCANVAS_CAP_ROUND                   "round"
167#define SKDEBUGCANVAS_CAP_SQUARE                  "square"
168
169#define SKDEBUGCANVAS_MITER_JOIN                  "miter"
170#define SKDEBUGCANVAS_ROUND_JOIN                  "round"
171#define SKDEBUGCANVAS_BEVEL_JOIN                  "bevel"
172
173#define SKDEBUGCANVAS_COLORTYPE_ARGB4444          "ARGB4444"
174#define SKDEBUGCANVAS_COLORTYPE_RGBA8888          "RGBA8888"
175#define SKDEBUGCANVAS_COLORTYPE_BGRA8888          "BGRA8888"
176#define SKDEBUGCANVAS_COLORTYPE_565               "565"
177#define SKDEBUGCANVAS_COLORTYPE_GRAY8             "Gray8"
178#define SKDEBUGCANVAS_COLORTYPE_INDEX8            "Index8"
179#define SKDEBUGCANVAS_COLORTYPE_ALPHA8            "Alpha8"
180
181#define SKDEBUGCANVAS_ALPHATYPE_OPAQUE            "opaque"
182#define SKDEBUGCANVAS_ALPHATYPE_PREMUL            "premul"
183#define SKDEBUGCANVAS_ALPHATYPE_UNPREMUL          "unpremul"
184#define SKDEBUGCANVAS_ALPHATYPE_UNKNOWN           "unknown"
185
186#define SKDEBUGCANVAS_FILTERQUALITY_NONE          "none"
187#define SKDEBUGCANVAS_FILTERQUALITY_LOW           "low"
188#define SKDEBUGCANVAS_FILTERQUALITY_MEDIUM        "medium"
189#define SKDEBUGCANVAS_FILTERQUALITY_HIGH          "high"
190
191#define SKDEBUGCANVAS_HINTING_NONE                "none"
192#define SKDEBUGCANVAS_HINTING_SLIGHT              "slight"
193#define SKDEBUGCANVAS_HINTING_NORMAL              "normal"
194#define SKDEBUGCANVAS_HINTING_FULL                "full"
195
196typedef SkDrawCommand* (*FROM_JSON)(Json::Value&, UrlDataManager&);
197
198static SkString* str_append(SkString* str, const SkRect& r) {
199    str->appendf(" [%g %g %g %g]", r.left(), r.top(), r.right(), r.bottom());
200    return str;
201}
202
203// TODO(chudy): Refactor into non subclass model.
204
205SkDrawCommand::SkDrawCommand(OpType type)
206    : fOpType(type)
207    , fVisible(true) {
208}
209
210SkDrawCommand::~SkDrawCommand() {
211    fInfo.deleteAll();
212}
213
214const char* SkDrawCommand::GetCommandString(OpType type) {
215    switch (type) {
216        case kBeginDrawPicture_OpType: return "BeginDrawPicture";
217        case kClipPath_OpType: return "ClipPath";
218        case kClipRegion_OpType: return "ClipRegion";
219        case kClipRect_OpType: return "ClipRect";
220        case kClipRRect_OpType: return "ClipRRect";
221        case kConcat_OpType: return "Concat";
222        case kDrawAnnotation_OpType: return "DrawAnnotation";
223        case kDrawBitmap_OpType: return "DrawBitmap";
224        case kDrawBitmapNine_OpType: return "DrawBitmapNine";
225        case kDrawBitmapRect_OpType: return "DrawBitmapRect";
226        case kDrawClear_OpType: return "DrawClear";
227        case kDrawDRRect_OpType: return "DrawDRRect";
228        case kDrawImage_OpType: return "DrawImage";
229        case kDrawImageLattice_OpType: return "DrawImageLattice";
230        case kDrawImageRect_OpType: return "DrawImageRect";
231        case kDrawOval_OpType: return "DrawOval";
232        case kDrawPaint_OpType: return "DrawPaint";
233        case kDrawPatch_OpType: return "DrawPatch";
234        case kDrawPath_OpType: return "DrawPath";
235        case kDrawPoints_OpType: return "DrawPoints";
236        case kDrawPosText_OpType: return "DrawPosText";
237        case kDrawPosTextH_OpType: return "DrawPosTextH";
238        case kDrawRect_OpType: return "DrawRect";
239        case kDrawRRect_OpType: return "DrawRRect";
240        case kDrawText_OpType: return "DrawText";
241        case kDrawTextBlob_OpType: return "DrawTextBlob";
242        case kDrawTextOnPath_OpType: return "DrawTextOnPath";
243        case kDrawTextRSXform_OpType: return "DrawTextRSXform";
244        case kDrawVertices_OpType: return "DrawVertices";
245        case kEndDrawPicture_OpType: return "EndDrawPicture";
246        case kRestore_OpType: return "Restore";
247        case kSave_OpType: return "Save";
248        case kSaveLayer_OpType: return "SaveLayer";
249        case kSetMatrix_OpType: return "SetMatrix";
250        default:
251            SkDebugf("OpType error 0x%08x\n", type);
252            SkASSERT(0);
253            break;
254    }
255    SkDEBUGFAIL("DrawType UNUSED\n");
256    return nullptr;
257}
258
259SkString SkDrawCommand::toString() const {
260    return SkString(GetCommandString(fOpType));
261}
262
263Json::Value SkDrawCommand::toJSON(UrlDataManager& urlDataManager) const {
264    Json::Value result;
265    result[SKDEBUGCANVAS_ATTRIBUTE_COMMAND] = this->GetCommandString(fOpType);
266    result[SKDEBUGCANVAS_ATTRIBUTE_VISIBLE] = Json::Value(this->isVisible());
267    return result;
268}
269
270#define INSTALL_FACTORY(name) factories.set(SkString(GetCommandString(k ## name ##_OpType)), \
271                                            (FROM_JSON) Sk ## name ## Command::fromJSON)
272SkDrawCommand* SkDrawCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
273    static SkTHashMap<SkString, FROM_JSON> factories;
274    static bool initialized = false;
275    if (!initialized) {
276        initialized = true;
277        INSTALL_FACTORY(Restore);
278        INSTALL_FACTORY(ClipPath);
279        INSTALL_FACTORY(ClipRegion);
280        INSTALL_FACTORY(ClipRect);
281        INSTALL_FACTORY(ClipRRect);
282        INSTALL_FACTORY(Concat);
283        INSTALL_FACTORY(DrawAnnotation);
284        INSTALL_FACTORY(DrawBitmap);
285        INSTALL_FACTORY(DrawBitmapRect);
286        INSTALL_FACTORY(DrawBitmapNine);
287        INSTALL_FACTORY(DrawImage);
288        INSTALL_FACTORY(DrawImageRect);
289        INSTALL_FACTORY(DrawOval);
290        INSTALL_FACTORY(DrawPaint);
291        INSTALL_FACTORY(DrawPath);
292        INSTALL_FACTORY(DrawPoints);
293        INSTALL_FACTORY(DrawText);
294        INSTALL_FACTORY(DrawPosText);
295        INSTALL_FACTORY(DrawPosTextH);
296        INSTALL_FACTORY(DrawTextOnPath);
297        INSTALL_FACTORY(DrawTextRSXform);
298        INSTALL_FACTORY(DrawTextBlob);
299
300        INSTALL_FACTORY(DrawRect);
301        INSTALL_FACTORY(DrawRRect);
302        INSTALL_FACTORY(DrawDRRect);
303        INSTALL_FACTORY(DrawPatch);
304        INSTALL_FACTORY(Save);
305        INSTALL_FACTORY(SaveLayer);
306        INSTALL_FACTORY(SetMatrix);
307    }
308    SkString name = SkString(command[SKDEBUGCANVAS_ATTRIBUTE_COMMAND].asCString());
309    FROM_JSON* factory = factories.find(name);
310    if (factory == nullptr) {
311        SkDebugf("no JSON factory for '%s'\n", name.c_str());
312        return nullptr;
313    }
314    return (*factory)(command, urlDataManager);
315}
316
317namespace {
318
319void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) {
320    const SkISize& size = canvas->getBaseLayerSize();
321
322    static const SkScalar kInsetFrac = 0.9f; // Leave a border around object
323
324    canvas->translate(size.fWidth/2.0f, size.fHeight/2.0f);
325    if (bounds.width() > bounds.height()) {
326        canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.width()),
327                      SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.width()));
328    } else {
329        canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.height()),
330                      SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.height()));
331    }
332    canvas->translate(-bounds.centerX(), -bounds.centerY());
333}
334
335
336void render_path(SkCanvas* canvas, const SkPath& path) {
337    canvas->clear(0xFFFFFFFF);
338
339    const SkRect& bounds = path.getBounds();
340    if (bounds.isEmpty()) {
341        return;
342    }
343
344    SkAutoCanvasRestore acr(canvas, true);
345    xlate_and_scale_to_bounds(canvas, bounds);
346
347    SkPaint p;
348    p.setColor(SK_ColorBLACK);
349    p.setStyle(SkPaint::kStroke_Style);
350
351    canvas->drawPath(path, p);
352}
353
354void render_bitmap(SkCanvas* canvas, const SkBitmap& input, const SkRect* srcRect = nullptr) {
355    const SkISize& size = canvas->getBaseLayerSize();
356
357    SkScalar xScale = SkIntToScalar(size.fWidth-2) / input.width();
358    SkScalar yScale = SkIntToScalar(size.fHeight-2) / input.height();
359
360    if (input.width() > input.height()) {
361        yScale *= input.height() / (float) input.width();
362    } else {
363        xScale *= input.width() / (float) input.height();
364    }
365
366    SkRect dst = SkRect::MakeXYWH(SK_Scalar1, SK_Scalar1,
367                                  xScale * input.width(),
368                                  yScale * input.height());
369
370    static const int kNumBlocks = 8;
371
372    canvas->clear(0xFFFFFFFF);
373    SkISize block = {
374        canvas->imageInfo().width()/kNumBlocks,
375        canvas->imageInfo().height()/kNumBlocks
376    };
377    for (int y = 0; y < kNumBlocks; ++y) {
378        for (int x = 0; x < kNumBlocks; ++x) {
379            SkPaint paint;
380            paint.setColor((x+y)%2 ? SK_ColorLTGRAY : SK_ColorDKGRAY);
381            SkRect r = SkRect::MakeXYWH(SkIntToScalar(x*block.width()),
382                                        SkIntToScalar(y*block.height()),
383                                        SkIntToScalar(block.width()),
384                                        SkIntToScalar(block.height()));
385            canvas->drawRect(r, paint);
386        }
387    }
388
389    canvas->drawBitmapRect(input, dst, nullptr);
390
391    if (srcRect) {
392        SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
393                                    srcRect->fTop * yScale + SK_Scalar1,
394                                    srcRect->fRight * xScale + SK_Scalar1,
395                                    srcRect->fBottom * yScale + SK_Scalar1);
396        SkPaint p;
397        p.setColor(SK_ColorRED);
398        p.setStyle(SkPaint::kStroke_Style);
399
400        canvas->drawRect(r, p);
401    }
402}
403
404void render_rrect(SkCanvas* canvas, const SkRRect& rrect) {
405    canvas->clear(0xFFFFFFFF);
406    canvas->save();
407
408    const SkRect& bounds = rrect.getBounds();
409
410    xlate_and_scale_to_bounds(canvas, bounds);
411
412    SkPaint p;
413    p.setColor(SK_ColorBLACK);
414    p.setStyle(SkPaint::kStroke_Style);
415
416    canvas->drawRRect(rrect, p);
417    canvas->restore();
418}
419
420void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) {
421    canvas->clear(0xFFFFFFFF);
422    canvas->save();
423
424    const SkRect& bounds = outer.getBounds();
425
426    xlate_and_scale_to_bounds(canvas, bounds);
427
428    SkPaint p;
429    p.setColor(SK_ColorBLACK);
430    p.setStyle(SkPaint::kStroke_Style);
431
432    canvas->drawDRRect(outer, inner, p);
433    canvas->restore();
434}
435
436static const char* const gBlendModeMap[] = {
437    "clear",
438    "src",
439    "dst",
440    "srcOver",
441    "dstOver",
442    "srcIn",
443    "dstIn",
444    "srcOut",
445    "dstOut",
446    "srcATop",
447    "dstATop",
448    "xor",
449    "plus",
450    "modulate",
451
452    "screen",
453
454    "overlay",
455    "darken",
456    "lighten",
457    "colorDodge",
458    "colorBurn",
459    "hardLight",
460    "softLight",
461    "difference",
462    "exclusion",
463    "multiply",
464
465    "hue",
466    "saturation",
467    "color",
468    "luminosity",
469};
470
471static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLastMode) + 1,
472              "blendMode mismatch");
473static_assert(SK_ARRAY_COUNT(gBlendModeMap) == static_cast<size_t>(SkBlendMode::kLuminosity) + 1,
474              "blendMode mismatch");
475
476void apply_paint_blend_mode(const SkPaint& paint, Json::Value* target) {
477    const auto mode = paint.getBlendMode();
478    if (mode != SkBlendMode::kSrcOver) {
479        SkASSERT(static_cast<size_t>(mode) < SK_ARRAY_COUNT(gBlendModeMap));
480        (*target)[SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE] =
481            Json::Value(gBlendModeMap[static_cast<size_t>(mode)]);
482    }
483}
484
485void extract_json_paint_blend_mode(Json::Value& jsonPaint, SkPaint* target) {
486    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE)) {
487        const char* mode = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_BLENDMODE].asCString();
488
489        for (size_t i = 0; i < SK_ARRAY_COUNT(gBlendModeMap); ++i) {
490            if (!strcmp(mode, gBlendModeMap[i])) {
491                target->setBlendMode(static_cast<SkBlendMode>(i));
492                break;
493            }
494        }
495    }
496}
497
498};
499
500Json::Value SkDrawCommand::MakeJsonColor(const SkColor color) {
501    Json::Value result(Json::arrayValue);
502    result.append(Json::Value(SkColorGetA(color)));
503    result.append(Json::Value(SkColorGetR(color)));
504    result.append(Json::Value(SkColorGetG(color)));
505    result.append(Json::Value(SkColorGetB(color)));
506    return result;
507}
508
509Json::Value SkDrawCommand::MakeJsonColor4f(const SkColor4f& color) {
510    Json::Value result(Json::arrayValue);
511    result.append(Json::Value(color.fA));
512    result.append(Json::Value(color.fR));
513    result.append(Json::Value(color.fG));
514    result.append(Json::Value(color.fB));
515    return result;
516}
517
518Json::Value SkDrawCommand::MakeJsonPoint(const SkPoint& point) {
519    Json::Value result(Json::arrayValue);
520    result.append(Json::Value(point.x()));
521    result.append(Json::Value(point.y()));
522    return result;
523}
524
525Json::Value SkDrawCommand::MakeJsonPoint(SkScalar x, SkScalar y) {
526    Json::Value result(Json::arrayValue);
527    result.append(Json::Value(x));
528    result.append(Json::Value(y));
529    return result;
530}
531
532Json::Value SkDrawCommand::MakeJsonRect(const SkRect& rect) {
533    Json::Value result(Json::arrayValue);
534    result.append(Json::Value(rect.left()));
535    result.append(Json::Value(rect.top()));
536    result.append(Json::Value(rect.right()));
537    result.append(Json::Value(rect.bottom()));
538    return result;
539}
540
541Json::Value SkDrawCommand::MakeJsonIRect(const SkIRect& rect) {
542    Json::Value result(Json::arrayValue);
543    result.append(Json::Value(rect.left()));
544    result.append(Json::Value(rect.top()));
545    result.append(Json::Value(rect.right()));
546    result.append(Json::Value(rect.bottom()));
547    return result;
548}
549
550static Json::Value make_json_rrect(const SkRRect& rrect) {
551    Json::Value result(Json::arrayValue);
552    result.append(SkDrawCommand::MakeJsonRect(rrect.rect()));
553    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kUpperLeft_Corner)));
554    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kUpperRight_Corner)));
555    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kLowerRight_Corner)));
556    result.append(SkDrawCommand::MakeJsonPoint(rrect.radii(SkRRect::kLowerLeft_Corner)));
557    return result;
558}
559
560Json::Value SkDrawCommand::MakeJsonMatrix(const SkMatrix& matrix) {
561    Json::Value result(Json::arrayValue);
562    Json::Value row1(Json::arrayValue);
563    row1.append(Json::Value(matrix[0]));
564    row1.append(Json::Value(matrix[1]));
565    row1.append(Json::Value(matrix[2]));
566    result.append(row1);
567    Json::Value row2(Json::arrayValue);
568    row2.append(Json::Value(matrix[3]));
569    row2.append(Json::Value(matrix[4]));
570    row2.append(Json::Value(matrix[5]));
571    result.append(row2);
572    Json::Value row3(Json::arrayValue);
573    row3.append(Json::Value(matrix[6]));
574    row3.append(Json::Value(matrix[7]));
575    row3.append(Json::Value(matrix[8]));
576    result.append(row3);
577    return result;
578}
579
580Json::Value SkDrawCommand::MakeJsonScalar(SkScalar z) {
581    Json::Value result(z);
582    return result;
583}
584
585Json::Value SkDrawCommand::MakeJsonPath(const SkPath& path) {
586    Json::Value result(Json::objectValue);
587    switch (path.getFillType()) {
588        case SkPath::kWinding_FillType:
589            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_WINDING;
590            break;
591        case SkPath::kEvenOdd_FillType:
592            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_EVENODD;
593            break;
594        case SkPath::kInverseWinding_FillType:
595            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING;
596            break;
597        case SkPath::kInverseEvenOdd_FillType:
598            result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD;
599            break;
600    }
601    Json::Value verbs(Json::arrayValue);
602    SkPath::Iter iter(path, false);
603    SkPoint pts[4];
604    SkPath::Verb verb;
605    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
606        switch (verb) {
607            case SkPath::kLine_Verb: {
608                Json::Value line(Json::objectValue);
609                line[SKDEBUGCANVAS_VERB_LINE] = MakeJsonPoint(pts[1]);
610                verbs.append(line);
611                break;
612            }
613            case SkPath::kQuad_Verb: {
614                Json::Value quad(Json::objectValue);
615                Json::Value coords(Json::arrayValue);
616                coords.append(MakeJsonPoint(pts[1]));
617                coords.append(MakeJsonPoint(pts[2]));
618                quad[SKDEBUGCANVAS_VERB_QUAD] = coords;
619                verbs.append(quad);
620                break;
621            }
622            case SkPath::kCubic_Verb: {
623                Json::Value cubic(Json::objectValue);
624                Json::Value coords(Json::arrayValue);
625                coords.append(MakeJsonPoint(pts[1]));
626                coords.append(MakeJsonPoint(pts[2]));
627                coords.append(MakeJsonPoint(pts[3]));
628                cubic[SKDEBUGCANVAS_VERB_CUBIC] = coords;
629                verbs.append(cubic);
630                break;
631            }
632            case SkPath::kConic_Verb: {
633                Json::Value conic(Json::objectValue);
634                Json::Value coords(Json::arrayValue);
635                coords.append(MakeJsonPoint(pts[1]));
636                coords.append(MakeJsonPoint(pts[2]));
637                coords.append(Json::Value(iter.conicWeight()));
638                conic[SKDEBUGCANVAS_VERB_CONIC] = coords;
639                verbs.append(conic);
640                break;
641            }
642            case SkPath::kMove_Verb: {
643                Json::Value move(Json::objectValue);
644                move[SKDEBUGCANVAS_VERB_MOVE] = MakeJsonPoint(pts[0]);
645                verbs.append(move);
646                break;
647            }
648            case SkPath::kClose_Verb:
649                verbs.append(Json::Value(SKDEBUGCANVAS_VERB_CLOSE));
650                break;
651            case SkPath::kDone_Verb:
652                break;
653        }
654    }
655    result[SKDEBUGCANVAS_ATTRIBUTE_VERBS] = verbs;
656    return result;
657}
658
659Json::Value SkDrawCommand::MakeJsonRegion(const SkRegion& region) {
660    return Json::Value("<unimplemented>");
661}
662
663static Json::Value make_json_regionop(SkClipOp op) {
664    switch (op) {
665        case kDifference_SkClipOp:
666            return Json::Value(SKDEBUGCANVAS_REGIONOP_DIFFERENCE);
667        case kIntersect_SkClipOp:
668            return Json::Value(SKDEBUGCANVAS_REGIONOP_INTERSECT);
669        case kUnion_SkClipOp:
670            return Json::Value(SKDEBUGCANVAS_REGIONOP_UNION);
671        case kXOR_SkClipOp:
672            return Json::Value(SKDEBUGCANVAS_REGIONOP_XOR);
673        case kReverseDifference_SkClipOp:
674            return Json::Value(SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE);
675        case kReplace_SkClipOp:
676            return Json::Value(SKDEBUGCANVAS_REGIONOP_REPLACE);
677        default:
678            SkASSERT(false);
679            return Json::Value("<invalid region op>");
680    };
681}
682
683static Json::Value make_json_pointmode(SkCanvas::PointMode mode) {
684    switch (mode) {
685        case SkCanvas::kPoints_PointMode:
686            return Json::Value(SKDEBUGCANVAS_POINTMODE_POINTS);
687        case SkCanvas::kLines_PointMode:
688            return Json::Value(SKDEBUGCANVAS_POINTMODE_LINES);
689        case SkCanvas::kPolygon_PointMode:
690            return Json::Value(SKDEBUGCANVAS_POINTMODE_POLYGON);
691        default:
692            SkASSERT(false);
693            return Json::Value("<invalid point mode>");
694    };
695}
696
697static void store_scalar(Json::Value* target, const char* key, SkScalar value,
698                         SkScalar defaultValue) {
699    if (value != defaultValue) {
700        (*target)[key] = Json::Value(value);
701    }
702}
703
704static void store_bool(Json::Value* target, const char* key, bool value, bool defaultValue) {
705    if (value != defaultValue) {
706        (*target)[key] = Json::Value(value);
707    }
708}
709
710static void encode_data(const void* bytes, size_t count, const char* contentType,
711                        UrlDataManager& urlDataManager, Json::Value* target) {
712    sk_sp<SkData> data(SkData::MakeWithCopy(bytes, count));
713    SkString url = urlDataManager.addData(data.get(), contentType);
714    *target = Json::Value(url.c_str());
715}
716
717void SkDrawCommand::flatten(const SkFlattenable* flattenable, Json::Value* target,
718                            UrlDataManager& urlDataManager) {
719    SkBinaryWriteBuffer buffer;
720    flattenable->flatten(buffer);
721    void* data = sk_malloc_throw(buffer.bytesWritten());
722    buffer.writeToMemory(data);
723    Json::Value jsonData;
724    encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager, &jsonData);
725    Json::Value jsonFlattenable;
726    jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_NAME] = Json::Value(flattenable->getTypeName());
727    jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData;
728
729    SkJsonWriteBuffer jsonBuffer(&urlDataManager);
730    flattenable->flatten(jsonBuffer);
731    jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_VALUES] = jsonBuffer.getValue();
732
733    (*target) = jsonFlattenable;
734    sk_free(data);
735}
736
737static void write_png_callback(png_structp png_ptr, png_bytep data, png_size_t length) {
738    SkWStream* out = (SkWStream*) png_get_io_ptr(png_ptr);
739    out->write(data, length);
740}
741
742void SkDrawCommand::WritePNG(const uint8_t* rgba, unsigned width, unsigned height,
743                             SkWStream& out, bool isOpaque) {
744    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
745    SkASSERT(png != nullptr);
746    png_infop info_ptr = png_create_info_struct(png);
747    SkASSERT(info_ptr != nullptr);
748    if (setjmp(png_jmpbuf(png))) {
749        SK_ABORT("png encode error");
750    }
751    png_set_write_fn(png, &out, write_png_callback, nullptr);
752    int colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA;
753    png_set_IHDR(png, info_ptr, width, height, 8, colorType, PNG_INTERLACE_NONE,
754                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
755    png_set_compression_level(png, 1);
756    png_bytepp rows = (png_bytepp) sk_malloc_throw(height * sizeof(png_byte*));
757    png_bytep pixels = (png_bytep) sk_malloc_throw(width * height * 4);
758    for (png_size_t y = 0; y < height; ++y) {
759        const uint8_t* src = rgba + y * width * 4;
760        rows[y] = pixels + y * width * 4;
761        for (png_size_t x = 0; x < width; ++x) {
762            rows[y][x * 4] = src[x * 4];
763            rows[y][x * 4 + 1] = src[x * 4 + 1];
764            rows[y][x * 4 + 2] = src[x * 4 + 2];
765            rows[y][x * 4 + 3] = src[x * 4 + 3];
766        }
767    }
768    png_write_info(png, info_ptr);
769    if (isOpaque) {
770        png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
771    }
772    png_set_filter(png, 0, PNG_NO_FILTERS);
773    png_write_image(png, &rows[0]);
774    png_destroy_write_struct(&png, nullptr);
775    sk_free(rows);
776    sk_free(pixels);
777}
778
779bool SkDrawCommand::flatten(const SkImage& image, Json::Value* target,
780                            UrlDataManager& urlDataManager) {
781    size_t rowBytes = 4 * image.width();
782    SkAutoMalloc buffer(rowBytes * image.height());
783    SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(),
784                                            kN32_SkColorType, kPremul_SkAlphaType);
785    if (!image.readPixels(dstInfo, buffer.get(), rowBytes, 0, 0)) {
786        SkDebugf("readPixels failed\n");
787        return false;
788    }
789
790    SkBitmap bm;
791    bm.installPixels(dstInfo, buffer.get(), rowBytes);
792    sk_sp<SkData> encodedBitmap = sk_tools::encode_bitmap_for_png(bm);
793
794    SkDynamicMemoryWStream out;
795    SkDrawCommand::WritePNG(encodedBitmap->bytes(), image.width(), image.height(),
796                            out, false);
797    sk_sp<SkData> encoded = out.detachAsData();
798    Json::Value jsonData;
799    encode_data(encoded->data(), encoded->size(), "image/png", urlDataManager, &jsonData);
800    (*target)[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData;
801    return true;
802}
803
804static const char* color_type_name(SkColorType colorType) {
805    switch (colorType) {
806        case kARGB_4444_SkColorType:
807            return SKDEBUGCANVAS_COLORTYPE_ARGB4444;
808        case kRGBA_8888_SkColorType:
809            return SKDEBUGCANVAS_COLORTYPE_RGBA8888;
810        case kBGRA_8888_SkColorType:
811            return SKDEBUGCANVAS_COLORTYPE_BGRA8888;
812        case kRGB_565_SkColorType:
813            return SKDEBUGCANVAS_COLORTYPE_565;
814        case kGray_8_SkColorType:
815            return SKDEBUGCANVAS_COLORTYPE_GRAY8;
816        case kAlpha_8_SkColorType:
817            return SKDEBUGCANVAS_COLORTYPE_ALPHA8;
818        default:
819            SkASSERT(false);
820            return SKDEBUGCANVAS_COLORTYPE_RGBA8888;
821    }
822}
823
824static const char* alpha_type_name(SkAlphaType alphaType) {
825    switch (alphaType) {
826        case kOpaque_SkAlphaType:
827            return SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
828        case kPremul_SkAlphaType:
829            return SKDEBUGCANVAS_ALPHATYPE_PREMUL;
830        case kUnpremul_SkAlphaType:
831            return SKDEBUGCANVAS_ALPHATYPE_UNPREMUL;
832        default:
833            SkASSERT(false);
834            return SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
835    }
836}
837
838static Json::ArrayIndex decode_data(Json::Value data, UrlDataManager& urlDataManager,
839                                    const void** target) {
840    UrlDataManager::UrlData* urlData = urlDataManager.getDataFromUrl(SkString(data.asCString()));
841    if (urlData == nullptr) {
842        SkASSERT(false);
843        *target = nullptr;
844        return 0;
845    }
846    *target = urlData->fData->data();
847    // cast should be safe for any reasonably-sized object...
848    return (Json::ArrayIndex) urlData->fData->size();
849}
850
851static SkFlattenable* load_flattenable(Json::Value jsonFlattenable,
852                                       UrlDataManager& urlDataManager) {
853    if (!jsonFlattenable.isMember(SKDEBUGCANVAS_ATTRIBUTE_NAME)) {
854        return nullptr;
855    }
856    const char* name = jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_NAME].asCString();
857    SkFlattenable::Factory factory = SkFlattenable::NameToFactory(name);
858    if (factory == nullptr) {
859        SkDebugf("no factory for loading '%s'\n", name);
860        return nullptr;
861    }
862    const void* data;
863    int size = decode_data(jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data);
864    SkReadBuffer buffer(data, size);
865    sk_sp<SkFlattenable> result = factory(buffer);
866    if (!buffer.isValid()) {
867        SkDebugf("invalid buffer loading flattenable\n");
868        return nullptr;
869    }
870    return result.release();
871}
872
873static SkColorType colortype_from_name(const char* name) {
874    if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_ARGB4444)) {
875        return kARGB_4444_SkColorType;
876    }
877    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_RGBA8888)) {
878        return kRGBA_8888_SkColorType;
879    }
880    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_BGRA8888)) {
881        return kBGRA_8888_SkColorType;
882    }
883    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_565)) {
884        return kRGB_565_SkColorType;
885    }
886    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_GRAY8)) {
887        return kGray_8_SkColorType;
888    }
889    else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_ALPHA8)) {
890        return kAlpha_8_SkColorType;
891    }
892    SkASSERT(false);
893    return kN32_SkColorType;
894}
895
896static SkBitmap* convert_colortype(SkBitmap* bitmap, SkColorType colorType) {
897    if (bitmap->colorType() == colorType  ) {
898        return bitmap;
899    }
900    SkBitmap* dst = new SkBitmap();
901    if (dst->tryAllocPixels(bitmap->info().makeColorType(colorType)) &&
902        bitmap->readPixels(dst->info(), dst->getPixels(), dst->rowBytes(), 0, 0))
903    {
904        delete bitmap;
905        return dst;
906    }
907    SkASSERT(false);
908    delete dst;
909    return bitmap;
910}
911
912// caller is responsible for freeing return value
913static SkBitmap* load_bitmap(const Json::Value& jsonBitmap, UrlDataManager& urlDataManager) {
914    if (!jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_DATA)) {
915        SkDebugf("invalid bitmap\n");
916        return nullptr;
917    }
918    const void* data;
919    int size = decode_data(jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data);
920    sk_sp<SkData> encoded(SkData::MakeWithoutCopy(data, size));
921    sk_sp<SkImage> image(SkImage::MakeFromEncoded(std::move(encoded), nullptr));
922
923    std::unique_ptr<SkBitmap> bitmap(new SkBitmap());
924    if (nullptr != image) {
925        if (!image->asLegacyBitmap(bitmap.get())) {
926            SkDebugf("image decode failed\n");
927            return nullptr;
928        }
929
930        if (jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLOR)) {
931            const char* ctName = jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_COLOR].asCString();
932            SkColorType ct = colortype_from_name(ctName);
933            bitmap.reset(convert_colortype(bitmap.release(), ct));
934        }
935        return bitmap.release();
936    }
937    SkDebugf("image decode failed\n");
938    return nullptr;
939}
940
941static sk_sp<SkImage> load_image(const Json::Value& jsonImage, UrlDataManager& urlDataManager) {
942    SkBitmap* bitmap = load_bitmap(jsonImage, urlDataManager);
943    if (bitmap == nullptr) {
944        return nullptr;
945    }
946    auto result = SkImage::MakeFromBitmap(*bitmap);
947    delete bitmap;
948    return result;
949}
950
951bool SkDrawCommand::flatten(const SkBitmap& bitmap, Json::Value* target,
952                            UrlDataManager& urlDataManager) {
953    sk_sp<SkImage> image(SkImage::MakeFromBitmap(bitmap));
954    (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = Json::Value(color_type_name(bitmap.colorType()));
955    (*target)[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = Json::Value(alpha_type_name(bitmap.alphaType()));
956    bool success = flatten(*image, target, urlDataManager);
957    return success;
958}
959
960static void apply_paint_hinting(const SkPaint& paint, Json::Value* target) {
961    SkPaint::Hinting hinting = paint.getHinting();
962    if (hinting != SkPaintDefaults_Hinting) {
963        switch (hinting) {
964            case SkPaint::kNo_Hinting:
965                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_NONE;
966                break;
967            case SkPaint::kSlight_Hinting:
968                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_SLIGHT;
969                break;
970            case SkPaint::kNormal_Hinting:
971                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_NORMAL;
972                break;
973            case SkPaint::kFull_Hinting:
974                (*target)[SKDEBUGCANVAS_ATTRIBUTE_HINTING] = SKDEBUGCANVAS_HINTING_FULL;
975                break;
976        }
977    }
978}
979
980static void apply_paint_color(const SkPaint& paint, Json::Value* target) {
981    SkColor color = paint.getColor();
982    if (color != SK_ColorBLACK) {
983        Json::Value colorValue(Json::arrayValue);
984        colorValue.append(Json::Value(SkColorGetA(color)));
985        colorValue.append(Json::Value(SkColorGetR(color)));
986        colorValue.append(Json::Value(SkColorGetG(color)));
987        colorValue.append(Json::Value(SkColorGetB(color)));
988        (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = colorValue;;
989    }
990}
991
992static void apply_paint_style(const SkPaint& paint, Json::Value* target) {
993    SkPaint::Style style = paint.getStyle();
994    if (style != SkPaint::kFill_Style) {
995        switch (style) {
996            case SkPaint::kStroke_Style: {
997                Json::Value stroke(SKDEBUGCANVAS_STYLE_STROKE);
998                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = stroke;
999                break;
1000            }
1001            case SkPaint::kStrokeAndFill_Style: {
1002                Json::Value strokeAndFill(SKDEBUGCANVAS_STYLE_STROKEANDFILL);
1003                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = strokeAndFill;
1004                break;
1005            }
1006            default: SkASSERT(false);
1007        }
1008    }
1009}
1010
1011static void apply_paint_cap(const SkPaint& paint, Json::Value* target) {
1012    SkPaint::Cap cap = paint.getStrokeCap();
1013    if (cap != SkPaint::kDefault_Cap) {
1014        switch (cap) {
1015            case SkPaint::kButt_Cap:
1016                (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_BUTT);
1017                break;
1018            case SkPaint::kRound_Cap:
1019                (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_ROUND);
1020                break;
1021            case SkPaint::kSquare_Cap:
1022                (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_SQUARE);
1023                break;
1024            default: SkASSERT(false);
1025        }
1026    }
1027}
1028
1029static void apply_paint_join(const SkPaint& paint, Json::Value* target) {
1030    SkPaint::Join join = paint.getStrokeJoin();
1031    if (join != SkPaint::kDefault_Join) {
1032        switch (join) {
1033            case SkPaint::kMiter_Join:
1034                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value(
1035                                                                          SKDEBUGCANVAS_MITER_JOIN);
1036                break;
1037            case SkPaint::kRound_Join:
1038                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value(
1039                                                                          SKDEBUGCANVAS_ROUND_JOIN);
1040                break;
1041            case SkPaint::kBevel_Join:
1042                (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value(
1043                                                                        SKDEBUGCANVAS_BEVEL_JOIN);
1044                break;
1045            default: SkASSERT(false);
1046        }
1047    }
1048}
1049
1050static void apply_paint_filterquality(const SkPaint& paint, Json::Value* target) {
1051    SkFilterQuality quality = paint.getFilterQuality();
1052    switch (quality) {
1053        case kNone_SkFilterQuality:
1054            break;
1055        case kLow_SkFilterQuality:
1056            (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value(
1057                                                                   SKDEBUGCANVAS_FILTERQUALITY_LOW);
1058            break;
1059        case kMedium_SkFilterQuality:
1060            (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value(
1061                                                                SKDEBUGCANVAS_FILTERQUALITY_MEDIUM);
1062            break;
1063        case kHigh_SkFilterQuality:
1064            (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value(
1065                                                                  SKDEBUGCANVAS_FILTERQUALITY_HIGH);
1066            break;
1067    }
1068}
1069
1070static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target,
1071                                   UrlDataManager& urlDataManager) {
1072    SkMaskFilter* maskFilter = paint.getMaskFilter();
1073    if (maskFilter != nullptr) {
1074        SkMaskFilterBase::BlurRec blurRec;
1075        if (as_MFB(maskFilter)->asABlur(&blurRec)) {
1076            Json::Value blur(Json::objectValue);
1077            blur[SKDEBUGCANVAS_ATTRIBUTE_SIGMA] = Json::Value(blurRec.fSigma);
1078            switch (blurRec.fStyle) {
1079                case SkBlurStyle::kNormal_SkBlurStyle:
1080                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
1081                                                                    SKDEBUGCANVAS_BLURSTYLE_NORMAL);
1082                    break;
1083                case SkBlurStyle::kSolid_SkBlurStyle:
1084                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
1085                                                                     SKDEBUGCANVAS_BLURSTYLE_SOLID);
1086                    break;
1087                case SkBlurStyle::kOuter_SkBlurStyle:
1088                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
1089                                                                     SKDEBUGCANVAS_BLURSTYLE_OUTER);
1090                    break;
1091                case SkBlurStyle::kInner_SkBlurStyle:
1092                    blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value(
1093                                                                     SKDEBUGCANVAS_BLURSTYLE_INNER);
1094                    break;
1095                default:
1096                    SkASSERT(false);
1097            }
1098            switch (blurRec.fQuality) {
1099                case SkBlurQuality::kLow_SkBlurQuality:
1100                    blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY] = Json::Value(
1101                                                                     SKDEBUGCANVAS_BLURQUALITY_LOW);
1102                    break;
1103                case SkBlurQuality::kHigh_SkBlurQuality:
1104                    blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY] = Json::Value(
1105                                                                    SKDEBUGCANVAS_BLURQUALITY_HIGH);
1106                    break;
1107                default:
1108                    SkASSERT(false);
1109            }
1110            (*target)[SKDEBUGCANVAS_ATTRIBUTE_BLUR] = blur;
1111        } else {
1112            Json::Value jsonMaskFilter;
1113            SkDrawCommand::flatten(maskFilter, &jsonMaskFilter, urlDataManager);
1114            (*target)[SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER] = jsonMaskFilter;
1115        }
1116    }
1117}
1118
1119static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target,
1120                                   UrlDataManager& urlDataManager) {
1121    SkPathEffect* pathEffect = paint.getPathEffect();
1122    if (pathEffect != nullptr) {
1123        SkPathEffect::DashInfo dashInfo;
1124        SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo);
1125        if (dashType == SkPathEffect::kDash_DashType) {
1126            dashInfo.fIntervals = (SkScalar*) sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar));
1127            pathEffect->asADash(&dashInfo);
1128            Json::Value dashing(Json::objectValue);
1129            Json::Value intervals(Json::arrayValue);
1130            for (int32_t i = 0; i < dashInfo.fCount; i++) {
1131                intervals.append(Json::Value(dashInfo.fIntervals[i]));
1132            }
1133            sk_free(dashInfo.fIntervals);
1134            dashing[SKDEBUGCANVAS_ATTRIBUTE_INTERVALS] = intervals;
1135            dashing[SKDEBUGCANVAS_ATTRIBUTE_PHASE] = dashInfo.fPhase;
1136            (*target)[SKDEBUGCANVAS_ATTRIBUTE_DASHING] = dashing;
1137        } else {
1138            Json::Value jsonPathEffect;
1139            SkDrawCommand::flatten(pathEffect, &jsonPathEffect, urlDataManager);
1140            (*target)[SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT] = jsonPathEffect;
1141        }
1142    }
1143}
1144
1145static void apply_paint_textalign(const SkPaint& paint, Json::Value* target) {
1146    SkPaint::Align textAlign = paint.getTextAlign();
1147    if (textAlign != SkPaint::kLeft_Align) {
1148        switch (textAlign) {
1149            case SkPaint::kCenter_Align: {
1150                (*target)[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN] = SKDEBUGCANVAS_ALIGN_CENTER;
1151                break;
1152            }
1153            case SkPaint::kRight_Align: {
1154                (*target)[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN] = SKDEBUGCANVAS_ALIGN_RIGHT;
1155                break;
1156            }
1157            default: SkASSERT(false);
1158        }
1159    }
1160}
1161
1162static void apply_paint_typeface(const SkPaint& paint, Json::Value* target,
1163                                 UrlDataManager& urlDataManager) {
1164    SkTypeface* typeface = paint.getTypeface();
1165    if (typeface != nullptr) {
1166        Json::Value jsonTypeface;
1167        SkDynamicMemoryWStream buffer;
1168        typeface->serialize(&buffer);
1169        void* data = sk_malloc_throw(buffer.bytesWritten());
1170        buffer.copyTo(data);
1171        Json::Value jsonData;
1172        encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager,
1173                    &jsonData);
1174        jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData;
1175        sk_free(data);
1176        (*target)[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE] = jsonTypeface;
1177    }
1178}
1179
1180static void apply_paint_shader(const SkPaint& paint, Json::Value* target,
1181                               UrlDataManager& urlDataManager) {
1182    SkFlattenable* shader = paint.getShader();
1183    if (shader != nullptr) {
1184        Json::Value jsonShader;
1185        SkDrawCommand::flatten(shader, &jsonShader, urlDataManager);
1186        (*target)[SKDEBUGCANVAS_ATTRIBUTE_SHADER] = jsonShader;
1187    }
1188}
1189
1190static void apply_paint_imagefilter(const SkPaint& paint, Json::Value* target,
1191                                    UrlDataManager& urlDataManager) {
1192    SkFlattenable* imageFilter = paint.getImageFilter();
1193    if (imageFilter != nullptr) {
1194        Json::Value jsonImageFilter;
1195        SkDrawCommand::flatten(imageFilter, &jsonImageFilter, urlDataManager);
1196        (*target)[SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER] = jsonImageFilter;
1197    }
1198}
1199
1200static void apply_paint_colorfilter(const SkPaint& paint, Json::Value* target,
1201                                    UrlDataManager& urlDataManager) {
1202    SkFlattenable* colorFilter = paint.getColorFilter();
1203    if (colorFilter != nullptr) {
1204        Json::Value jsonColorFilter;
1205        SkDrawCommand::flatten(colorFilter, &jsonColorFilter, urlDataManager);
1206        (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER] = jsonColorFilter;
1207    }
1208}
1209
1210static void apply_paint_looper(const SkPaint& paint, Json::Value* target,
1211                               UrlDataManager& urlDataManager) {
1212    SkFlattenable* looper = paint.getLooper();
1213    if (looper != nullptr) {
1214        Json::Value jsonLooper;
1215        SkDrawCommand::flatten(looper, &jsonLooper, urlDataManager);
1216        (*target)[SKDEBUGCANVAS_ATTRIBUTE_LOOPER] = jsonLooper;
1217    }
1218}
1219
1220Json::Value SkDrawCommand::MakeJsonPaint(const SkPaint& paint, UrlDataManager& urlDataManager) {
1221    Json::Value result(Json::objectValue);
1222    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f);
1223    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER, paint.getStrokeMiter(),
1224                 SkPaintDefaults_MiterLimit);
1225    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false);
1226    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_DITHER, paint.isDither(), false);
1227    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT, paint.isFakeBoldText(), false);
1228    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT, paint.isLinearText(), false);
1229    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT, paint.isSubpixelText(), false);
1230    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT, paint.isDevKernText(), false);
1231    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT, paint.isLCDRenderText(), false);
1232    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT, paint.isEmbeddedBitmapText(), false);
1233    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING, paint.isAutohinted(), false);
1234    store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT, paint.isVerticalText(), false);
1235    //kGenA8FromLCD_Flag
1236
1237    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(),
1238                 SkPaintDefaults_TextSize);
1239    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1);
1240    store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f);
1241    apply_paint_hinting(paint, &result);
1242    apply_paint_color(paint, &result);
1243    apply_paint_style(paint, &result);
1244    apply_paint_blend_mode(paint, &result);
1245    apply_paint_cap(paint, &result);
1246    apply_paint_join(paint, &result);
1247    apply_paint_filterquality(paint, &result);
1248    apply_paint_textalign(paint, &result);
1249    apply_paint_patheffect(paint, &result, urlDataManager);
1250    apply_paint_maskfilter(paint, &result, urlDataManager);
1251    apply_paint_shader(paint, &result, urlDataManager);
1252    apply_paint_looper(paint, &result, urlDataManager);
1253    apply_paint_imagefilter(paint, &result, urlDataManager);
1254    apply_paint_colorfilter(paint, &result, urlDataManager);
1255    apply_paint_typeface(paint, &result, urlDataManager);
1256    return result;
1257}
1258
1259Json::Value SkDrawCommand::MakeJsonLattice(const SkCanvas::Lattice& lattice) {
1260    Json::Value result(Json::objectValue);
1261    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEXCOUNT] = Json::Value(lattice.fXCount);
1262    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEYCOUNT] = Json::Value(lattice.fYCount);
1263    if (nullptr != lattice.fBounds) {
1264        result[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS] = MakeJsonIRect(*lattice.fBounds);
1265    }
1266    Json::Value XDivs(Json::arrayValue);
1267    for (int i = 0; i < lattice.fXCount; i++) {
1268        XDivs.append(Json::Value(lattice.fXDivs[i]));
1269    }
1270    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEXDIVS] = XDivs;
1271    Json::Value YDivs(Json::arrayValue);
1272    for (int i = 0; i < lattice.fYCount; i++) {
1273        YDivs.append(Json::Value(lattice.fYDivs[i]));
1274    }
1275    result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEYDIVS] = YDivs;
1276    if (nullptr != lattice.fRectTypes) {
1277        Json::Value flags(Json::arrayValue);
1278        int flagCount = 0;
1279        for (int row = 0; row < lattice.fYCount+1; row++) {
1280            Json::Value flagsRow(Json::arrayValue);
1281            for (int column = 0; column < lattice.fXCount+1; column++) {
1282                flagsRow.append(Json::Value(lattice.fRectTypes[flagCount++]));
1283            }
1284            flags.append(flagsRow);
1285        }
1286        result[SKDEBUGCANVAS_ATTRIBUTE_LATTICEFLAGS] = flags;
1287    }
1288    return result;
1289}
1290
1291static SkPoint get_json_point(Json::Value point) {
1292    return SkPoint::Make(point[0].asFloat(), point[1].asFloat());
1293}
1294
1295static SkColor get_json_color(Json::Value color) {
1296    return SkColorSetARGB(color[0].asInt(), color[1].asInt(), color[2].asInt(), color[3].asInt());
1297}
1298
1299static void extract_json_paint_color(Json::Value& jsonPaint, SkPaint* target) {
1300    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLOR)) {
1301        target->setColor(get_json_color(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_COLOR]));
1302    }
1303}
1304
1305static void extract_json_paint_shader(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
1306                                      SkPaint* target) {
1307    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_SHADER)) {
1308        Json::Value jsonShader = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_SHADER];
1309        SkShader* shader = (SkShader*) load_flattenable(jsonShader, urlDataManager);
1310        if (shader != nullptr) {
1311            target->setShader(sk_ref_sp(shader));
1312        }
1313    }
1314}
1315
1316static void extract_json_paint_patheffect(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
1317                                          SkPaint* target) {
1318    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT)) {
1319        Json::Value jsonPathEffect = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT];
1320        sk_sp<SkPathEffect> pathEffect((SkPathEffect*)load_flattenable(jsonPathEffect,
1321                                                                       urlDataManager));
1322        if (pathEffect != nullptr) {
1323            target->setPathEffect(pathEffect);
1324        }
1325    }
1326}
1327
1328static void extract_json_paint_maskfilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
1329                                          SkPaint* target) {
1330    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER)) {
1331        Json::Value jsonMaskFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER];
1332        sk_sp<SkMaskFilter> maskFilter((SkMaskFilter*)load_flattenable(jsonMaskFilter,
1333                                                                       urlDataManager));
1334        if (maskFilter) {
1335            target->setMaskFilter(std::move(maskFilter));
1336        }
1337    }
1338}
1339
1340static void extract_json_paint_colorfilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
1341                                           SkPaint* target) {
1342    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER)) {
1343        Json::Value jsonColorFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER];
1344        sk_sp<SkColorFilter> colorFilter((SkColorFilter*)load_flattenable(jsonColorFilter,
1345                                                                          urlDataManager));
1346        if (colorFilter != nullptr) {
1347            target->setColorFilter(colorFilter);
1348        }
1349    }
1350}
1351
1352static void extract_json_paint_looper(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
1353                                      SkPaint* target) {
1354    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_LOOPER)) {
1355        Json::Value jsonLooper = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_LOOPER];
1356        sk_sp<SkDrawLooper> looper((SkDrawLooper*) load_flattenable(jsonLooper, urlDataManager));
1357        if (looper != nullptr) {
1358            target->setLooper(std::move(looper));
1359        }
1360    }
1361}
1362
1363static void extract_json_paint_imagefilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
1364                                           SkPaint* target) {
1365    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER)) {
1366        Json::Value jsonImageFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER];
1367        sk_sp<SkImageFilter> imageFilter((SkImageFilter*) load_flattenable(jsonImageFilter,
1368                                                                           urlDataManager));
1369        if (imageFilter != nullptr) {
1370            target->setImageFilter(imageFilter);
1371        }
1372    }
1373}
1374
1375static void extract_json_paint_typeface(Json::Value& jsonPaint, UrlDataManager& urlDataManager,
1376                                        SkPaint* target) {
1377    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE)) {
1378        Json::Value jsonTypeface = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE];
1379        Json::Value jsonData = jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_DATA];
1380        const void* data;
1381        Json::ArrayIndex length = decode_data(jsonData, urlDataManager, &data);
1382        SkMemoryStream buffer(data, length);
1383        target->setTypeface(SkTypeface::MakeDeserialize(&buffer));
1384    }
1385}
1386
1387static void extract_json_paint_hinting(Json::Value& jsonPaint, SkPaint* target) {
1388    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_HINTING)) {
1389        const char* hinting = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_HINTING].asCString();
1390        if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_NONE)) {
1391            target->setHinting(SkPaint::kNo_Hinting);
1392        } else if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_SLIGHT)) {
1393            target->setHinting(SkPaint::kSlight_Hinting);
1394        } else if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_NORMAL)) {
1395            target->setHinting(SkPaint::kNormal_Hinting);
1396        } else if (!strcmp(hinting, SKDEBUGCANVAS_HINTING_FULL)) {
1397            target->setHinting(SkPaint::kFull_Hinting);
1398        }
1399    }
1400}
1401
1402static void extract_json_paint_style(Json::Value& jsonPaint, SkPaint* target) {
1403    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STYLE)) {
1404        const char* style = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STYLE].asCString();
1405        if (!strcmp(style, SKDEBUGCANVAS_STYLE_FILL)) {
1406            target->setStyle(SkPaint::kFill_Style);
1407        }
1408        else if (!strcmp(style, SKDEBUGCANVAS_STYLE_STROKE)) {
1409            target->setStyle(SkPaint::kStroke_Style);
1410        }
1411        else if (!strcmp(style, SKDEBUGCANVAS_STYLE_STROKEANDFILL)) {
1412            target->setStyle(SkPaint::kStrokeAndFill_Style);
1413        }
1414    }
1415}
1416
1417static void extract_json_paint_strokewidth(Json::Value& jsonPaint, SkPaint* target) {
1418    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH)) {
1419        float strokeWidth = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH].asFloat();
1420        target->setStrokeWidth(strokeWidth);
1421    }
1422}
1423
1424static void extract_json_paint_strokemiter(Json::Value& jsonPaint, SkPaint* target) {
1425    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER)) {
1426        float strokeMiter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER].asFloat();
1427        target->setStrokeMiter(strokeMiter);
1428    }
1429}
1430
1431static void extract_json_paint_strokejoin(Json::Value& jsonPaint, SkPaint* target) {
1432    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN)) {
1433        const char* join = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN].asCString();
1434        if (!strcmp(join, SKDEBUGCANVAS_MITER_JOIN)) {
1435            target->setStrokeJoin(SkPaint::kMiter_Join);
1436        }
1437        else if (!strcmp(join, SKDEBUGCANVAS_ROUND_JOIN)) {
1438            target->setStrokeJoin(SkPaint::kRound_Join);
1439        }
1440        else if (!strcmp(join, SKDEBUGCANVAS_BEVEL_JOIN)) {
1441            target->setStrokeJoin(SkPaint::kBevel_Join);
1442        }
1443        else {
1444            SkASSERT(false);
1445        }
1446    }
1447}
1448
1449static void extract_json_paint_cap(Json::Value& jsonPaint, SkPaint* target) {
1450    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_CAP)) {
1451        const char* cap = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_CAP].asCString();
1452        if (!strcmp(cap, SKDEBUGCANVAS_CAP_BUTT)) {
1453            target->setStrokeCap(SkPaint::kButt_Cap);
1454        }
1455        else if (!strcmp(cap, SKDEBUGCANVAS_CAP_ROUND)) {
1456            target->setStrokeCap(SkPaint::kRound_Cap);
1457        }
1458        else if (!strcmp(cap, SKDEBUGCANVAS_CAP_SQUARE)) {
1459            target->setStrokeCap(SkPaint::kSquare_Cap);
1460        }
1461    }
1462}
1463
1464static void extract_json_paint_filterquality(Json::Value& jsonPaint, SkPaint* target) {
1465    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY)) {
1466        const char* quality = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY].asCString();
1467        if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_NONE)) {
1468            target->setFilterQuality(kNone_SkFilterQuality);
1469        }
1470        else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_LOW)) {
1471            target->setFilterQuality(kLow_SkFilterQuality);
1472        }
1473        else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_MEDIUM)) {
1474            target->setFilterQuality(kMedium_SkFilterQuality);
1475        }
1476        else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_HIGH)) {
1477            target->setFilterQuality(kHigh_SkFilterQuality);
1478        }
1479    }
1480}
1481
1482static void extract_json_paint_antialias(Json::Value& jsonPaint, SkPaint* target) {
1483    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS)) {
1484        target->setAntiAlias(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
1485    }
1486}
1487
1488static void extract_json_paint_dither(Json::Value& jsonPaint, SkPaint* target) {
1489    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DITHER)) {
1490        target->setDither(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DITHER].asBool());
1491    }
1492}
1493
1494static void extract_json_paint_fakeboldtext(Json::Value& jsonPaint, SkPaint* target) {
1495    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT)) {
1496        target->setFakeBoldText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_FAKEBOLDTEXT].asBool());
1497    }
1498}
1499
1500static void extract_json_paint_lineartext(Json::Value& jsonPaint, SkPaint* target) {
1501    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT)) {
1502        target->setLinearText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_LINEARTEXT].asBool());
1503    }
1504}
1505
1506static void extract_json_paint_subpixeltext(Json::Value& jsonPaint, SkPaint* target) {
1507    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT)) {
1508        target->setSubpixelText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_SUBPIXELTEXT].asBool());
1509    }
1510}
1511
1512static void extract_json_paint_devkerntext(Json::Value& jsonPaint, SkPaint* target) {
1513    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT)) {
1514        target->setDevKernText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DEVKERNTEXT].asBool());
1515    }
1516}
1517
1518static void extract_json_paint_lcdrendertext(Json::Value& jsonPaint, SkPaint* target) {
1519    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT)) {
1520        target->setLCDRenderText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_LCDRENDERTEXT].asBool());
1521    }
1522}
1523
1524static void extract_json_paint_embeddedbitmaptext(Json::Value& jsonPaint, SkPaint* target) {
1525    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT)) {
1526        target->setEmbeddedBitmapText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_EMBEDDEDBITMAPTEXT].asBool());
1527    }
1528}
1529
1530static void extract_json_paint_autohinting(Json::Value& jsonPaint, SkPaint* target) {
1531    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING)) {
1532        target->setAutohinted(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_AUTOHINTING].asBool());
1533    }
1534}
1535
1536static void extract_json_paint_verticaltext(Json::Value& jsonPaint, SkPaint* target) {
1537    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT)) {
1538        target->setVerticalText(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_VERTICALTEXT].asBool());
1539    }
1540}
1541
1542static void extract_json_paint_blur(Json::Value& jsonPaint, SkPaint* target) {
1543    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_BLUR)) {
1544        Json::Value blur = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_BLUR];
1545        SkScalar sigma = blur[SKDEBUGCANVAS_ATTRIBUTE_SIGMA].asFloat();
1546        SkBlurStyle style;
1547        const char* jsonStyle = blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE].asCString();
1548        if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_NORMAL)) {
1549            style = SkBlurStyle::kNormal_SkBlurStyle;
1550        }
1551        else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_SOLID)) {
1552            style = SkBlurStyle::kSolid_SkBlurStyle;
1553        }
1554        else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_OUTER)) {
1555            style = SkBlurStyle::kOuter_SkBlurStyle;
1556        }
1557        else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_INNER)) {
1558            style = SkBlurStyle::kInner_SkBlurStyle;
1559        }
1560        else {
1561            SkASSERT(false);
1562            style = SkBlurStyle::kNormal_SkBlurStyle;
1563        }
1564        SkBlurMaskFilter::BlurFlags flags;
1565        const char* jsonQuality = blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY].asCString();
1566        if (!strcmp(jsonQuality, SKDEBUGCANVAS_BLURQUALITY_LOW)) {
1567            flags = SkBlurMaskFilter::BlurFlags::kNone_BlurFlag;
1568        }
1569        else if (!strcmp(jsonQuality, SKDEBUGCANVAS_BLURQUALITY_HIGH)) {
1570            flags = SkBlurMaskFilter::BlurFlags::kHighQuality_BlurFlag;
1571        }
1572        else {
1573            SkASSERT(false);
1574            flags = SkBlurMaskFilter::BlurFlags::kNone_BlurFlag;
1575        }
1576        target->setMaskFilter(SkBlurMaskFilter::Make(style, sigma, flags));
1577    }
1578}
1579
1580static void extract_json_paint_dashing(Json::Value& jsonPaint, SkPaint* target) {
1581    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DASHING)) {
1582        Json::Value dash = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DASHING];
1583        Json::Value jsonIntervals = dash[SKDEBUGCANVAS_ATTRIBUTE_INTERVALS];
1584        Json::ArrayIndex count = jsonIntervals.size();
1585        SkScalar* intervals = (SkScalar*) sk_malloc_throw(count * sizeof(SkScalar));
1586        for (Json::ArrayIndex i = 0; i < count; i++) {
1587            intervals[i] = jsonIntervals[i].asFloat();
1588        }
1589        SkScalar phase = dash[SKDEBUGCANVAS_ATTRIBUTE_PHASE].asFloat();
1590        target->setPathEffect(SkDashPathEffect::Make(intervals, count, phase));
1591        sk_free(intervals);
1592    }
1593}
1594
1595static void extract_json_paint_textalign(Json::Value& jsonPaint, SkPaint* target) {
1596    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN)) {
1597        SkPaint::Align textAlign;
1598        const char* jsonAlign = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN].asCString();
1599        if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_LEFT)) {
1600            textAlign = SkPaint::kLeft_Align;
1601        }
1602        else if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_CENTER)) {
1603            textAlign = SkPaint::kCenter_Align;
1604        }
1605        else if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_RIGHT)) {
1606            textAlign = SkPaint::kRight_Align;
1607        }
1608        else {
1609            SkASSERT(false);
1610            textAlign = SkPaint::kLeft_Align;
1611        }
1612        target->setTextAlign(textAlign);
1613    }
1614}
1615
1616static void extract_json_paint_textsize(Json::Value& jsonPaint, SkPaint* target) {
1617    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE)) {
1618        float textSize = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE].asFloat();
1619        target->setTextSize(textSize);
1620    }
1621}
1622
1623static void extract_json_paint_textscalex(Json::Value& jsonPaint, SkPaint* target) {
1624    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX)) {
1625        float textScaleX = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX].asFloat();
1626        target->setTextScaleX(textScaleX);
1627    }
1628}
1629
1630static void extract_json_paint_textskewx(Json::Value& jsonPaint, SkPaint* target) {
1631    if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX)) {
1632        float textSkewX = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX].asFloat();
1633        target->setTextSkewX(textSkewX);
1634    }
1635}
1636
1637static void extract_json_paint(Json::Value& paint, UrlDataManager& urlDataManager,
1638                               SkPaint* result) {
1639    extract_json_paint_hinting(paint, result);
1640    extract_json_paint_color(paint, result);
1641    extract_json_paint_shader(paint, urlDataManager, result);
1642    extract_json_paint_patheffect(paint, urlDataManager, result);
1643    extract_json_paint_maskfilter(paint, urlDataManager, result);
1644    extract_json_paint_colorfilter(paint, urlDataManager, result);
1645    extract_json_paint_looper(paint, urlDataManager, result);
1646    extract_json_paint_imagefilter(paint, urlDataManager, result);
1647    extract_json_paint_typeface(paint, urlDataManager, result);
1648    extract_json_paint_style(paint, result);
1649    extract_json_paint_blend_mode(paint, result);
1650    extract_json_paint_strokewidth(paint, result);
1651    extract_json_paint_strokemiter(paint, result);
1652    extract_json_paint_strokejoin(paint, result);
1653    extract_json_paint_cap(paint, result);
1654    extract_json_paint_filterquality(paint, result);
1655    extract_json_paint_antialias(paint, result);
1656    extract_json_paint_dither(paint, result);
1657    extract_json_paint_fakeboldtext(paint, result);
1658    extract_json_paint_lineartext(paint, result);
1659    extract_json_paint_subpixeltext(paint, result);
1660    extract_json_paint_devkerntext(paint, result);
1661    extract_json_paint_lcdrendertext(paint, result);
1662    extract_json_paint_embeddedbitmaptext(paint, result);
1663    extract_json_paint_autohinting(paint, result);
1664    extract_json_paint_verticaltext(paint, result);
1665    extract_json_paint_blur(paint, result);
1666    extract_json_paint_dashing(paint, result);
1667    extract_json_paint_textalign(paint, result);
1668    extract_json_paint_textsize(paint, result);
1669    extract_json_paint_textscalex(paint, result);
1670    extract_json_paint_textskewx(paint, result);
1671}
1672
1673static void extract_json_rect(Json::Value& rect, SkRect* result) {
1674    result->set(rect[0].asFloat(), rect[1].asFloat(), rect[2].asFloat(), rect[3].asFloat());
1675}
1676
1677static void extract_json_irect(Json::Value& rect, SkIRect* result) {
1678    result->set(rect[0].asInt(), rect[1].asInt(), rect[2].asInt(), rect[3].asInt());
1679}
1680
1681static void extract_json_rrect(Json::Value& rrect, SkRRect* result) {
1682    SkVector radii[4] = {
1683                            { rrect[1][0].asFloat(), rrect[1][1].asFloat() },
1684                            { rrect[2][0].asFloat(), rrect[2][1].asFloat() },
1685                            { rrect[3][0].asFloat(), rrect[3][1].asFloat() },
1686                            { rrect[4][0].asFloat(), rrect[4][1].asFloat() }
1687                        };
1688    result->setRectRadii(SkRect::MakeLTRB(rrect[0][0].asFloat(), rrect[0][1].asFloat(),
1689                                          rrect[0][2].asFloat(), rrect[0][3].asFloat()),
1690                                          radii);
1691}
1692
1693static void extract_json_matrix(Json::Value& matrix, SkMatrix* result) {
1694    SkScalar values[] = {
1695        matrix[0][0].asFloat(), matrix[0][1].asFloat(), matrix[0][2].asFloat(),
1696        matrix[1][0].asFloat(), matrix[1][1].asFloat(), matrix[1][2].asFloat(),
1697        matrix[2][0].asFloat(), matrix[2][1].asFloat(), matrix[2][2].asFloat()
1698    };
1699    result->set9(values);
1700}
1701
1702static void extract_json_path(Json::Value& path, SkPath* result) {
1703    const char* fillType = path[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE].asCString();
1704    if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_WINDING)) {
1705        result->setFillType(SkPath::kWinding_FillType);
1706    }
1707    else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_EVENODD)) {
1708        result->setFillType(SkPath::kEvenOdd_FillType);
1709    }
1710    else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING)) {
1711        result->setFillType(SkPath::kInverseWinding_FillType);
1712    }
1713    else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD)) {
1714        result->setFillType(SkPath::kInverseEvenOdd_FillType);
1715    }
1716    Json::Value verbs = path[SKDEBUGCANVAS_ATTRIBUTE_VERBS];
1717    for (Json::ArrayIndex i = 0; i < verbs.size(); i++) {
1718        Json::Value verb = verbs[i];
1719        if (verb.isString()) {
1720            SkASSERT(!strcmp(verb.asCString(), SKDEBUGCANVAS_VERB_CLOSE));
1721            result->close();
1722        }
1723        else {
1724            if (verb.isMember(SKDEBUGCANVAS_VERB_MOVE)) {
1725                Json::Value move = verb[SKDEBUGCANVAS_VERB_MOVE];
1726                result->moveTo(move[0].asFloat(), move[1].asFloat());
1727            }
1728            else if (verb.isMember(SKDEBUGCANVAS_VERB_LINE)) {
1729                Json::Value line = verb[SKDEBUGCANVAS_VERB_LINE];
1730                result->lineTo(line[0].asFloat(), line[1].asFloat());
1731            }
1732            else if (verb.isMember(SKDEBUGCANVAS_VERB_QUAD)) {
1733                Json::Value quad = verb[SKDEBUGCANVAS_VERB_QUAD];
1734                result->quadTo(quad[0][0].asFloat(), quad[0][1].asFloat(),
1735                               quad[1][0].asFloat(), quad[1][1].asFloat());
1736            }
1737            else if (verb.isMember(SKDEBUGCANVAS_VERB_CUBIC)) {
1738                Json::Value cubic = verb[SKDEBUGCANVAS_VERB_CUBIC];
1739                result->cubicTo(cubic[0][0].asFloat(), cubic[0][1].asFloat(),
1740                                cubic[1][0].asFloat(), cubic[1][1].asFloat(),
1741                                cubic[2][0].asFloat(), cubic[2][1].asFloat());
1742            }
1743            else if (verb.isMember(SKDEBUGCANVAS_VERB_CONIC)) {
1744                Json::Value conic = verb[SKDEBUGCANVAS_VERB_CONIC];
1745                result->conicTo(conic[0][0].asFloat(), conic[0][1].asFloat(),
1746                                conic[1][0].asFloat(), conic[1][1].asFloat(),
1747                                conic[2].asFloat());
1748            }
1749            else {
1750                SkASSERT(false);
1751            }
1752        }
1753    }
1754}
1755
1756SkClipOp get_json_clipop(Json::Value& jsonOp) {
1757    const char* op = jsonOp.asCString();
1758    if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_DIFFERENCE)) {
1759        return kDifference_SkClipOp;
1760    }
1761    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_INTERSECT)) {
1762        return kIntersect_SkClipOp;
1763    }
1764    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_UNION)) {
1765        return kUnion_SkClipOp;
1766    }
1767    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_XOR)) {
1768        return kXOR_SkClipOp;
1769    }
1770    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE)) {
1771        return kReverseDifference_SkClipOp;
1772    }
1773    else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_REPLACE)) {
1774        return kReplace_SkClipOp;
1775    }
1776    SkASSERT(false);
1777    return kIntersect_SkClipOp;
1778}
1779
1780SkClearCommand::SkClearCommand(SkColor color) : INHERITED(kDrawClear_OpType) {
1781    fColor = color;
1782    fInfo.push(SkObjectParser::CustomTextToString("No Parameters"));
1783}
1784
1785void SkClearCommand::execute(SkCanvas* canvas) const {
1786    canvas->clear(fColor);
1787}
1788
1789Json::Value SkClearCommand::toJSON(UrlDataManager& urlDataManager) const {
1790    Json::Value result = INHERITED::toJSON(urlDataManager);
1791    result[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = MakeJsonColor(fColor);
1792    return result;
1793}
1794
1795 SkClearCommand* SkClearCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
1796    Json::Value color = command[SKDEBUGCANVAS_ATTRIBUTE_COLOR];
1797    return new SkClearCommand(get_json_color(color));
1798}
1799
1800SkClipPathCommand::SkClipPathCommand(const SkPath& path, SkClipOp op, bool doAA)
1801    : INHERITED(kClipPath_OpType) {
1802    fPath = path;
1803    fOp = op;
1804    fDoAA = doAA;
1805
1806    fInfo.push(SkObjectParser::PathToString(path));
1807    fInfo.push(SkObjectParser::ClipOpToString(op));
1808    fInfo.push(SkObjectParser::BoolToString(doAA));
1809}
1810
1811void SkClipPathCommand::execute(SkCanvas* canvas) const {
1812    canvas->clipPath(fPath, fOp, fDoAA);
1813}
1814
1815bool SkClipPathCommand::render(SkCanvas* canvas) const {
1816    render_path(canvas, fPath);
1817    return true;
1818}
1819
1820Json::Value SkClipPathCommand::toJSON(UrlDataManager& urlDataManager) const {
1821    Json::Value result = INHERITED::toJSON(urlDataManager);
1822    result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = MakeJsonPath(fPath);
1823    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
1824    result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = fDoAA;
1825    return result;
1826}
1827
1828SkClipPathCommand* SkClipPathCommand::fromJSON(Json::Value& command,
1829                                               UrlDataManager& urlDataManager) {
1830    SkPath path;
1831    extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
1832    return new SkClipPathCommand(path, get_json_clipop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]),
1833                                 command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
1834}
1835
1836SkClipRegionCommand::SkClipRegionCommand(const SkRegion& region, SkClipOp op)
1837    : INHERITED(kClipRegion_OpType) {
1838    fRegion = region;
1839    fOp = op;
1840
1841    fInfo.push(SkObjectParser::RegionToString(region));
1842    fInfo.push(SkObjectParser::ClipOpToString(op));
1843}
1844
1845void SkClipRegionCommand::execute(SkCanvas* canvas) const {
1846    canvas->clipRegion(fRegion, fOp);
1847}
1848
1849Json::Value SkClipRegionCommand::toJSON(UrlDataManager& urlDataManager) const {
1850    Json::Value result = INHERITED::toJSON(urlDataManager);
1851    result[SKDEBUGCANVAS_ATTRIBUTE_REGION] = MakeJsonRegion(fRegion);
1852    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
1853    return result;
1854}
1855
1856SkClipRegionCommand* SkClipRegionCommand::fromJSON(Json::Value& command,
1857                                                   UrlDataManager& urlDataManager) {
1858    SkASSERT(false);
1859    return nullptr;
1860}
1861
1862SkClipRectCommand::SkClipRectCommand(const SkRect& rect, SkClipOp op, bool doAA)
1863    : INHERITED(kClipRect_OpType) {
1864    fRect = rect;
1865    fOp = op;
1866    fDoAA = doAA;
1867
1868    fInfo.push(SkObjectParser::RectToString(rect));
1869    fInfo.push(SkObjectParser::ClipOpToString(op));
1870    fInfo.push(SkObjectParser::BoolToString(doAA));
1871}
1872
1873void SkClipRectCommand::execute(SkCanvas* canvas) const {
1874    canvas->clipRect(fRect, fOp, fDoAA);
1875}
1876
1877Json::Value SkClipRectCommand::toJSON(UrlDataManager& urlDataManager) const {
1878    Json::Value result = INHERITED::toJSON(urlDataManager);
1879    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fRect);
1880    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
1881    result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = Json::Value(fDoAA);
1882
1883    SkString desc;
1884    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fRect)->c_str());
1885
1886    return result;
1887}
1888
1889SkClipRectCommand* SkClipRectCommand::fromJSON(Json::Value& command,
1890                                               UrlDataManager& urlDataManager) {
1891    SkRect rect;
1892    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rect);
1893    return new SkClipRectCommand(rect, get_json_clipop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]),
1894                                 command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
1895}
1896
1897SkClipRRectCommand::SkClipRRectCommand(const SkRRect& rrect, SkClipOp op, bool doAA)
1898    : INHERITED(kClipRRect_OpType) {
1899    fRRect = rrect;
1900    fOp = op;
1901    fDoAA = doAA;
1902
1903    fInfo.push(SkObjectParser::RRectToString(rrect));
1904    fInfo.push(SkObjectParser::ClipOpToString(op));
1905    fInfo.push(SkObjectParser::BoolToString(doAA));
1906}
1907
1908void SkClipRRectCommand::execute(SkCanvas* canvas) const {
1909    canvas->clipRRect(fRRect, fOp, fDoAA);
1910}
1911
1912bool SkClipRRectCommand::render(SkCanvas* canvas) const {
1913    render_rrect(canvas, fRRect);
1914    return true;
1915}
1916
1917Json::Value SkClipRRectCommand::toJSON(UrlDataManager& urlDataManager) const {
1918    Json::Value result = INHERITED::toJSON(urlDataManager);
1919    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rrect(fRRect);
1920    result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp);
1921    result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = Json::Value(fDoAA);
1922    return result;
1923}
1924
1925SkClipRRectCommand* SkClipRRectCommand::fromJSON(Json::Value& command,
1926                                                 UrlDataManager& urlDataManager) {
1927    SkRRect rrect;
1928    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rrect);
1929    return new SkClipRRectCommand(rrect,
1930                                  get_json_clipop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]),
1931                                  command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
1932}
1933
1934SkConcatCommand::SkConcatCommand(const SkMatrix& matrix)
1935    : INHERITED(kConcat_OpType) {
1936    fMatrix = matrix;
1937
1938    fInfo.push(SkObjectParser::MatrixToString(matrix));
1939}
1940
1941void SkConcatCommand::execute(SkCanvas* canvas) const {
1942    canvas->concat(fMatrix);
1943}
1944
1945Json::Value SkConcatCommand::toJSON(UrlDataManager& urlDataManager) const {
1946    Json::Value result = INHERITED::toJSON(urlDataManager);
1947    result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix);
1948    return result;
1949}
1950
1951SkConcatCommand* SkConcatCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
1952    SkMatrix matrix;
1953    extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
1954    return new SkConcatCommand(matrix);
1955}
1956
1957////
1958
1959SkDrawAnnotationCommand::SkDrawAnnotationCommand(const SkRect& rect, const char key[],
1960                                                 sk_sp<SkData> value)
1961    : INHERITED(kDrawAnnotation_OpType)
1962    , fRect(rect)
1963    , fKey(key)
1964    , fValue(std::move(value))
1965{
1966    SkString str;
1967    str.appendf("Key: %s Value: ", key);
1968    if (fValue && fValue->size()) {
1969        str.append((const char*) fValue->bytes(), fValue->size());
1970    } else {
1971        str.appendf("no value");
1972    }
1973    str.appendf("\n");
1974    fInfo.push(new SkString(str));
1975}
1976
1977void SkDrawAnnotationCommand::execute(SkCanvas* canvas) const {
1978    canvas->drawAnnotation(fRect, fKey.c_str(), fValue);
1979}
1980
1981Json::Value SkDrawAnnotationCommand::toJSON(UrlDataManager& urlDataManager) const {
1982    Json::Value result = INHERITED::toJSON(urlDataManager);
1983
1984    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fRect);
1985    result["key"] = Json::Value(fKey.c_str());
1986    if (fValue.get()) {
1987        // TODO: dump out the "value"
1988    }
1989
1990    SkString desc;
1991    str_append(&desc, fRect)->appendf(" %s", fKey.c_str());
1992    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(desc.c_str());
1993
1994    return result;
1995}
1996
1997SkDrawAnnotationCommand* SkDrawAnnotationCommand::fromJSON(Json::Value& command,
1998                                                           UrlDataManager& urlDataManager) {
1999    SkRect rect;
2000    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rect);
2001    sk_sp<SkData> data(nullptr); // TODO: extract "value" from the Json
2002    return new SkDrawAnnotationCommand(rect, command["key"].asCString(), data);
2003}
2004
2005////
2006
2007SkDrawBitmapCommand::SkDrawBitmapCommand(const SkBitmap& bitmap, SkScalar left, SkScalar top,
2008                                         const SkPaint* paint)
2009    : INHERITED(kDrawBitmap_OpType) {
2010    fBitmap = bitmap;
2011    fLeft = left;
2012    fTop = top;
2013    if (paint) {
2014        fPaint = *paint;
2015        fPaintPtr = &fPaint;
2016    } else {
2017        fPaintPtr = nullptr;
2018    }
2019
2020    fInfo.push(SkObjectParser::BitmapToString(bitmap));
2021    fInfo.push(SkObjectParser::ScalarToString(left, "SkScalar left: "));
2022    fInfo.push(SkObjectParser::ScalarToString(top, "SkScalar top: "));
2023    if (paint) {
2024        fInfo.push(SkObjectParser::PaintToString(*paint));
2025    }
2026}
2027
2028void SkDrawBitmapCommand::execute(SkCanvas* canvas) const {
2029    canvas->drawBitmap(fBitmap, fLeft, fTop, fPaintPtr);
2030}
2031
2032bool SkDrawBitmapCommand::render(SkCanvas* canvas) const {
2033    render_bitmap(canvas, fBitmap);
2034    return true;
2035}
2036
2037Json::Value SkDrawBitmapCommand::toJSON(UrlDataManager& urlDataManager) const {
2038    Json::Value result = INHERITED::toJSON(urlDataManager);
2039    Json::Value encoded;
2040    if (flatten(fBitmap, &encoded, urlDataManager)) {
2041        Json::Value command(Json::objectValue);
2042        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
2043        result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(fLeft, fTop);
2044        if (fPaintPtr != nullptr) {
2045            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr, urlDataManager);
2046        }
2047    }
2048    return result;
2049}
2050
2051SkDrawBitmapCommand* SkDrawBitmapCommand::fromJSON(Json::Value& command,
2052                                                   UrlDataManager& urlDataManager) {
2053    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
2054    if (bitmap == nullptr) {
2055        return nullptr;
2056    }
2057    Json::Value point = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
2058    SkPaint* paintPtr;
2059    SkPaint paint;
2060    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
2061        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2062        paintPtr = &paint;
2063    }
2064    else {
2065        paintPtr = nullptr;
2066    }
2067    SkDrawBitmapCommand* result = new SkDrawBitmapCommand(*bitmap, point[0].asFloat(),
2068                                                          point[1].asFloat(), paintPtr);
2069    delete bitmap;
2070    return result;
2071}
2072
2073SkDrawBitmapNineCommand::SkDrawBitmapNineCommand(const SkBitmap& bitmap, const SkIRect& center,
2074                                                 const SkRect& dst, const SkPaint* paint)
2075    : INHERITED(kDrawBitmapNine_OpType) {
2076    fBitmap = bitmap;
2077    fCenter = center;
2078    fDst = dst;
2079    if (paint) {
2080        fPaint = *paint;
2081        fPaintPtr = &fPaint;
2082    } else {
2083        fPaintPtr = nullptr;
2084    }
2085
2086    fInfo.push(SkObjectParser::BitmapToString(bitmap));
2087    fInfo.push(SkObjectParser::IRectToString(center));
2088    fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
2089    if (paint) {
2090        fInfo.push(SkObjectParser::PaintToString(*paint));
2091    }
2092}
2093
2094void SkDrawBitmapNineCommand::execute(SkCanvas* canvas) const {
2095    canvas->drawBitmapNine(fBitmap, fCenter, fDst, fPaintPtr);
2096}
2097
2098bool SkDrawBitmapNineCommand::render(SkCanvas* canvas) const {
2099    SkRect tmp = SkRect::Make(fCenter);
2100    render_bitmap(canvas, fBitmap, &tmp);
2101    return true;
2102}
2103
2104Json::Value SkDrawBitmapNineCommand::toJSON(UrlDataManager& urlDataManager) const {
2105    Json::Value result = INHERITED::toJSON(urlDataManager);
2106    Json::Value encoded;
2107    if (flatten(fBitmap, &encoded, urlDataManager)) {
2108        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
2109        result[SKDEBUGCANVAS_ATTRIBUTE_CENTER] = MakeJsonIRect(fCenter);
2110        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
2111        if (fPaintPtr != nullptr) {
2112            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr, urlDataManager);
2113        }
2114    }
2115    return result;
2116}
2117
2118SkDrawBitmapNineCommand* SkDrawBitmapNineCommand::fromJSON(Json::Value& command,
2119                                                           UrlDataManager& urlDataManager) {
2120    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
2121    if (bitmap == nullptr) {
2122        return nullptr;
2123    }
2124    SkIRect center;
2125    extract_json_irect(command[SKDEBUGCANVAS_ATTRIBUTE_CENTER], &center);
2126    SkRect dst;
2127    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst);
2128    SkPaint* paintPtr;
2129    SkPaint paint;
2130    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
2131        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2132        paintPtr = &paint;
2133    }
2134    else {
2135        paintPtr = nullptr;
2136    }
2137    SkDrawBitmapNineCommand* result = new SkDrawBitmapNineCommand(*bitmap, center, dst, paintPtr);
2138    delete bitmap;
2139    return result;
2140}
2141
2142SkDrawBitmapRectCommand::SkDrawBitmapRectCommand(const SkBitmap& bitmap, const SkRect* src,
2143                                                 const SkRect& dst, const SkPaint* paint,
2144                                                 SkCanvas::SrcRectConstraint constraint)
2145    : INHERITED(kDrawBitmapRect_OpType) {
2146    fBitmap = bitmap;
2147    if (src) {
2148        fSrc = *src;
2149    } else {
2150        fSrc.setEmpty();
2151    }
2152    fDst = dst;
2153
2154    if (paint) {
2155        fPaint = *paint;
2156        fPaintPtr = &fPaint;
2157    } else {
2158        fPaintPtr = nullptr;
2159    }
2160    fConstraint = constraint;
2161
2162    fInfo.push(SkObjectParser::BitmapToString(bitmap));
2163    if (src) {
2164        fInfo.push(SkObjectParser::RectToString(*src, "Src: "));
2165    }
2166    fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
2167    if (paint) {
2168        fInfo.push(SkObjectParser::PaintToString(*paint));
2169    }
2170    fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: "));
2171}
2172
2173void SkDrawBitmapRectCommand::execute(SkCanvas* canvas) const {
2174    canvas->legacy_drawBitmapRect(fBitmap, this->srcRect(), fDst, fPaintPtr, fConstraint);
2175}
2176
2177bool SkDrawBitmapRectCommand::render(SkCanvas* canvas) const {
2178    render_bitmap(canvas, fBitmap, this->srcRect());
2179    return true;
2180}
2181
2182Json::Value SkDrawBitmapRectCommand::toJSON(UrlDataManager& urlDataManager) const {
2183    Json::Value result = INHERITED::toJSON(urlDataManager);
2184    Json::Value encoded;
2185    if (flatten(fBitmap, &encoded, urlDataManager)) {
2186        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
2187        if (!fSrc.isEmpty()) {
2188            result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = MakeJsonRect(fSrc);
2189        }
2190        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
2191        if (fPaintPtr != nullptr) {
2192            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr, urlDataManager);
2193        }
2194        if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
2195            result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
2196        }
2197    }
2198
2199    SkString desc;
2200    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fDst)->c_str());
2201
2202    return result;
2203}
2204
2205SkDrawBitmapRectCommand* SkDrawBitmapRectCommand::fromJSON(Json::Value& command,
2206                                                           UrlDataManager& urlDataManager) {
2207    SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager);
2208    if (bitmap == nullptr) {
2209        return nullptr;
2210    }
2211    SkRect dst;
2212    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst);
2213    SkPaint* paintPtr;
2214    SkPaint paint;
2215    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
2216        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2217        paintPtr = &paint;
2218    }
2219    else {
2220        paintPtr = nullptr;
2221    }
2222    SkCanvas::SrcRectConstraint constraint;
2223    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_STRICT) &&
2224        command[SKDEBUGCANVAS_ATTRIBUTE_STRICT].asBool()) {
2225        constraint = SkCanvas::kStrict_SrcRectConstraint;
2226    }
2227    else {
2228        constraint = SkCanvas::kFast_SrcRectConstraint;
2229    }
2230    SkRect* srcPtr;
2231    SkRect src;
2232    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_SRC)) {
2233        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_SRC], &src);
2234        srcPtr = &src;
2235    }
2236    else {
2237        srcPtr = nullptr;
2238    }
2239    SkDrawBitmapRectCommand* result = new SkDrawBitmapRectCommand(*bitmap, srcPtr, dst, paintPtr,
2240                                                                  constraint);
2241    delete bitmap;
2242    return result;
2243}
2244
2245SkDrawImageCommand::SkDrawImageCommand(const SkImage* image, SkScalar left, SkScalar top,
2246                                       const SkPaint* paint)
2247    : INHERITED(kDrawImage_OpType)
2248    , fImage(SkRef(image))
2249    , fLeft(left)
2250    , fTop(top) {
2251
2252    fInfo.push(SkObjectParser::ImageToString(image));
2253    fInfo.push(SkObjectParser::ScalarToString(left, "Left: "));
2254    fInfo.push(SkObjectParser::ScalarToString(top, "Top: "));
2255
2256    if (paint) {
2257        fPaint.set(*paint);
2258        fInfo.push(SkObjectParser::PaintToString(*paint));
2259    }
2260}
2261
2262void SkDrawImageCommand::execute(SkCanvas* canvas) const {
2263    canvas->drawImage(fImage.get(), fLeft, fTop, fPaint.getMaybeNull());
2264}
2265
2266bool SkDrawImageCommand::render(SkCanvas* canvas) const {
2267    SkAutoCanvasRestore acr(canvas, true);
2268    canvas->clear(0xFFFFFFFF);
2269
2270    xlate_and_scale_to_bounds(canvas, SkRect::MakeXYWH(fLeft, fTop,
2271                                                       SkIntToScalar(fImage->width()),
2272                                                       SkIntToScalar(fImage->height())));
2273    this->execute(canvas);
2274    return true;
2275}
2276
2277Json::Value SkDrawImageCommand::toJSON(UrlDataManager& urlDataManager) const {
2278    Json::Value result = INHERITED::toJSON(urlDataManager);
2279    Json::Value encoded;
2280    if (flatten(*fImage, &encoded, urlDataManager)) {
2281        result[SKDEBUGCANVAS_ATTRIBUTE_IMAGE] = encoded;
2282        result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(fLeft, fTop);
2283        if (fPaint.isValid()) {
2284            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaint.get(), urlDataManager);
2285        }
2286
2287        result[SKDEBUGCANVAS_ATTRIBUTE_UNIQUE_ID] = fImage->uniqueID();
2288        result[SKDEBUGCANVAS_ATTRIBUTE_WIDTH] = fImage->width();
2289        result[SKDEBUGCANVAS_ATTRIBUTE_HEIGHT] = fImage->height();
2290        switch (fImage->alphaType()) {
2291            case kOpaque_SkAlphaType:
2292                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_OPAQUE;
2293                break;
2294            case kPremul_SkAlphaType:
2295                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_PREMUL;
2296                break;
2297            case kUnpremul_SkAlphaType:
2298                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_UNPREMUL;
2299                break;
2300            default:
2301                result[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = SKDEBUGCANVAS_ALPHATYPE_UNKNOWN;
2302                break;
2303        }
2304    }
2305    return result;
2306}
2307
2308SkDrawImageCommand* SkDrawImageCommand::fromJSON(Json::Value& command,
2309                                                 UrlDataManager& urlDataManager) {
2310    sk_sp<SkImage> image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager);
2311    if (image == nullptr) {
2312        return nullptr;
2313    }
2314    Json::Value point = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
2315    SkPaint* paintPtr;
2316    SkPaint paint;
2317    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
2318        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2319        paintPtr = &paint;
2320    }
2321    else {
2322        paintPtr = nullptr;
2323    }
2324    SkDrawImageCommand* result = new SkDrawImageCommand(image.get(), point[0].asFloat(),
2325                                                        point[1].asFloat(), paintPtr);
2326    return result;
2327}
2328
2329SkDrawImageLatticeCommand::SkDrawImageLatticeCommand(const SkImage* image,
2330                                                     const SkCanvas::Lattice& lattice,
2331                                                     const SkRect& dst, const SkPaint* paint)
2332    : INHERITED(kDrawImageLattice_OpType)
2333    , fImage(SkRef(image))
2334    , fLattice(lattice)
2335    , fDst(dst) {
2336
2337      fInfo.push(SkObjectParser::ImageToString(image));
2338      fInfo.push(SkObjectParser::LatticeToString(lattice));
2339      fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
2340      if (paint) {
2341          fPaint.set(*paint);
2342          fInfo.push(SkObjectParser::PaintToString(*paint));
2343      }
2344}
2345
2346void SkDrawImageLatticeCommand::execute(SkCanvas* canvas) const {
2347    SkLatticeIter iter(fLattice, fDst);
2348    SkRect srcR, dstR;
2349    while (iter.next(&srcR, &dstR)) {
2350        canvas->legacy_drawImageRect(fImage.get(), &srcR, dstR,
2351                                     fPaint.getMaybeNull(), SkCanvas::kStrict_SrcRectConstraint);
2352    }
2353}
2354
2355bool SkDrawImageLatticeCommand::render(SkCanvas* canvas) const {
2356    SkAutoCanvasRestore acr(canvas, true);
2357    canvas->clear(0xFFFFFFFF);
2358
2359    xlate_and_scale_to_bounds(canvas, fDst);
2360
2361    this->execute(canvas);
2362    return true;
2363}
2364
2365Json::Value SkDrawImageLatticeCommand::toJSON(UrlDataManager& urlDataManager) const {
2366    Json::Value result = INHERITED::toJSON(urlDataManager);
2367    Json::Value encoded;
2368    if (flatten(*fImage.get(), &encoded, urlDataManager)) {
2369        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
2370        result[SKDEBUGCANVAS_ATTRIBUTE_LATTICE] = MakeJsonLattice(fLattice);
2371        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
2372        if (fPaint.isValid()) {
2373            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaint.get(), urlDataManager);
2374        }
2375    }
2376
2377    SkString desc;
2378    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fDst)->c_str());
2379
2380    return result;
2381}
2382
2383SkDrawImageRectCommand::SkDrawImageRectCommand(const SkImage* image, const SkRect* src,
2384                                               const SkRect& dst, const SkPaint* paint,
2385                                               SkCanvas::SrcRectConstraint constraint)
2386    : INHERITED(kDrawImageRect_OpType)
2387    , fImage(SkRef(image))
2388    , fDst(dst)
2389    , fConstraint(constraint) {
2390
2391    if (src) {
2392        fSrc.set(*src);
2393    }
2394
2395    if (paint) {
2396        fPaint.set(*paint);
2397    }
2398
2399    fInfo.push(SkObjectParser::ImageToString(image));
2400    if (src) {
2401        fInfo.push(SkObjectParser::RectToString(*src, "Src: "));
2402    }
2403    fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
2404    if (paint) {
2405        fInfo.push(SkObjectParser::PaintToString(*paint));
2406    }
2407    fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: "));
2408}
2409
2410void SkDrawImageRectCommand::execute(SkCanvas* canvas) const {
2411    canvas->legacy_drawImageRect(fImage.get(), fSrc.getMaybeNull(), fDst,
2412                                 fPaint.getMaybeNull(), fConstraint);
2413}
2414
2415bool SkDrawImageRectCommand::render(SkCanvas* canvas) const {
2416    SkAutoCanvasRestore acr(canvas, true);
2417    canvas->clear(0xFFFFFFFF);
2418
2419    xlate_and_scale_to_bounds(canvas, fDst);
2420
2421    this->execute(canvas);
2422    return true;
2423}
2424
2425Json::Value SkDrawImageRectCommand::toJSON(UrlDataManager& urlDataManager) const {
2426    Json::Value result = INHERITED::toJSON(urlDataManager);
2427    Json::Value encoded;
2428    if (flatten(*fImage.get(), &encoded, urlDataManager)) {
2429        result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded;
2430        if (fSrc.isValid()) {
2431            result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = MakeJsonRect(*fSrc.get());
2432        }
2433        result[SKDEBUGCANVAS_ATTRIBUTE_DST] = MakeJsonRect(fDst);
2434        if (fPaint.isValid()) {
2435            result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaint.get(), urlDataManager);
2436        }
2437        if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) {
2438            result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
2439        }
2440    }
2441
2442    SkString desc;
2443    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fDst)->c_str());
2444
2445    return result;
2446}
2447
2448SkDrawImageRectCommand* SkDrawImageRectCommand::fromJSON(Json::Value& command,
2449                                                         UrlDataManager& urlDataManager) {
2450    sk_sp<SkImage> image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager);
2451    if (image == nullptr) {
2452        return nullptr;
2453    }
2454    SkRect dst;
2455    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst);
2456    SkPaint* paintPtr;
2457    SkPaint paint;
2458    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
2459        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2460        paintPtr = &paint;
2461    }
2462    else {
2463        paintPtr = nullptr;
2464    }
2465    SkCanvas::SrcRectConstraint constraint;
2466    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_STRICT) &&
2467        command[SKDEBUGCANVAS_ATTRIBUTE_STRICT].asBool()) {
2468        constraint = SkCanvas::kStrict_SrcRectConstraint;
2469    }
2470    else {
2471        constraint = SkCanvas::kFast_SrcRectConstraint;
2472    }
2473    SkRect* srcPtr;
2474    SkRect src;
2475    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_SRC)) {
2476        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_SRC], &src);
2477        srcPtr = &src;
2478    }
2479    else {
2480        srcPtr = nullptr;
2481    }
2482    SkDrawImageRectCommand* result = new SkDrawImageRectCommand(image.get(), srcPtr, dst, paintPtr,
2483                                                                constraint);
2484    return result;
2485}
2486
2487SkDrawOvalCommand::SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint)
2488    : INHERITED(kDrawOval_OpType) {
2489    fOval = oval;
2490    fPaint = paint;
2491
2492    fInfo.push(SkObjectParser::RectToString(oval));
2493    fInfo.push(SkObjectParser::PaintToString(paint));
2494}
2495
2496void SkDrawOvalCommand::execute(SkCanvas* canvas) const {
2497    canvas->drawOval(fOval, fPaint);
2498}
2499
2500bool SkDrawOvalCommand::render(SkCanvas* canvas) const {
2501    canvas->clear(0xFFFFFFFF);
2502    canvas->save();
2503
2504    xlate_and_scale_to_bounds(canvas, fOval);
2505
2506    SkPaint p;
2507    p.setColor(SK_ColorBLACK);
2508    p.setStyle(SkPaint::kStroke_Style);
2509
2510    canvas->drawOval(fOval, p);
2511    canvas->restore();
2512
2513    return true;
2514}
2515
2516Json::Value SkDrawOvalCommand::toJSON(UrlDataManager& urlDataManager) const {
2517    Json::Value result = INHERITED::toJSON(urlDataManager);
2518    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fOval);
2519    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
2520    return result;
2521}
2522
2523SkDrawOvalCommand* SkDrawOvalCommand::fromJSON(Json::Value& command,
2524                                               UrlDataManager& urlDataManager) {
2525    SkRect coords;
2526    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
2527    SkPaint paint;
2528    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2529    return new SkDrawOvalCommand(coords, paint);
2530}
2531
2532SkDrawArcCommand::SkDrawArcCommand(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
2533                                   bool useCenter, const SkPaint& paint)
2534        : INHERITED(kDrawOval_OpType) {
2535    fOval = oval;
2536    fStartAngle = startAngle;
2537    fSweepAngle = sweepAngle;
2538    fUseCenter = useCenter;
2539    fPaint = paint;
2540
2541    fInfo.push(SkObjectParser::RectToString(oval));
2542    fInfo.push(SkObjectParser::ScalarToString(startAngle, "StartAngle: "));
2543    fInfo.push(SkObjectParser::ScalarToString(sweepAngle, "SweepAngle: "));
2544    fInfo.push(SkObjectParser::BoolToString(useCenter));
2545    fInfo.push(SkObjectParser::PaintToString(paint));
2546}
2547
2548void SkDrawArcCommand::execute(SkCanvas* canvas) const {
2549    canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, fPaint);
2550}
2551
2552bool SkDrawArcCommand::render(SkCanvas* canvas) const {
2553    canvas->clear(0xFFFFFFFF);
2554    canvas->save();
2555
2556    xlate_and_scale_to_bounds(canvas, fOval);
2557
2558    SkPaint p;
2559    p.setColor(SK_ColorBLACK);
2560    p.setStyle(SkPaint::kStroke_Style);
2561
2562    canvas->drawArc(fOval, fStartAngle, fSweepAngle, fUseCenter, p);
2563    canvas->restore();
2564
2565    return true;
2566}
2567
2568Json::Value SkDrawArcCommand::toJSON(UrlDataManager& urlDataManager) const {
2569    Json::Value result = INHERITED::toJSON(urlDataManager);
2570    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fOval);
2571    result[SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE] = MakeJsonScalar(fStartAngle);
2572    result[SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE] = MakeJsonScalar(fSweepAngle);
2573    result[SKDEBUGCANVAS_ATTRIBUTE_USECENTER] = fUseCenter;
2574    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
2575    return result;
2576}
2577
2578SkDrawArcCommand* SkDrawArcCommand::fromJSON(Json::Value& command,
2579                                             UrlDataManager& urlDataManager) {
2580    SkRect coords;
2581    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
2582    SkScalar startAngle = command[SKDEBUGCANVAS_ATTRIBUTE_STARTANGLE].asFloat();
2583    SkScalar sweepAngle = command[SKDEBUGCANVAS_ATTRIBUTE_SWEEPANGLE].asFloat();
2584    bool useCenter = command[SKDEBUGCANVAS_ATTRIBUTE_USECENTER].asBool();
2585    SkPaint paint;
2586    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2587    return new SkDrawArcCommand(coords, startAngle, sweepAngle, useCenter, paint);
2588}
2589
2590SkDrawPaintCommand::SkDrawPaintCommand(const SkPaint& paint)
2591    : INHERITED(kDrawPaint_OpType) {
2592    fPaint = paint;
2593
2594    fInfo.push(SkObjectParser::PaintToString(paint));
2595}
2596
2597void SkDrawPaintCommand::execute(SkCanvas* canvas) const {
2598    canvas->drawPaint(fPaint);
2599}
2600
2601bool SkDrawPaintCommand::render(SkCanvas* canvas) const {
2602    canvas->clear(0xFFFFFFFF);
2603    canvas->drawPaint(fPaint);
2604    return true;
2605}
2606
2607Json::Value SkDrawPaintCommand::toJSON(UrlDataManager& urlDataManager) const {
2608    Json::Value result = INHERITED::toJSON(urlDataManager);
2609    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
2610    return result;
2611}
2612
2613SkDrawPaintCommand* SkDrawPaintCommand::fromJSON(Json::Value& command,
2614                                                 UrlDataManager& urlDataManager) {
2615    SkPaint paint;
2616    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2617    return new SkDrawPaintCommand(paint);
2618}
2619
2620SkDrawPathCommand::SkDrawPathCommand(const SkPath& path, const SkPaint& paint)
2621    : INHERITED(kDrawPath_OpType) {
2622    fPath = path;
2623    fPaint = paint;
2624
2625    fInfo.push(SkObjectParser::PathToString(path));
2626    fInfo.push(SkObjectParser::PaintToString(paint));
2627}
2628
2629void SkDrawPathCommand::execute(SkCanvas* canvas) const {
2630    canvas->drawPath(fPath, fPaint);
2631}
2632
2633bool SkDrawPathCommand::render(SkCanvas* canvas) const {
2634    render_path(canvas, fPath);
2635    return true;
2636}
2637
2638Json::Value SkDrawPathCommand::toJSON(UrlDataManager& urlDataManager) const {
2639    Json::Value result = INHERITED::toJSON(urlDataManager);
2640    result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = MakeJsonPath(fPath);
2641    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
2642    return result;
2643}
2644
2645SkDrawPathCommand* SkDrawPathCommand::fromJSON(Json::Value& command,
2646                                               UrlDataManager& urlDataManager) {
2647    SkPath path;
2648    extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
2649    SkPaint paint;
2650    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2651    return new SkDrawPathCommand(path, paint);
2652}
2653
2654SkBeginDrawPictureCommand::SkBeginDrawPictureCommand(const SkPicture* picture,
2655                                                     const SkMatrix* matrix,
2656                                                     const SkPaint* paint)
2657    : INHERITED(kBeginDrawPicture_OpType)
2658    , fPicture(SkRef(picture)) {
2659
2660    SkString* str = new SkString;
2661    str->appendf("SkPicture: L: %f T: %f R: %f B: %f",
2662                 picture->cullRect().fLeft, picture->cullRect().fTop,
2663                 picture->cullRect().fRight, picture->cullRect().fBottom);
2664    fInfo.push(str);
2665
2666    if (matrix) {
2667        fMatrix.set(*matrix);
2668        fInfo.push(SkObjectParser::MatrixToString(*matrix));
2669    }
2670
2671    if (paint) {
2672        fPaint.set(*paint);
2673        fInfo.push(SkObjectParser::PaintToString(*paint));
2674    }
2675
2676}
2677
2678void SkBeginDrawPictureCommand::execute(SkCanvas* canvas) const {
2679    if (fPaint.isValid()) {
2680        SkRect bounds = fPicture->cullRect();
2681        if (fMatrix.isValid()) {
2682            fMatrix.get()->mapRect(&bounds);
2683        }
2684        canvas->saveLayer(&bounds, fPaint.get());
2685    }
2686
2687    if (fMatrix.isValid()) {
2688        if (!fPaint.isValid()) {
2689            canvas->save();
2690        }
2691        canvas->concat(*fMatrix.get());
2692    }
2693}
2694
2695bool SkBeginDrawPictureCommand::render(SkCanvas* canvas) const {
2696    canvas->clear(0xFFFFFFFF);
2697    canvas->save();
2698
2699    xlate_and_scale_to_bounds(canvas, fPicture->cullRect());
2700
2701    canvas->drawPicture(fPicture.get());
2702
2703    canvas->restore();
2704
2705    return true;
2706}
2707
2708SkEndDrawPictureCommand::SkEndDrawPictureCommand(bool restore)
2709    : INHERITED(kEndDrawPicture_OpType) , fRestore(restore) { }
2710
2711void SkEndDrawPictureCommand::execute(SkCanvas* canvas) const {
2712    if (fRestore) {
2713        canvas->restore();
2714    }
2715}
2716
2717SkDrawPointsCommand::SkDrawPointsCommand(SkCanvas::PointMode mode, size_t count,
2718                                         const SkPoint pts[], const SkPaint& paint)
2719    : INHERITED(kDrawPoints_OpType) {
2720    fMode = mode;
2721    fCount = count;
2722    fPts = new SkPoint[count];
2723    memcpy(fPts, pts, count * sizeof(SkPoint));
2724    fPaint = paint;
2725
2726    fInfo.push(SkObjectParser::PointsToString(pts, count));
2727    fInfo.push(SkObjectParser::ScalarToString(SkIntToScalar((unsigned int)count),
2728                                              "Points: "));
2729    fInfo.push(SkObjectParser::PointModeToString(mode));
2730    fInfo.push(SkObjectParser::PaintToString(paint));
2731}
2732
2733void SkDrawPointsCommand::execute(SkCanvas* canvas) const {
2734    canvas->drawPoints(fMode, fCount, fPts, fPaint);
2735}
2736
2737bool SkDrawPointsCommand::render(SkCanvas* canvas) const {
2738    canvas->clear(0xFFFFFFFF);
2739    canvas->save();
2740
2741    SkRect bounds;
2742
2743    bounds.setEmpty();
2744    for (unsigned int i = 0; i < fCount; ++i) {
2745        SkRectPriv::GrowToInclude(&bounds, fPts[i]);
2746    }
2747
2748    xlate_and_scale_to_bounds(canvas, bounds);
2749
2750    SkPaint p;
2751    p.setColor(SK_ColorBLACK);
2752    p.setStyle(SkPaint::kStroke_Style);
2753
2754    canvas->drawPoints(fMode, fCount, fPts, p);
2755    canvas->restore();
2756
2757    return true;
2758}
2759
2760Json::Value SkDrawPointsCommand::toJSON(UrlDataManager& urlDataManager) const {
2761    Json::Value result = INHERITED::toJSON(urlDataManager);
2762    result[SKDEBUGCANVAS_ATTRIBUTE_MODE] = make_json_pointmode(fMode);
2763    Json::Value points(Json::arrayValue);
2764    for (size_t i = 0; i < fCount; i++) {
2765        points.append(MakeJsonPoint(fPts[i]));
2766    }
2767    result[SKDEBUGCANVAS_ATTRIBUTE_POINTS] = points;
2768    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
2769    return result;
2770}
2771
2772SkDrawPointsCommand* SkDrawPointsCommand::fromJSON(Json::Value& command,
2773                                                   UrlDataManager& urlDataManager) {
2774    SkCanvas::PointMode mode;
2775    const char* jsonMode = command[SKDEBUGCANVAS_ATTRIBUTE_MODE].asCString();
2776    if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_POINTS)) {
2777        mode = SkCanvas::kPoints_PointMode;
2778    }
2779    else if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_LINES)) {
2780        mode = SkCanvas::kLines_PointMode;
2781    }
2782    else if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_POLYGON)) {
2783        mode = SkCanvas::kPolygon_PointMode;
2784    }
2785    else {
2786        SkASSERT(false);
2787        return nullptr;
2788    }
2789    Json::Value jsonPoints = command[SKDEBUGCANVAS_ATTRIBUTE_POINTS];
2790    int count = (int) jsonPoints.size();
2791    SkPoint* points = (SkPoint*) sk_malloc_throw(count * sizeof(SkPoint));
2792    for (int i = 0; i < count; i++) {
2793        points[i] = SkPoint::Make(jsonPoints[i][0].asFloat(), jsonPoints[i][1].asFloat());
2794    }
2795    SkPaint paint;
2796    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2797    SkDrawPointsCommand* result = new SkDrawPointsCommand(mode, count, points, paint);
2798    sk_free(points);
2799    return result;
2800}
2801
2802SkDrawPosTextCommand::SkDrawPosTextCommand(const void* text, size_t byteLength,
2803                                           const SkPoint pos[], const SkPaint& paint)
2804    : INHERITED(kDrawPosText_OpType) {
2805    size_t numPts = paint.countText(text, byteLength);
2806
2807    fText = new char[byteLength];
2808    memcpy(fText, text, byteLength);
2809    fByteLength = byteLength;
2810
2811    fPos = new SkPoint[numPts];
2812    memcpy(fPos, pos, numPts * sizeof(SkPoint));
2813
2814    fPaint = paint;
2815
2816    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
2817    // TODO(chudy): Test that this works.
2818    fInfo.push(SkObjectParser::PointsToString(pos, 1));
2819    fInfo.push(SkObjectParser::PaintToString(paint));
2820}
2821
2822void SkDrawPosTextCommand::execute(SkCanvas* canvas) const {
2823    canvas->drawPosText(fText, fByteLength, fPos, fPaint);
2824}
2825
2826Json::Value SkDrawPosTextCommand::toJSON(UrlDataManager& urlDataManager) const {
2827    Json::Value result = INHERITED::toJSON(urlDataManager);
2828    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
2829                                                       ((const char*) fText) + fByteLength);
2830    Json::Value coords(Json::arrayValue);
2831    size_t numCoords = fPaint.textToGlyphs(fText, fByteLength, nullptr);
2832    for (size_t i = 0; i < numCoords; i++) {
2833        coords.append(MakeJsonPoint(fPos[i]));
2834    }
2835    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = coords;
2836    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
2837    return result;
2838}
2839
2840SkDrawPosTextCommand* SkDrawPosTextCommand::fromJSON(Json::Value& command,
2841                                                     UrlDataManager& urlDataManager) {
2842    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
2843    SkPaint paint;
2844    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2845    Json::Value coords = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
2846    int count = (int) coords.size();
2847    SkPoint* points = (SkPoint*) sk_malloc_throw(count * sizeof(SkPoint));
2848    for (int i = 0; i < count; i++) {
2849        points[i] = SkPoint::Make(coords[i][0].asFloat(), coords[i][1].asFloat());
2850    }
2851    return new SkDrawPosTextCommand(text, strlen(text), points, paint);
2852}
2853
2854SkDrawPosTextHCommand::SkDrawPosTextHCommand(const void* text, size_t byteLength,
2855                                             const SkScalar xpos[], SkScalar constY,
2856                                             const SkPaint& paint)
2857    : INHERITED(kDrawPosTextH_OpType) {
2858    size_t numPts = paint.countText(text, byteLength);
2859
2860    fText = new char[byteLength];
2861    memcpy(fText, text, byteLength);
2862    fByteLength = byteLength;
2863
2864    fXpos = new SkScalar[numPts];
2865    memcpy(fXpos, xpos, numPts * sizeof(SkScalar));
2866
2867    fConstY = constY;
2868    fPaint = paint;
2869
2870    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
2871    fInfo.push(SkObjectParser::ScalarToString(xpos[0], "XPOS: "));
2872    fInfo.push(SkObjectParser::ScalarToString(constY, "SkScalar constY: "));
2873    fInfo.push(SkObjectParser::PaintToString(paint));
2874}
2875
2876void SkDrawPosTextHCommand::execute(SkCanvas* canvas) const {
2877    canvas->drawPosTextH(fText, fByteLength, fXpos, fConstY, fPaint);
2878}
2879
2880Json::Value SkDrawPosTextHCommand::toJSON(UrlDataManager& urlDataManager) const {
2881    Json::Value result = INHERITED::toJSON(urlDataManager);
2882    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
2883                                                       ((const char*) fText) + fByteLength);
2884    result[SKDEBUGCANVAS_ATTRIBUTE_Y] = Json::Value(fConstY);
2885    Json::Value xpos(Json::arrayValue);
2886    size_t numXpos = fPaint.textToGlyphs(fText, fByteLength, nullptr);
2887    for (size_t i = 0; i < numXpos; i++) {
2888        xpos.append(Json::Value(fXpos[i]));
2889    }
2890    result[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS] = xpos;
2891    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
2892    return result;
2893}
2894
2895SkDrawPosTextHCommand* SkDrawPosTextHCommand::fromJSON(Json::Value& command,
2896                                                       UrlDataManager& urlDataManager) {
2897    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
2898    SkPaint paint;
2899    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
2900    Json::Value jsonXpos = command[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS];
2901    int count = (int) jsonXpos.size();
2902    SkScalar* xpos = (SkScalar*) sk_malloc_throw(count * sizeof(SkScalar));
2903    for (int i = 0; i < count; i++) {
2904        xpos[i] = jsonXpos[i].asFloat();
2905    }
2906    SkScalar y = command[SKDEBUGCANVAS_ATTRIBUTE_Y].asFloat();
2907    return new SkDrawPosTextHCommand(text, strlen(text), xpos, y, paint);
2908}
2909
2910static const char* gPositioningLabels[] = {
2911    "kDefault_Positioning",
2912    "kHorizontal_Positioning",
2913    "kFull_Positioning",
2914};
2915
2916SkDrawTextBlobCommand::SkDrawTextBlobCommand(sk_sp<SkTextBlob> blob, SkScalar x, SkScalar y,
2917                                             const SkPaint& paint)
2918    : INHERITED(kDrawTextBlob_OpType)
2919    , fBlob(std::move(blob))
2920    , fXPos(x)
2921    , fYPos(y)
2922    , fPaint(paint) {
2923
2924    std::unique_ptr<SkString> runsStr(new SkString);
2925    fInfo.push(SkObjectParser::ScalarToString(x, "XPOS: "));
2926    fInfo.push(SkObjectParser::ScalarToString(y, "YPOS: "));
2927    fInfo.push(SkObjectParser::RectToString(fBlob->bounds(), "Bounds: "));
2928    fInfo.push(runsStr.get());
2929    fInfo.push(SkObjectParser::PaintToString(paint));
2930
2931    unsigned runs = 0;
2932    SkPaint runPaint(paint);
2933    SkTextBlobRunIterator iter(fBlob.get());
2934    while (!iter.done()) {
2935        std::unique_ptr<SkString> tmpStr(new SkString);
2936        tmpStr->printf("==== Run [%d] ====", runs++);
2937        fInfo.push(tmpStr.release());
2938
2939        fInfo.push(SkObjectParser::IntToString(iter.glyphCount(), "GlyphCount: "));
2940        tmpStr.reset(new SkString("GlyphPositioning: "));
2941        tmpStr->append(gPositioningLabels[iter.positioning()]);
2942        fInfo.push(tmpStr.release());
2943
2944        iter.applyFontToPaint(&runPaint);
2945        fInfo.push(SkObjectParser::PaintToString(runPaint));
2946
2947        iter.next();
2948    }
2949
2950    runsStr->printf("Runs: %d", runs);
2951    // runStr is owned by fInfo at this point.
2952    runsStr.release();
2953}
2954
2955void SkDrawTextBlobCommand::execute(SkCanvas* canvas) const {
2956    canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
2957}
2958
2959bool SkDrawTextBlobCommand::render(SkCanvas* canvas) const {
2960    canvas->clear(SK_ColorWHITE);
2961    canvas->save();
2962
2963    SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos);
2964    xlate_and_scale_to_bounds(canvas, bounds);
2965
2966    canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
2967
2968    canvas->restore();
2969
2970    return true;
2971}
2972
2973Json::Value SkDrawTextBlobCommand::toJSON(UrlDataManager& urlDataManager) const {
2974    Json::Value result = INHERITED::toJSON(urlDataManager);
2975    Json::Value runs(Json::arrayValue);
2976    SkTextBlobRunIterator iter(fBlob.get());
2977    while (!iter.done()) {
2978        Json::Value run(Json::objectValue);
2979        Json::Value jsonPositions(Json::arrayValue);
2980        Json::Value jsonGlyphs(Json::arrayValue);
2981        const SkScalar* iterPositions = iter.pos();
2982        const uint16_t* iterGlyphs = iter.glyphs();
2983        for (uint32_t i = 0; i < iter.glyphCount(); i++) {
2984            switch (iter.positioning()) {
2985                case SkTextBlob::kFull_Positioning:
2986                    jsonPositions.append(MakeJsonPoint(iterPositions[i * 2],
2987                                                       iterPositions[i * 2 + 1]));
2988                    break;
2989                case SkTextBlob::kHorizontal_Positioning:
2990                    jsonPositions.append(Json::Value(iterPositions[i]));
2991                    break;
2992                case SkTextBlob::kDefault_Positioning:
2993                    break;
2994            }
2995            jsonGlyphs.append(Json::Value(iterGlyphs[i]));
2996        }
2997        if (iter.positioning() != SkTextBlob::kDefault_Positioning) {
2998            run[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS] = jsonPositions;
2999        }
3000        run[SKDEBUGCANVAS_ATTRIBUTE_GLYPHS] = jsonGlyphs;
3001        SkPaint fontPaint;
3002        iter.applyFontToPaint(&fontPaint);
3003        run[SKDEBUGCANVAS_ATTRIBUTE_FONT] = MakeJsonPaint(fontPaint, urlDataManager);
3004        run[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(iter.offset());
3005        runs.append(run);
3006        iter.next();
3007    }
3008    SkRect bounds = fBlob->bounds();
3009    result[SKDEBUGCANVAS_ATTRIBUTE_RUNS] = runs;
3010    result[SKDEBUGCANVAS_ATTRIBUTE_X] = Json::Value(fXPos);
3011    result[SKDEBUGCANVAS_ATTRIBUTE_Y] = Json::Value(fYPos);
3012    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(bounds);
3013    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
3014
3015    SkString desc;
3016    // make the bounds local by applying the x,y
3017    bounds.offset(fXPos, fYPos);
3018    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, bounds)->c_str());
3019
3020    return result;
3021}
3022
3023SkDrawTextBlobCommand* SkDrawTextBlobCommand::fromJSON(Json::Value& command,
3024                                                       UrlDataManager& urlDataManager) {
3025    SkTextBlobBuilder builder;
3026    Json::Value runs = command[SKDEBUGCANVAS_ATTRIBUTE_RUNS];
3027    for (Json::ArrayIndex i = 0 ; i < runs.size(); i++) {
3028        Json::Value run = runs[i];
3029        SkPaint font;
3030        font.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
3031        extract_json_paint(run[SKDEBUGCANVAS_ATTRIBUTE_FONT], urlDataManager, &font);
3032        Json::Value glyphs = run[SKDEBUGCANVAS_ATTRIBUTE_GLYPHS];
3033        int count = glyphs.size();
3034        Json::Value coords = run[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
3035        SkScalar x = coords[0].asFloat();
3036        SkScalar y = coords[1].asFloat();
3037        SkRect bounds;
3038        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &bounds);
3039
3040        if (run.isMember(SKDEBUGCANVAS_ATTRIBUTE_POSITIONS)) {
3041            Json::Value positions = run[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS];
3042            if (positions.size() > 0 && positions[0].isNumeric()) {
3043                SkTextBlobBuilder::RunBuffer buffer = builder.allocRunPosH(font, count, y, &bounds);
3044                for (int j = 0; j < count; j++) {
3045                    buffer.glyphs[j] = glyphs[j].asUInt();
3046                    buffer.pos[j] = positions[j].asFloat();
3047                }
3048            }
3049            else {
3050                SkTextBlobBuilder::RunBuffer buffer = builder.allocRunPos(font, count, &bounds);
3051                for (int j = 0; j < count; j++) {
3052                    buffer.glyphs[j] = glyphs[j].asUInt();
3053                    buffer.pos[j * 2] = positions[j][0].asFloat();
3054                    buffer.pos[j * 2 + 1] = positions[j][1].asFloat();
3055                }
3056            }
3057        }
3058        else {
3059            SkTextBlobBuilder::RunBuffer buffer = builder.allocRun(font, count, x, y, &bounds);
3060            for (int j = 0; j < count; j++) {
3061                buffer.glyphs[j] = glyphs[j].asUInt();
3062            }
3063        }
3064    }
3065    SkScalar x = command[SKDEBUGCANVAS_ATTRIBUTE_X].asFloat();
3066    SkScalar y = command[SKDEBUGCANVAS_ATTRIBUTE_Y].asFloat();
3067    SkPaint paint;
3068    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3069    return new SkDrawTextBlobCommand(builder.make(), x, y, paint);
3070}
3071
3072SkDrawPatchCommand::SkDrawPatchCommand(const SkPoint cubics[12], const SkColor colors[4],
3073                                       const SkPoint texCoords[4], SkBlendMode bmode,
3074                                       const SkPaint& paint)
3075    : INHERITED(kDrawPatch_OpType)
3076    , fBlendMode(bmode)
3077{
3078    memcpy(fCubics, cubics, sizeof(fCubics));
3079    if (colors != nullptr) {
3080        memcpy(fColors, colors, sizeof(fColors));
3081        fColorsPtr = fColors;
3082    } else {
3083        fColorsPtr = nullptr;
3084    }
3085    if (texCoords != nullptr) {
3086        memcpy(fTexCoords, texCoords, sizeof(fTexCoords));
3087        fTexCoordsPtr = fTexCoords;
3088    } else {
3089        fTexCoordsPtr = nullptr;
3090    }
3091    fPaint = paint;
3092
3093    fInfo.push(SkObjectParser::PaintToString(paint));
3094}
3095
3096void SkDrawPatchCommand::execute(SkCanvas* canvas) const {
3097    canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fBlendMode, fPaint);
3098}
3099
3100Json::Value SkDrawPatchCommand::toJSON(UrlDataManager& urlDataManager) const {
3101    Json::Value result = INHERITED::toJSON(urlDataManager);
3102    Json::Value cubics = Json::Value(Json::arrayValue);
3103    for (int i = 0; i < 12; i++) {
3104        cubics.append(MakeJsonPoint(fCubics[i]));
3105    }
3106    result[SKDEBUGCANVAS_ATTRIBUTE_CUBICS] = cubics;
3107    if (fColorsPtr != nullptr) {
3108        Json::Value colors = Json::Value(Json::arrayValue);
3109        for (int i = 0; i < 4; i++) {
3110            colors.append(MakeJsonColor(fColorsPtr[i]));
3111        }
3112        result[SKDEBUGCANVAS_ATTRIBUTE_COLORS] = colors;
3113    }
3114    if (fTexCoordsPtr != nullptr) {
3115        Json::Value texCoords = Json::Value(Json::arrayValue);
3116        for (int i = 0; i < 4; i++) {
3117            texCoords.append(MakeJsonPoint(fTexCoords[i]));
3118        }
3119        result[SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS] = texCoords;
3120    }
3121    // fBlendMode
3122    return result;
3123}
3124
3125SkDrawPatchCommand* SkDrawPatchCommand::fromJSON(Json::Value& command,
3126                                                 UrlDataManager& urlDataManager) {
3127    Json::Value jsonCubics = command[SKDEBUGCANVAS_ATTRIBUTE_CUBICS];
3128    SkPoint cubics[12];
3129    for (int i = 0; i < 12; i++) {
3130        cubics[i] = get_json_point(jsonCubics[i]);
3131    }
3132    SkColor* colorsPtr;
3133    SkColor colors[4];
3134    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLORS)) {
3135        Json::Value jsonColors = command[SKDEBUGCANVAS_ATTRIBUTE_COLORS];
3136        for (int i = 0; i < 4; i++) {
3137            colors[i] = get_json_color(jsonColors[i]);
3138        }
3139        colorsPtr = colors;
3140    }
3141    else {
3142        colorsPtr = nullptr;
3143    }
3144    SkPoint* texCoordsPtr;
3145    SkPoint texCoords[4];
3146    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS)) {
3147        Json::Value jsonTexCoords = command[SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS];
3148        for (int i = 0; i < 4; i++) {
3149            texCoords[i] = get_json_point(jsonTexCoords[i]);
3150        }
3151        texCoordsPtr = texCoords;
3152    }
3153    else {
3154        texCoordsPtr = nullptr;
3155    }
3156
3157    SkBlendMode bmode = SkBlendMode::kSrcOver; // TODO: extract from json
3158
3159    SkPaint paint;
3160    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3161    return new SkDrawPatchCommand(cubics, colorsPtr, texCoordsPtr, bmode, paint);
3162}
3163
3164SkDrawRectCommand::SkDrawRectCommand(const SkRect& rect, const SkPaint& paint)
3165    : INHERITED(kDrawRect_OpType) {
3166    fRect = rect;
3167    fPaint = paint;
3168
3169    fInfo.push(SkObjectParser::RectToString(rect));
3170    fInfo.push(SkObjectParser::PaintToString(paint));
3171}
3172
3173void SkDrawRectCommand::execute(SkCanvas* canvas) const {
3174    canvas->drawRect(fRect, fPaint);
3175}
3176
3177Json::Value SkDrawRectCommand::toJSON(UrlDataManager& urlDataManager) const {
3178    Json::Value result = INHERITED::toJSON(urlDataManager);
3179    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonRect(fRect);
3180    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
3181
3182    SkString desc;
3183    result[SKDEBUGCANVAS_ATTRIBUTE_SHORTDESC] = Json::Value(str_append(&desc, fRect)->c_str());
3184
3185    return result;
3186}
3187
3188SkDrawRectCommand* SkDrawRectCommand::fromJSON(Json::Value& command,
3189                                               UrlDataManager& urlDataManager) {
3190    SkRect coords;
3191    extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
3192    SkPaint paint;
3193    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3194    return new SkDrawRectCommand(coords, paint);
3195}
3196
3197SkDrawRRectCommand::SkDrawRRectCommand(const SkRRect& rrect, const SkPaint& paint)
3198    : INHERITED(kDrawRRect_OpType) {
3199    fRRect = rrect;
3200    fPaint = paint;
3201
3202    fInfo.push(SkObjectParser::RRectToString(rrect));
3203    fInfo.push(SkObjectParser::PaintToString(paint));
3204}
3205
3206void SkDrawRRectCommand::execute(SkCanvas* canvas) const {
3207    canvas->drawRRect(fRRect, fPaint);
3208}
3209
3210bool SkDrawRRectCommand::render(SkCanvas* canvas) const {
3211    render_rrect(canvas, fRRect);
3212    return true;
3213}
3214
3215Json::Value SkDrawRRectCommand::toJSON(UrlDataManager& urlDataManager) const {
3216    Json::Value result = INHERITED::toJSON(urlDataManager);
3217    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rrect(fRRect);
3218    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
3219    return result;
3220}
3221
3222SkDrawRRectCommand* SkDrawRRectCommand::fromJSON(Json::Value& command,
3223                                                 UrlDataManager& urlDataManager) {
3224    SkRRect coords;
3225    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords);
3226    SkPaint paint;
3227    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3228    return new SkDrawRRectCommand(coords, paint);
3229}
3230
3231SkDrawDRRectCommand::SkDrawDRRectCommand(const SkRRect& outer,
3232                                         const SkRRect& inner,
3233                                         const SkPaint& paint)
3234    : INHERITED(kDrawDRRect_OpType) {
3235    fOuter = outer;
3236    fInner = inner;
3237    fPaint = paint;
3238
3239    fInfo.push(SkObjectParser::RRectToString(outer));
3240    fInfo.push(SkObjectParser::RRectToString(inner));
3241    fInfo.push(SkObjectParser::PaintToString(paint));
3242}
3243
3244void SkDrawDRRectCommand::execute(SkCanvas* canvas) const {
3245    canvas->drawDRRect(fOuter, fInner, fPaint);
3246}
3247
3248bool SkDrawDRRectCommand::render(SkCanvas* canvas) const {
3249    render_drrect(canvas, fOuter, fInner);
3250    return true;
3251}
3252
3253Json::Value SkDrawDRRectCommand::toJSON(UrlDataManager& urlDataManager) const {
3254    Json::Value result = INHERITED::toJSON(urlDataManager);
3255    result[SKDEBUGCANVAS_ATTRIBUTE_OUTER] = make_json_rrect(fOuter);
3256    result[SKDEBUGCANVAS_ATTRIBUTE_INNER] = make_json_rrect(fInner);
3257    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
3258    return result;
3259}
3260
3261SkDrawDRRectCommand* SkDrawDRRectCommand::fromJSON(Json::Value& command,
3262                                                   UrlDataManager& urlDataManager) {
3263    SkRRect outer;
3264    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_INNER], &outer);
3265    SkRRect inner;
3266    extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_INNER], &inner);
3267    SkPaint paint;
3268    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3269    return new SkDrawDRRectCommand(outer, inner, paint);
3270}
3271
3272SkDrawTextCommand::SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y,
3273                                     const SkPaint& paint)
3274    : INHERITED(kDrawText_OpType) {
3275    fText = new char[byteLength];
3276    memcpy(fText, text, byteLength);
3277    fByteLength = byteLength;
3278    fX = x;
3279    fY = y;
3280    fPaint = paint;
3281
3282    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
3283    fInfo.push(SkObjectParser::ScalarToString(x, "SkScalar x: "));
3284    fInfo.push(SkObjectParser::ScalarToString(y, "SkScalar y: "));
3285    fInfo.push(SkObjectParser::PaintToString(paint));
3286}
3287
3288void SkDrawTextCommand::execute(SkCanvas* canvas) const {
3289    canvas->drawText(fText, fByteLength, fX, fY, fPaint);
3290}
3291
3292Json::Value SkDrawTextCommand::toJSON(UrlDataManager& urlDataManager) const {
3293    Json::Value result = INHERITED::toJSON(urlDataManager);
3294    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
3295                                                       ((const char*) fText) + fByteLength);
3296    Json::Value coords(Json::arrayValue);
3297    result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = MakeJsonPoint(fX, fY);
3298    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
3299    return result;
3300}
3301
3302SkDrawTextCommand* SkDrawTextCommand::fromJSON(Json::Value& command,
3303                                               UrlDataManager& urlDataManager) {
3304    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
3305    SkPaint paint;
3306    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3307    Json::Value coords = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS];
3308    return new SkDrawTextCommand(text, strlen(text), coords[0].asFloat(), coords[1].asFloat(),
3309                                 paint);
3310}
3311
3312///////////////////////////////////////////////////////////////////////////////////////////////////
3313
3314SkDrawTextOnPathCommand::SkDrawTextOnPathCommand(const void* text, size_t byteLength,
3315                                                 const SkPath& path, const SkMatrix* matrix,
3316                                                 const SkPaint& paint)
3317    : INHERITED(kDrawTextOnPath_OpType) {
3318    fText = new char[byteLength];
3319    memcpy(fText, text, byteLength);
3320    fByteLength = byteLength;
3321    fPath = path;
3322    if (matrix) {
3323        fMatrix = *matrix;
3324    } else {
3325        fMatrix.setIdentity();
3326    }
3327    fPaint = paint;
3328
3329    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
3330    fInfo.push(SkObjectParser::PathToString(path));
3331    if (matrix) {
3332        fInfo.push(SkObjectParser::MatrixToString(*matrix));
3333    }
3334    fInfo.push(SkObjectParser::PaintToString(paint));
3335}
3336
3337void SkDrawTextOnPathCommand::execute(SkCanvas* canvas) const {
3338    canvas->drawTextOnPath(fText, fByteLength, fPath,
3339                           fMatrix.isIdentity() ? nullptr : &fMatrix,
3340                           fPaint);
3341}
3342
3343Json::Value SkDrawTextOnPathCommand::toJSON(UrlDataManager& urlDataManager) const {
3344    Json::Value result = INHERITED::toJSON(urlDataManager);
3345    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
3346                                                       ((const char*) fText) + fByteLength);
3347    Json::Value coords(Json::arrayValue);
3348    result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = MakeJsonPath(fPath);
3349    if (!fMatrix.isIdentity()) {
3350        result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix);
3351    }
3352    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
3353    return result;
3354}
3355
3356SkDrawTextOnPathCommand* SkDrawTextOnPathCommand::fromJSON(Json::Value& command,
3357                                                           UrlDataManager& urlDataManager) {
3358    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
3359    SkPaint paint;
3360    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3361    SkPath path;
3362    extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path);
3363    SkMatrix* matrixPtr;
3364    SkMatrix matrix;
3365    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_MATRIX)) {
3366        extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
3367        matrixPtr = &matrix;
3368    }
3369    else {
3370        matrixPtr = nullptr;
3371    }
3372    return new SkDrawTextOnPathCommand(text, strlen(text), path, matrixPtr, paint);
3373}
3374
3375///////////////////////////////////////////////////////////////////////////////////////////////////
3376
3377SkDrawTextRSXformCommand::SkDrawTextRSXformCommand(const void* text, size_t byteLength,
3378                                                   const SkRSXform xform[], const SkRect* cull,
3379                                                   const SkPaint& paint)
3380    : INHERITED(kDrawTextRSXform_OpType)
3381{
3382    fText = new char[byteLength];
3383    memcpy(fText, text, byteLength);
3384    fByteLength = byteLength;
3385    int count = paint.countText(text, byteLength);
3386    fXform = new SkRSXform[count];
3387    memcpy(fXform, xform, count * sizeof(SkRSXform));
3388    if (cull) {
3389        fCullStorage = *cull;
3390        fCull = &fCullStorage;
3391    } else {
3392        fCull = nullptr;
3393    }
3394    fPaint = paint;
3395
3396    fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
3397    fInfo.push(SkObjectParser::PaintToString(paint));
3398}
3399
3400void SkDrawTextRSXformCommand::execute(SkCanvas* canvas) const {
3401    canvas->drawTextRSXform(fText, fByteLength, fXform, fCull, fPaint);
3402}
3403
3404Json::Value SkDrawTextRSXformCommand::toJSON(UrlDataManager& urlDataManager) const {
3405    Json::Value result = INHERITED::toJSON(urlDataManager);
3406    result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText,
3407                                                       ((const char*) fText) + fByteLength);
3408    result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(fPaint, urlDataManager);
3409    return result;
3410}
3411
3412SkDrawTextRSXformCommand* SkDrawTextRSXformCommand::fromJSON(Json::Value& command,
3413                                                             UrlDataManager& urlDataManager) {
3414    const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString();
3415    size_t byteLength = strlen(text);
3416    SkPaint paint;
3417    extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3418
3419    // TODO: handle xform and cull
3420    int count = paint.countText(text, byteLength);
3421    SkAutoTArray<SkRSXform> xform(count);
3422    for (int i = 0; i < count; ++i) {
3423        xform[i].fSCos = 1;
3424        xform[i].fSSin = xform[i].fTx = xform[i].fTy = 0;
3425    }
3426    return new SkDrawTextRSXformCommand(text, byteLength, &xform[0], nullptr, paint);
3427}
3428
3429///////////////////////////////////////////////////////////////////////////////////////////////////
3430
3431SkDrawVerticesCommand::SkDrawVerticesCommand(sk_sp<SkVertices> vertices, SkBlendMode bmode,
3432                                             const SkPaint& paint)
3433    : INHERITED(kDrawVertices_OpType)
3434    , fVertices(std::move(vertices))
3435    , fBlendMode(bmode)
3436    , fPaint(paint)
3437{
3438    // TODO(chudy)
3439    fInfo.push(SkObjectParser::CustomTextToString("To be implemented."));
3440    fInfo.push(SkObjectParser::PaintToString(paint));
3441}
3442
3443void SkDrawVerticesCommand::execute(SkCanvas* canvas) const {
3444    canvas->drawVertices(fVertices, fBlendMode, fPaint);
3445}
3446
3447SkRestoreCommand::SkRestoreCommand()
3448    : INHERITED(kRestore_OpType) {
3449    fInfo.push(SkObjectParser::CustomTextToString("No Parameters"));
3450}
3451
3452void SkRestoreCommand::execute(SkCanvas* canvas) const {
3453    canvas->restore();
3454}
3455
3456SkRestoreCommand* SkRestoreCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
3457    return new SkRestoreCommand();
3458}
3459
3460SkSaveCommand::SkSaveCommand()
3461    : INHERITED(kSave_OpType) {
3462}
3463
3464void SkSaveCommand::execute(SkCanvas* canvas) const {
3465    canvas->save();
3466}
3467
3468SkSaveCommand* SkSaveCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) {
3469    return new SkSaveCommand();
3470}
3471
3472SkSaveLayerCommand::SkSaveLayerCommand(const SkCanvas::SaveLayerRec& rec)
3473    : INHERITED(kSaveLayer_OpType) {
3474    if (rec.fBounds) {
3475        fBounds = *rec.fBounds;
3476    } else {
3477        fBounds.setEmpty();
3478    }
3479
3480    if (rec.fPaint) {
3481        fPaint = *rec.fPaint;
3482        fPaintPtr = &fPaint;
3483    } else {
3484        fPaintPtr = nullptr;
3485    }
3486    fSaveLayerFlags = rec.fSaveLayerFlags;
3487
3488    if (rec.fBackdrop) {
3489        fBackdrop = rec.fBackdrop;
3490        fBackdrop->ref();
3491    } else {
3492        fBackdrop = nullptr;
3493    }
3494
3495    if (rec.fBounds) {
3496        fInfo.push(SkObjectParser::RectToString(*rec.fBounds, "Bounds: "));
3497    }
3498    if (rec.fPaint) {
3499        fInfo.push(SkObjectParser::PaintToString(*rec.fPaint));
3500    }
3501    fInfo.push(SkObjectParser::SaveLayerFlagsToString(fSaveLayerFlags));
3502}
3503
3504SkSaveLayerCommand::~SkSaveLayerCommand() {
3505    if (fBackdrop != nullptr) {
3506        fBackdrop->unref();
3507    }
3508}
3509
3510void SkSaveLayerCommand::execute(SkCanvas* canvas) const {
3511    canvas->saveLayer(SkCanvas::SaveLayerRec(fBounds.isEmpty() ? nullptr : &fBounds,
3512                                             fPaintPtr,
3513                                             fSaveLayerFlags));
3514}
3515
3516void SkSaveLayerCommand::vizExecute(SkCanvas* canvas) const {
3517    canvas->save();
3518}
3519
3520Json::Value SkSaveLayerCommand::toJSON(UrlDataManager& urlDataManager) const {
3521    Json::Value result = INHERITED::toJSON(urlDataManager);
3522    if (!fBounds.isEmpty()) {
3523        result[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS] = MakeJsonRect(fBounds);
3524    }
3525    if (fPaintPtr != nullptr) {
3526        result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = MakeJsonPaint(*fPaintPtr,
3527                                                                urlDataManager);
3528    }
3529    if (fBackdrop != nullptr) {
3530        Json::Value jsonBackdrop;
3531        flatten(fBackdrop, &jsonBackdrop, urlDataManager);
3532        result[SKDEBUGCANVAS_ATTRIBUTE_BACKDROP] = jsonBackdrop;
3533    }
3534    if (fSaveLayerFlags != 0) {
3535        SkDebugf("unsupported: saveLayer flags\n");
3536        SkASSERT(false);
3537    }
3538    return result;
3539}
3540
3541SkSaveLayerCommand* SkSaveLayerCommand::fromJSON(Json::Value& command,
3542                                                 UrlDataManager& urlDataManager) {
3543    SkCanvas::SaveLayerRec rec;
3544    SkRect bounds;
3545    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_BOUNDS)) {
3546        extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS], &bounds);
3547        rec.fBounds = &bounds;
3548    }
3549    SkPaint paint;
3550    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) {
3551        extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint);
3552        rec.fPaint = &paint;
3553    }
3554    if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_BACKDROP)) {
3555        Json::Value backdrop = command[SKDEBUGCANVAS_ATTRIBUTE_BACKDROP];
3556        rec.fBackdrop = (SkImageFilter*) load_flattenable(backdrop, urlDataManager);
3557    }
3558    SkSaveLayerCommand* result = new SkSaveLayerCommand(rec);
3559    if (rec.fBackdrop != nullptr) {
3560        rec.fBackdrop->unref();
3561    }
3562    return result;
3563}
3564
3565SkSetMatrixCommand::SkSetMatrixCommand(const SkMatrix& matrix)
3566    : INHERITED(kSetMatrix_OpType) {
3567    fUserMatrix.reset();
3568    fMatrix = matrix;
3569    fInfo.push(SkObjectParser::MatrixToString(matrix));
3570}
3571
3572void SkSetMatrixCommand::setUserMatrix(const SkMatrix& userMatrix) {
3573    fUserMatrix = userMatrix;
3574}
3575
3576void SkSetMatrixCommand::execute(SkCanvas* canvas) const {
3577    SkMatrix temp = SkMatrix::Concat(fUserMatrix, fMatrix);
3578    canvas->setMatrix(temp);
3579}
3580
3581Json::Value SkSetMatrixCommand::toJSON(UrlDataManager& urlDataManager) const {
3582    Json::Value result = INHERITED::toJSON(urlDataManager);
3583    result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix);
3584    return result;
3585}
3586
3587SkSetMatrixCommand* SkSetMatrixCommand::fromJSON(Json::Value& command,
3588                                                 UrlDataManager& urlDataManager) {
3589    SkMatrix matrix;
3590    extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix);
3591    return new SkSetMatrixCommand(matrix);
3592}
3593