|  |  | 
|  | /* | 
|  | * Copyright 2012 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include "SkDrawCommand.h" | 
|  |  | 
|  | #include "SkBlurMaskFilter.h" | 
|  | #include "SkColorFilter.h" | 
|  | #include "SkDashPathEffect.h" | 
|  | #include "SkImageFilter.h" | 
|  | #include "SkMaskFilter.h" | 
|  | #include "SkObjectParser.h" | 
|  | #include "SkPaintDefaults.h" | 
|  | #include "SkPathEffect.h" | 
|  | #include "SkPicture.h" | 
|  | #include "SkTextBlob.h" | 
|  | #include "SkTextBlobRunIterator.h" | 
|  | #include "SkTHash.h" | 
|  | #include "SkTypeface.h" | 
|  | #include "SkValidatingReadBuffer.h" | 
|  | #include "SkWriteBuffer.h" | 
|  |  | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_COMMAND           "command" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_VISIBLE           "visible" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_MATRIX            "matrix" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_COORDS            "coords" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_BOUNDS            "bounds" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_PAINT             "paint" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_OUTER             "outer" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_INNER             "inner" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_MODE              "mode" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_POINTS            "points" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_PATH              "path" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_TEXT              "text" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_COLOR             "color" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_ALPHA             "alpha" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_STYLE             "style" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH       "strokeWidth" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER       "strokeMiter" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN        "strokeJoin" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_CAP               "cap" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS         "antiAlias" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_DITHER            "dither" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_REGION            "region" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_REGIONOP          "op" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_EDGESTYLE         "edgeStyle" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_DEVICEREGION      "deviceRegion" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_BLUR              "blur" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_SIGMA             "sigma" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_QUALITY           "quality" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN         "textAlign" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE          "textSize" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX        "textScaleX" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX         "textSkewX" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_DASHING           "dashing" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_INTERVALS         "intervals" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_PHASE             "phase" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE          "fillType" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_VERBS             "verbs" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_NAME              "name" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_DATA              "data" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_SHADER            "shader" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT        "pathEffect" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER        "maskFilter" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_XFERMODE          "xfermode" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_LOOPER            "looper" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_BACKDROP          "backdrop" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER       "colorfilter" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER       "imagefilter" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_IMAGE             "image" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_BITMAP            "bitmap" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_SRC               "src" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_DST               "dst" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_CENTER            "center" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_STRICT            "strict" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_DESCRIPTION       "description" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_X                 "x" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_Y                 "y" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_RUNS              "runs" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_POSITIONS         "positions" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_GLYPHS            "glyphs" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_FONT              "font" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE          "typeface" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_CUBICS            "cubics" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_COLORS            "colors" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS     "textureCoords" | 
|  | #define SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY     "filterQuality" | 
|  |  | 
|  | #define SKDEBUGCANVAS_VERB_MOVE                   "move" | 
|  | #define SKDEBUGCANVAS_VERB_LINE                   "line" | 
|  | #define SKDEBUGCANVAS_VERB_QUAD                   "quad" | 
|  | #define SKDEBUGCANVAS_VERB_CUBIC                  "cubic" | 
|  | #define SKDEBUGCANVAS_VERB_CONIC                  "conic" | 
|  | #define SKDEBUGCANVAS_VERB_CLOSE                  "close" | 
|  |  | 
|  | #define SKDEBUGCANVAS_STYLE_FILL                  "fill" | 
|  | #define SKDEBUGCANVAS_STYLE_STROKE                "stroke" | 
|  | #define SKDEBUGCANVAS_STYLE_STROKEANDFILL         "strokeAndFill" | 
|  |  | 
|  | #define SKDEBUGCANVAS_POINTMODE_POINTS            "points" | 
|  | #define SKDEBUGCANVAS_POINTMODE_LINES             "lines" | 
|  | #define SKDEBUGCANVAS_POINTMODE_POLYGON           "polygon" | 
|  |  | 
|  | #define SKDEBUGCANVAS_REGIONOP_DIFFERENCE         "difference" | 
|  | #define SKDEBUGCANVAS_REGIONOP_INTERSECT          "intersect" | 
|  | #define SKDEBUGCANVAS_REGIONOP_UNION              "union" | 
|  | #define SKDEBUGCANVAS_REGIONOP_XOR                "xor" | 
|  | #define SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE "reverseDifference" | 
|  | #define SKDEBUGCANVAS_REGIONOP_REPLACE            "replace" | 
|  |  | 
|  | #define SKDEBUGCANVAS_BLURSTYLE_NORMAL            "normal" | 
|  | #define SKDEBUGCANVAS_BLURSTYLE_SOLID             "solid" | 
|  | #define SKDEBUGCANVAS_BLURSTYLE_OUTER             "outer" | 
|  | #define SKDEBUGCANVAS_BLURSTYLE_INNER             "inner" | 
|  |  | 
|  | #define SKDEBUGCANVAS_BLURQUALITY_LOW             "low" | 
|  | #define SKDEBUGCANVAS_BLURQUALITY_HIGH            "high" | 
|  |  | 
|  | #define SKDEBUGCANVAS_ALIGN_LEFT                  "left" | 
|  | #define SKDEBUGCANVAS_ALIGN_CENTER                "center" | 
|  | #define SKDEBUGCANVAS_ALIGN_RIGHT                 "right" | 
|  |  | 
|  | #define SKDEBUGCANVAS_FILLTYPE_WINDING            "winding" | 
|  | #define SKDEBUGCANVAS_FILLTYPE_EVENODD            "evenOdd" | 
|  | #define SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING     "inverseWinding" | 
|  | #define SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD     "inverseEvenOdd" | 
|  |  | 
|  | #define SKDEBUGCANVAS_CAP_BUTT                    "butt" | 
|  | #define SKDEBUGCANVAS_CAP_ROUND                   "round" | 
|  | #define SKDEBUGCANVAS_CAP_SQUARE                  "square" | 
|  |  | 
|  | #define SKDEBUGCANVAS_MITER_JOIN                  "miter" | 
|  | #define SKDEBUGCANVAS_ROUND_JOIN                  "round" | 
|  | #define SKDEBUGCANVAS_BEVEL_JOIN                  "bevel" | 
|  |  | 
|  | #define SKDEBUGCANVAS_COLORTYPE_ARGB4444          "ARGB4444" | 
|  | #define SKDEBUGCANVAS_COLORTYPE_RGBA8888          "RGBA8888" | 
|  | #define SKDEBUGCANVAS_COLORTYPE_BGRA8888          "BGRA8888" | 
|  | #define SKDEBUGCANVAS_COLORTYPE_565               "565" | 
|  | #define SKDEBUGCANVAS_COLORTYPE_GRAY8             "Gray8" | 
|  | #define SKDEBUGCANVAS_COLORTYPE_INDEX8            "Index8" | 
|  | #define SKDEBUGCANVAS_COLORTYPE_ALPHA8            "Alpha8" | 
|  |  | 
|  | #define SKDEBUGCANVAS_ALPHATYPE_OPAQUE            "opaque" | 
|  | #define SKDEBUGCANVAS_ALPHATYPE_PREMUL            "premul" | 
|  | #define SKDEBUGCANVAS_ALPHATYPE_UNPREMUL          "unpremul" | 
|  |  | 
|  | #define SKDEBUGCANVAS_FILTERQUALITY_NONE          "none" | 
|  | #define SKDEBUGCANVAS_FILTERQUALITY_LOW           "low" | 
|  | #define SKDEBUGCANVAS_FILTERQUALITY_MEDIUM        "medium" | 
|  | #define SKDEBUGCANVAS_FILTERQUALITY_HIGH          "high" | 
|  |  | 
|  | typedef SkDrawCommand* (*FROM_JSON)(Json::Value&, UrlDataManager&); | 
|  |  | 
|  | // TODO(chudy): Refactor into non subclass model. | 
|  |  | 
|  | SkDrawCommand::SkDrawCommand(OpType type) | 
|  | : fOpType(type) | 
|  | , fVisible(true) { | 
|  | } | 
|  |  | 
|  | SkDrawCommand::~SkDrawCommand() { | 
|  | fInfo.deleteAll(); | 
|  | } | 
|  |  | 
|  | const char* SkDrawCommand::GetCommandString(OpType type) { | 
|  | switch (type) { | 
|  | case kBeginDrawPicture_OpType: return "BeginDrawPicture"; | 
|  | case kClipPath_OpType: return "ClipPath"; | 
|  | case kClipRegion_OpType: return "ClipRegion"; | 
|  | case kClipRect_OpType: return "ClipRect"; | 
|  | case kClipRRect_OpType: return "ClipRRect"; | 
|  | case kConcat_OpType: return "Concat"; | 
|  | case kDrawBitmap_OpType: return "DrawBitmap"; | 
|  | case kDrawBitmapNine_OpType: return "DrawBitmapNine"; | 
|  | case kDrawBitmapRect_OpType: return "DrawBitmapRect"; | 
|  | case kDrawClear_OpType: return "DrawClear"; | 
|  | case kDrawDRRect_OpType: return "DrawDRRect"; | 
|  | case kDrawImage_OpType: return "DrawImage"; | 
|  | case kDrawImageRect_OpType: return "DrawImageRect"; | 
|  | case kDrawOval_OpType: return "DrawOval"; | 
|  | case kDrawPaint_OpType: return "DrawPaint"; | 
|  | case kDrawPatch_OpType: return "DrawPatch"; | 
|  | case kDrawPath_OpType: return "DrawPath"; | 
|  | case kDrawPoints_OpType: return "DrawPoints"; | 
|  | case kDrawPosText_OpType: return "DrawPosText"; | 
|  | case kDrawPosTextH_OpType: return "DrawPosTextH"; | 
|  | case kDrawRect_OpType: return "DrawRect"; | 
|  | case kDrawRRect_OpType: return "DrawRRect"; | 
|  | case kDrawText_OpType: return "DrawText"; | 
|  | case kDrawTextBlob_OpType: return "DrawTextBlob"; | 
|  | case kDrawTextOnPath_OpType: return "DrawTextOnPath"; | 
|  | case kDrawVertices_OpType: return "DrawVertices"; | 
|  | case kEndDrawPicture_OpType: return "EndDrawPicture"; | 
|  | case kRestore_OpType: return "Restore"; | 
|  | case kSave_OpType: return "Save"; | 
|  | case kSaveLayer_OpType: return "SaveLayer"; | 
|  | case kSetMatrix_OpType: return "SetMatrix"; | 
|  | default: | 
|  | SkDebugf("OpType error 0x%08x\n", type); | 
|  | SkASSERT(0); | 
|  | break; | 
|  | } | 
|  | SkDEBUGFAIL("DrawType UNUSED\n"); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | SkString SkDrawCommand::toString() const { | 
|  | return SkString(GetCommandString(fOpType)); | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COMMAND] = this->GetCommandString(fOpType); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_VISIBLE] = Json::Value(this->isVisible()); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | #define INSTALL_FACTORY(name) factories.set(SkString(GetCommandString(k ## name ##_OpType)), \ | 
|  | (FROM_JSON) Sk ## name ## Command::fromJSON) | 
|  | SkDrawCommand* SkDrawCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) { | 
|  | static SkTHashMap<SkString, FROM_JSON> factories; | 
|  | static bool initialized = false; | 
|  | if (!initialized) { | 
|  | initialized = true; | 
|  | INSTALL_FACTORY(Restore); | 
|  | INSTALL_FACTORY(ClipPath); | 
|  | INSTALL_FACTORY(ClipRegion); | 
|  | INSTALL_FACTORY(ClipRect); | 
|  | INSTALL_FACTORY(ClipRRect); | 
|  | INSTALL_FACTORY(Concat); | 
|  | INSTALL_FACTORY(DrawBitmap); | 
|  | INSTALL_FACTORY(DrawBitmapRect); | 
|  | INSTALL_FACTORY(DrawBitmapNine); | 
|  | INSTALL_FACTORY(DrawImage); | 
|  | INSTALL_FACTORY(DrawImageRect); | 
|  | INSTALL_FACTORY(DrawOval); | 
|  | INSTALL_FACTORY(DrawPaint); | 
|  | INSTALL_FACTORY(DrawPath); | 
|  | INSTALL_FACTORY(DrawPoints); | 
|  | INSTALL_FACTORY(DrawText); | 
|  | INSTALL_FACTORY(DrawPosText); | 
|  | INSTALL_FACTORY(DrawPosTextH); | 
|  | INSTALL_FACTORY(DrawTextOnPath); | 
|  | INSTALL_FACTORY(DrawTextBlob); | 
|  |  | 
|  | INSTALL_FACTORY(DrawRect); | 
|  | INSTALL_FACTORY(DrawRRect); | 
|  | INSTALL_FACTORY(DrawDRRect); | 
|  | INSTALL_FACTORY(DrawPatch); | 
|  | INSTALL_FACTORY(Save); | 
|  | INSTALL_FACTORY(SaveLayer); | 
|  | INSTALL_FACTORY(SetMatrix); | 
|  | } | 
|  | SkString name = SkString(command[SKDEBUGCANVAS_ATTRIBUTE_COMMAND].asCString()); | 
|  | FROM_JSON* factory = factories.find(name); | 
|  | if (factory == nullptr) { | 
|  | SkDebugf("no JSON factory for '%s'\n", name.c_str()); | 
|  | return nullptr; | 
|  | } | 
|  | return (*factory)(command, urlDataManager); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) { | 
|  | const SkISize& size = canvas->getDeviceSize(); | 
|  |  | 
|  | static const SkScalar kInsetFrac = 0.9f; // Leave a border around object | 
|  |  | 
|  | canvas->translate(size.fWidth/2.0f, size.fHeight/2.0f); | 
|  | if (bounds.width() > bounds.height()) { | 
|  | canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.width()), | 
|  | SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.width())); | 
|  | } else { | 
|  | canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.height()), | 
|  | SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.height())); | 
|  | } | 
|  | canvas->translate(-bounds.centerX(), -bounds.centerY()); | 
|  | } | 
|  |  | 
|  |  | 
|  | void render_path(SkCanvas* canvas, const SkPath& path) { | 
|  | canvas->clear(0xFFFFFFFF); | 
|  |  | 
|  | const SkRect& bounds = path.getBounds(); | 
|  | if (bounds.isEmpty()) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | SkAutoCanvasRestore acr(canvas, true); | 
|  | xlate_and_scale_to_bounds(canvas, bounds); | 
|  |  | 
|  | SkPaint p; | 
|  | p.setColor(SK_ColorBLACK); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  |  | 
|  | canvas->drawPath(path, p); | 
|  | } | 
|  |  | 
|  | void render_bitmap(SkCanvas* canvas, const SkBitmap& input, const SkRect* srcRect = nullptr) { | 
|  | const SkISize& size = canvas->getDeviceSize(); | 
|  |  | 
|  | SkScalar xScale = SkIntToScalar(size.fWidth-2) / input.width(); | 
|  | SkScalar yScale = SkIntToScalar(size.fHeight-2) / input.height(); | 
|  |  | 
|  | if (input.width() > input.height()) { | 
|  | yScale *= input.height() / (float) input.width(); | 
|  | } else { | 
|  | xScale *= input.width() / (float) input.height(); | 
|  | } | 
|  |  | 
|  | SkRect dst = SkRect::MakeXYWH(SK_Scalar1, SK_Scalar1, | 
|  | xScale * input.width(), | 
|  | yScale * input.height()); | 
|  |  | 
|  | static const int kNumBlocks = 8; | 
|  |  | 
|  | canvas->clear(0xFFFFFFFF); | 
|  | SkISize block = { | 
|  | canvas->imageInfo().width()/kNumBlocks, | 
|  | canvas->imageInfo().height()/kNumBlocks | 
|  | }; | 
|  | for (int y = 0; y < kNumBlocks; ++y) { | 
|  | for (int x = 0; x < kNumBlocks; ++x) { | 
|  | SkPaint paint; | 
|  | paint.setColor((x+y)%2 ? SK_ColorLTGRAY : SK_ColorDKGRAY); | 
|  | SkRect r = SkRect::MakeXYWH(SkIntToScalar(x*block.width()), | 
|  | SkIntToScalar(y*block.height()), | 
|  | SkIntToScalar(block.width()), | 
|  | SkIntToScalar(block.height())); | 
|  | canvas->drawRect(r, paint); | 
|  | } | 
|  | } | 
|  |  | 
|  | canvas->drawBitmapRect(input, dst, nullptr); | 
|  |  | 
|  | if (srcRect) { | 
|  | SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1, | 
|  | srcRect->fTop * yScale + SK_Scalar1, | 
|  | srcRect->fRight * xScale + SK_Scalar1, | 
|  | srcRect->fBottom * yScale + SK_Scalar1); | 
|  | SkPaint p; | 
|  | p.setColor(SK_ColorRED); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  |  | 
|  | canvas->drawRect(r, p); | 
|  | } | 
|  | } | 
|  |  | 
|  | void render_rrect(SkCanvas* canvas, const SkRRect& rrect) { | 
|  | canvas->clear(0xFFFFFFFF); | 
|  | canvas->save(); | 
|  |  | 
|  | const SkRect& bounds = rrect.getBounds(); | 
|  |  | 
|  | xlate_and_scale_to_bounds(canvas, bounds); | 
|  |  | 
|  | SkPaint p; | 
|  | p.setColor(SK_ColorBLACK); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  |  | 
|  | canvas->drawRRect(rrect, p); | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) { | 
|  | canvas->clear(0xFFFFFFFF); | 
|  | canvas->save(); | 
|  |  | 
|  | const SkRect& bounds = outer.getBounds(); | 
|  |  | 
|  | xlate_and_scale_to_bounds(canvas, bounds); | 
|  |  | 
|  | SkPaint p; | 
|  | p.setColor(SK_ColorBLACK); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  |  | 
|  | canvas->drawDRRect(outer, inner, p); | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | }; | 
|  |  | 
|  | static Json::Value make_json_color(const SkColor color) { | 
|  | Json::Value result(Json::arrayValue); | 
|  | result.append(Json::Value(SkColorGetA(color))); | 
|  | result.append(Json::Value(SkColorGetR(color))); | 
|  | result.append(Json::Value(SkColorGetG(color))); | 
|  | result.append(Json::Value(SkColorGetB(color))); | 
|  | return result; | 
|  | } | 
|  |  | 
|  |  | 
|  | static Json::Value make_json_point(const SkPoint& point) { | 
|  | Json::Value result(Json::arrayValue); | 
|  | result.append(Json::Value(point.x())); | 
|  | result.append(Json::Value(point.y())); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static Json::Value make_json_point(SkScalar x, SkScalar y) { | 
|  | Json::Value result(Json::arrayValue); | 
|  | result.append(Json::Value(x)); | 
|  | result.append(Json::Value(y)); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static Json::Value make_json_rect(const SkRect& rect) { | 
|  | Json::Value result(Json::arrayValue); | 
|  | result.append(Json::Value(rect.left())); | 
|  | result.append(Json::Value(rect.top())); | 
|  | result.append(Json::Value(rect.right())); | 
|  | result.append(Json::Value(rect.bottom())); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawCommand::MakeJsonIRect(const SkIRect& rect) { | 
|  | Json::Value result(Json::arrayValue); | 
|  | result.append(Json::Value(rect.left())); | 
|  | result.append(Json::Value(rect.top())); | 
|  | result.append(Json::Value(rect.right())); | 
|  | result.append(Json::Value(rect.bottom())); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static Json::Value make_json_rrect(const SkRRect& rrect) { | 
|  | Json::Value result(Json::arrayValue); | 
|  | result.append(make_json_rect(rrect.rect())); | 
|  | result.append(make_json_point(rrect.radii(SkRRect::kUpperLeft_Corner))); | 
|  | result.append(make_json_point(rrect.radii(SkRRect::kUpperRight_Corner))); | 
|  | result.append(make_json_point(rrect.radii(SkRRect::kLowerRight_Corner))); | 
|  | result.append(make_json_point(rrect.radii(SkRRect::kLowerLeft_Corner))); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawCommand::MakeJsonMatrix(const SkMatrix& matrix) { | 
|  | Json::Value result(Json::arrayValue); | 
|  | Json::Value row1(Json::arrayValue); | 
|  | row1.append(Json::Value(matrix[0])); | 
|  | row1.append(Json::Value(matrix[1])); | 
|  | row1.append(Json::Value(matrix[2])); | 
|  | result.append(row1); | 
|  | Json::Value row2(Json::arrayValue); | 
|  | row2.append(Json::Value(matrix[3])); | 
|  | row2.append(Json::Value(matrix[4])); | 
|  | row2.append(Json::Value(matrix[5])); | 
|  | result.append(row2); | 
|  | Json::Value row3(Json::arrayValue); | 
|  | row3.append(Json::Value(matrix[6])); | 
|  | row3.append(Json::Value(matrix[7])); | 
|  | row3.append(Json::Value(matrix[8])); | 
|  | result.append(row3); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static Json::Value make_json_path(const SkPath& path) { | 
|  | Json::Value result(Json::objectValue); | 
|  | switch (path.getFillType()) { | 
|  | case SkPath::kWinding_FillType: | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_WINDING; | 
|  | break; | 
|  | case SkPath::kEvenOdd_FillType: | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_EVENODD; | 
|  | break; | 
|  | case SkPath::kInverseWinding_FillType: | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING; | 
|  | break; | 
|  | case SkPath::kInverseEvenOdd_FillType: | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE] = SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD; | 
|  | break; | 
|  | } | 
|  | Json::Value verbs(Json::arrayValue); | 
|  | SkPath::Iter iter(path, false); | 
|  | SkPoint pts[4]; | 
|  | SkPath::Verb verb; | 
|  | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 
|  | switch (verb) { | 
|  | case SkPath::kLine_Verb: { | 
|  | Json::Value line(Json::objectValue); | 
|  | line[SKDEBUGCANVAS_VERB_LINE] = make_json_point(pts[1]); | 
|  | verbs.append(line); | 
|  | break; | 
|  | } | 
|  | case SkPath::kQuad_Verb: { | 
|  | Json::Value quad(Json::objectValue); | 
|  | Json::Value coords(Json::arrayValue); | 
|  | coords.append(make_json_point(pts[1])); | 
|  | coords.append(make_json_point(pts[2])); | 
|  | quad[SKDEBUGCANVAS_VERB_QUAD] = coords; | 
|  | verbs.append(quad); | 
|  | break; | 
|  | } | 
|  | case SkPath::kCubic_Verb: { | 
|  | Json::Value cubic(Json::objectValue); | 
|  | Json::Value coords(Json::arrayValue); | 
|  | coords.append(make_json_point(pts[1])); | 
|  | coords.append(make_json_point(pts[2])); | 
|  | coords.append(make_json_point(pts[3])); | 
|  | cubic[SKDEBUGCANVAS_VERB_CUBIC] = coords; | 
|  | verbs.append(cubic); | 
|  | break; | 
|  | } | 
|  | case SkPath::kConic_Verb: { | 
|  | Json::Value conic(Json::objectValue); | 
|  | Json::Value coords(Json::arrayValue); | 
|  | coords.append(make_json_point(pts[1])); | 
|  | coords.append(make_json_point(pts[2])); | 
|  | coords.append(Json::Value(iter.conicWeight())); | 
|  | conic[SKDEBUGCANVAS_VERB_CONIC] = coords; | 
|  | verbs.append(conic); | 
|  | break; | 
|  | } | 
|  | case SkPath::kMove_Verb: { | 
|  | Json::Value move(Json::objectValue); | 
|  | move[SKDEBUGCANVAS_VERB_MOVE] = make_json_point(pts[0]); | 
|  | verbs.append(move); | 
|  | break; | 
|  | } | 
|  | case SkPath::kClose_Verb: | 
|  | verbs.append(Json::Value(SKDEBUGCANVAS_VERB_CLOSE)); | 
|  | break; | 
|  | case SkPath::kDone_Verb: | 
|  | break; | 
|  | } | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_VERBS] = verbs; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static Json::Value make_json_region(const SkRegion& region) { | 
|  | return Json::Value("<unimplemented>"); | 
|  | } | 
|  |  | 
|  | static Json::Value make_json_regionop(SkRegion::Op op) { | 
|  | switch (op) { | 
|  | case SkRegion::kDifference_Op: | 
|  | return Json::Value(SKDEBUGCANVAS_REGIONOP_DIFFERENCE); | 
|  | case SkRegion::kIntersect_Op: | 
|  | return Json::Value(SKDEBUGCANVAS_REGIONOP_INTERSECT); | 
|  | case SkRegion::kUnion_Op: | 
|  | return Json::Value(SKDEBUGCANVAS_REGIONOP_UNION); | 
|  | case SkRegion::kXOR_Op: | 
|  | return Json::Value(SKDEBUGCANVAS_REGIONOP_XOR); | 
|  | case SkRegion::kReverseDifference_Op: | 
|  | return Json::Value(SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE); | 
|  | case SkRegion::kReplace_Op: | 
|  | return Json::Value(SKDEBUGCANVAS_REGIONOP_REPLACE); | 
|  | default: | 
|  | SkASSERT(false); | 
|  | return Json::Value("<invalid region op>"); | 
|  | }; | 
|  | } | 
|  |  | 
|  | static Json::Value make_json_pointmode(SkCanvas::PointMode mode) { | 
|  | switch (mode) { | 
|  | case SkCanvas::kPoints_PointMode: | 
|  | return Json::Value(SKDEBUGCANVAS_POINTMODE_POINTS); | 
|  | case SkCanvas::kLines_PointMode: | 
|  | return Json::Value(SKDEBUGCANVAS_POINTMODE_LINES); | 
|  | case SkCanvas::kPolygon_PointMode: | 
|  | return Json::Value(SKDEBUGCANVAS_POINTMODE_POLYGON); | 
|  | default: | 
|  | SkASSERT(false); | 
|  | return Json::Value("<invalid point mode>"); | 
|  | }; | 
|  | } | 
|  |  | 
|  | static void store_scalar(Json::Value* target, const char* key, SkScalar value, | 
|  | SkScalar defaultValue) { | 
|  | if (value != defaultValue) { | 
|  | (*target)[key] = Json::Value(value); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void store_bool(Json::Value* target, const char* key, bool value, bool defaultValue) { | 
|  | if (value != defaultValue) { | 
|  | (*target)[key] = Json::Value(value); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void encode_data(const void* bytes, size_t count, const char* contentType, | 
|  | UrlDataManager& urlDataManager, Json::Value* target) { | 
|  | SkAutoTUnref<SkData> data(SkData::NewWithCopy(bytes, count)); | 
|  | SkString url = urlDataManager.addData(data, contentType); | 
|  | *target = Json::Value(url.c_str()); | 
|  | } | 
|  |  | 
|  | static void flatten(const SkFlattenable* flattenable, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkWriteBuffer buffer; | 
|  | flattenable->flatten(buffer); | 
|  | void* data = sk_malloc_throw(buffer.bytesWritten()); | 
|  | buffer.writeToMemory(data); | 
|  | Json::Value jsonData; | 
|  | encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager, &jsonData); | 
|  | Json::Value jsonFlattenable; | 
|  | jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_NAME] = Json::Value(flattenable->getTypeName()); | 
|  | jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData; | 
|  | (*target) = jsonFlattenable; | 
|  | sk_free(data); | 
|  | } | 
|  |  | 
|  | static void write_png_callback(png_structp png_ptr, png_bytep data, png_size_t length) { | 
|  | SkWStream* out = (SkWStream*) png_get_io_ptr(png_ptr); | 
|  | out->write(data, length); | 
|  | } | 
|  |  | 
|  | void SkDrawCommand::WritePNG(const png_bytep rgba, png_uint_32 width, png_uint_32 height, | 
|  | SkWStream& out) { | 
|  | png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | 
|  | SkASSERT(png != nullptr); | 
|  | png_infop info_ptr = png_create_info_struct(png); | 
|  | SkASSERT(info_ptr != nullptr); | 
|  | if (setjmp(png_jmpbuf(png))) { | 
|  | SkFAIL("png encode error"); | 
|  | } | 
|  | png_set_IHDR(png, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, | 
|  | PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); | 
|  | png_set_compression_level(png, 1); | 
|  | png_bytepp rows = (png_bytepp) sk_malloc_throw(height * sizeof(png_byte*)); | 
|  | png_bytep pixels = (png_bytep) sk_malloc_throw(width * height * 3); | 
|  | for (png_size_t y = 0; y < height; ++y) { | 
|  | const png_bytep src = rgba + y * width * 4; | 
|  | rows[y] = pixels + y * width * 3; | 
|  | // convert from RGBA to RGB | 
|  | for (png_size_t x = 0; x < width; ++x) { | 
|  | rows[y][x * 3] = src[x * 4]; | 
|  | rows[y][x * 3 + 1] = src[x * 4 + 1]; | 
|  | rows[y][x * 3 + 2] = src[x * 4 + 2]; | 
|  | } | 
|  | } | 
|  | png_set_filter(png, 0, PNG_NO_FILTERS); | 
|  | png_set_rows(png, info_ptr, &rows[0]); | 
|  | png_set_write_fn(png, &out, write_png_callback, NULL); | 
|  | png_write_png(png, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); | 
|  | png_destroy_write_struct(&png, NULL); | 
|  | sk_free(rows); | 
|  | sk_free(pixels); | 
|  | } | 
|  |  | 
|  | static bool SK_WARN_UNUSED_RESULT flatten(const SkImage& image, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | size_t rowBytes = 4 * image.width(); | 
|  | SkAutoFree buffer(sk_malloc_throw(rowBytes * image.height())); | 
|  | SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(), | 
|  | kN32_SkColorType, kPremul_SkAlphaType); | 
|  | if (!image.readPixels(dstInfo, buffer.get(), rowBytes, 0, 0)) { | 
|  | SkDebugf("readPixels failed\n"); | 
|  | return false; | 
|  | } | 
|  | SkDynamicMemoryWStream out; | 
|  | SkDrawCommand::WritePNG((png_bytep) buffer.get(), image.width(), image.height(), out); | 
|  | SkData* encoded = out.copyToData(); | 
|  | Json::Value jsonData; | 
|  | encode_data(encoded->data(), encoded->size(), "image/png", urlDataManager, &jsonData); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData; | 
|  | encoded->unref(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static const char* color_type_name(SkColorType colorType) { | 
|  | switch (colorType) { | 
|  | case kARGB_4444_SkColorType: | 
|  | return SKDEBUGCANVAS_COLORTYPE_ARGB4444; | 
|  | case kRGBA_8888_SkColorType: | 
|  | return SKDEBUGCANVAS_COLORTYPE_RGBA8888; | 
|  | case kBGRA_8888_SkColorType: | 
|  | return SKDEBUGCANVAS_COLORTYPE_BGRA8888; | 
|  | case kRGB_565_SkColorType: | 
|  | return SKDEBUGCANVAS_COLORTYPE_565; | 
|  | case kGray_8_SkColorType: | 
|  | return SKDEBUGCANVAS_COLORTYPE_GRAY8; | 
|  | case kIndex_8_SkColorType: | 
|  | return SKDEBUGCANVAS_COLORTYPE_INDEX8; | 
|  | case kAlpha_8_SkColorType: | 
|  | return SKDEBUGCANVAS_COLORTYPE_ALPHA8; | 
|  | default: | 
|  | SkASSERT(false); | 
|  | return SKDEBUGCANVAS_COLORTYPE_RGBA8888; | 
|  | } | 
|  | } | 
|  |  | 
|  | static const char* alpha_type_name(SkAlphaType alphaType) { | 
|  | switch (alphaType) { | 
|  | case kOpaque_SkAlphaType: | 
|  | return SKDEBUGCANVAS_ALPHATYPE_OPAQUE; | 
|  | case kPremul_SkAlphaType: | 
|  | return SKDEBUGCANVAS_ALPHATYPE_PREMUL; | 
|  | case kUnpremul_SkAlphaType: | 
|  | return SKDEBUGCANVAS_ALPHATYPE_UNPREMUL; | 
|  | default: | 
|  | SkASSERT(false); | 
|  | return SKDEBUGCANVAS_ALPHATYPE_OPAQUE; | 
|  | } | 
|  | } | 
|  |  | 
|  | static Json::ArrayIndex decode_data(Json::Value data, UrlDataManager& urlDataManager, | 
|  | const void** target) { | 
|  | UrlDataManager::UrlData* urlData = urlDataManager.getDataFromUrl(SkString(data.asCString())); | 
|  | if (urlData == nullptr) { | 
|  | SkASSERT(false); | 
|  | *target = nullptr; | 
|  | return 0; | 
|  | } | 
|  | *target = urlData->fData->data(); | 
|  | // cast should be safe for any reasonably-sized object... | 
|  | return (Json::ArrayIndex) urlData->fData->size(); | 
|  | } | 
|  |  | 
|  | static SkFlattenable* load_flattenable(Json::Value jsonFlattenable, | 
|  | UrlDataManager& urlDataManager) { | 
|  | if (!jsonFlattenable.isMember(SKDEBUGCANVAS_ATTRIBUTE_NAME)) { | 
|  | return nullptr; | 
|  | } | 
|  | const char* name = jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_NAME].asCString(); | 
|  | SkFlattenable::Factory factory = SkFlattenable::NameToFactory(name); | 
|  | if (factory == nullptr) { | 
|  | SkDebugf("no factory for loading '%s'\n", name); | 
|  | return nullptr; | 
|  | } | 
|  | const void* data; | 
|  | int size = decode_data(jsonFlattenable[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data); | 
|  | SkValidatingReadBuffer buffer(data, size); | 
|  | SkFlattenable* result = factory(buffer); | 
|  | if (!buffer.isValid()) { | 
|  | SkDebugf("invalid buffer loading flattenable\n"); | 
|  | return nullptr; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static SkColorType colortype_from_name(const char* name) { | 
|  | if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_ARGB4444)) { | 
|  | return kARGB_4444_SkColorType; | 
|  | } | 
|  | else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_RGBA8888)) { | 
|  | return kRGBA_8888_SkColorType; | 
|  | } | 
|  | else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_BGRA8888)) { | 
|  | return kBGRA_8888_SkColorType; | 
|  | } | 
|  | else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_565)) { | 
|  | return kRGB_565_SkColorType; | 
|  | } | 
|  | else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_GRAY8)) { | 
|  | return kGray_8_SkColorType; | 
|  | } | 
|  | else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_INDEX8)) { | 
|  | return kIndex_8_SkColorType; | 
|  | } | 
|  | else if (!strcmp(name, SKDEBUGCANVAS_COLORTYPE_ALPHA8)) { | 
|  | return kAlpha_8_SkColorType; | 
|  | } | 
|  | SkASSERT(false); | 
|  | return kN32_SkColorType; | 
|  | } | 
|  |  | 
|  | static SkBitmap* convert_colortype(SkBitmap* bitmap, SkColorType colorType) { | 
|  | if (bitmap->colorType() == colorType  ) { | 
|  | return bitmap; | 
|  | } | 
|  | SkBitmap* dst = new SkBitmap(); | 
|  | if (bitmap->copyTo(dst, colorType)) { | 
|  | delete bitmap; | 
|  | return dst; | 
|  | } | 
|  | SkASSERT(false); | 
|  | delete dst; | 
|  | return bitmap; | 
|  | } | 
|  |  | 
|  | // caller is responsible for freeing return value | 
|  | static SkBitmap* load_bitmap(const Json::Value& jsonBitmap, UrlDataManager& urlDataManager) { | 
|  | if (!jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_DATA)) { | 
|  | SkDebugf("invalid bitmap\n"); | 
|  | return nullptr; | 
|  | } | 
|  | const void* data; | 
|  | int size = decode_data(jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_DATA], urlDataManager, &data); | 
|  | sk_sp<SkData> encoded(SkData::NewWithoutCopy(data, size)); | 
|  | sk_sp<SkImage> image(SkImage::MakeFromEncoded(std::move(encoded), nullptr)); | 
|  |  | 
|  | SkAutoTDelete<SkBitmap> bitmap(new SkBitmap()); | 
|  | if (nullptr != image) { | 
|  | if (!image->asLegacyBitmap(bitmap, SkImage::kRW_LegacyBitmapMode)) { | 
|  | SkDebugf("image decode failed\n"); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | if (jsonBitmap.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLOR)) { | 
|  | const char* ctName = jsonBitmap[SKDEBUGCANVAS_ATTRIBUTE_COLOR].asCString(); | 
|  | SkColorType ct = colortype_from_name(ctName); | 
|  | if (ct != kIndex_8_SkColorType) { | 
|  | bitmap.reset(convert_colortype(bitmap.release(), ct)); | 
|  | } | 
|  | } | 
|  | return bitmap.release(); | 
|  | } | 
|  | SkDebugf("image decode failed\n"); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | static sk_sp<SkImage> load_image(const Json::Value& jsonImage, UrlDataManager& urlDataManager) { | 
|  | SkBitmap* bitmap = load_bitmap(jsonImage, urlDataManager); | 
|  | if (bitmap == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | auto result = SkImage::MakeFromBitmap(*bitmap); | 
|  | delete bitmap; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static bool SK_WARN_UNUSED_RESULT flatten(const SkBitmap& bitmap, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | bitmap.lockPixels(); | 
|  | sk_sp<SkImage> image(SkImage::MakeFromBitmap(bitmap)); | 
|  | bitmap.unlockPixels(); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = Json::Value(color_type_name(bitmap.colorType())); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_ALPHA] = Json::Value(alpha_type_name(bitmap.alphaType())); | 
|  | bool success = flatten(*image, target, urlDataManager); | 
|  | return success; | 
|  | } | 
|  |  | 
|  | static void apply_paint_color(const SkPaint& paint, Json::Value* target) { | 
|  | SkColor color = paint.getColor(); | 
|  | if (color != SK_ColorBLACK) { | 
|  | Json::Value colorValue(Json::arrayValue); | 
|  | colorValue.append(Json::Value(SkColorGetA(color))); | 
|  | colorValue.append(Json::Value(SkColorGetR(color))); | 
|  | colorValue.append(Json::Value(SkColorGetG(color))); | 
|  | colorValue.append(Json::Value(SkColorGetB(color))); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = colorValue;; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_style(const SkPaint& paint, Json::Value* target) { | 
|  | SkPaint::Style style = paint.getStyle(); | 
|  | if (style != SkPaint::kFill_Style) { | 
|  | switch (style) { | 
|  | case SkPaint::kStroke_Style: { | 
|  | Json::Value stroke(SKDEBUGCANVAS_STYLE_STROKE); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = stroke; | 
|  | break; | 
|  | } | 
|  | case SkPaint::kStrokeAndFill_Style: { | 
|  | Json::Value strokeAndFill(SKDEBUGCANVAS_STYLE_STROKEANDFILL); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = strokeAndFill; | 
|  | break; | 
|  | } | 
|  | default: SkASSERT(false); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_cap(const SkPaint& paint, Json::Value* target) { | 
|  | SkPaint::Cap cap = paint.getStrokeCap(); | 
|  | if (cap != SkPaint::kDefault_Cap) { | 
|  | switch (cap) { | 
|  | case SkPaint::kButt_Cap: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_BUTT); | 
|  | break; | 
|  | case SkPaint::kRound_Cap: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_ROUND); | 
|  | break; | 
|  | case SkPaint::kSquare_Cap: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_CAP] = Json::Value(SKDEBUGCANVAS_CAP_SQUARE); | 
|  | break; | 
|  | default: SkASSERT(false); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_join(const SkPaint& paint, Json::Value* target) { | 
|  | SkPaint::Join join = paint.getStrokeJoin(); | 
|  | if (join != SkPaint::kDefault_Join) { | 
|  | switch (join) { | 
|  | case SkPaint::kMiter_Join: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value( | 
|  | SKDEBUGCANVAS_MITER_JOIN); | 
|  | break; | 
|  | case SkPaint::kRound_Join: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value( | 
|  | SKDEBUGCANVAS_ROUND_JOIN); | 
|  | break; | 
|  | case SkPaint::kBevel_Join: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN] = Json::Value( | 
|  | SKDEBUGCANVAS_BEVEL_JOIN); | 
|  | break; | 
|  | default: SkASSERT(false); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_filterquality(const SkPaint& paint, Json::Value* target) { | 
|  | SkFilterQuality quality = paint.getFilterQuality(); | 
|  | switch (quality) { | 
|  | case kNone_SkFilterQuality: | 
|  | break; | 
|  | case kLow_SkFilterQuality: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value( | 
|  | SKDEBUGCANVAS_FILTERQUALITY_LOW); | 
|  | break; | 
|  | case kMedium_SkFilterQuality: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value( | 
|  | SKDEBUGCANVAS_FILTERQUALITY_MEDIUM); | 
|  | break; | 
|  | case kHigh_SkFilterQuality: | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY] = Json::Value( | 
|  | SKDEBUGCANVAS_FILTERQUALITY_HIGH); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkMaskFilter* maskFilter = paint.getMaskFilter(); | 
|  | if (maskFilter != nullptr) { | 
|  | SkMaskFilter::BlurRec blurRec; | 
|  | if (maskFilter->asABlur(&blurRec)) { | 
|  | Json::Value blur(Json::objectValue); | 
|  | blur[SKDEBUGCANVAS_ATTRIBUTE_SIGMA] = Json::Value(blurRec.fSigma); | 
|  | switch (blurRec.fStyle) { | 
|  | case SkBlurStyle::kNormal_SkBlurStyle: | 
|  | blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value( | 
|  | SKDEBUGCANVAS_BLURSTYLE_NORMAL); | 
|  | break; | 
|  | case SkBlurStyle::kSolid_SkBlurStyle: | 
|  | blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value( | 
|  | SKDEBUGCANVAS_BLURSTYLE_SOLID); | 
|  | break; | 
|  | case SkBlurStyle::kOuter_SkBlurStyle: | 
|  | blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value( | 
|  | SKDEBUGCANVAS_BLURSTYLE_OUTER); | 
|  | break; | 
|  | case SkBlurStyle::kInner_SkBlurStyle: | 
|  | blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE] = Json::Value( | 
|  | SKDEBUGCANVAS_BLURSTYLE_INNER); | 
|  | break; | 
|  | default: | 
|  | SkASSERT(false); | 
|  | } | 
|  | switch (blurRec.fQuality) { | 
|  | case SkBlurQuality::kLow_SkBlurQuality: | 
|  | blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY] = Json::Value( | 
|  | SKDEBUGCANVAS_BLURQUALITY_LOW); | 
|  | break; | 
|  | case SkBlurQuality::kHigh_SkBlurQuality: | 
|  | blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY] = Json::Value( | 
|  | SKDEBUGCANVAS_BLURQUALITY_HIGH); | 
|  | break; | 
|  | default: | 
|  | SkASSERT(false); | 
|  | } | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_BLUR] = blur; | 
|  | } else { | 
|  | Json::Value jsonMaskFilter; | 
|  | flatten(maskFilter, &jsonMaskFilter, urlDataManager); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER] = jsonMaskFilter; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkPathEffect* pathEffect = paint.getPathEffect(); | 
|  | if (pathEffect != nullptr) { | 
|  | SkPathEffect::DashInfo dashInfo; | 
|  | SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo); | 
|  | if (dashType == SkPathEffect::kDash_DashType) { | 
|  | dashInfo.fIntervals = (SkScalar*) sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar)); | 
|  | pathEffect->asADash(&dashInfo); | 
|  | Json::Value dashing(Json::objectValue); | 
|  | Json::Value intervals(Json::arrayValue); | 
|  | for (int32_t i = 0; i < dashInfo.fCount; i++) { | 
|  | intervals.append(Json::Value(dashInfo.fIntervals[i])); | 
|  | } | 
|  | sk_free(dashInfo.fIntervals); | 
|  | dashing[SKDEBUGCANVAS_ATTRIBUTE_INTERVALS] = intervals; | 
|  | dashing[SKDEBUGCANVAS_ATTRIBUTE_PHASE] = dashInfo.fPhase; | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_DASHING] = dashing; | 
|  | } else { | 
|  | Json::Value jsonPathEffect; | 
|  | flatten(pathEffect, &jsonPathEffect, urlDataManager); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT] = jsonPathEffect; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_textalign(const SkPaint& paint, Json::Value* target) { | 
|  | SkPaint::Align textAlign = paint.getTextAlign(); | 
|  | if (textAlign != SkPaint::kLeft_Align) { | 
|  | switch (textAlign) { | 
|  | case SkPaint::kCenter_Align: { | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN] = SKDEBUGCANVAS_ALIGN_CENTER; | 
|  | break; | 
|  | } | 
|  | case SkPaint::kRight_Align: { | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN] = SKDEBUGCANVAS_ALIGN_RIGHT; | 
|  | break; | 
|  | } | 
|  | default: SkASSERT(false); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_typeface(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkTypeface* typeface = paint.getTypeface(); | 
|  | if (typeface != nullptr) { | 
|  | Json::Value jsonTypeface; | 
|  | SkDynamicMemoryWStream buffer; | 
|  | typeface->serialize(&buffer); | 
|  | void* data = sk_malloc_throw(buffer.bytesWritten()); | 
|  | buffer.copyTo(data); | 
|  | Json::Value jsonData; | 
|  | encode_data(data, buffer.bytesWritten(), "application/octet-stream", urlDataManager, | 
|  | &jsonData); | 
|  | jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_DATA] = jsonData; | 
|  | sk_free(data); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE] = jsonTypeface; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_shader(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkFlattenable* shader = paint.getShader(); | 
|  | if (shader != nullptr) { | 
|  | Json::Value jsonShader; | 
|  | flatten(shader, &jsonShader, urlDataManager); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_SHADER] = jsonShader; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_xfermode(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkFlattenable* xfermode = paint.getXfermode(); | 
|  | if (xfermode != nullptr) { | 
|  | Json::Value jsonXfermode; | 
|  | flatten(xfermode, &jsonXfermode, urlDataManager); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE] = jsonXfermode; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_imagefilter(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkFlattenable* imageFilter = paint.getImageFilter(); | 
|  | if (imageFilter != nullptr) { | 
|  | Json::Value jsonImageFilter; | 
|  | flatten(imageFilter, &jsonImageFilter, urlDataManager); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER] = jsonImageFilter; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_colorfilter(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkFlattenable* colorFilter = paint.getColorFilter(); | 
|  | if (colorFilter != nullptr) { | 
|  | Json::Value jsonColorFilter; | 
|  | flatten(colorFilter, &jsonColorFilter, urlDataManager); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER] = jsonColorFilter; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void apply_paint_looper(const SkPaint& paint, Json::Value* target, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkFlattenable* looper = paint.getLooper(); | 
|  | if (looper != nullptr) { | 
|  | Json::Value jsonLooper; | 
|  | flatten(looper, &jsonLooper, urlDataManager); | 
|  | (*target)[SKDEBUGCANVAS_ATTRIBUTE_LOOPER] = jsonLooper; | 
|  | } | 
|  | } | 
|  |  | 
|  | Json::Value make_json_paint(const SkPaint& paint, UrlDataManager& urlDataManager) { | 
|  | Json::Value result(Json::objectValue); | 
|  | store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f); | 
|  | store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER, paint.getStrokeMiter(), | 
|  | SkPaintDefaults_MiterLimit); | 
|  | store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false); | 
|  | store_bool(&result, SKDEBUGCANVAS_ATTRIBUTE_DITHER, paint.isDither(), false); | 
|  | store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(), | 
|  | SkPaintDefaults_TextSize); | 
|  | store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1); | 
|  | store_scalar(&result, SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f); | 
|  | apply_paint_color(paint, &result); | 
|  | apply_paint_style(paint, &result); | 
|  | apply_paint_cap(paint, &result); | 
|  | apply_paint_join(paint, &result); | 
|  | apply_paint_filterquality(paint, &result); | 
|  | apply_paint_textalign(paint, &result); | 
|  | apply_paint_patheffect(paint, &result, urlDataManager); | 
|  | apply_paint_maskfilter(paint, &result, urlDataManager); | 
|  | apply_paint_shader(paint, &result, urlDataManager); | 
|  | apply_paint_xfermode(paint, &result, urlDataManager); | 
|  | apply_paint_looper(paint, &result, urlDataManager); | 
|  | apply_paint_imagefilter(paint, &result, urlDataManager); | 
|  | apply_paint_colorfilter(paint, &result, urlDataManager); | 
|  | apply_paint_typeface(paint, &result, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | static SkPoint get_json_point(Json::Value point) { | 
|  | return SkPoint::Make(point[0].asFloat(), point[1].asFloat()); | 
|  | } | 
|  |  | 
|  | static SkColor get_json_color(Json::Value color) { | 
|  | return SkColorSetARGB(color[0].asInt(), color[1].asInt(), color[2].asInt(), color[3].asInt()); | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_color(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLOR)) { | 
|  | target->setColor(get_json_color(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_COLOR])); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_shader(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_SHADER)) { | 
|  | Json::Value jsonShader = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_SHADER]; | 
|  | SkShader* shader = (SkShader*) load_flattenable(jsonShader, urlDataManager); | 
|  | if (shader != nullptr) { | 
|  | target->setShader(sk_ref_sp(shader)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_patheffect(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT)) { | 
|  | Json::Value jsonPathEffect = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_PATHEFFECT]; | 
|  | sk_sp<SkPathEffect> pathEffect((SkPathEffect*)load_flattenable(jsonPathEffect, | 
|  | urlDataManager)); | 
|  | if (pathEffect != nullptr) { | 
|  | target->setPathEffect(pathEffect); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_maskfilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER)) { | 
|  | Json::Value jsonMaskFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_MASKFILTER]; | 
|  | SkMaskFilter* maskFilter = (SkMaskFilter*) load_flattenable(jsonMaskFilter, urlDataManager); | 
|  | if (maskFilter != nullptr) { | 
|  | target->setMaskFilter(maskFilter); | 
|  | maskFilter->unref(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_colorfilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER)) { | 
|  | Json::Value jsonColorFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_COLORFILTER]; | 
|  | sk_sp<SkColorFilter> colorFilter((SkColorFilter*)load_flattenable(jsonColorFilter, | 
|  | urlDataManager)); | 
|  | if (colorFilter != nullptr) { | 
|  | target->setColorFilter(colorFilter); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_xfermode(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_XFERMODE)) { | 
|  | Json::Value jsonXfermode = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE]; | 
|  | SkXfermode* xfermode = (SkXfermode*) load_flattenable(jsonXfermode, urlDataManager); | 
|  | if (xfermode != nullptr) { | 
|  | target->setXfermode(xfermode); | 
|  | xfermode->unref(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_looper(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_LOOPER)) { | 
|  | Json::Value jsonLooper = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_LOOPER]; | 
|  | sk_sp<SkDrawLooper> looper((SkDrawLooper*) load_flattenable(jsonLooper, urlDataManager)); | 
|  | if (looper != nullptr) { | 
|  | target->setLooper(std::move(looper)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_imagefilter(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER)) { | 
|  | Json::Value jsonImageFilter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_IMAGEFILTER]; | 
|  | SkImageFilter* imageFilter = (SkImageFilter*) load_flattenable(jsonImageFilter, | 
|  | urlDataManager); | 
|  | if (imageFilter != nullptr) { | 
|  | target->setImageFilter(imageFilter); | 
|  | imageFilter->unref(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_typeface(Json::Value& jsonPaint, UrlDataManager& urlDataManager, | 
|  | SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE)) { | 
|  | Json::Value jsonTypeface = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TYPEFACE]; | 
|  | Json::Value jsonData = jsonTypeface[SKDEBUGCANVAS_ATTRIBUTE_DATA]; | 
|  | const void* data; | 
|  | Json::ArrayIndex length = decode_data(jsonData, urlDataManager, &data); | 
|  | SkMemoryStream buffer(data, length); | 
|  | SkTypeface* typeface = SkTypeface::Deserialize(&buffer); | 
|  | target->setTypeface(typeface); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_style(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STYLE)) { | 
|  | const char* style = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STYLE].asCString(); | 
|  | if (!strcmp(style, SKDEBUGCANVAS_STYLE_FILL)) { | 
|  | target->setStyle(SkPaint::kFill_Style); | 
|  | } | 
|  | else if (!strcmp(style, SKDEBUGCANVAS_STYLE_STROKE)) { | 
|  | target->setStyle(SkPaint::kStroke_Style); | 
|  | } | 
|  | else if (!strcmp(style, SKDEBUGCANVAS_STYLE_STROKEANDFILL)) { | 
|  | target->setStyle(SkPaint::kStrokeAndFill_Style); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_strokewidth(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH)) { | 
|  | float strokeWidth = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEWIDTH].asFloat(); | 
|  | target->setStrokeWidth(strokeWidth); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_strokemiter(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER)) { | 
|  | float strokeMiter = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEMITER].asFloat(); | 
|  | target->setStrokeMiter(strokeMiter); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_strokejoin(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN)) { | 
|  | const char* join = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_STROKEJOIN].asCString(); | 
|  | if (!strcmp(join, SKDEBUGCANVAS_MITER_JOIN)) { | 
|  | target->setStrokeJoin(SkPaint::kMiter_Join); | 
|  | } | 
|  | else if (!strcmp(join, SKDEBUGCANVAS_ROUND_JOIN)) { | 
|  | target->setStrokeJoin(SkPaint::kRound_Join); | 
|  | } | 
|  | else if (!strcmp(join, SKDEBUGCANVAS_BEVEL_JOIN)) { | 
|  | target->setStrokeJoin(SkPaint::kBevel_Join); | 
|  | } | 
|  | else { | 
|  | SkASSERT(false); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_cap(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_CAP)) { | 
|  | const char* cap = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_CAP].asCString(); | 
|  | if (!strcmp(cap, SKDEBUGCANVAS_CAP_BUTT)) { | 
|  | target->setStrokeCap(SkPaint::kButt_Cap); | 
|  | } | 
|  | else if (!strcmp(cap, SKDEBUGCANVAS_CAP_ROUND)) { | 
|  | target->setStrokeCap(SkPaint::kRound_Cap); | 
|  | } | 
|  | else if (!strcmp(cap, SKDEBUGCANVAS_CAP_SQUARE)) { | 
|  | target->setStrokeCap(SkPaint::kSquare_Cap); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_filterquality(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY)) { | 
|  | const char* quality = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_FILTERQUALITY].asCString(); | 
|  | if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_NONE)) { | 
|  | target->setFilterQuality(kNone_SkFilterQuality); | 
|  | } | 
|  | else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_LOW)) { | 
|  | target->setFilterQuality(kLow_SkFilterQuality); | 
|  | } | 
|  | else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_MEDIUM)) { | 
|  | target->setFilterQuality(kMedium_SkFilterQuality); | 
|  | } | 
|  | else if (!strcmp(quality, SKDEBUGCANVAS_FILTERQUALITY_HIGH)) { | 
|  | target->setFilterQuality(kHigh_SkFilterQuality); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_antialias(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS)) { | 
|  | target->setAntiAlias(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool()); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_dither(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DITHER)) { | 
|  | target->setDither(jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DITHER].asBool()); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_blur(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_BLUR)) { | 
|  | Json::Value blur = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_BLUR]; | 
|  | SkScalar sigma = blur[SKDEBUGCANVAS_ATTRIBUTE_SIGMA].asFloat(); | 
|  | SkBlurStyle style; | 
|  | const char* jsonStyle = blur[SKDEBUGCANVAS_ATTRIBUTE_STYLE].asCString(); | 
|  | if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_NORMAL)) { | 
|  | style = SkBlurStyle::kNormal_SkBlurStyle; | 
|  | } | 
|  | else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_SOLID)) { | 
|  | style = SkBlurStyle::kSolid_SkBlurStyle; | 
|  | } | 
|  | else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_OUTER)) { | 
|  | style = SkBlurStyle::kOuter_SkBlurStyle; | 
|  | } | 
|  | else if (!strcmp(jsonStyle, SKDEBUGCANVAS_BLURSTYLE_INNER)) { | 
|  | style = SkBlurStyle::kInner_SkBlurStyle; | 
|  | } | 
|  | else { | 
|  | SkASSERT(false); | 
|  | style = SkBlurStyle::kNormal_SkBlurStyle; | 
|  | } | 
|  | SkBlurMaskFilter::BlurFlags flags; | 
|  | const char* jsonQuality = blur[SKDEBUGCANVAS_ATTRIBUTE_QUALITY].asCString(); | 
|  | if (!strcmp(jsonQuality, SKDEBUGCANVAS_BLURQUALITY_LOW)) { | 
|  | flags = SkBlurMaskFilter::BlurFlags::kNone_BlurFlag; | 
|  | } | 
|  | else if (!strcmp(jsonQuality, SKDEBUGCANVAS_BLURQUALITY_HIGH)) { | 
|  | flags = SkBlurMaskFilter::BlurFlags::kHighQuality_BlurFlag; | 
|  | } | 
|  | else { | 
|  | SkASSERT(false); | 
|  | flags = SkBlurMaskFilter::BlurFlags::kNone_BlurFlag; | 
|  | } | 
|  | target->setMaskFilter(SkBlurMaskFilter::Create(style, sigma, flags)); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_dashing(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_DASHING)) { | 
|  | Json::Value dash = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_DASHING]; | 
|  | Json::Value jsonIntervals = dash[SKDEBUGCANVAS_ATTRIBUTE_INTERVALS]; | 
|  | Json::ArrayIndex count = jsonIntervals.size(); | 
|  | SkScalar* intervals = (SkScalar*) sk_malloc_throw(count * sizeof(SkScalar)); | 
|  | for (Json::ArrayIndex i = 0; i < count; i++) { | 
|  | intervals[i] = jsonIntervals[i].asFloat(); | 
|  | } | 
|  | SkScalar phase = dash[SKDEBUGCANVAS_ATTRIBUTE_PHASE].asFloat(); | 
|  | target->setPathEffect(SkDashPathEffect::Make(intervals, count, phase)); | 
|  | sk_free(intervals); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_textalign(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN)) { | 
|  | SkPaint::Align textAlign; | 
|  | const char* jsonAlign = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTALIGN].asCString(); | 
|  | if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_LEFT)) { | 
|  | textAlign = SkPaint::kLeft_Align; | 
|  | } | 
|  | else if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_CENTER)) { | 
|  | textAlign = SkPaint::kCenter_Align; | 
|  | } | 
|  | else if (!strcmp(jsonAlign, SKDEBUGCANVAS_ALIGN_RIGHT)) { | 
|  | textAlign = SkPaint::kRight_Align; | 
|  | } | 
|  | else { | 
|  | SkASSERT(false); | 
|  | textAlign = SkPaint::kLeft_Align; | 
|  | } | 
|  | target->setTextAlign(textAlign); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_textsize(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE)) { | 
|  | float textSize = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSIZE].asFloat(); | 
|  | target->setTextSize(textSize); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_textscalex(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX)) { | 
|  | float textScaleX = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSCALEX].asFloat(); | 
|  | target->setTextScaleX(textScaleX); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint_textskewx(Json::Value& jsonPaint, SkPaint* target) { | 
|  | if (jsonPaint.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX)) { | 
|  | float textSkewX = jsonPaint[SKDEBUGCANVAS_ATTRIBUTE_TEXTSKEWX].asFloat(); | 
|  | target->setTextSkewX(textSkewX); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void extract_json_paint(Json::Value& paint, UrlDataManager& urlDataManager, | 
|  | SkPaint* result) { | 
|  | extract_json_paint_color(paint, result); | 
|  | extract_json_paint_shader(paint, urlDataManager, result); | 
|  | extract_json_paint_patheffect(paint, urlDataManager, result); | 
|  | extract_json_paint_maskfilter(paint, urlDataManager, result); | 
|  | extract_json_paint_colorfilter(paint, urlDataManager, result); | 
|  | extract_json_paint_xfermode(paint, urlDataManager, result); | 
|  | extract_json_paint_looper(paint, urlDataManager, result); | 
|  | extract_json_paint_imagefilter(paint, urlDataManager, result); | 
|  | extract_json_paint_typeface(paint, urlDataManager, result); | 
|  | extract_json_paint_style(paint, result); | 
|  | extract_json_paint_strokewidth(paint, result); | 
|  | extract_json_paint_strokemiter(paint, result); | 
|  | extract_json_paint_strokejoin(paint, result); | 
|  | extract_json_paint_cap(paint, result); | 
|  | extract_json_paint_filterquality(paint, result); | 
|  | extract_json_paint_antialias(paint, result); | 
|  | extract_json_paint_dither(paint, result); | 
|  | extract_json_paint_blur(paint, result); | 
|  | extract_json_paint_dashing(paint, result); | 
|  | extract_json_paint_textalign(paint, result); | 
|  | extract_json_paint_textsize(paint, result); | 
|  | extract_json_paint_textscalex(paint, result); | 
|  | extract_json_paint_textskewx(paint, result); | 
|  | } | 
|  |  | 
|  | static void extract_json_rect(Json::Value& rect, SkRect* result) { | 
|  | result->set(rect[0].asFloat(), rect[1].asFloat(), rect[2].asFloat(), rect[3].asFloat()); | 
|  | } | 
|  |  | 
|  | static void extract_json_irect(Json::Value& rect, SkIRect* result) { | 
|  | result->set(rect[0].asInt(), rect[1].asInt(), rect[2].asInt(), rect[3].asInt()); | 
|  | } | 
|  |  | 
|  | static void extract_json_rrect(Json::Value& rrect, SkRRect* result) { | 
|  | SkVector radii[4] = { | 
|  | { rrect[1][0].asFloat(), rrect[1][1].asFloat() }, | 
|  | { rrect[2][0].asFloat(), rrect[2][1].asFloat() }, | 
|  | { rrect[3][0].asFloat(), rrect[3][1].asFloat() }, | 
|  | { rrect[4][0].asFloat(), rrect[4][1].asFloat() } | 
|  | }; | 
|  | result->setRectRadii(SkRect::MakeLTRB(rrect[0][0].asFloat(), rrect[0][1].asFloat(), | 
|  | rrect[0][2].asFloat(), rrect[0][3].asFloat()), | 
|  | radii); | 
|  | } | 
|  |  | 
|  | static void extract_json_matrix(Json::Value& matrix, SkMatrix* result) { | 
|  | SkScalar values[] = { | 
|  | matrix[0][0].asFloat(), matrix[0][1].asFloat(), matrix[0][2].asFloat(), | 
|  | matrix[1][0].asFloat(), matrix[1][1].asFloat(), matrix[1][2].asFloat(), | 
|  | matrix[2][0].asFloat(), matrix[2][1].asFloat(), matrix[2][2].asFloat() | 
|  | }; | 
|  | result->set9(values); | 
|  | } | 
|  |  | 
|  | static void extract_json_path(Json::Value& path, SkPath* result) { | 
|  | const char* fillType = path[SKDEBUGCANVAS_ATTRIBUTE_FILLTYPE].asCString(); | 
|  | if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_WINDING)) { | 
|  | result->setFillType(SkPath::kWinding_FillType); | 
|  | } | 
|  | else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_EVENODD)) { | 
|  | result->setFillType(SkPath::kEvenOdd_FillType); | 
|  | } | 
|  | else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_INVERSEWINDING)) { | 
|  | result->setFillType(SkPath::kInverseWinding_FillType); | 
|  | } | 
|  | else if (!strcmp(fillType, SKDEBUGCANVAS_FILLTYPE_INVERSEEVENODD)) { | 
|  | result->setFillType(SkPath::kInverseEvenOdd_FillType); | 
|  | } | 
|  | Json::Value verbs = path[SKDEBUGCANVAS_ATTRIBUTE_VERBS]; | 
|  | for (Json::ArrayIndex i = 0; i < verbs.size(); i++) { | 
|  | Json::Value verb = verbs[i]; | 
|  | if (verb.isString()) { | 
|  | SkASSERT(!strcmp(verb.asCString(), SKDEBUGCANVAS_VERB_CLOSE)); | 
|  | result->close(); | 
|  | } | 
|  | else { | 
|  | if (verb.isMember(SKDEBUGCANVAS_VERB_MOVE)) { | 
|  | Json::Value move = verb[SKDEBUGCANVAS_VERB_MOVE]; | 
|  | result->moveTo(move[0].asFloat(), move[1].asFloat()); | 
|  | } | 
|  | else if (verb.isMember(SKDEBUGCANVAS_VERB_LINE)) { | 
|  | Json::Value line = verb[SKDEBUGCANVAS_VERB_LINE]; | 
|  | result->lineTo(line[0].asFloat(), line[1].asFloat()); | 
|  | } | 
|  | else if (verb.isMember(SKDEBUGCANVAS_VERB_QUAD)) { | 
|  | Json::Value quad = verb[SKDEBUGCANVAS_VERB_QUAD]; | 
|  | result->quadTo(quad[0][0].asFloat(), quad[0][1].asFloat(), | 
|  | quad[1][0].asFloat(), quad[1][1].asFloat()); | 
|  | } | 
|  | else if (verb.isMember(SKDEBUGCANVAS_VERB_CUBIC)) { | 
|  | Json::Value cubic = verb[SKDEBUGCANVAS_VERB_CUBIC]; | 
|  | result->cubicTo(cubic[0][0].asFloat(), cubic[0][1].asFloat(), | 
|  | cubic[1][0].asFloat(), cubic[1][1].asFloat(), | 
|  | cubic[2][0].asFloat(), cubic[2][1].asFloat()); | 
|  | } | 
|  | else if (verb.isMember(SKDEBUGCANVAS_VERB_CONIC)) { | 
|  | Json::Value conic = verb[SKDEBUGCANVAS_VERB_CONIC]; | 
|  | result->conicTo(conic[0][0].asFloat(), conic[0][1].asFloat(), | 
|  | conic[1][0].asFloat(), conic[1][1].asFloat(), | 
|  | conic[2].asFloat()); | 
|  | } | 
|  | else { | 
|  | SkASSERT(false); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | SkRegion::Op get_json_regionop(Json::Value& jsonOp) { | 
|  | const char* op = jsonOp.asCString(); | 
|  | if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_DIFFERENCE)) { | 
|  | return SkRegion::kDifference_Op; | 
|  | } | 
|  | else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_INTERSECT)) { | 
|  | return SkRegion::kIntersect_Op; | 
|  | } | 
|  | else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_UNION)) { | 
|  | return SkRegion::kUnion_Op; | 
|  | } | 
|  | else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_XOR)) { | 
|  | return SkRegion::kXOR_Op; | 
|  | } | 
|  | else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_REVERSE_DIFFERENCE)) { | 
|  | return SkRegion::kReverseDifference_Op; | 
|  | } | 
|  | else if (!strcmp(op, SKDEBUGCANVAS_REGIONOP_REPLACE)) { | 
|  | return SkRegion::kReplace_Op; | 
|  | } | 
|  | SkASSERT(false); | 
|  | return SkRegion::kIntersect_Op; | 
|  | } | 
|  |  | 
|  | SkClearCommand::SkClearCommand(SkColor color) : INHERITED(kDrawClear_OpType) { | 
|  | fColor = color; | 
|  | fInfo.push(SkObjectParser::CustomTextToString("No Parameters")); | 
|  | } | 
|  |  | 
|  | void SkClearCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->clear(fColor); | 
|  | } | 
|  |  | 
|  | Json::Value SkClearCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COLOR] = make_json_color(fColor); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkClearCommand* SkClearCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) { | 
|  | Json::Value color = command[SKDEBUGCANVAS_ATTRIBUTE_COLOR]; | 
|  | return new SkClearCommand(get_json_color(color)); | 
|  | } | 
|  |  | 
|  | SkClipPathCommand::SkClipPathCommand(const SkPath& path, SkRegion::Op op, bool doAA) | 
|  | : INHERITED(kClipPath_OpType) { | 
|  | fPath = path; | 
|  | fOp = op; | 
|  | fDoAA = doAA; | 
|  |  | 
|  | fInfo.push(SkObjectParser::PathToString(path)); | 
|  | fInfo.push(SkObjectParser::RegionOpToString(op)); | 
|  | fInfo.push(SkObjectParser::BoolToString(doAA)); | 
|  | } | 
|  |  | 
|  | void SkClipPathCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->clipPath(fPath, fOp, fDoAA); | 
|  | } | 
|  |  | 
|  | bool SkClipPathCommand::render(SkCanvas* canvas) const { | 
|  | render_path(canvas, fPath); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkClipPathCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = make_json_path(fPath); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = fDoAA; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkClipPathCommand* SkClipPathCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkPath path; | 
|  | extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path); | 
|  | return new SkClipPathCommand(path, get_json_regionop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]), | 
|  | command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool()); | 
|  | } | 
|  |  | 
|  | SkClipRegionCommand::SkClipRegionCommand(const SkRegion& region, SkRegion::Op op) | 
|  | : INHERITED(kClipRegion_OpType) { | 
|  | fRegion = region; | 
|  | fOp = op; | 
|  |  | 
|  | fInfo.push(SkObjectParser::RegionToString(region)); | 
|  | fInfo.push(SkObjectParser::RegionOpToString(op)); | 
|  | } | 
|  |  | 
|  | void SkClipRegionCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->clipRegion(fRegion, fOp); | 
|  | } | 
|  |  | 
|  | Json::Value SkClipRegionCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_REGION] = make_json_region(fRegion); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkClipRegionCommand* SkClipRegionCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkASSERT(false); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | SkClipRectCommand::SkClipRectCommand(const SkRect& rect, SkRegion::Op op, bool doAA) | 
|  | : INHERITED(kClipRect_OpType) { | 
|  | fRect = rect; | 
|  | fOp = op; | 
|  | fDoAA = doAA; | 
|  |  | 
|  | fInfo.push(SkObjectParser::RectToString(rect)); | 
|  | fInfo.push(SkObjectParser::RegionOpToString(op)); | 
|  | fInfo.push(SkObjectParser::BoolToString(doAA)); | 
|  | } | 
|  |  | 
|  | void SkClipRectCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->clipRect(fRect, fOp, fDoAA); | 
|  | } | 
|  |  | 
|  | Json::Value SkClipRectCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rect(fRect); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = Json::Value(fDoAA); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkClipRectCommand* SkClipRectCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkRect rect; | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rect); | 
|  | return new SkClipRectCommand(rect, get_json_regionop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]), | 
|  | command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool()); | 
|  | } | 
|  |  | 
|  | SkClipRRectCommand::SkClipRRectCommand(const SkRRect& rrect, SkRegion::Op op, bool doAA) | 
|  | : INHERITED(kClipRRect_OpType) { | 
|  | fRRect = rrect; | 
|  | fOp = op; | 
|  | fDoAA = doAA; | 
|  |  | 
|  | fInfo.push(SkObjectParser::RRectToString(rrect)); | 
|  | fInfo.push(SkObjectParser::RegionOpToString(op)); | 
|  | fInfo.push(SkObjectParser::BoolToString(doAA)); | 
|  | } | 
|  |  | 
|  | void SkClipRRectCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->clipRRect(fRRect, fOp, fDoAA); | 
|  | } | 
|  |  | 
|  | bool SkClipRRectCommand::render(SkCanvas* canvas) const { | 
|  | render_rrect(canvas, fRRect); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkClipRRectCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rrect(fRRect); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP] = make_json_regionop(fOp); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS] = Json::Value(fDoAA); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkClipRRectCommand* SkClipRRectCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkRRect rrect; | 
|  | extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &rrect); | 
|  | return new SkClipRRectCommand(rrect, | 
|  | get_json_regionop(command[SKDEBUGCANVAS_ATTRIBUTE_REGIONOP]), | 
|  | command[SKDEBUGCANVAS_ATTRIBUTE_ANTIALIAS].asBool()); | 
|  | } | 
|  |  | 
|  | SkConcatCommand::SkConcatCommand(const SkMatrix& matrix) | 
|  | : INHERITED(kConcat_OpType) { | 
|  | fMatrix = matrix; | 
|  |  | 
|  | fInfo.push(SkObjectParser::MatrixToString(matrix)); | 
|  | } | 
|  |  | 
|  | void SkConcatCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->concat(fMatrix); | 
|  | } | 
|  |  | 
|  | Json::Value SkConcatCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkConcatCommand* SkConcatCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) { | 
|  | SkMatrix matrix; | 
|  | extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix); | 
|  | return new SkConcatCommand(matrix); | 
|  | } | 
|  |  | 
|  | SkDrawBitmapCommand::SkDrawBitmapCommand(const SkBitmap& bitmap, SkScalar left, SkScalar top, | 
|  | const SkPaint* paint) | 
|  | : INHERITED(kDrawBitmap_OpType) { | 
|  | fBitmap = bitmap; | 
|  | fLeft = left; | 
|  | fTop = top; | 
|  | if (paint) { | 
|  | fPaint = *paint; | 
|  | fPaintPtr = &fPaint; | 
|  | } else { | 
|  | fPaintPtr = nullptr; | 
|  | } | 
|  |  | 
|  | fInfo.push(SkObjectParser::BitmapToString(bitmap)); | 
|  | fInfo.push(SkObjectParser::ScalarToString(left, "SkScalar left: ")); | 
|  | fInfo.push(SkObjectParser::ScalarToString(top, "SkScalar top: ")); | 
|  | if (paint) { | 
|  | fInfo.push(SkObjectParser::PaintToString(*paint)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkDrawBitmapCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawBitmap(fBitmap, fLeft, fTop, fPaintPtr); | 
|  | } | 
|  |  | 
|  | bool SkDrawBitmapCommand::render(SkCanvas* canvas) const { | 
|  | render_bitmap(canvas, fBitmap); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawBitmapCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | Json::Value encoded; | 
|  | if (flatten(fBitmap, &encoded, urlDataManager)) { | 
|  | Json::Value command(Json::objectValue); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_point(fLeft, fTop); | 
|  | if (fPaintPtr != nullptr) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, urlDataManager); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawBitmapCommand* SkDrawBitmapCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager); | 
|  | if (bitmap == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | Json::Value point = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS]; | 
|  | SkPaint* paintPtr; | 
|  | SkPaint paint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) { | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | paintPtr = &paint; | 
|  | } | 
|  | else { | 
|  | paintPtr = nullptr; | 
|  | } | 
|  | SkDrawBitmapCommand* result = new SkDrawBitmapCommand(*bitmap, point[0].asFloat(), | 
|  | point[1].asFloat(), paintPtr); | 
|  | delete bitmap; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawBitmapNineCommand::SkDrawBitmapNineCommand(const SkBitmap& bitmap, const SkIRect& center, | 
|  | const SkRect& dst, const SkPaint* paint) | 
|  | : INHERITED(kDrawBitmapNine_OpType) { | 
|  | fBitmap = bitmap; | 
|  | fCenter = center; | 
|  | fDst = dst; | 
|  | if (paint) { | 
|  | fPaint = *paint; | 
|  | fPaintPtr = &fPaint; | 
|  | } else { | 
|  | fPaintPtr = nullptr; | 
|  | } | 
|  |  | 
|  | fInfo.push(SkObjectParser::BitmapToString(bitmap)); | 
|  | fInfo.push(SkObjectParser::IRectToString(center)); | 
|  | fInfo.push(SkObjectParser::RectToString(dst, "Dst: ")); | 
|  | if (paint) { | 
|  | fInfo.push(SkObjectParser::PaintToString(*paint)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkDrawBitmapNineCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawBitmapNine(fBitmap, fCenter, fDst, fPaintPtr); | 
|  | } | 
|  |  | 
|  | bool SkDrawBitmapNineCommand::render(SkCanvas* canvas) const { | 
|  | SkRect tmp = SkRect::Make(fCenter); | 
|  | render_bitmap(canvas, fBitmap, &tmp); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawBitmapNineCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | Json::Value encoded; | 
|  | if (flatten(fBitmap, &encoded, urlDataManager)) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_CENTER] = MakeJsonIRect(fCenter); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_DST] = make_json_rect(fDst); | 
|  | if (fPaintPtr != nullptr) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, urlDataManager); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawBitmapNineCommand* SkDrawBitmapNineCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager); | 
|  | if (bitmap == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | SkIRect center; | 
|  | extract_json_irect(command[SKDEBUGCANVAS_ATTRIBUTE_CENTER], ¢er); | 
|  | SkRect dst; | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst); | 
|  | SkPaint* paintPtr; | 
|  | SkPaint paint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) { | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | paintPtr = &paint; | 
|  | } | 
|  | else { | 
|  | paintPtr = nullptr; | 
|  | } | 
|  | SkDrawBitmapNineCommand* result = new SkDrawBitmapNineCommand(*bitmap, center, dst, paintPtr); | 
|  | delete bitmap; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawBitmapRectCommand::SkDrawBitmapRectCommand(const SkBitmap& bitmap, const SkRect* src, | 
|  | const SkRect& dst, const SkPaint* paint, | 
|  | SkCanvas::SrcRectConstraint constraint) | 
|  | : INHERITED(kDrawBitmapRect_OpType) { | 
|  | fBitmap = bitmap; | 
|  | if (src) { | 
|  | fSrc = *src; | 
|  | } else { | 
|  | fSrc.setEmpty(); | 
|  | } | 
|  | fDst = dst; | 
|  |  | 
|  | if (paint) { | 
|  | fPaint = *paint; | 
|  | fPaintPtr = &fPaint; | 
|  | } else { | 
|  | fPaintPtr = nullptr; | 
|  | } | 
|  | fConstraint = constraint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::BitmapToString(bitmap)); | 
|  | if (src) { | 
|  | fInfo.push(SkObjectParser::RectToString(*src, "Src: ")); | 
|  | } | 
|  | fInfo.push(SkObjectParser::RectToString(dst, "Dst: ")); | 
|  | if (paint) { | 
|  | fInfo.push(SkObjectParser::PaintToString(*paint)); | 
|  | } | 
|  | fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: ")); | 
|  | } | 
|  |  | 
|  | void SkDrawBitmapRectCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->legacy_drawBitmapRect(fBitmap, this->srcRect(), fDst, fPaintPtr, fConstraint); | 
|  | } | 
|  |  | 
|  | bool SkDrawBitmapRectCommand::render(SkCanvas* canvas) const { | 
|  | render_bitmap(canvas, fBitmap, this->srcRect()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawBitmapRectCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | Json::Value encoded; | 
|  | if (flatten(fBitmap, &encoded, urlDataManager)) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded; | 
|  | if (!fSrc.isEmpty()) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = make_json_rect(fSrc); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_DST] = make_json_rect(fDst); | 
|  | if (fPaintPtr != nullptr) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, urlDataManager); | 
|  | } | 
|  | if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawBitmapRectCommand* SkDrawBitmapRectCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkBitmap* bitmap = load_bitmap(command[SKDEBUGCANVAS_ATTRIBUTE_BITMAP], urlDataManager); | 
|  | if (bitmap == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | SkRect dst; | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst); | 
|  | SkPaint* paintPtr; | 
|  | SkPaint paint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) { | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | paintPtr = &paint; | 
|  | } | 
|  | else { | 
|  | paintPtr = nullptr; | 
|  | } | 
|  | SkCanvas::SrcRectConstraint constraint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_STRICT) && | 
|  | command[SKDEBUGCANVAS_ATTRIBUTE_STRICT].asBool()) { | 
|  | constraint = SkCanvas::kStrict_SrcRectConstraint; | 
|  | } | 
|  | else { | 
|  | constraint = SkCanvas::kFast_SrcRectConstraint; | 
|  | } | 
|  | SkRect* srcPtr; | 
|  | SkRect src; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_SRC)) { | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_SRC], &src); | 
|  | srcPtr = &src; | 
|  | } | 
|  | else { | 
|  | srcPtr = nullptr; | 
|  | } | 
|  | SkDrawBitmapRectCommand* result = new SkDrawBitmapRectCommand(*bitmap, srcPtr, dst, paintPtr, | 
|  | constraint); | 
|  | delete bitmap; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawImageCommand::SkDrawImageCommand(const SkImage* image, SkScalar left, SkScalar top, | 
|  | const SkPaint* paint) | 
|  | : INHERITED(kDrawImage_OpType) | 
|  | , fImage(SkRef(image)) | 
|  | , fLeft(left) | 
|  | , fTop(top) { | 
|  |  | 
|  | fInfo.push(SkObjectParser::ImageToString(image)); | 
|  | fInfo.push(SkObjectParser::ScalarToString(left, "Left: ")); | 
|  | fInfo.push(SkObjectParser::ScalarToString(top, "Top: ")); | 
|  |  | 
|  | if (paint) { | 
|  | fPaint.set(*paint); | 
|  | fInfo.push(SkObjectParser::PaintToString(*paint)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkDrawImageCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawImage(fImage, fLeft, fTop, fPaint.getMaybeNull()); | 
|  | } | 
|  |  | 
|  | bool SkDrawImageCommand::render(SkCanvas* canvas) const { | 
|  | SkAutoCanvasRestore acr(canvas, true); | 
|  | canvas->clear(0xFFFFFFFF); | 
|  |  | 
|  | xlate_and_scale_to_bounds(canvas, SkRect::MakeXYWH(fLeft, fTop, | 
|  | SkIntToScalar(fImage->width()), | 
|  | SkIntToScalar(fImage->height()))); | 
|  | this->execute(canvas); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawImageCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | Json::Value encoded; | 
|  | if (flatten(*fImage, &encoded, urlDataManager)) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_IMAGE] = encoded; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_point(fLeft, fTop); | 
|  | if (fPaint.isValid()) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaint.get(), urlDataManager); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawImageCommand* SkDrawImageCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | sk_sp<SkImage> image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager); | 
|  | if (image == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | Json::Value point = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS]; | 
|  | SkPaint* paintPtr; | 
|  | SkPaint paint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) { | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | paintPtr = &paint; | 
|  | } | 
|  | else { | 
|  | paintPtr = nullptr; | 
|  | } | 
|  | SkDrawImageCommand* result = new SkDrawImageCommand(image.get(), point[0].asFloat(), | 
|  | point[1].asFloat(), paintPtr); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawImageRectCommand::SkDrawImageRectCommand(const SkImage* image, const SkRect* src, | 
|  | const SkRect& dst, const SkPaint* paint, | 
|  | SkCanvas::SrcRectConstraint constraint) | 
|  | : INHERITED(kDrawImageRect_OpType) | 
|  | , fImage(SkRef(image)) | 
|  | , fDst(dst) | 
|  | , fConstraint(constraint) { | 
|  |  | 
|  | if (src) { | 
|  | fSrc.set(*src); | 
|  | } | 
|  |  | 
|  | if (paint) { | 
|  | fPaint.set(*paint); | 
|  | } | 
|  |  | 
|  | fInfo.push(SkObjectParser::ImageToString(image)); | 
|  | if (src) { | 
|  | fInfo.push(SkObjectParser::RectToString(*src, "Src: ")); | 
|  | } | 
|  | fInfo.push(SkObjectParser::RectToString(dst, "Dst: ")); | 
|  | if (paint) { | 
|  | fInfo.push(SkObjectParser::PaintToString(*paint)); | 
|  | } | 
|  | fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: ")); | 
|  | } | 
|  |  | 
|  | void SkDrawImageRectCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->legacy_drawImageRect(fImage, fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), | 
|  | fConstraint); | 
|  | } | 
|  |  | 
|  | bool SkDrawImageRectCommand::render(SkCanvas* canvas) const { | 
|  | SkAutoCanvasRestore acr(canvas, true); | 
|  | canvas->clear(0xFFFFFFFF); | 
|  |  | 
|  | xlate_and_scale_to_bounds(canvas, fDst); | 
|  |  | 
|  | this->execute(canvas); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawImageRectCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | Json::Value encoded; | 
|  | if (flatten(*fImage.get(), &encoded, urlDataManager)) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_BITMAP] = encoded; | 
|  | if (fSrc.isValid()) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_SRC] = make_json_rect(*fSrc.get()); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_DST] = make_json_rect(fDst); | 
|  | if (fPaint.isValid()) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaint.get(), urlDataManager); | 
|  | } | 
|  | if (fConstraint == SkCanvas::kStrict_SrcRectConstraint) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_STRICT] = Json::Value(true); | 
|  | } | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawImageRectCommand* SkDrawImageRectCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | sk_sp<SkImage> image = load_image(command[SKDEBUGCANVAS_ATTRIBUTE_IMAGE], urlDataManager); | 
|  | if (image == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | SkRect dst; | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_DST], &dst); | 
|  | SkPaint* paintPtr; | 
|  | SkPaint paint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) { | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | paintPtr = &paint; | 
|  | } | 
|  | else { | 
|  | paintPtr = nullptr; | 
|  | } | 
|  | SkCanvas::SrcRectConstraint constraint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_STRICT) && | 
|  | command[SKDEBUGCANVAS_ATTRIBUTE_STRICT].asBool()) { | 
|  | constraint = SkCanvas::kStrict_SrcRectConstraint; | 
|  | } | 
|  | else { | 
|  | constraint = SkCanvas::kFast_SrcRectConstraint; | 
|  | } | 
|  | SkRect* srcPtr; | 
|  | SkRect src; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_SRC)) { | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_SRC], &src); | 
|  | srcPtr = &src; | 
|  | } | 
|  | else { | 
|  | srcPtr = nullptr; | 
|  | } | 
|  | SkDrawImageRectCommand* result = new SkDrawImageRectCommand(image.get(), srcPtr, dst, paintPtr, | 
|  | constraint); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawOvalCommand::SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint) | 
|  | : INHERITED(kDrawOval_OpType) { | 
|  | fOval = oval; | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::RectToString(oval)); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawOvalCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawOval(fOval, fPaint); | 
|  | } | 
|  |  | 
|  | bool SkDrawOvalCommand::render(SkCanvas* canvas) const { | 
|  | canvas->clear(0xFFFFFFFF); | 
|  | canvas->save(); | 
|  |  | 
|  | xlate_and_scale_to_bounds(canvas, fOval); | 
|  |  | 
|  | SkPaint p; | 
|  | p.setColor(SK_ColorBLACK); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  |  | 
|  | canvas->drawOval(fOval, p); | 
|  | canvas->restore(); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawOvalCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rect(fOval); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawOvalCommand* SkDrawOvalCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkRect coords; | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawOvalCommand(coords, paint); | 
|  | } | 
|  |  | 
|  | SkDrawPaintCommand::SkDrawPaintCommand(const SkPaint& paint) | 
|  | : INHERITED(kDrawPaint_OpType) { | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawPaintCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawPaint(fPaint); | 
|  | } | 
|  |  | 
|  | bool SkDrawPaintCommand::render(SkCanvas* canvas) const { | 
|  | canvas->clear(0xFFFFFFFF); | 
|  | canvas->drawPaint(fPaint); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawPaintCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawPaintCommand* SkDrawPaintCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawPaintCommand(paint); | 
|  | } | 
|  |  | 
|  | SkDrawPathCommand::SkDrawPathCommand(const SkPath& path, const SkPaint& paint) | 
|  | : INHERITED(kDrawPath_OpType) { | 
|  | fPath = path; | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::PathToString(path)); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawPathCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawPath(fPath, fPaint); | 
|  | } | 
|  |  | 
|  | bool SkDrawPathCommand::render(SkCanvas* canvas) const { | 
|  | render_path(canvas, fPath); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawPathCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = make_json_path(fPath); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawPathCommand* SkDrawPathCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkPath path; | 
|  | extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawPathCommand(path, paint); | 
|  | } | 
|  |  | 
|  | SkBeginDrawPictureCommand::SkBeginDrawPictureCommand(const SkPicture* picture, | 
|  | const SkMatrix* matrix, | 
|  | const SkPaint* paint) | 
|  | : INHERITED(kBeginDrawPicture_OpType) | 
|  | , fPicture(SkRef(picture)) { | 
|  |  | 
|  | SkString* str = new SkString; | 
|  | str->appendf("SkPicture: L: %f T: %f R: %f B: %f", | 
|  | picture->cullRect().fLeft, picture->cullRect().fTop, | 
|  | picture->cullRect().fRight, picture->cullRect().fBottom); | 
|  | fInfo.push(str); | 
|  |  | 
|  | if (matrix) { | 
|  | fMatrix.set(*matrix); | 
|  | fInfo.push(SkObjectParser::MatrixToString(*matrix)); | 
|  | } | 
|  |  | 
|  | if (paint) { | 
|  | fPaint.set(*paint); | 
|  | fInfo.push(SkObjectParser::PaintToString(*paint)); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | void SkBeginDrawPictureCommand::execute(SkCanvas* canvas) const { | 
|  | if (fPaint.isValid()) { | 
|  | SkRect bounds = fPicture->cullRect(); | 
|  | if (fMatrix.isValid()) { | 
|  | fMatrix.get()->mapRect(&bounds); | 
|  | } | 
|  | canvas->saveLayer(&bounds, fPaint.get()); | 
|  | } | 
|  |  | 
|  | if (fMatrix.isValid()) { | 
|  | if (!fPaint.isValid()) { | 
|  | canvas->save(); | 
|  | } | 
|  | canvas->concat(*fMatrix.get()); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SkBeginDrawPictureCommand::render(SkCanvas* canvas) const { | 
|  | canvas->clear(0xFFFFFFFF); | 
|  | canvas->save(); | 
|  |  | 
|  | xlate_and_scale_to_bounds(canvas, fPicture->cullRect()); | 
|  |  | 
|  | canvas->drawPicture(fPicture.get()); | 
|  |  | 
|  | canvas->restore(); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | SkEndDrawPictureCommand::SkEndDrawPictureCommand(bool restore) | 
|  | : INHERITED(kEndDrawPicture_OpType) , fRestore(restore) { } | 
|  |  | 
|  | void SkEndDrawPictureCommand::execute(SkCanvas* canvas) const { | 
|  | if (fRestore) { | 
|  | canvas->restore(); | 
|  | } | 
|  | } | 
|  |  | 
|  | SkDrawPointsCommand::SkDrawPointsCommand(SkCanvas::PointMode mode, size_t count, | 
|  | const SkPoint pts[], const SkPaint& paint) | 
|  | : INHERITED(kDrawPoints_OpType) { | 
|  | fMode = mode; | 
|  | fCount = count; | 
|  | fPts = new SkPoint[count]; | 
|  | memcpy(fPts, pts, count * sizeof(SkPoint)); | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::PointsToString(pts, count)); | 
|  | fInfo.push(SkObjectParser::ScalarToString(SkIntToScalar((unsigned int)count), | 
|  | "Points: ")); | 
|  | fInfo.push(SkObjectParser::PointModeToString(mode)); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawPointsCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawPoints(fMode, fCount, fPts, fPaint); | 
|  | } | 
|  |  | 
|  | bool SkDrawPointsCommand::render(SkCanvas* canvas) const { | 
|  | canvas->clear(0xFFFFFFFF); | 
|  | canvas->save(); | 
|  |  | 
|  | SkRect bounds; | 
|  |  | 
|  | bounds.setEmpty(); | 
|  | for (unsigned int i = 0; i < fCount; ++i) { | 
|  | bounds.growToInclude(fPts[i].fX, fPts[i].fY); | 
|  | } | 
|  |  | 
|  | xlate_and_scale_to_bounds(canvas, bounds); | 
|  |  | 
|  | SkPaint p; | 
|  | p.setColor(SK_ColorBLACK); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  |  | 
|  | canvas->drawPoints(fMode, fCount, fPts, p); | 
|  | canvas->restore(); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawPointsCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_MODE] = make_json_pointmode(fMode); | 
|  | Json::Value points(Json::arrayValue); | 
|  | for (size_t i = 0; i < fCount; i++) { | 
|  | points.append(make_json_point(fPts[i])); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_POINTS] = points; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawPointsCommand* SkDrawPointsCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkCanvas::PointMode mode; | 
|  | const char* jsonMode = command[SKDEBUGCANVAS_ATTRIBUTE_MODE].asCString(); | 
|  | if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_POINTS)) { | 
|  | mode = SkCanvas::kPoints_PointMode; | 
|  | } | 
|  | else if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_LINES)) { | 
|  | mode = SkCanvas::kLines_PointMode; | 
|  | } | 
|  | else if (!strcmp(jsonMode, SKDEBUGCANVAS_POINTMODE_POLYGON)) { | 
|  | mode = SkCanvas::kPolygon_PointMode; | 
|  | } | 
|  | else { | 
|  | SkASSERT(false); | 
|  | return nullptr; | 
|  | } | 
|  | Json::Value jsonPoints = command[SKDEBUGCANVAS_ATTRIBUTE_POINTS]; | 
|  | int count = (int) jsonPoints.size(); | 
|  | SkPoint* points = (SkPoint*) sk_malloc_throw(count * sizeof(SkPoint)); | 
|  | for (int i = 0; i < count; i++) { | 
|  | points[i] = SkPoint::Make(jsonPoints[i][0].asFloat(), jsonPoints[i][1].asFloat()); | 
|  | } | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | SkDrawPointsCommand* result = new SkDrawPointsCommand(mode, count, points, paint); | 
|  | sk_free(points); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawPosTextCommand::SkDrawPosTextCommand(const void* text, size_t byteLength, | 
|  | const SkPoint pos[], const SkPaint& paint) | 
|  | : INHERITED(kDrawPosText_OpType) { | 
|  | size_t numPts = paint.countText(text, byteLength); | 
|  |  | 
|  | fText = new char[byteLength]; | 
|  | memcpy(fText, text, byteLength); | 
|  | fByteLength = byteLength; | 
|  |  | 
|  | fPos = new SkPoint[numPts]; | 
|  | memcpy(fPos, pos, numPts * sizeof(SkPoint)); | 
|  |  | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding())); | 
|  | // TODO(chudy): Test that this works. | 
|  | fInfo.push(SkObjectParser::PointsToString(pos, 1)); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawPosTextCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawPosText(fText, fByteLength, fPos, fPaint); | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawPosTextCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText, | 
|  | ((const char*) fText) + fByteLength); | 
|  | Json::Value coords(Json::arrayValue); | 
|  | size_t numCoords = fPaint.textToGlyphs(fText, fByteLength, nullptr); | 
|  | for (size_t i = 0; i < numCoords; i++) { | 
|  | coords.append(make_json_point(fPos[i])); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = coords; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawPosTextCommand* SkDrawPosTextCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString(); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | Json::Value coords = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS]; | 
|  | int count = (int) coords.size(); | 
|  | SkPoint* points = (SkPoint*) sk_malloc_throw(count * sizeof(SkPoint)); | 
|  | for (int i = 0; i < count; i++) { | 
|  | points[i] = SkPoint::Make(coords[i][0].asFloat(), coords[i][1].asFloat()); | 
|  | } | 
|  | return new SkDrawPosTextCommand(text, strlen(text), points, paint); | 
|  | } | 
|  |  | 
|  | SkDrawPosTextHCommand::SkDrawPosTextHCommand(const void* text, size_t byteLength, | 
|  | const SkScalar xpos[], SkScalar constY, | 
|  | const SkPaint& paint) | 
|  | : INHERITED(kDrawPosTextH_OpType) { | 
|  | size_t numPts = paint.countText(text, byteLength); | 
|  |  | 
|  | fText = new char[byteLength]; | 
|  | memcpy(fText, text, byteLength); | 
|  | fByteLength = byteLength; | 
|  |  | 
|  | fXpos = new SkScalar[numPts]; | 
|  | memcpy(fXpos, xpos, numPts * sizeof(SkScalar)); | 
|  |  | 
|  | fConstY = constY; | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding())); | 
|  | fInfo.push(SkObjectParser::ScalarToString(xpos[0], "XPOS: ")); | 
|  | fInfo.push(SkObjectParser::ScalarToString(constY, "SkScalar constY: ")); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawPosTextHCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawPosTextH(fText, fByteLength, fXpos, fConstY, fPaint); | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawPosTextHCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText, | 
|  | ((const char*) fText) + fByteLength); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_Y] = Json::Value(fConstY); | 
|  | Json::Value xpos(Json::arrayValue); | 
|  | size_t numXpos = fPaint.textToGlyphs(fText, fByteLength, nullptr); | 
|  | for (size_t i = 0; i < numXpos; i++) { | 
|  | xpos.append(Json::Value(fXpos[i])); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS] = xpos; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawPosTextHCommand* SkDrawPosTextHCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString(); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | Json::Value jsonXpos = command[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS]; | 
|  | int count = (int) jsonXpos.size(); | 
|  | SkScalar* xpos = (SkScalar*) sk_malloc_throw(count * sizeof(SkScalar)); | 
|  | for (int i = 0; i < count; i++) { | 
|  | xpos[i] = jsonXpos[i].asFloat(); | 
|  | } | 
|  | SkScalar y = command[SKDEBUGCANVAS_ATTRIBUTE_Y].asFloat(); | 
|  | return new SkDrawPosTextHCommand(text, strlen(text), xpos, y, paint); | 
|  | } | 
|  |  | 
|  | static const char* gPositioningLabels[] = { | 
|  | "kDefault_Positioning", | 
|  | "kHorizontal_Positioning", | 
|  | "kFull_Positioning", | 
|  | }; | 
|  |  | 
|  | SkDrawTextBlobCommand::SkDrawTextBlobCommand(const SkTextBlob* blob, SkScalar x, SkScalar y, | 
|  | const SkPaint& paint) | 
|  | : INHERITED(kDrawTextBlob_OpType) | 
|  | , fBlob(SkRef(blob)) | 
|  | , fXPos(x) | 
|  | , fYPos(y) | 
|  | , fPaint(paint) { | 
|  |  | 
|  | SkAutoTDelete<SkString> runsStr(new SkString); | 
|  | fInfo.push(SkObjectParser::ScalarToString(x, "XPOS: ")); | 
|  | fInfo.push(SkObjectParser::ScalarToString(y, "YPOS: ")); | 
|  | fInfo.push(SkObjectParser::RectToString(fBlob->bounds(), "Bounds: ")); | 
|  | fInfo.push(runsStr); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  |  | 
|  | unsigned runs = 0; | 
|  | SkPaint runPaint(paint); | 
|  | SkTextBlobRunIterator iter(blob); | 
|  | while (!iter.done()) { | 
|  | SkAutoTDelete<SkString> tmpStr(new SkString); | 
|  | tmpStr->printf("==== Run [%d] ====", runs++); | 
|  | fInfo.push(tmpStr.release()); | 
|  |  | 
|  | fInfo.push(SkObjectParser::IntToString(iter.glyphCount(), "GlyphCount: ")); | 
|  | tmpStr.reset(new SkString("GlyphPositioning: ")); | 
|  | tmpStr->append(gPositioningLabels[iter.positioning()]); | 
|  | fInfo.push(tmpStr.release()); | 
|  |  | 
|  | iter.applyFontToPaint(&runPaint); | 
|  | fInfo.push(SkObjectParser::PaintToString(runPaint)); | 
|  |  | 
|  | iter.next(); | 
|  | } | 
|  |  | 
|  | runsStr->printf("Runs: %d", runs); | 
|  | // runStr is owned by fInfo at this point. | 
|  | runsStr.release(); | 
|  | } | 
|  |  | 
|  | void SkDrawTextBlobCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint); | 
|  | } | 
|  |  | 
|  | bool SkDrawTextBlobCommand::render(SkCanvas* canvas) const { | 
|  | canvas->clear(SK_ColorWHITE); | 
|  | canvas->save(); | 
|  |  | 
|  | SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos); | 
|  | xlate_and_scale_to_bounds(canvas, bounds); | 
|  |  | 
|  | canvas->drawTextBlob(fBlob.get(), fXPos, fYPos, fPaint); | 
|  |  | 
|  | canvas->restore(); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawTextBlobCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | Json::Value runs(Json::arrayValue); | 
|  | SkTextBlobRunIterator iter(fBlob.get()); | 
|  | while (!iter.done()) { | 
|  | Json::Value run(Json::objectValue); | 
|  | Json::Value jsonPositions(Json::arrayValue); | 
|  | Json::Value jsonGlyphs(Json::arrayValue); | 
|  | const SkScalar* iterPositions = iter.pos(); | 
|  | const uint16_t* iterGlyphs = iter.glyphs(); | 
|  | for (uint32_t i = 0; i < iter.glyphCount(); i++) { | 
|  | switch (iter.positioning()) { | 
|  | case SkTextBlob::kFull_Positioning: | 
|  | jsonPositions.append(make_json_point(iterPositions[i * 2], | 
|  | iterPositions[i * 2 + 1])); | 
|  | break; | 
|  | case SkTextBlob::kHorizontal_Positioning: | 
|  | jsonPositions.append(Json::Value(iterPositions[i])); | 
|  | break; | 
|  | case SkTextBlob::kDefault_Positioning: | 
|  | break; | 
|  | } | 
|  | jsonGlyphs.append(Json::Value(iterGlyphs[i])); | 
|  | } | 
|  | if (iter.positioning() != SkTextBlob::kDefault_Positioning) { | 
|  | run[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS] = jsonPositions; | 
|  | } | 
|  | run[SKDEBUGCANVAS_ATTRIBUTE_GLYPHS] = jsonGlyphs; | 
|  | SkPaint fontPaint; | 
|  | iter.applyFontToPaint(&fontPaint); | 
|  | run[SKDEBUGCANVAS_ATTRIBUTE_FONT] = make_json_paint(fontPaint, urlDataManager); | 
|  | run[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_point(iter.offset()); | 
|  | runs.append(run); | 
|  | iter.next(); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_RUNS] = runs; | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_X] = Json::Value(fXPos); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_Y] = Json::Value(fYPos); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawTextBlobCommand* SkDrawTextBlobCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkTextBlobBuilder builder; | 
|  | Json::Value runs = command[SKDEBUGCANVAS_ATTRIBUTE_RUNS]; | 
|  | for (Json::ArrayIndex i = 0 ; i < runs.size(); i++) { | 
|  | Json::Value run = runs[i]; | 
|  | SkPaint font; | 
|  | font.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 
|  | extract_json_paint(run[SKDEBUGCANVAS_ATTRIBUTE_FONT], urlDataManager, &font); | 
|  | Json::Value glyphs = run[SKDEBUGCANVAS_ATTRIBUTE_GLYPHS]; | 
|  | int count = glyphs.size(); | 
|  | Json::Value coords = run[SKDEBUGCANVAS_ATTRIBUTE_COORDS]; | 
|  | SkScalar x = coords[0].asFloat(); | 
|  | SkScalar y = coords[1].asFloat(); | 
|  | if (run.isMember(SKDEBUGCANVAS_ATTRIBUTE_POSITIONS)) { | 
|  | Json::Value positions = run[SKDEBUGCANVAS_ATTRIBUTE_POSITIONS]; | 
|  | if (positions.size() > 0 && positions[0].isNumeric()) { | 
|  | SkTextBlobBuilder::RunBuffer buffer = builder.allocRunPosH(font, count, y); | 
|  | for (int j = 0; j < count; j++) { | 
|  | buffer.glyphs[j] = glyphs[j].asUInt(); | 
|  | buffer.pos[j] = positions[j].asFloat(); | 
|  | } | 
|  | } | 
|  | else { | 
|  | SkTextBlobBuilder::RunBuffer buffer = builder.allocRunPos(font, count); | 
|  | for (int j = 0; j < count; j++) { | 
|  | buffer.glyphs[j] = glyphs[j].asUInt(); | 
|  | buffer.pos[j * 2] = positions[j][0].asFloat(); | 
|  | buffer.pos[j * 2 + 1] = positions[j][1].asFloat(); | 
|  | } | 
|  | } | 
|  | } | 
|  | else { | 
|  | SkTextBlobBuilder::RunBuffer buffer = builder.allocRun(font, count, x, y); | 
|  | for (int j = 0; j < count; j++) { | 
|  | buffer.glyphs[j] = glyphs[j].asUInt(); | 
|  | } | 
|  | } | 
|  | } | 
|  | SkScalar x = command[SKDEBUGCANVAS_ATTRIBUTE_X].asFloat(); | 
|  | SkScalar y = command[SKDEBUGCANVAS_ATTRIBUTE_Y].asFloat(); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawTextBlobCommand(builder.build(), x, y, paint); | 
|  | } | 
|  |  | 
|  | SkDrawPatchCommand::SkDrawPatchCommand(const SkPoint cubics[12], const SkColor colors[4], | 
|  | const SkPoint texCoords[4], SkXfermode* xfermode, | 
|  | const SkPaint& paint) | 
|  | : INHERITED(kDrawPatch_OpType) { | 
|  | memcpy(fCubics, cubics, sizeof(fCubics)); | 
|  | if (colors != nullptr) { | 
|  | memcpy(fColors, colors, sizeof(fColors)); | 
|  | fColorsPtr = fColors; | 
|  | } else { | 
|  | fColorsPtr = nullptr; | 
|  | } | 
|  | if (texCoords != nullptr) { | 
|  | memcpy(fTexCoords, texCoords, sizeof(fTexCoords)); | 
|  | fTexCoordsPtr = fTexCoords; | 
|  | } else { | 
|  | fTexCoordsPtr = nullptr; | 
|  | } | 
|  | if (xfermode != nullptr) { | 
|  | fXfermode.reset(SkRef(xfermode)); | 
|  | } | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawPatchCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawPatch(fCubics, fColorsPtr, fTexCoordsPtr, fXfermode, fPaint); | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawPatchCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | Json::Value cubics = Json::Value(Json::arrayValue); | 
|  | for (int i = 0; i < 12; i++) { | 
|  | cubics.append(make_json_point(fCubics[i])); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_CUBICS] = cubics; | 
|  | if (fColorsPtr != nullptr) { | 
|  | Json::Value colors = Json::Value(Json::arrayValue); | 
|  | for (int i = 0; i < 4; i++) { | 
|  | colors.append(make_json_color(fColorsPtr[i])); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COLORS] = colors; | 
|  | } | 
|  | if (fTexCoordsPtr != nullptr) { | 
|  | Json::Value texCoords = Json::Value(Json::arrayValue); | 
|  | for (int i = 0; i < 4; i++) { | 
|  | texCoords.append(make_json_point(fTexCoords[i])); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS] = texCoords; | 
|  | } | 
|  | if (fXfermode.get() != nullptr) { | 
|  | Json::Value jsonXfermode; | 
|  | flatten(fXfermode, &jsonXfermode, urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE] = jsonXfermode; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawPatchCommand* SkDrawPatchCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | Json::Value jsonCubics = command[SKDEBUGCANVAS_ATTRIBUTE_CUBICS]; | 
|  | SkPoint cubics[12]; | 
|  | for (int i = 0; i < 12; i++) { | 
|  | cubics[i] = get_json_point(jsonCubics[i]); | 
|  | } | 
|  | SkColor* colorsPtr; | 
|  | SkColor colors[4]; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_COLORS)) { | 
|  | Json::Value jsonColors = command[SKDEBUGCANVAS_ATTRIBUTE_COLORS]; | 
|  | for (int i = 0; i < 4; i++) { | 
|  | colors[i] = get_json_color(jsonColors[i]); | 
|  | } | 
|  | colorsPtr = colors; | 
|  | } | 
|  | else { | 
|  | colorsPtr = nullptr; | 
|  | } | 
|  | SkPoint* texCoordsPtr; | 
|  | SkPoint texCoords[4]; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS)) { | 
|  | Json::Value jsonTexCoords = command[SKDEBUGCANVAS_ATTRIBUTE_TEXTURECOORDS]; | 
|  | for (int i = 0; i < 4; i++) { | 
|  | texCoords[i] = get_json_point(jsonTexCoords[i]); | 
|  | } | 
|  | texCoordsPtr = texCoords; | 
|  | } | 
|  | else { | 
|  | texCoordsPtr = nullptr; | 
|  | } | 
|  | SkAutoTUnref<SkXfermode> xfermode; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_XFERMODE)) { | 
|  | Json::Value jsonXfermode = command[SKDEBUGCANVAS_ATTRIBUTE_XFERMODE]; | 
|  | xfermode.reset((SkXfermode*) load_flattenable(jsonXfermode, urlDataManager)); | 
|  | } | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawPatchCommand(cubics, colorsPtr, texCoordsPtr, xfermode, paint); | 
|  | } | 
|  |  | 
|  | SkDrawRectCommand::SkDrawRectCommand(const SkRect& rect, const SkPaint& paint) | 
|  | : INHERITED(kDrawRect_OpType) { | 
|  | fRect = rect; | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::RectToString(rect)); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawRectCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawRect(fRect, fPaint); | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawRectCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rect(fRect); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawRectCommand* SkDrawRectCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkRect coords; | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawRectCommand(coords, paint); | 
|  | } | 
|  |  | 
|  | SkDrawRRectCommand::SkDrawRRectCommand(const SkRRect& rrect, const SkPaint& paint) | 
|  | : INHERITED(kDrawRRect_OpType) { | 
|  | fRRect = rrect; | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::RRectToString(rrect)); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawRRectCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawRRect(fRRect, fPaint); | 
|  | } | 
|  |  | 
|  | bool SkDrawRRectCommand::render(SkCanvas* canvas) const { | 
|  | render_rrect(canvas, fRRect); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawRRectCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_rrect(fRRect); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawRRectCommand* SkDrawRRectCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkRRect coords; | 
|  | extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_COORDS], &coords); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawRRectCommand(coords, paint); | 
|  | } | 
|  |  | 
|  | SkDrawDRRectCommand::SkDrawDRRectCommand(const SkRRect& outer, | 
|  | const SkRRect& inner, | 
|  | const SkPaint& paint) | 
|  | : INHERITED(kDrawDRRect_OpType) { | 
|  | fOuter = outer; | 
|  | fInner = inner; | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::RRectToString(outer)); | 
|  | fInfo.push(SkObjectParser::RRectToString(inner)); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawDRRectCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawDRRect(fOuter, fInner, fPaint); | 
|  | } | 
|  |  | 
|  | bool SkDrawDRRectCommand::render(SkCanvas* canvas) const { | 
|  | render_drrect(canvas, fOuter, fInner); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawDRRectCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_OUTER] = make_json_rrect(fOuter); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_INNER] = make_json_rrect(fInner); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawDRRectCommand* SkDrawDRRectCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkRRect outer; | 
|  | extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_INNER], &outer); | 
|  | SkRRect inner; | 
|  | extract_json_rrect(command[SKDEBUGCANVAS_ATTRIBUTE_INNER], &inner); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | return new SkDrawDRRectCommand(outer, inner, paint); | 
|  | } | 
|  |  | 
|  | SkDrawTextCommand::SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y, | 
|  | const SkPaint& paint) | 
|  | : INHERITED(kDrawText_OpType) { | 
|  | fText = new char[byteLength]; | 
|  | memcpy(fText, text, byteLength); | 
|  | fByteLength = byteLength; | 
|  | fX = x; | 
|  | fY = y; | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding())); | 
|  | fInfo.push(SkObjectParser::ScalarToString(x, "SkScalar x: ")); | 
|  | fInfo.push(SkObjectParser::ScalarToString(y, "SkScalar y: ")); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawTextCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawText(fText, fByteLength, fX, fY, fPaint); | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawTextCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText, | 
|  | ((const char*) fText) + fByteLength); | 
|  | Json::Value coords(Json::arrayValue); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_COORDS] = make_json_point(fX, fY); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawTextCommand* SkDrawTextCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString(); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | Json::Value coords = command[SKDEBUGCANVAS_ATTRIBUTE_COORDS]; | 
|  | return new SkDrawTextCommand(text, strlen(text), coords[0].asFloat(), coords[1].asFloat(), | 
|  | paint); | 
|  | } | 
|  |  | 
|  | SkDrawTextOnPathCommand::SkDrawTextOnPathCommand(const void* text, size_t byteLength, | 
|  | const SkPath& path, const SkMatrix* matrix, | 
|  | const SkPaint& paint) | 
|  | : INHERITED(kDrawTextOnPath_OpType) { | 
|  | fText = new char[byteLength]; | 
|  | memcpy(fText, text, byteLength); | 
|  | fByteLength = byteLength; | 
|  | fPath = path; | 
|  | if (matrix) { | 
|  | fMatrix = *matrix; | 
|  | } else { | 
|  | fMatrix.setIdentity(); | 
|  | } | 
|  | fPaint = paint; | 
|  |  | 
|  | fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding())); | 
|  | fInfo.push(SkObjectParser::PathToString(path)); | 
|  | if (matrix) { | 
|  | fInfo.push(SkObjectParser::MatrixToString(*matrix)); | 
|  | } | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | void SkDrawTextOnPathCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawTextOnPath(fText, fByteLength, fPath, | 
|  | fMatrix.isIdentity() ? nullptr : &fMatrix, | 
|  | fPaint); | 
|  | } | 
|  |  | 
|  | Json::Value SkDrawTextOnPathCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) fText, | 
|  | ((const char*) fText) + fByteLength); | 
|  | Json::Value coords(Json::arrayValue); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PATH] = make_json_path(fPath); | 
|  | if (!fMatrix.isIdentity()) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix); | 
|  | } | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(fPaint, urlDataManager); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkDrawTextOnPathCommand* SkDrawTextOnPathCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | const char* text = command[SKDEBUGCANVAS_ATTRIBUTE_TEXT].asCString(); | 
|  | SkPaint paint; | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | SkPath path; | 
|  | extract_json_path(command[SKDEBUGCANVAS_ATTRIBUTE_PATH], &path); | 
|  | SkMatrix* matrixPtr; | 
|  | SkMatrix matrix; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_MATRIX)) { | 
|  | extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix); | 
|  | matrixPtr = &matrix; | 
|  | } | 
|  | else { | 
|  | matrixPtr = nullptr; | 
|  | } | 
|  | return new SkDrawTextOnPathCommand(text, strlen(text), path, matrixPtr, paint); | 
|  | } | 
|  |  | 
|  | SkDrawVerticesCommand::SkDrawVerticesCommand(SkCanvas::VertexMode vmode, int vertexCount, | 
|  | const SkPoint vertices[], const SkPoint texs[], | 
|  | const SkColor colors[], SkXfermode* xfermode, | 
|  | const uint16_t indices[], int indexCount, | 
|  | const SkPaint& paint) | 
|  | : INHERITED(kDrawVertices_OpType) { | 
|  | fVmode = vmode; | 
|  |  | 
|  | fVertexCount = vertexCount; | 
|  |  | 
|  | fVertices = new SkPoint[vertexCount]; | 
|  | memcpy(fVertices, vertices, vertexCount * sizeof(SkPoint)); | 
|  |  | 
|  | if (texs) { | 
|  | fTexs = new SkPoint[vertexCount]; | 
|  | memcpy(fTexs, texs, vertexCount * sizeof(SkPoint)); | 
|  | } else { | 
|  | fTexs = nullptr; | 
|  | } | 
|  |  | 
|  | if (colors) { | 
|  | fColors = new SkColor[vertexCount]; | 
|  | memcpy(fColors, colors, vertexCount * sizeof(SkColor)); | 
|  | } else { | 
|  | fColors = nullptr; | 
|  | } | 
|  |  | 
|  | fXfermode = xfermode; | 
|  | if (fXfermode) { | 
|  | fXfermode->ref(); | 
|  | } | 
|  |  | 
|  | if (indexCount > 0) { | 
|  | fIndices = new uint16_t[indexCount]; | 
|  | memcpy(fIndices, indices, indexCount * sizeof(uint16_t)); | 
|  | } else { | 
|  | fIndices = nullptr; | 
|  | } | 
|  |  | 
|  | fIndexCount = indexCount; | 
|  | fPaint = paint; | 
|  |  | 
|  | // TODO(chudy) | 
|  | fInfo.push(SkObjectParser::CustomTextToString("To be implemented.")); | 
|  | fInfo.push(SkObjectParser::PaintToString(paint)); | 
|  | } | 
|  |  | 
|  | SkDrawVerticesCommand::~SkDrawVerticesCommand() { | 
|  | delete [] fVertices; | 
|  | delete [] fTexs; | 
|  | delete [] fColors; | 
|  | SkSafeUnref(fXfermode); | 
|  | delete [] fIndices; | 
|  | } | 
|  |  | 
|  | void SkDrawVerticesCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->drawVertices(fVmode, fVertexCount, fVertices, | 
|  | fTexs, fColors, fXfermode, fIndices, | 
|  | fIndexCount, fPaint); | 
|  | } | 
|  |  | 
|  | SkRestoreCommand::SkRestoreCommand() | 
|  | : INHERITED(kRestore_OpType) { | 
|  | fInfo.push(SkObjectParser::CustomTextToString("No Parameters")); | 
|  | } | 
|  |  | 
|  | void SkRestoreCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | SkRestoreCommand* SkRestoreCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) { | 
|  | return new SkRestoreCommand(); | 
|  | } | 
|  |  | 
|  | SkSaveCommand::SkSaveCommand() | 
|  | : INHERITED(kSave_OpType) { | 
|  | } | 
|  |  | 
|  | void SkSaveCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->save(); | 
|  | } | 
|  |  | 
|  | SkSaveCommand* SkSaveCommand::fromJSON(Json::Value& command, UrlDataManager& urlDataManager) { | 
|  | return new SkSaveCommand(); | 
|  | } | 
|  |  | 
|  | SkSaveLayerCommand::SkSaveLayerCommand(const SkCanvas::SaveLayerRec& rec) | 
|  | : INHERITED(kSaveLayer_OpType) { | 
|  | if (rec.fBounds) { | 
|  | fBounds = *rec.fBounds; | 
|  | } else { | 
|  | fBounds.setEmpty(); | 
|  | } | 
|  |  | 
|  | if (rec.fPaint) { | 
|  | fPaint = *rec.fPaint; | 
|  | fPaintPtr = &fPaint; | 
|  | } else { | 
|  | fPaintPtr = nullptr; | 
|  | } | 
|  | fSaveLayerFlags = rec.fSaveLayerFlags; | 
|  |  | 
|  | if (rec.fBackdrop) { | 
|  | fBackdrop = rec.fBackdrop; | 
|  | fBackdrop->ref(); | 
|  | } else { | 
|  | fBackdrop = nullptr; | 
|  | } | 
|  |  | 
|  | if (rec.fBounds) { | 
|  | fInfo.push(SkObjectParser::RectToString(*rec.fBounds, "Bounds: ")); | 
|  | } | 
|  | if (rec.fPaint) { | 
|  | fInfo.push(SkObjectParser::PaintToString(*rec.fPaint)); | 
|  | } | 
|  | fInfo.push(SkObjectParser::SaveLayerFlagsToString(fSaveLayerFlags)); | 
|  | } | 
|  |  | 
|  | SkSaveLayerCommand::~SkSaveLayerCommand() { | 
|  | if (fBackdrop != nullptr) { | 
|  | fBackdrop->unref(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkSaveLayerCommand::execute(SkCanvas* canvas) const { | 
|  | canvas->saveLayer(SkCanvas::SaveLayerRec(fBounds.isEmpty() ? nullptr : &fBounds, | 
|  | fPaintPtr, | 
|  | fSaveLayerFlags)); | 
|  | } | 
|  |  | 
|  | void SkSaveLayerCommand::vizExecute(SkCanvas* canvas) const { | 
|  | canvas->save(); | 
|  | } | 
|  |  | 
|  | Json::Value SkSaveLayerCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | if (!fBounds.isEmpty()) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS] = make_json_rect(fBounds); | 
|  | } | 
|  | if (fPaintPtr != nullptr) { | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_PAINT] = make_json_paint(*fPaintPtr, | 
|  | urlDataManager); | 
|  | } | 
|  | if (fBackdrop != nullptr) { | 
|  | Json::Value jsonBackdrop; | 
|  | flatten(fBackdrop, &jsonBackdrop, urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_BACKDROP] = jsonBackdrop; | 
|  | } | 
|  | if (fSaveLayerFlags != 0) { | 
|  | SkDebugf("unsupported: saveLayer flags\n"); | 
|  | SkASSERT(false); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkSaveLayerCommand* SkSaveLayerCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkCanvas::SaveLayerRec rec; | 
|  | SkRect bounds; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_BOUNDS)) { | 
|  | extract_json_rect(command[SKDEBUGCANVAS_ATTRIBUTE_BOUNDS], &bounds); | 
|  | rec.fBounds = &bounds; | 
|  | } | 
|  | SkPaint paint; | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_PAINT)) { | 
|  | extract_json_paint(command[SKDEBUGCANVAS_ATTRIBUTE_PAINT], urlDataManager, &paint); | 
|  | rec.fPaint = &paint; | 
|  | } | 
|  | if (command.isMember(SKDEBUGCANVAS_ATTRIBUTE_BACKDROP)) { | 
|  | Json::Value backdrop = command[SKDEBUGCANVAS_ATTRIBUTE_BACKDROP]; | 
|  | rec.fBackdrop = (SkImageFilter*) load_flattenable(backdrop, urlDataManager); | 
|  | } | 
|  | SkSaveLayerCommand* result = new SkSaveLayerCommand(rec); | 
|  | if (rec.fBackdrop != nullptr) { | 
|  | rec.fBackdrop->unref(); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkSetMatrixCommand::SkSetMatrixCommand(const SkMatrix& matrix) | 
|  | : INHERITED(kSetMatrix_OpType) { | 
|  | fUserMatrix.reset(); | 
|  | fMatrix = matrix; | 
|  | fInfo.push(SkObjectParser::MatrixToString(matrix)); | 
|  | } | 
|  |  | 
|  | void SkSetMatrixCommand::setUserMatrix(const SkMatrix& userMatrix) { | 
|  | fUserMatrix = userMatrix; | 
|  | } | 
|  |  | 
|  | void SkSetMatrixCommand::execute(SkCanvas* canvas) const { | 
|  | SkMatrix temp = SkMatrix::Concat(fUserMatrix, fMatrix); | 
|  | canvas->setMatrix(temp); | 
|  | } | 
|  |  | 
|  | Json::Value SkSetMatrixCommand::toJSON(UrlDataManager& urlDataManager) const { | 
|  | Json::Value result = INHERITED::toJSON(urlDataManager); | 
|  | result[SKDEBUGCANVAS_ATTRIBUTE_MATRIX] = MakeJsonMatrix(fMatrix); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | SkSetMatrixCommand* SkSetMatrixCommand::fromJSON(Json::Value& command, | 
|  | UrlDataManager& urlDataManager) { | 
|  | SkMatrix matrix; | 
|  | extract_json_matrix(command[SKDEBUGCANVAS_ATTRIBUTE_MATRIX], &matrix); | 
|  | return new SkSetMatrixCommand(matrix); | 
|  | } |