Home | History | Annotate | Download | only in json
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkJSONCanvas.h"
      9 #include "SkColorFilter.h"
     10 #include "SkImageFilter.h"
     11 #include "SkMaskFilter.h"
     12 #include "SkPaintDefaults.h"
     13 #include "SkPath.h"
     14 #include "SkPathEffect.h"
     15 #include "SkRRect.h"
     16 #include "SkTextBlob.h"
     17 #include "SkTextBlobRunIterator.h"
     18 #include "SkTypeface.h"
     19 #include "SkWriteBuffer.h"
     20 
     21 SkJSONCanvas::SkJSONCanvas(int width, int height, SkWStream& out, bool sendBinaries)
     22     : INHERITED(width, height)
     23     , fOut(out)
     24     , fRoot(Json::objectValue)
     25     , fCommands(Json::arrayValue)
     26     , fSendBinaries(sendBinaries) {
     27     fRoot[SKJSONCANVAS_VERSION] = Json::Value(1);
     28 }
     29 
     30 void SkJSONCanvas::finish() {
     31     fRoot[SKJSONCANVAS_COMMANDS] = fCommands;
     32     fOut.writeText(Json::FastWriter().write(fRoot).c_str());
     33 }
     34 
     35 Json::Value SkJSONCanvas::makePoint(const SkPoint& point) {
     36     Json::Value result(Json::arrayValue);
     37     result.append(Json::Value(point.x()));
     38     result.append(Json::Value(point.y()));
     39     return result;
     40 }
     41 
     42 Json::Value SkJSONCanvas::makePoint(SkScalar x, SkScalar y) {
     43     Json::Value result(Json::arrayValue);
     44     result.append(Json::Value(x));
     45     result.append(Json::Value(y));
     46     return result;
     47 }
     48 
     49 Json::Value SkJSONCanvas::makeRect(const SkRect& rect) {
     50     Json::Value result(Json::arrayValue);
     51     result.append(Json::Value(rect.left()));
     52     result.append(Json::Value(rect.top()));
     53     result.append(Json::Value(rect.right()));
     54     result.append(Json::Value(rect.bottom()));
     55     return result;
     56 }
     57 
     58 Json::Value SkJSONCanvas::makeRRect(const SkRRect& rrect) {
     59     Json::Value result(Json::arrayValue);
     60     result.append(this->makeRect(rrect.rect()));
     61     result.append(this->makePoint(rrect.radii(SkRRect::kUpperLeft_Corner)));
     62     result.append(this->makePoint(rrect.radii(SkRRect::kUpperRight_Corner)));
     63     result.append(this->makePoint(rrect.radii(SkRRect::kLowerRight_Corner)));
     64     result.append(this->makePoint(rrect.radii(SkRRect::kLowerLeft_Corner)));
     65     return result;
     66 }
     67 
     68 Json::Value SkJSONCanvas::makePath(const SkPath& path) {
     69     Json::Value result(Json::objectValue);
     70     switch (path.getFillType()) {
     71         case SkPath::kWinding_FillType:
     72             result[SKJSONCANVAS_ATTRIBUTE_FILLTYPE] = SKJSONCANVAS_FILLTYPE_WINDING;
     73             break;
     74         case SkPath::kEvenOdd_FillType:
     75             result[SKJSONCANVAS_ATTRIBUTE_FILLTYPE] = SKJSONCANVAS_FILLTYPE_EVENODD;
     76             break;
     77         case SkPath::kInverseWinding_FillType:
     78             result[SKJSONCANVAS_ATTRIBUTE_FILLTYPE] = SKJSONCANVAS_FILLTYPE_INVERSEWINDING;
     79             break;
     80         case SkPath::kInverseEvenOdd_FillType:
     81             result[SKJSONCANVAS_ATTRIBUTE_FILLTYPE] = SKJSONCANVAS_FILLTYPE_INVERSEEVENODD;
     82             break;
     83     }
     84     Json::Value verbs(Json::arrayValue);
     85     SkPath::Iter iter(path, false);
     86     SkPoint pts[4];
     87     SkPath::Verb verb;
     88     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
     89         switch (verb) {
     90             case SkPath::kLine_Verb: {
     91                 Json::Value line(Json::objectValue);
     92                 line[SKJSONCANVAS_VERB_LINE] = this->makePoint(pts[1]);
     93                 verbs.append(line);
     94                 break;
     95             }
     96             case SkPath::kQuad_Verb: {
     97                 Json::Value quad(Json::objectValue);
     98                 Json::Value coords(Json::arrayValue);
     99                 coords.append(this->makePoint(pts[1]));
    100                 coords.append(this->makePoint(pts[2]));
    101                 quad[SKJSONCANVAS_VERB_QUAD] = coords;
    102                 verbs.append(quad);
    103                 break;
    104             }
    105             case SkPath::kCubic_Verb: {
    106                 Json::Value cubic(Json::objectValue);
    107                 Json::Value coords(Json::arrayValue);
    108                 coords.append(this->makePoint(pts[1]));
    109                 coords.append(this->makePoint(pts[2]));
    110                 coords.append(this->makePoint(pts[3]));
    111                 cubic[SKJSONCANVAS_VERB_CUBIC] = coords;
    112                 verbs.append(cubic);
    113                 break;
    114             }
    115             case SkPath::kConic_Verb: {
    116                 Json::Value conic(Json::objectValue);
    117                 Json::Value coords(Json::arrayValue);
    118                 coords.append(this->makePoint(pts[1]));
    119                 coords.append(this->makePoint(pts[2]));
    120                 coords.append(Json::Value(iter.conicWeight()));
    121                 conic[SKJSONCANVAS_VERB_CONIC] = coords;
    122                 verbs.append(conic);
    123                 break;
    124             }
    125             case SkPath::kMove_Verb: {
    126                 Json::Value move(Json::objectValue);
    127                 move[SKJSONCANVAS_VERB_MOVE] = this->makePoint(pts[0]);
    128                 verbs.append(move);
    129                 break;
    130             }
    131             case SkPath::kClose_Verb:
    132                 verbs.append(Json::Value(SKJSONCANVAS_VERB_CLOSE));
    133                 break;
    134             case SkPath::kDone_Verb:
    135                 break;
    136         }
    137     }
    138     result[SKJSONCANVAS_ATTRIBUTE_VERBS] = verbs;
    139     return result;
    140 }
    141 
    142 Json::Value SkJSONCanvas::makeRegion(const SkRegion& region) {
    143     return Json::Value("<unimplemented>");
    144 }
    145 
    146 static void store_scalar(Json::Value* target, const char* key, SkScalar value,
    147                          SkScalar defaultValue) {
    148     if (value != defaultValue) {
    149         (*target)[key] = Json::Value(value);
    150     }
    151 }
    152 
    153 static void store_bool(Json::Value* target, const char* key, bool value, bool defaultValue) {
    154     if (value != defaultValue) {
    155         (*target)[key] = Json::Value(value);
    156     }
    157 }
    158 
    159 static void encode_data(const void* data, size_t count, Json::Value* target) {
    160     // just use a brain-dead JSON array for now, switch to base64 or something else smarter down the
    161     // road
    162     for (size_t i = 0; i < count; i++) {
    163         target->append(((const uint8_t*)data)[i]);
    164     }
    165 }
    166 
    167 static void flatten(const SkFlattenable* flattenable, Json::Value* target, bool sendBinaries) {
    168     if (sendBinaries) {
    169         SkWriteBuffer buffer;
    170         flattenable->flatten(buffer);
    171         void* data = sk_malloc_throw(buffer.bytesWritten());
    172         buffer.writeToMemory(data);
    173         Json::Value bytes;
    174         encode_data(data, buffer.bytesWritten(), &bytes);
    175         Json::Value jsonFlattenable;
    176         jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_NAME] = Json::Value(flattenable->getTypeName());
    177         jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes;
    178         (*target) = jsonFlattenable;
    179         free(data);
    180     }
    181     else {
    182         (*target)[SKJSONCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(flattenable->getTypeName());
    183     }
    184 }
    185 
    186 static bool SK_WARN_UNUSED_RESULT flatten(const SkImage& image, Json::Value* target,
    187                                           bool sendBinaries) {
    188     if (sendBinaries) {
    189         SkData* encoded = image.encode(SkImageEncoder::kPNG_Type, 100);
    190         if (encoded == nullptr) {
    191             // PNG encode doesn't necessarily support all color formats, convert to a different
    192             // format
    193             size_t rowBytes = 4 * image.width();
    194             void* buffer = sk_malloc_throw(rowBytes * image.height());
    195             SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(),
    196                                                     kN32_SkColorType, kPremul_SkAlphaType);
    197             if (!image.readPixels(dstInfo, buffer, rowBytes, 0, 0)) {
    198                 SkDebugf("readPixels failed\n");
    199                 return false;
    200             }
    201             SkImage* converted = SkImage::NewRasterCopy(dstInfo, buffer, rowBytes);
    202             encoded = converted->encode(SkImageEncoder::kPNG_Type, 100);
    203             if (encoded == nullptr) {
    204                 SkDebugf("image encode failed\n");
    205                 return false;
    206             }
    207             free(converted);
    208             free(buffer);
    209         }
    210         Json::Value bytes;
    211         encode_data(encoded->data(), encoded->size(), &bytes);
    212         (*target)[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes;
    213         encoded->unref();
    214     }
    215     else {
    216         SkString description = SkStringPrintf("%dx%d pixel image", image.width(), image.height());
    217         (*target)[SKJSONCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(description.c_str());
    218     }
    219     return true;
    220 }
    221 
    222 static const char* color_type_name(SkColorType colorType) {
    223     switch (colorType) {
    224         case kARGB_4444_SkColorType:
    225             return SKJSONCANVAS_COLORTYPE_ARGB4444;
    226         case kRGBA_8888_SkColorType:
    227             return SKJSONCANVAS_COLORTYPE_RGBA8888;
    228         case kBGRA_8888_SkColorType:
    229             return SKJSONCANVAS_COLORTYPE_BGRA8888;
    230         case kRGB_565_SkColorType:
    231             return SKJSONCANVAS_COLORTYPE_565;
    232         case kGray_8_SkColorType:
    233             return SKJSONCANVAS_COLORTYPE_GRAY8;
    234         case kIndex_8_SkColorType:
    235             return SKJSONCANVAS_COLORTYPE_INDEX8;
    236         case kAlpha_8_SkColorType:
    237             return SKJSONCANVAS_COLORTYPE_ALPHA8;
    238         default:
    239             SkASSERT(false);
    240             return SKJSONCANVAS_COLORTYPE_RGBA8888;
    241     }
    242 }
    243 
    244 static const char* alpha_type_name(SkAlphaType alphaType) {
    245     switch (alphaType) {
    246         case kOpaque_SkAlphaType:
    247             return SKJSONCANVAS_ALPHATYPE_OPAQUE;
    248         case kPremul_SkAlphaType:
    249             return SKJSONCANVAS_ALPHATYPE_PREMUL;
    250         case kUnpremul_SkAlphaType:
    251             return SKJSONCANVAS_ALPHATYPE_UNPREMUL;
    252         default:
    253             SkASSERT(false);
    254             return SKJSONCANVAS_ALPHATYPE_OPAQUE;
    255     }
    256 }
    257 
    258 static bool SK_WARN_UNUSED_RESULT flatten(const SkBitmap& bitmap, Json::Value* target,
    259                                           bool sendBinaries) {
    260     bitmap.lockPixels();
    261     SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bitmap));
    262     bitmap.unlockPixels();
    263     (*target)[SKJSONCANVAS_ATTRIBUTE_COLOR] = Json::Value(color_type_name(bitmap.colorType()));
    264     (*target)[SKJSONCANVAS_ATTRIBUTE_ALPHA] = Json::Value(alpha_type_name(bitmap.alphaType()));
    265     bool success = flatten(*image, target, sendBinaries);
    266     return success;
    267 }
    268 
    269 static void apply_paint_color(const SkPaint& paint, Json::Value* target) {
    270     SkColor color = paint.getColor();
    271     if (color != SK_ColorBLACK) {
    272         Json::Value colorValue(Json::arrayValue);
    273         colorValue.append(Json::Value(SkColorGetA(color)));
    274         colorValue.append(Json::Value(SkColorGetR(color)));
    275         colorValue.append(Json::Value(SkColorGetG(color)));
    276         colorValue.append(Json::Value(SkColorGetB(color)));
    277         (*target)[SKJSONCANVAS_ATTRIBUTE_COLOR] = colorValue;;
    278     }
    279 }
    280 
    281 static void apply_paint_style(const SkPaint& paint, Json::Value* target) {
    282     SkPaint::Style style = paint.getStyle();
    283     if (style != SkPaint::kFill_Style) {
    284         switch (style) {
    285             case SkPaint::kStroke_Style: {
    286                 Json::Value stroke(SKJSONCANVAS_STYLE_STROKE);
    287                 (*target)[SKJSONCANVAS_ATTRIBUTE_STYLE] = stroke;
    288                 break;
    289             }
    290             case SkPaint::kStrokeAndFill_Style: {
    291                 Json::Value strokeAndFill(SKJSONCANVAS_STYLE_STROKEANDFILL);
    292                 (*target)[SKJSONCANVAS_ATTRIBUTE_STYLE] = strokeAndFill;
    293                 break;
    294             }
    295             default: SkASSERT(false);
    296         }
    297     }
    298 }
    299 
    300 static void apply_paint_cap(const SkPaint& paint, Json::Value* target) {
    301     SkPaint::Cap cap = paint.getStrokeCap();
    302     if (cap != SkPaint::kDefault_Cap) {
    303         switch (cap) {
    304             case SkPaint::kButt_Cap: {
    305                 (*target)[SKJSONCANVAS_ATTRIBUTE_CAP] = Json::Value(SKJSONCANVAS_CAP_BUTT);
    306                 break;
    307             }
    308             case SkPaint::kRound_Cap: {
    309                 (*target)[SKJSONCANVAS_ATTRIBUTE_CAP] = Json::Value(SKJSONCANVAS_CAP_ROUND);
    310                 break;
    311             }
    312             case SkPaint::kSquare_Cap: {
    313                 (*target)[SKJSONCANVAS_ATTRIBUTE_CAP] = Json::Value(SKJSONCANVAS_CAP_SQUARE);
    314                 break;
    315             }
    316             default: SkASSERT(false);
    317         }
    318     }
    319 }
    320 static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
    321     SkMaskFilter* maskFilter = paint.getMaskFilter();
    322     if (maskFilter != nullptr) {
    323         SkMaskFilter::BlurRec blurRec;
    324         if (maskFilter->asABlur(&blurRec)) {
    325             Json::Value blur(Json::objectValue);
    326             blur[SKJSONCANVAS_ATTRIBUTE_SIGMA] = Json::Value(blurRec.fSigma);
    327             switch (blurRec.fStyle) {
    328                 case SkBlurStyle::kNormal_SkBlurStyle:
    329                     blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_NORMAL);
    330                     break;
    331                 case SkBlurStyle::kSolid_SkBlurStyle:
    332                     blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_SOLID);
    333                     break;
    334                 case SkBlurStyle::kOuter_SkBlurStyle:
    335                     blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_OUTER);
    336                     break;
    337                 case SkBlurStyle::kInner_SkBlurStyle:
    338                     blur[SKJSONCANVAS_ATTRIBUTE_STYLE] = Json::Value(SKJSONCANVAS_BLURSTYLE_INNER);
    339                     break;
    340                 default:
    341                     SkASSERT(false);
    342             }
    343             switch (blurRec.fQuality) {
    344                 case SkBlurQuality::kLow_SkBlurQuality:
    345                     blur[SKJSONCANVAS_ATTRIBUTE_QUALITY] = Json::Value(SKJSONCANVAS_BLURQUALITY_LOW);
    346                     break;
    347                 case SkBlurQuality::kHigh_SkBlurQuality:
    348                     blur[SKJSONCANVAS_ATTRIBUTE_QUALITY] = Json::Value(SKJSONCANVAS_BLURQUALITY_HIGH);
    349                     break;
    350                 default:
    351                     SkASSERT(false);
    352             }
    353             (*target)[SKJSONCANVAS_ATTRIBUTE_BLUR] = blur;
    354         }
    355         else {
    356             Json::Value jsonMaskFilter;
    357             flatten(maskFilter, &jsonMaskFilter, sendBinaries);
    358             (*target)[SKJSONCANVAS_ATTRIBUTE_MASKFILTER] = jsonMaskFilter;
    359         }
    360     }
    361 }
    362 
    363 static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
    364     SkPathEffect* pathEffect = paint.getPathEffect();
    365     if (pathEffect != nullptr) {
    366         SkPathEffect::DashInfo dashInfo;
    367         SkPathEffect::DashType dashType = pathEffect->asADash(&dashInfo);
    368         if (dashType == SkPathEffect::kDash_DashType) {
    369             dashInfo.fIntervals = (SkScalar*) sk_malloc_throw(dashInfo.fCount * sizeof(SkScalar));
    370             pathEffect->asADash(&dashInfo);
    371             Json::Value dashing(Json::objectValue);
    372             Json::Value intervals(Json::arrayValue);
    373             for (int32_t i = 0; i < dashInfo.fCount; i++) {
    374                 intervals.append(Json::Value(dashInfo.fIntervals[i]));
    375             }
    376             free(dashInfo.fIntervals);
    377             dashing[SKJSONCANVAS_ATTRIBUTE_INTERVALS] = intervals;
    378             dashing[SKJSONCANVAS_ATTRIBUTE_PHASE] = dashInfo.fPhase;
    379             (*target)[SKJSONCANVAS_ATTRIBUTE_DASHING] = dashing;
    380         }
    381         else {
    382             Json::Value jsonPathEffect;
    383             flatten(pathEffect, &jsonPathEffect, sendBinaries);
    384             (*target)[SKJSONCANVAS_ATTRIBUTE_PATHEFFECT] = jsonPathEffect;
    385         }
    386     }
    387 }
    388 
    389 static void apply_paint_textalign(const SkPaint& paint, Json::Value* target) {
    390     SkPaint::Align textAlign = paint.getTextAlign();
    391     if (textAlign != SkPaint::kLeft_Align) {
    392         switch (textAlign) {
    393             case SkPaint::kCenter_Align: {
    394                 (*target)[SKJSONCANVAS_ATTRIBUTE_TEXTALIGN] = SKJSONCANVAS_ALIGN_CENTER;
    395                 break;
    396             }
    397             case SkPaint::kRight_Align: {
    398                 (*target)[SKJSONCANVAS_ATTRIBUTE_TEXTALIGN] = SKJSONCANVAS_ALIGN_RIGHT;
    399                 break;
    400             }
    401             default: SkASSERT(false);
    402         }
    403     }
    404 }
    405 
    406 static void apply_paint_typeface(const SkPaint& paint, Json::Value* target,
    407                                  bool sendBinaries) {
    408     SkTypeface* typeface = paint.getTypeface();
    409     if (typeface != nullptr) {
    410         if (sendBinaries) {
    411             Json::Value jsonTypeface;
    412             SkDynamicMemoryWStream buffer;
    413             typeface->serialize(&buffer);
    414             void* data = sk_malloc_throw(buffer.bytesWritten());
    415             buffer.copyTo(data);
    416             Json::Value bytes;
    417             encode_data(data, buffer.bytesWritten(), &bytes);
    418             jsonTypeface[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes;
    419             free(data);
    420             (*target)[SKJSONCANVAS_ATTRIBUTE_TYPEFACE] = jsonTypeface;
    421         }
    422     }
    423 }
    424 
    425 static void apply_paint_shader(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
    426     SkFlattenable* shader = paint.getShader();
    427     if (shader != nullptr) {
    428         Json::Value jsonShader;
    429         flatten(shader, &jsonShader, sendBinaries);
    430         (*target)[SKJSONCANVAS_ATTRIBUTE_SHADER] = jsonShader;
    431     }
    432 }
    433 
    434 static void apply_paint_xfermode(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
    435     SkFlattenable* xfermode = paint.getXfermode();
    436     if (xfermode != nullptr) {
    437         Json::Value jsonXfermode;
    438         flatten(xfermode, &jsonXfermode, sendBinaries);
    439         (*target)[SKJSONCANVAS_ATTRIBUTE_XFERMODE] = jsonXfermode;
    440     }
    441 }
    442 
    443 static void apply_paint_imagefilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
    444     SkFlattenable* imageFilter = paint.getImageFilter();
    445     if (imageFilter != nullptr) {
    446         Json::Value jsonImageFilter;
    447         flatten(imageFilter, &jsonImageFilter, sendBinaries);
    448         (*target)[SKJSONCANVAS_ATTRIBUTE_IMAGEFILTER] = jsonImageFilter;
    449     }
    450 }
    451 
    452 static void apply_paint_colorfilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) {
    453     SkFlattenable* colorFilter = paint.getColorFilter();
    454     if (colorFilter != nullptr) {
    455         Json::Value jsonColorFilter;
    456         flatten(colorFilter, &jsonColorFilter, sendBinaries);
    457         (*target)[SKJSONCANVAS_ATTRIBUTE_COLORFILTER] = jsonColorFilter;
    458     }
    459 }
    460 
    461 Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) {
    462     Json::Value result(Json::objectValue);
    463     store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f);
    464     store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEMITER, paint.getStrokeMiter(),
    465                  SkPaintDefaults_MiterLimit);
    466     store_bool(&result, SKJSONCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false);
    467     store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(),
    468                  SkPaintDefaults_TextSize);
    469     store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1);
    470     store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f);
    471     apply_paint_color(paint, &result);
    472     apply_paint_style(paint, &result);
    473     apply_paint_cap(paint, &result);
    474     apply_paint_textalign(paint, &result);
    475     apply_paint_patheffect(paint, &result, fSendBinaries);
    476     apply_paint_maskfilter(paint, &result, fSendBinaries);
    477     apply_paint_shader(paint, &result, fSendBinaries);
    478     apply_paint_xfermode(paint, &result, fSendBinaries);
    479     apply_paint_imagefilter(paint, &result, fSendBinaries);
    480     apply_paint_colorfilter(paint, &result, fSendBinaries);
    481     apply_paint_typeface(paint, &result, fSendBinaries);
    482     return result;
    483 }
    484 
    485 Json::Value SkJSONCanvas::MakeIRect(const SkIRect& rect) {
    486     Json::Value result(Json::arrayValue);
    487     result.append(Json::Value(rect.left()));
    488     result.append(Json::Value(rect.top()));
    489     result.append(Json::Value(rect.right()));
    490     result.append(Json::Value(rect.bottom()));
    491     return result;
    492 }
    493 
    494 Json::Value SkJSONCanvas::MakeMatrix(const SkMatrix& matrix) {
    495     Json::Value result(Json::arrayValue);
    496     Json::Value row1(Json::arrayValue);
    497     row1.append(Json::Value(matrix[0]));
    498     row1.append(Json::Value(matrix[1]));
    499     row1.append(Json::Value(matrix[2]));
    500     result.append(row1);
    501     Json::Value row2(Json::arrayValue);
    502     row2.append(Json::Value(matrix[3]));
    503     row2.append(Json::Value(matrix[4]));
    504     row2.append(Json::Value(matrix[5]));
    505     result.append(row2);
    506     Json::Value row3(Json::arrayValue);
    507     row3.append(Json::Value(matrix[6]));
    508     row3.append(Json::Value(matrix[7]));
    509     row3.append(Json::Value(matrix[8]));
    510     result.append(row3);
    511     return result;
    512 }
    513 
    514 Json::Value SkJSONCanvas::makeRegionOp(SkRegion::Op op) {
    515     switch (op) {
    516         case SkRegion::kDifference_Op:
    517             return Json::Value(SKJSONCANVAS_REGIONOP_DIFFERENCE);
    518         case SkRegion::kIntersect_Op:
    519             return Json::Value(SKJSONCANVAS_REGIONOP_INTERSECT);
    520         case SkRegion::kUnion_Op:
    521             return Json::Value(SKJSONCANVAS_REGIONOP_UNION);
    522         case SkRegion::kXOR_Op:
    523             return Json::Value(SKJSONCANVAS_REGIONOP_XOR);
    524         case SkRegion::kReverseDifference_Op:
    525             return Json::Value(SKJSONCANVAS_REGIONOP_REVERSE_DIFFERENCE);
    526         case SkRegion::kReplace_Op:
    527             return Json::Value(SKJSONCANVAS_REGIONOP_REPLACE);
    528         default:
    529             SkASSERT(false);
    530             return Json::Value("<invalid region op>");
    531     };
    532 }
    533 
    534 Json::Value SkJSONCanvas::makePointMode(SkCanvas::PointMode mode) {
    535     switch (mode) {
    536         case SkCanvas::kPoints_PointMode:
    537             return Json::Value(SKJSONCANVAS_POINTMODE_POINTS);
    538         case SkCanvas::kLines_PointMode:
    539             return Json::Value(SKJSONCANVAS_POINTMODE_LINES);
    540         case SkCanvas::kPolygon_PointMode:
    541             return Json::Value(SKJSONCANVAS_POINTMODE_POLYGON);
    542         default:
    543             SkASSERT(false);
    544             return Json::Value("<invalid point mode>");
    545     };
    546 }
    547 
    548 void SkJSONCanvas::didConcat(const SkMatrix& matrix) {
    549     Json::Value command(Json::objectValue);
    550     switch (matrix.getType()) {
    551         case SkMatrix::kTranslate_Mask:
    552             command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_TRANSLATE);
    553             command[SKJSONCANVAS_ATTRIBUTE_X] = Json::Value(matrix.get(SkMatrix::kMTransX));
    554             command[SKJSONCANVAS_ATTRIBUTE_Y] = Json::Value(matrix.get(SkMatrix::kMTransY));
    555             break;
    556         case SkMatrix::kScale_Mask:
    557             command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_SCALE);
    558             command[SKJSONCANVAS_ATTRIBUTE_X] = Json::Value(matrix.get(SkMatrix::kMScaleX));
    559             command[SKJSONCANVAS_ATTRIBUTE_Y] = Json::Value(matrix.get(SkMatrix::kMScaleY));
    560             break;
    561         default:
    562             this->didSetMatrix(this->getTotalMatrix());
    563             return;
    564     }
    565     fCommands.append(command);
    566 }
    567 
    568 void SkJSONCanvas::didSetMatrix(const SkMatrix& matrix) {
    569     Json::Value command(Json::objectValue);
    570     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_MATRIX);
    571     command[SKJSONCANVAS_ATTRIBUTE_MATRIX] = this->MakeMatrix(matrix);
    572     fCommands.append(command);
    573 }
    574 
    575 void SkJSONCanvas::onDrawPaint(const SkPaint& paint) {
    576     Json::Value command(Json::objectValue);
    577     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_PAINT);
    578     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    579     fCommands.append(command);
    580 }
    581 
    582 void SkJSONCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
    583     Json::Value command(Json::objectValue);
    584     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_RECT);
    585     command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makeRect(rect);
    586     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    587     fCommands.append(command);
    588 }
    589 
    590 void SkJSONCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
    591     Json::Value command(Json::objectValue);
    592     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_OVAL);
    593     command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makeRect(rect);
    594     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    595     fCommands.append(command);
    596 }
    597 
    598 void SkJSONCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
    599     Json::Value command(Json::objectValue);
    600     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_RRECT);
    601     command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makeRRect(rrect);
    602     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    603     fCommands.append(command);
    604 }
    605 
    606 void SkJSONCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
    607     Json::Value command(Json::objectValue);
    608     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_RRECT);
    609     command[SKJSONCANVAS_ATTRIBUTE_INNER] = this->makeRRect(inner);
    610     command[SKJSONCANVAS_ATTRIBUTE_OUTER] = this->makeRRect(outer);
    611     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    612     fCommands.append(command);
    613 }
    614 
    615 void SkJSONCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
    616                                 const SkPaint& paint) {
    617     Json::Value command(Json::objectValue);
    618     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_POINTS);
    619     command[SKJSONCANVAS_ATTRIBUTE_MODE] = this->makePointMode(mode);
    620     Json::Value points(Json::arrayValue);
    621     for (size_t i = 0; i < count; i++) {
    622         points.append(this->makePoint(pts[i]));
    623     }
    624     command[SKJSONCANVAS_ATTRIBUTE_POINTS] = points;
    625     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    626     fCommands.append(command);
    627 }
    628 
    629 void SkJSONCanvas::onDrawVertices(SkCanvas::VertexMode, int vertexCount, const SkPoint vertices[],
    630                                   const SkPoint texs[], const SkColor colors[], SkXfermode*,
    631                                   const uint16_t indices[], int indexCount, const SkPaint&) {
    632     SkDebugf("unsupported: drawVertices\n");
    633     Json::Value command(Json::objectValue);
    634     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_VERTICES);
    635     fCommands.append(command);
    636 }
    637 
    638 void SkJSONCanvas::onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
    639                                int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) {
    640     SkDebugf("unsupported: drawAtlas\n");
    641     Json::Value command(Json::objectValue);
    642     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_ATLAS);
    643     fCommands.append(command);
    644 }
    645 
    646 void SkJSONCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
    647     Json::Value command(Json::objectValue);
    648     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_PATH);
    649     command[SKJSONCANVAS_ATTRIBUTE_PATH] = this->makePath(path);
    650     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    651     fCommands.append(command);
    652 }
    653 
    654 void SkJSONCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy,
    655                                const SkPaint* paint) {
    656     Json::Value encoded;
    657     if (flatten(*image, &encoded, fSendBinaries)) {
    658         Json::Value command(Json::objectValue);
    659         command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_IMAGE);
    660         command[SKJSONCANVAS_ATTRIBUTE_IMAGE] = encoded;
    661         command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makePoint(dx, dy);
    662         if (paint != nullptr) {
    663             command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint);
    664         }
    665         fCommands.append(command);
    666     }
    667 }
    668 
    669 void SkJSONCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
    670                                    const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) {
    671     Json::Value encoded;
    672     if (flatten(*image, &encoded, fSendBinaries)) {
    673         Json::Value command(Json::objectValue);
    674         command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_IMAGERECT);
    675         command[SKJSONCANVAS_ATTRIBUTE_IMAGE] = encoded;
    676         if (src != nullptr) {
    677             command[SKJSONCANVAS_ATTRIBUTE_SRC] = this->makeRect(*src);
    678         }
    679         command[SKJSONCANVAS_ATTRIBUTE_DST] = this->makeRect(dst);
    680         if (paint != nullptr) {
    681             command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint);
    682         }
    683         if (constraint == SkCanvas::kStrict_SrcRectConstraint) {
    684             command[SKJSONCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
    685         }
    686         fCommands.append(command);
    687     }
    688 }
    689 
    690 void SkJSONCanvas::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
    691                                    const SkPaint*) {
    692     SkDebugf("unsupported: drawImageNine\n");
    693     Json::Value command(Json::objectValue);
    694     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_IMAGENINE);
    695     fCommands.append(command);
    696 }
    697 
    698 void SkJSONCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy,
    699                                 const SkPaint* paint) {
    700     Json::Value encoded;
    701     if (flatten(bitmap, &encoded, fSendBinaries)) {
    702         Json::Value command(Json::objectValue);
    703         command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_BITMAP);
    704         command[SKJSONCANVAS_ATTRIBUTE_BITMAP] = encoded;
    705         command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makePoint(dx, dy);
    706         if (paint != nullptr) {
    707             command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint);
    708         }
    709         fCommands.append(command);
    710     }
    711 }
    712 
    713 void SkJSONCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
    714                                    const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) {
    715     Json::Value encoded;
    716     if (flatten(bitmap, &encoded, fSendBinaries)) {
    717         Json::Value command(Json::objectValue);
    718         command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_BITMAPRECT);
    719         command[SKJSONCANVAS_ATTRIBUTE_BITMAP] = encoded;
    720         if (src != nullptr) {
    721             command[SKJSONCANVAS_ATTRIBUTE_SRC] = this->makeRect(*src);
    722         }
    723         command[SKJSONCANVAS_ATTRIBUTE_DST] = this->makeRect(dst);
    724         if (paint != nullptr) {
    725             command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint);
    726         }
    727         if (constraint == SkCanvas::kStrict_SrcRectConstraint) {
    728             command[SKJSONCANVAS_ATTRIBUTE_STRICT] = Json::Value(true);
    729         }
    730         fCommands.append(command);
    731     }
    732 }
    733 
    734 void SkJSONCanvas::onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
    735                                     const SkPaint*) {
    736     SkDebugf("unsupported: drawBitmapNine\n");
    737     Json::Value command(Json::objectValue);
    738     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_BITMAPNINE);
    739     fCommands.append(command);
    740 }
    741 
    742 void SkJSONCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x,
    743                               SkScalar y, const SkPaint& paint) {
    744     Json::Value command(Json::objectValue);
    745     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_TEXT);
    746     command[SKJSONCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) text,
    747                                                        ((const char*) text) + byteLength);
    748     command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makePoint(x, y);
    749     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    750     fCommands.append(command);
    751 }
    752 
    753 void SkJSONCanvas::onDrawPosText(const void* text, size_t byteLength,
    754                                  const SkPoint pos[], const SkPaint& paint) {
    755     Json::Value command(Json::objectValue);
    756     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_POSTEXT);
    757     command[SKJSONCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) text,
    758                                                        ((const char*) text) + byteLength);
    759     Json::Value coords(Json::arrayValue);
    760     for (size_t i = 0; i < byteLength; i++) {
    761         coords.append(this->makePoint(pos[i]));
    762     }
    763     command[SKJSONCANVAS_ATTRIBUTE_COORDS] = coords;
    764     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    765     fCommands.append(command);
    766 }
    767 
    768 void SkJSONCanvas::onDrawPosTextH(const void* text, size_t byteLength,
    769                                   const SkScalar xpos[], SkScalar constY,
    770                                   const SkPaint& paint) {
    771     SkDebugf("unsupported: drawPosTextH\n");
    772     Json::Value command(Json::objectValue);
    773     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_POSTEXTH);
    774     fCommands.append(command);
    775 }
    776 
    777 void SkJSONCanvas::onDrawTextOnPath(const void* text, size_t byteLength,
    778                                     const SkPath& path, const SkMatrix* matrix,
    779                                     const SkPaint& paint) {
    780     Json::Value command(Json::objectValue);
    781     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_TEXTONPATH);
    782     command[SKJSONCANVAS_ATTRIBUTE_TEXT] = Json::Value((const char*) text,
    783                                                        ((const char*) text) + byteLength);
    784     command[SKJSONCANVAS_ATTRIBUTE_PATH] = this->makePath(path);
    785     if (matrix != nullptr) {
    786         command[SKJSONCANVAS_ATTRIBUTE_MATRIX] = this->MakeMatrix(*matrix);
    787     }
    788     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    789     fCommands.append(command);
    790 }
    791 
    792 void SkJSONCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
    793                                   const SkPaint& paint) {
    794     Json::Value command(Json::objectValue);
    795     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_TEXTBLOB);
    796     Json::Value runs(Json::arrayValue);
    797     SkTextBlobRunIterator iter(blob);
    798     while (!iter.done()) {
    799         Json::Value run(Json::objectValue);
    800         Json::Value jsonPositions(Json::arrayValue);
    801         Json::Value jsonGlyphs(Json::arrayValue);
    802         const SkScalar* iterPositions = iter.pos();
    803         const uint16_t* iterGlyphs = iter.glyphs();
    804         for (uint32_t i = 0; i < iter.glyphCount(); i++) {
    805             switch (iter.positioning()) {
    806                 case SkTextBlob::kFull_Positioning:
    807                     jsonPositions.append(this->makePoint(iterPositions[i * 2],
    808                                                          iterPositions[i * 2 + 1]));
    809                     break;
    810                 case SkTextBlob::kHorizontal_Positioning:
    811                     jsonPositions.append(Json::Value(iterPositions[i]));
    812                     break;
    813                 case SkTextBlob::kDefault_Positioning:
    814                     break;
    815             }
    816             jsonGlyphs.append(Json::Value(iterGlyphs[i]));
    817         }
    818         if (iter.positioning() != SkTextBlob::kDefault_Positioning) {
    819             run[SKJSONCANVAS_ATTRIBUTE_POSITIONS] = jsonPositions;
    820         }
    821         run[SKJSONCANVAS_ATTRIBUTE_GLYPHS] = jsonGlyphs;
    822         SkPaint fontPaint;
    823         iter.applyFontToPaint(&fontPaint);
    824         run[SKJSONCANVAS_ATTRIBUTE_FONT] = this->makePaint(fontPaint);
    825         run[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makePoint(iter.offset());
    826         runs.append(run);
    827         iter.next();
    828     }
    829     command[SKJSONCANVAS_ATTRIBUTE_RUNS] = runs;
    830     command[SKJSONCANVAS_ATTRIBUTE_X] = Json::Value(x);
    831     command[SKJSONCANVAS_ATTRIBUTE_Y] = Json::Value(y);
    832     command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(paint);
    833     fCommands.append(command);
    834 }
    835 
    836 void SkJSONCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
    837                                const SkPoint texCoords[4], SkXfermode* xmode,
    838                                const SkPaint& paint) {
    839     SkDebugf("unsupported: drawPatch\n");
    840     Json::Value command(Json::objectValue);
    841     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_PATCH);
    842     fCommands.append(command);
    843 }
    844 
    845 void SkJSONCanvas::onDrawDrawable(SkDrawable*, const SkMatrix*) {
    846     SkDebugf("unsupported: drawDrawable\n");
    847     Json::Value command(Json::objectValue);
    848     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_DRAWABLE);
    849     fCommands.append(command);
    850 }
    851 
    852 void SkJSONCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    853     Json::Value command(Json::objectValue);
    854     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_CLIPRECT);
    855     command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makeRect(rect);
    856     command[SKJSONCANVAS_ATTRIBUTE_REGIONOP] = this->makeRegionOp(op);
    857     command[SKJSONCANVAS_ATTRIBUTE_ANTIALIAS] = (edgeStyle == SkCanvas::kSoft_ClipEdgeStyle);
    858     fCommands.append(command);
    859 }
    860 
    861 void SkJSONCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    862     Json::Value command(Json::objectValue);
    863     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_CLIPRRECT);
    864     command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makeRRect(rrect);
    865     command[SKJSONCANVAS_ATTRIBUTE_REGIONOP] = this->makeRegionOp(op);
    866     command[SKJSONCANVAS_ATTRIBUTE_ANTIALIAS] = (edgeStyle == SkCanvas::kSoft_ClipEdgeStyle);
    867     fCommands.append(command);
    868 }
    869 
    870 void SkJSONCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    871     Json::Value command(Json::objectValue);
    872     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_CLIPPATH);
    873     command[SKJSONCANVAS_ATTRIBUTE_PATH] = this->makePath(path);
    874     command[SKJSONCANVAS_ATTRIBUTE_REGIONOP] = this->makeRegionOp(op);
    875     command[SKJSONCANVAS_ATTRIBUTE_ANTIALIAS] = (edgeStyle == SkCanvas::kSoft_ClipEdgeStyle);
    876     fCommands.append(command);
    877 }
    878 
    879 void SkJSONCanvas::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
    880     Json::Value command(Json::objectValue);
    881     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_CLIPREGION);
    882     command[SKJSONCANVAS_ATTRIBUTE_REGION] = this->makeRegion(deviceRgn);
    883     command[SKJSONCANVAS_ATTRIBUTE_REGIONOP] = this->makeRegionOp(op);
    884     fCommands.append(command);
    885 }
    886 
    887 void SkJSONCanvas::willSave() {
    888     Json::Value command(Json::objectValue);
    889     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_SAVE);
    890     fCommands.append(command);
    891 }
    892 
    893 void SkJSONCanvas::willRestore() {
    894     Json::Value command(Json::objectValue);
    895     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_RESTORE);
    896     fCommands.append(command);
    897 }
    898 
    899 SkCanvas::SaveLayerStrategy SkJSONCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
    900     Json::Value command(Json::objectValue);
    901     command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_SAVELAYER);
    902     if (rec.fBounds != nullptr) {
    903         command[SKJSONCANVAS_ATTRIBUTE_BOUNDS] = this->makeRect(*rec.fBounds);
    904     }
    905     if (rec.fPaint != nullptr) {
    906         command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*rec.fPaint);
    907     }
    908     if (rec.fBackdrop != nullptr) {
    909         Json::Value backdrop;
    910         flatten(rec.fBackdrop, &backdrop, fSendBinaries);
    911         command[SKJSONCANVAS_ATTRIBUTE_BACKDROP] = backdrop;
    912     }
    913     if (rec.fSaveLayerFlags != 0) {
    914         SkDebugf("unsupported: saveLayer flags\n");
    915     }
    916     fCommands.append(command);
    917     return this->INHERITED::getSaveLayerStrategy(rec);
    918 }
    919