Index: tools/json/SkJSONCanvas.cpp |
diff --git a/tools/json/SkJSONCanvas.cpp b/tools/json/SkJSONCanvas.cpp |
index 106b59ff563f77443f4d14079184a0cdc33b78eb..efc4acd1a319013a84a8611a65e4b962d3ee9faa 100644 |
--- a/tools/json/SkJSONCanvas.cpp |
+++ b/tools/json/SkJSONCanvas.cpp |
@@ -6,17 +6,20 @@ |
*/ |
#include "SkJSONCanvas.h" |
+#include "SkImageFilter.h" |
#include "SkMaskFilter.h" |
#include "SkPaintDefaults.h" |
#include "SkPath.h" |
#include "SkPathEffect.h" |
#include "SkRRect.h" |
+#include "SkWriteBuffer.h" |
-SkJSONCanvas::SkJSONCanvas(int width, int height, SkWStream& out) |
+SkJSONCanvas::SkJSONCanvas(int width, int height, SkWStream& out, bool sendBinaries) |
: INHERITED(width, height) |
, fOut(out) |
, fRoot(Json::objectValue) |
- , fCommands(Json::arrayValue) { |
+ , fCommands(Json::arrayValue) |
+ , fSendBinaries(sendBinaries) { |
fRoot[SKJSONCANVAS_VERSION] = Json::Value(1); |
} |
@@ -148,8 +151,62 @@ void store_bool(Json::Value* target, const char* key, bool value, bool defaultVa |
} |
} |
-Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) { |
- Json::Value result(Json::objectValue); |
+static void encode_data(const void* data, size_t count, Json::Value* target) { |
+ // just use a brain-dead JSON array for now, switch to base64 or something else smarter down the |
+ // road |
+ for (size_t i = 0; i < count; i++) { |
+ target->append(((const uint8_t*)data)[i]); |
+ } |
+} |
+ |
+static void flatten(const SkFlattenable* flattenable, Json::Value* target, bool sendBinaries) { |
+ if (sendBinaries) { |
+ SkWriteBuffer buffer; |
+ flattenable->flatten(buffer); |
+ void* data = sk_malloc_throw(buffer.bytesWritten()); |
+ buffer.writeToMemory(data); |
+ Json::Value bytes; |
+ encode_data(data, buffer.bytesWritten(), &bytes); |
+ Json::Value jsonFlattenable; |
+ jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_NAME] = Json::Value(flattenable->getTypeName()); |
+ jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes; |
+ (*target) = jsonFlattenable; |
+ free(data); |
+ } |
+ else { |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(flattenable->getTypeName()); |
+ } |
+} |
+ |
+static bool SK_WARN_UNUSED_RESULT flatten(const SkImage& image, Json::Value* target, |
+ bool sendBinaries) { |
+ if (sendBinaries) { |
+ SkData* png = image.encode(SkImageEncoder::kPNG_Type, 100); |
+ if (png == nullptr) { |
+ SkDebugf("could not encode image\n"); |
+ return false; |
+ } |
+ Json::Value bytes; |
+ encode_data(png->data(), png->size(), &bytes); |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes; |
+ png->unref(); |
+ } |
+ else { |
+ SkString description = SkStringPrintf("%dx%d pixel image", image.width(), image.height()); |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(description.c_str()); |
+ } |
+ return true; |
+} |
+ |
+static bool SK_WARN_UNUSED_RESULT flatten(const SkBitmap& bitmap, Json::Value* target, |
+ bool sendBinaries) { |
+ SkImage* image = SkImage::NewFromBitmap(bitmap); |
+ bool success = flatten(*image, target, sendBinaries); |
+ image->unref(); |
+ 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); |
@@ -157,26 +214,50 @@ Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) { |
colorValue.append(Json::Value(SkColorGetR(color))); |
colorValue.append(Json::Value(SkColorGetG(color))); |
colorValue.append(Json::Value(SkColorGetB(color))); |
- result[SKJSONCANVAS_ATTRIBUTE_COLOR] = colorValue;; |
+ (*target)[SKJSONCANVAS_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(SKJSONCANVAS_STYLE_STROKE); |
- result[SKJSONCANVAS_ATTRIBUTE_STYLE] = stroke; |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_STYLE] = stroke; |
break; |
} |
case SkPaint::kStrokeAndFill_Style: { |
Json::Value strokeAndFill(SKJSONCANVAS_STYLE_STROKEANDFILL); |
- result[SKJSONCANVAS_ATTRIBUTE_STYLE] = strokeAndFill; |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_STYLE] = strokeAndFill; |
break; |
} |
default: SkASSERT(false); |
} |
} |
- store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f); |
- store_bool(&result, SKJSONCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), 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)[SKJSONCANVAS_ATTRIBUTE_CAP] = Json::Value(SKJSONCANVAS_CAP_BUTT); |
+ break; |
+ } |
+ case SkPaint::kRound_Cap: { |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_CAP] = Json::Value(SKJSONCANVAS_CAP_ROUND); |
+ break; |
+ } |
+ case SkPaint::kSquare_Cap: { |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_CAP] = Json::Value(SKJSONCANVAS_CAP_SQUARE); |
+ break; |
+ } |
+ default: SkASSERT(false); |
+ } |
+ } |
+} |
+static void apply_paint_maskfilter(const SkPaint& paint, Json::Value* target, bool sendBinaries) { |
SkMaskFilter* maskFilter = paint.getMaskFilter(); |
if (maskFilter != nullptr) { |
SkMaskFilter::BlurRec blurRec; |
@@ -209,13 +290,17 @@ Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) { |
default: |
SkASSERT(false); |
} |
- result[SKJSONCANVAS_ATTRIBUTE_BLUR] = blur; |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_BLUR] = blur; |
} |
else { |
- SkDebugf("unimplemented: non-blur maskfilter"); |
- SkASSERT(false); |
+ Json::Value jsonMaskFilter; |
+ flatten(maskFilter, &jsonMaskFilter, sendBinaries); |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_MASKFILTER] = jsonMaskFilter; |
} |
} |
+} |
+ |
+static void apply_paint_patheffect(const SkPaint& paint, Json::Value* target, bool sendBinaries) { |
SkPathEffect* pathEffect = paint.getPathEffect(); |
if (pathEffect != nullptr) { |
SkPathEffect::DashInfo dashInfo; |
@@ -231,31 +316,69 @@ Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) { |
free(dashInfo.fIntervals); |
dashing[SKJSONCANVAS_ATTRIBUTE_INTERVALS] = intervals; |
dashing[SKJSONCANVAS_ATTRIBUTE_PHASE] = dashInfo.fPhase; |
- result[SKJSONCANVAS_ATTRIBUTE_DASHING] = dashing; |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_DASHING] = dashing; |
} |
else { |
- SkDebugf("unimplemented: non-dash patheffect"); |
- SkASSERT(false); |
+ Json::Value jsonPathEffect; |
+ flatten(pathEffect, &jsonPathEffect, sendBinaries); |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_PATHEFFECT] = jsonPathEffect; |
} |
} |
- store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(), |
- SkPaintDefaults_TextSize); |
- store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1); |
- store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f); |
+} |
+ |
+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: { |
- result[SKJSONCANVAS_ATTRIBUTE_TEXTALIGN] = SKJSONCANVAS_ALIGN_CENTER; |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_TEXTALIGN] = SKJSONCANVAS_ALIGN_CENTER; |
break; |
} |
case SkPaint::kRight_Align: { |
- result[SKJSONCANVAS_ATTRIBUTE_TEXTALIGN] = SKJSONCANVAS_ALIGN_RIGHT; |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_TEXTALIGN] = SKJSONCANVAS_ALIGN_RIGHT; |
break; |
} |
default: SkASSERT(false); |
} |
} |
+} |
+ |
+static void apply_paint_shader(const SkPaint& paint, Json::Value* target, bool sendBinaries) { |
+ SkFlattenable* shader = paint.getShader(); |
+ if (shader != nullptr) { |
+ Json::Value jsonShader; |
+ flatten(shader, &jsonShader, sendBinaries); |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_SHADER] = jsonShader; |
+ } |
+} |
+ |
+static void apply_paint_xfermode(const SkPaint& paint, Json::Value* target, bool sendBinaries) { |
+ SkFlattenable* xfermode = paint.getXfermode(); |
+ if (xfermode != nullptr) { |
+ Json::Value jsonXfermode; |
+ flatten(xfermode, &jsonXfermode, sendBinaries); |
+ (*target)[SKJSONCANVAS_ATTRIBUTE_XFERMODE] = jsonXfermode; |
+ } |
+} |
+ |
+Json::Value SkJSONCanvas::makePaint(const SkPaint& paint) { |
+ Json::Value result(Json::objectValue); |
+ store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH, paint.getStrokeWidth(), 0.0f); |
+ store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_STROKEMITER, paint.getStrokeMiter(), |
+ SkPaintDefaults_MiterLimit); |
+ store_bool(&result, SKJSONCANVAS_ATTRIBUTE_ANTIALIAS, paint.isAntiAlias(), false); |
+ store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSIZE, paint.getTextSize(), |
+ SkPaintDefaults_TextSize); |
+ store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextScaleX(), SK_Scalar1); |
+ store_scalar(&result, SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX, paint.getTextSkewX(), 0.0f); |
+ apply_paint_color(paint, &result); |
+ apply_paint_style(paint, &result); |
+ apply_paint_cap(paint, &result); |
+ apply_paint_textalign(paint, &result); |
+ apply_paint_patheffect(paint, &result, fSendBinaries); |
+ apply_paint_maskfilter(paint, &result, fSendBinaries); |
+ apply_paint_shader(paint, &result, fSendBinaries); |
+ apply_paint_xfermode(paint, &result, fSendBinaries); |
return result; |
} |
@@ -403,13 +526,42 @@ void SkJSONCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { |
fCommands.append(command); |
} |
-void SkJSONCanvas::onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) { |
- SkDebugf("unsupported: drawImage\n"); |
+void SkJSONCanvas::onDrawImage(const SkImage* image, SkScalar dx, SkScalar dy, |
+ const SkPaint* paint) { |
+ Json::Value encoded; |
+ if (flatten(*image, &encoded, fSendBinaries)) { |
+ this->updateMatrix(); |
+ Json::Value command(Json::objectValue); |
+ command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_IMAGE); |
+ command[SKJSONCANVAS_ATTRIBUTE_IMAGE] = encoded; |
+ command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makePoint(dx, dy); |
+ if (paint != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint); |
+ } |
+ fCommands.append(command); |
+ } |
} |
-void SkJSONCanvas::onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, |
- SkCanvas::SrcRectConstraint) { |
- SkDebugf("unsupported: drawImageRect\n"); |
+void SkJSONCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, |
+ const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) { |
+ Json::Value encoded; |
+ if (flatten(*image, &encoded, fSendBinaries)) { |
+ this->updateMatrix(); |
+ Json::Value command(Json::objectValue); |
+ command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_IMAGERECT); |
+ command[SKJSONCANVAS_ATTRIBUTE_IMAGE] = encoded; |
+ if (src != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_SRC] = this->makeRect(*src); |
+ } |
+ command[SKJSONCANVAS_ATTRIBUTE_DST] = this->makeRect(dst); |
+ if (paint != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint); |
+ } |
+ if (constraint == SkCanvas::kStrict_SrcRectConstraint) { |
+ command[SKJSONCANVAS_ATTRIBUTE_STRICT] = Json::Value(true); |
+ } |
+ fCommands.append(command); |
+ } |
} |
void SkJSONCanvas::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, |
@@ -417,13 +569,42 @@ void SkJSONCanvas::onDrawImageNine(const SkImage*, const SkIRect& center, const |
SkDebugf("unsupported: drawImageNine\n"); |
} |
-void SkJSONCanvas::onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) { |
- SkDebugf("unsupported: drawBitmap\n"); |
+void SkJSONCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar dx, SkScalar dy, |
+ const SkPaint* paint) { |
+ Json::Value encoded; |
+ if (flatten(bitmap, &encoded, fSendBinaries)) { |
+ this->updateMatrix(); |
+ Json::Value command(Json::objectValue); |
+ command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_BITMAP); |
+ command[SKJSONCANVAS_ATTRIBUTE_BITMAP] = encoded; |
+ command[SKJSONCANVAS_ATTRIBUTE_COORDS] = this->makePoint(dx, dy); |
+ if (paint != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint); |
+ } |
+ fCommands.append(command); |
+ } |
} |
-void SkJSONCanvas::onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, |
- SkCanvas::SrcRectConstraint) { |
- SkDebugf("unsupported: drawBitmapRect\n"); |
+void SkJSONCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, |
+ const SkPaint* paint, SkCanvas::SrcRectConstraint constraint) { |
+ Json::Value encoded; |
+ if (flatten(bitmap, &encoded, fSendBinaries)) { |
+ this->updateMatrix(); |
+ Json::Value command(Json::objectValue); |
+ command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_BITMAPRECT); |
+ command[SKJSONCANVAS_ATTRIBUTE_IMAGE] = encoded; |
+ if (src != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_SRC] = this->makeRect(*src); |
+ } |
+ command[SKJSONCANVAS_ATTRIBUTE_DST] = this->makeRect(dst); |
+ if (paint != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*paint); |
+ } |
+ if (constraint == SkCanvas::kStrict_SrcRectConstraint) { |
+ command[SKJSONCANVAS_ATTRIBUTE_STRICT] = Json::Value(true); |
+ } |
+ fCommands.append(command); |
+ } |
} |
void SkJSONCanvas::onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, |
@@ -537,3 +718,24 @@ void SkJSONCanvas::willRestore() { |
command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_RESTORE); |
fCommands.append(command); |
} |
+ |
+SkCanvas::SaveLayerStrategy SkJSONCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) { |
+ Json::Value command(Json::objectValue); |
+ command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_SAVELAYER); |
+ if (rec.fBounds != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_BOUNDS] = this->makeRect(*rec.fBounds); |
+ } |
+ if (rec.fPaint != nullptr) { |
+ command[SKJSONCANVAS_ATTRIBUTE_PAINT] = this->makePaint(*rec.fPaint); |
+ } |
+ if (rec.fBackdrop != nullptr) { |
+ Json::Value backdrop; |
+ flatten(rec.fBackdrop, &backdrop, fSendBinaries); |
+ command[SKJSONCANVAS_ATTRIBUTE_BACKDROP] = backdrop; |
+ } |
+ if (rec.fSaveLayerFlags != 0) { |
+ SkDebugf("unsupported: saveLayer flags\n"); |
+ } |
+ fCommands.append(command); |
+ return this->INHERITED::getSaveLayerStrategy(rec); |
+} |