aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/json
diff options
context:
space:
mode:
authorGravatar ethannicholas <ethannicholas@google.com>2016-02-02 08:36:58 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-02 08:36:58 -0800
commit30c5dde90d099c7651b5f77f5b1b7a485fd69dc9 (patch)
tree4643c0e61e4d94930dc7438e58553b65701978a7 /tools/json
parent2ea6ff7f0d2f8f578460de8dd4e2e4ad3eed6e4c (diff)
support for more features when rendering to/from JSON
Diffstat (limited to 'tools/json')
-rw-r--r--tools/json/SkJSONCanvas.cpp264
-rw-r--r--tools/json/SkJSONCanvas.h26
-rw-r--r--tools/json/SkJSONRenderer.cpp357
3 files changed, 601 insertions, 46 deletions
diff --git a/tools/json/SkJSONCanvas.cpp b/tools/json/SkJSONCanvas.cpp
index 106b59ff56..efc4acd1a3 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);
+}
diff --git a/tools/json/SkJSONCanvas.h b/tools/json/SkJSONCanvas.h
index 27cb398a36..76d1be0ac5 100644
--- a/tools/json/SkJSONCanvas.h
+++ b/tools/json/SkJSONCanvas.h
@@ -45,9 +45,11 @@
#define SKJSONCANVAS_COMMAND_CLIPREGION "ClipRegion"
#define SKJSONCANVAS_COMMAND_SAVE "Save"
#define SKJSONCANVAS_COMMAND_RESTORE "Restore"
+#define SKJSONCANVAS_COMMAND_SAVELAYER "SaveLayer"
#define SKJSONCANVAS_ATTRIBUTE_MATRIX "matrix"
#define SKJSONCANVAS_ATTRIBUTE_COORDS "coords"
+#define SKJSONCANVAS_ATTRIBUTE_BOUNDS "bounds"
#define SKJSONCANVAS_ATTRIBUTE_PAINT "paint"
#define SKJSONCANVAS_ATTRIBUTE_OUTER "outer"
#define SKJSONCANVAS_ATTRIBUTE_INNER "inner"
@@ -58,6 +60,8 @@
#define SKJSONCANVAS_ATTRIBUTE_COLOR "color"
#define SKJSONCANVAS_ATTRIBUTE_STYLE "style"
#define SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH "strokeWidth"
+#define SKJSONCANVAS_ATTRIBUTE_STROKEMITER "strokeMiter"
+#define SKJSONCANVAS_ATTRIBUTE_CAP "cap"
#define SKJSONCANVAS_ATTRIBUTE_ANTIALIAS "antiAlias"
#define SKJSONCANVAS_ATTRIBUTE_REGION "region"
#define SKJSONCANVAS_ATTRIBUTE_REGIONOP "op"
@@ -75,6 +79,19 @@
#define SKJSONCANVAS_ATTRIBUTE_PHASE "phase"
#define SKJSONCANVAS_ATTRIBUTE_FILLTYPE "fillType"
#define SKJSONCANVAS_ATTRIBUTE_VERBS "verbs"
+#define SKJSONCANVAS_ATTRIBUTE_NAME "name"
+#define SKJSONCANVAS_ATTRIBUTE_BYTES "bytes"
+#define SKJSONCANVAS_ATTRIBUTE_SHADER "shader"
+#define SKJSONCANVAS_ATTRIBUTE_PATHEFFECT "pathEffect"
+#define SKJSONCANVAS_ATTRIBUTE_MASKFILTER "maskFilter"
+#define SKJSONCANVAS_ATTRIBUTE_XFERMODE "xfermode"
+#define SKJSONCANVAS_ATTRIBUTE_BACKDROP "backdrop"
+#define SKJSONCANVAS_ATTRIBUTE_IMAGE "image"
+#define SKJSONCANVAS_ATTRIBUTE_BITMAP "bitmap"
+#define SKJSONCANVAS_ATTRIBUTE_SRC "src"
+#define SKJSONCANVAS_ATTRIBUTE_DST "dst"
+#define SKJSONCANVAS_ATTRIBUTE_STRICT "strict"
+#define SKJSONCANVAS_ATTRIBUTE_DESCRIPTION "description"
#define SKJSONCANVAS_VERB_MOVE "move"
#define SKJSONCANVAS_VERB_LINE "line"
@@ -115,6 +132,10 @@
#define SKJSONCANVAS_FILLTYPE_INVERSEWINDING "inverseWinding"
#define SKJSONCANVAS_FILLTYPE_INVERSEEVENODD "inverseEvenOdd"
+#define SKJSONCANVAS_CAP_BUTT "butt"
+#define SKJSONCANVAS_CAP_ROUND "round"
+#define SKJSONCANVAS_CAP_SQUARE "square"
+
/*
* Implementation of SkCanvas which writes JSON when drawn to. The JSON describes all of the draw
* commands issued to the canvas, and can later be turned back into draw commands using
@@ -123,7 +144,7 @@
class SkJSONCanvas : public SkCanvas {
public:
/* Create a canvas which writes to the specified output stream. */
- SkJSONCanvas(int width, int height, SkWStream& out);
+ SkJSONCanvas(int width, int height, SkWStream& out, bool sendBinaries = false);
/* Complete the JSON document. */
void finish();
@@ -202,6 +223,8 @@ public:
void willRestore() override;
+ SkCanvas::SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override;
+
private:
Json::Value makePoint(const SkPoint& point);
@@ -231,6 +254,7 @@ private:
SkMatrix fLastMatrix;
Json::Value fRoot;
Json::Value fCommands;
+ bool fSendBinaries;
typedef SkCanvas INHERITED;
};
diff --git a/tools/json/SkJSONRenderer.cpp b/tools/json/SkJSONRenderer.cpp
index a830fe0fb5..734ce116b4 100644
--- a/tools/json/SkJSONRenderer.cpp
+++ b/tools/json/SkJSONRenderer.cpp
@@ -12,6 +12,7 @@
#include "SkJSONCanvas.h"
#include "SkJSONCPP.h"
#include "SkPath.h"
+#include "SkValidatingReadBuffer.h"
namespace SkJSONRenderer {
@@ -35,6 +36,8 @@ public:
void processRestore(Json::Value& command, SkCanvas* target);
+ void processSaveLayer(Json::Value& command, SkCanvas* target);
+
void processPaint(Json::Value& command, SkCanvas* target);
void processRect(Json::Value& command, SkCanvas* target);
@@ -51,6 +54,14 @@ public:
void processPoints(Json::Value& command, SkCanvas* target);
+ void processImage(Json::Value& command, SkCanvas* target);
+
+ void processImageRect(Json::Value& command, SkCanvas* target);
+
+ void processBitmap(Json::Value& command, SkCanvas* target);
+
+ void processBitmapRect(Json::Value& command, SkCanvas* target);
+
void processClipRect(Json::Value& command, SkCanvas* target);
void processClipRRect(Json::Value& command, SkCanvas* target);
@@ -70,6 +81,9 @@ void Renderer::processCommand(Json::Value& command, SkCanvas* target) {
else if (!strcmp(name, SKJSONCANVAS_COMMAND_RESTORE)) {
this->processRestore(command, target);
}
+ else if (!strcmp(name, SKJSONCANVAS_COMMAND_SAVELAYER)) {
+ this->processSaveLayer(command, target);
+ }
else if (!strcmp(name, SKJSONCANVAS_COMMAND_PAINT)) {
this->processPaint(command, target);
}
@@ -94,6 +108,18 @@ void Renderer::processCommand(Json::Value& command, SkCanvas* target) {
else if (!strcmp(name, SKJSONCANVAS_COMMAND_POINTS)) {
this->processPoints(command, target);
}
+ else if (!strcmp(name, SKJSONCANVAS_COMMAND_IMAGE)) {
+ this->processImage(command, target);
+ }
+ else if (!strcmp(name, SKJSONCANVAS_COMMAND_IMAGERECT)) {
+ this->processImageRect(command, target);
+ }
+ else if (!strcmp(name, SKJSONCANVAS_COMMAND_BITMAP)) {
+ this->processBitmap(command, target);
+ }
+ else if (!strcmp(name, SKJSONCANVAS_COMMAND_BITMAPRECT)) {
+ this->processBitmapRect(command, target);
+ }
else if (!strcmp(name, SKJSONCANVAS_COMMAND_CLIPRECT)) {
this->processClipRect(command, target);
}
@@ -108,32 +134,171 @@ void Renderer::processCommand(Json::Value& command, SkCanvas* target) {
}
}
-void Renderer::getPaint(Json::Value& command, SkPaint* result) {
- Json::Value jsonPaint = command[SKJSONCANVAS_ATTRIBUTE_PAINT];
+static void apply_paint_color(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_COLOR)) {
Json::Value color = jsonPaint[SKJSONCANVAS_ATTRIBUTE_COLOR];
- result->setColor(SkColorSetARGB(color[0].asInt(), color[1].asInt(), color[2].asInt(),
+ target->setColor(SkColorSetARGB(color[0].asInt(), color[1].asInt(), color[2].asInt(),
color[3].asInt()));
}
+}
+
+// note that the caller is responsible for freeing the pointer
+static Json::ArrayIndex decode_data(Json::Value bytes, void** target) {
+ Json::ArrayIndex size = bytes.size();
+ *target = sk_malloc_throw(size);
+ for (Json::ArrayIndex i = 0; i < size; i++) {
+ ((uint8_t*) *target)[i] = bytes[i].asInt();
+ }
+ return size;
+}
+
+static SkFlattenable* load_flattenable(Json::Value jsonFlattenable) {
+ if (!jsonFlattenable.isMember(SKJSONCANVAS_ATTRIBUTE_NAME)) {
+ return nullptr;
+ }
+ const char* name = jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_NAME].asCString();
+ SkFlattenable::Factory factory = SkFlattenable::NameToFactory(name);
+ if (factory == nullptr) {
+ return nullptr;
+ }
+ void* data;
+ int size = decode_data(jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_BYTES], &data);
+ SkValidatingReadBuffer buffer(data, size);
+ SkFlattenable* result = factory(buffer);
+ free(data);
+ if (!buffer.isValid()) {
+ return nullptr;
+ }
+ return result;
+}
+
+// caller is responsible for freeing return value
+static SkBitmap* load_bitmap(Json::Value jsonBitmap) {
+ if (!jsonBitmap.isMember(SKJSONCANVAS_ATTRIBUTE_BYTES)) {
+ return nullptr;
+ }
+ void* data;
+ int size = decode_data(jsonBitmap[SKJSONCANVAS_ATTRIBUTE_BYTES], &data);
+ SkMemoryStream stream(data, size);
+ SkImageDecoder* decoder = SkImageDecoder::Factory(&stream);
+ SkBitmap* bitmap = new SkBitmap();
+ SkImageDecoder::Result result = decoder->decode(&stream, bitmap,
+ SkImageDecoder::kDecodePixels_Mode);
+ free(decoder);
+ if (result != SkImageDecoder::kFailure) {
+ free(data);
+ return bitmap;
+ }
+ SkDebugf("image decode failed");
+ free(data);
+ return nullptr;
+}
+
+static SkImage* load_image(Json::Value jsonImage) {
+ SkBitmap* bitmap = load_bitmap(jsonImage);
+ if (bitmap == nullptr) {
+ return nullptr;
+ }
+ SkImage* result = SkImage::NewFromBitmap(*bitmap);
+ free(bitmap);
+ return result;
+}
+
+static void apply_paint_shader(Json::Value& jsonPaint, SkPaint* target) {
+ if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_SHADER)) {
+ Json::Value jsonShader = jsonPaint[SKJSONCANVAS_ATTRIBUTE_SHADER];
+ SkShader* shader = (SkShader*) load_flattenable(jsonShader);
+ if (shader != nullptr) {
+ target->setShader(shader);
+ shader->unref();
+ }
+ }
+}
+
+static void apply_paint_patheffect(Json::Value& jsonPaint, SkPaint* target) {
+ if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_PATHEFFECT)) {
+ Json::Value jsonPathEffect = jsonPaint[SKJSONCANVAS_ATTRIBUTE_PATHEFFECT];
+ SkPathEffect* pathEffect = (SkPathEffect*) load_flattenable(jsonPathEffect);
+ if (pathEffect != nullptr) {
+ target->setPathEffect(pathEffect);
+ pathEffect->unref();
+ }
+ }
+}
+
+static void apply_paint_maskfilter(Json::Value& jsonPaint, SkPaint* target) {
+ if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_MASKFILTER)) {
+ Json::Value jsonMaskFilter = jsonPaint[SKJSONCANVAS_ATTRIBUTE_MASKFILTER];
+ SkMaskFilter* maskFilter = (SkMaskFilter*) load_flattenable(jsonMaskFilter);
+ if (maskFilter != nullptr) {
+ target->setMaskFilter(maskFilter);
+ maskFilter->unref();
+ }
+ }
+}
+
+static void apply_paint_xfermode(Json::Value& jsonPaint, SkPaint* target) {
+ if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_XFERMODE)) {
+ Json::Value jsonXfermode = jsonPaint[SKJSONCANVAS_ATTRIBUTE_XFERMODE];
+ SkXfermode* xfermode = (SkXfermode*) load_flattenable(jsonXfermode);
+ if (xfermode != nullptr) {
+ target->setXfermode(xfermode);
+ xfermode->unref();
+ }
+ }
+}
+
+static void apply_paint_style(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_STYLE)) {
const char* style = jsonPaint[SKJSONCANVAS_ATTRIBUTE_STYLE].asCString();
if (!strcmp(style, SKJSONCANVAS_STYLE_FILL)) {
- result->setStyle(SkPaint::kFill_Style);
+ target->setStyle(SkPaint::kFill_Style);
}
else if (!strcmp(style, SKJSONCANVAS_STYLE_STROKE)) {
- result->setStyle(SkPaint::kStroke_Style);
+ target->setStyle(SkPaint::kStroke_Style);
}
else if (!strcmp(style, SKJSONCANVAS_STYLE_STROKEANDFILL)) {
- result->setStyle(SkPaint::kStrokeAndFill_Style);
+ target->setStyle(SkPaint::kStrokeAndFill_Style);
}
}
+}
+
+static void apply_paint_strokewidth(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH)) {
float strokeWidth = jsonPaint[SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH].asFloat();
- result->setStrokeWidth(strokeWidth);
+ target->setStrokeWidth(strokeWidth);
+ }
+}
+
+static void apply_paint_strokemiter(Json::Value& jsonPaint, SkPaint* target) {
+ if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_STROKEMITER)) {
+ float strokeMiter = jsonPaint[SKJSONCANVAS_ATTRIBUTE_STROKEMITER].asFloat();
+ target->setStrokeMiter(strokeMiter);
+ }
+}
+
+static void apply_paint_cap(Json::Value& jsonPaint, SkPaint* target) {
+ if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_CAP)) {
+ const char* cap = jsonPaint[SKJSONCANVAS_ATTRIBUTE_CAP].asCString();
+ if (!strcmp(cap, SKJSONCANVAS_CAP_BUTT)) {
+ target->setStrokeCap(SkPaint::kButt_Cap);
+ }
+ else if (!strcmp(cap, SKJSONCANVAS_CAP_ROUND)) {
+ target->setStrokeCap(SkPaint::kRound_Cap);
+ }
+ else if (!strcmp(cap, SKJSONCANVAS_CAP_SQUARE)) {
+ target->setStrokeCap(SkPaint::kSquare_Cap);
+ }
}
+}
+
+static void apply_paint_antialias(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_ANTIALIAS)) {
- result->setAntiAlias(jsonPaint[SKJSONCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
+ target->setAntiAlias(jsonPaint[SKJSONCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
}
+}
+
+static void apply_paint_blur(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_BLUR)) {
Json::Value blur = jsonPaint[SKJSONCANVAS_ATTRIBUTE_BLUR];
SkScalar sigma = blur[SKJSONCANVAS_ATTRIBUTE_SIGMA].asFloat();
@@ -167,8 +332,11 @@ void Renderer::getPaint(Json::Value& command, SkPaint* result) {
SkASSERT(false);
flags = SkBlurMaskFilter::BlurFlags::kNone_BlurFlag;
}
- result->setMaskFilter(SkBlurMaskFilter::Create(style, sigma, flags));
+ target->setMaskFilter(SkBlurMaskFilter::Create(style, sigma, flags));
}
+}
+
+static void apply_paint_dashing(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_DASHING)) {
Json::Value dash = jsonPaint[SKJSONCANVAS_ATTRIBUTE_DASHING];
Json::Value jsonIntervals = dash[SKJSONCANVAS_ATTRIBUTE_INTERVALS];
@@ -178,9 +346,12 @@ void Renderer::getPaint(Json::Value& command, SkPaint* result) {
intervals[i] = jsonIntervals[i].asFloat();
}
SkScalar phase = dash[SKJSONCANVAS_ATTRIBUTE_PHASE].asFloat();
- result->setPathEffect(SkDashPathEffect::Create(intervals, count, phase));
+ target->setPathEffect(SkDashPathEffect::Create(intervals, count, phase));
free(intervals);
}
+}
+
+static void apply_paint_textalign(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_TEXTALIGN)) {
SkPaint::Align textAlign;
const char* jsonAlign = jsonPaint[SKJSONCANVAS_ATTRIBUTE_TEXTALIGN].asCString();
@@ -197,22 +368,51 @@ void Renderer::getPaint(Json::Value& command, SkPaint* result) {
SkASSERT(false);
textAlign = SkPaint::kLeft_Align;
}
- result->setTextAlign(textAlign);
+ target->setTextAlign(textAlign);
}
+}
+
+static void apply_paint_textsize(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_TEXTSIZE)) {
float textSize = jsonPaint[SKJSONCANVAS_ATTRIBUTE_TEXTSIZE].asFloat();
- result->setTextSize(textSize);
+ target->setTextSize(textSize);
}
+}
+
+static void apply_paint_textscalex(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX)) {
float textScaleX = jsonPaint[SKJSONCANVAS_ATTRIBUTE_TEXTSCALEX].asFloat();
- result->setTextScaleX(textScaleX);
+ target->setTextScaleX(textScaleX);
}
+}
+
+static void apply_paint_textskewx(Json::Value& jsonPaint, SkPaint* target) {
if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_TEXTSKEWX)) {
float textSkewX = jsonPaint[SKJSONCANVAS_ATTRIBUTE_TEXTSKEWX].asFloat();
- result->setTextSkewX(textSkewX);
+ target->setTextSkewX(textSkewX);
}
}
+void Renderer::getPaint(Json::Value& command, SkPaint* result) {
+ Json::Value jsonPaint = command[SKJSONCANVAS_ATTRIBUTE_PAINT];
+ apply_paint_color(jsonPaint, result);
+ apply_paint_shader(jsonPaint, result);
+ apply_paint_patheffect(jsonPaint, result);
+ apply_paint_maskfilter(jsonPaint, result);
+ apply_paint_xfermode(jsonPaint, result);
+ apply_paint_style(jsonPaint, result);
+ apply_paint_strokewidth(jsonPaint, result);
+ apply_paint_strokemiter(jsonPaint, result);
+ apply_paint_cap(jsonPaint, result);
+ apply_paint_antialias(jsonPaint, result);
+ apply_paint_blur(jsonPaint, result);
+ apply_paint_dashing(jsonPaint, result);
+ apply_paint_textalign(jsonPaint, result);
+ apply_paint_textsize(jsonPaint, result);
+ apply_paint_textscalex(jsonPaint, result);
+ apply_paint_textskewx(jsonPaint, result);
+}
+
void Renderer::getRect(Json::Value& command, const char* name, SkRect* result) {
Json::Value rect = command[name];
result->set(rect[0].asFloat(), rect[1].asFloat(), rect[2].asFloat(), rect[3].asFloat());
@@ -330,6 +530,27 @@ void Renderer::processRestore(Json::Value& command, SkCanvas* target) {
target->restore();
}
+void Renderer::processSaveLayer(Json::Value& command, SkCanvas* target) {
+ SkCanvas::SaveLayerRec rec;
+ SkRect bounds;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_BOUNDS)) {
+ this->getRect(command, SKJSONCANVAS_ATTRIBUTE_BOUNDS, &bounds);
+ rec.fBounds = &bounds;
+ }
+ SkPaint paint;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_PAINT)) {
+ this->getPaint(command, &paint);
+ rec.fPaint = &paint;
+ }
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_BACKDROP)) {
+ rec.fBackdrop = (SkImageFilter*) load_flattenable(command[SKJSONCANVAS_ATTRIBUTE_BACKDROP]);
+ }
+ target->saveLayer(rec);
+ if (rec.fBackdrop != nullptr) {
+ rec.fBackdrop->unref();
+ }
+}
+
void Renderer::processPaint(Json::Value& command, SkCanvas* target) {
SkPaint paint;
this->getPaint(command, &paint);
@@ -440,6 +661,114 @@ void Renderer::processClipPath(Json::Value& command, SkCanvas* target) {
command[SKJSONCANVAS_ATTRIBUTE_ANTIALIAS].asBool());
}
+void Renderer::processImage(Json::Value& command, SkCanvas* target) {
+ SkImage* image = load_image(command[SKJSONCANVAS_ATTRIBUTE_IMAGE]);
+ if (image == nullptr) {
+ return;
+ }
+ Json::Value point = command[SKJSONCANVAS_ATTRIBUTE_COORDS];
+ SkPaint* paintPtr;
+ SkPaint paint;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_PAINT)) {
+ this->getPaint(command, &paint);
+ paintPtr = &paint;
+ }
+ else {
+ paintPtr = nullptr;
+ }
+ target->drawImage(image, point[0].asFloat(), point[1].asFloat(), paintPtr);
+ image->unref();
+}
+
+void Renderer::processImageRect(Json::Value& command, SkCanvas* target) {
+ SkImage* image = load_image(command[SKJSONCANVAS_ATTRIBUTE_IMAGE]);
+ if (image == nullptr) {
+ return;
+ }
+ SkRect dst;
+ this->getRect(command, SKJSONCANVAS_ATTRIBUTE_DST, &dst);
+ SkPaint* paintPtr;
+ SkPaint paint;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_PAINT)) {
+ this->getPaint(command, &paint);
+ paintPtr = &paint;
+ }
+ else {
+ paintPtr = nullptr;
+ }
+ SkCanvas::SrcRectConstraint constraint;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_STRICT) &&
+ command[SKJSONCANVAS_ATTRIBUTE_STRICT].asBool()) {
+ constraint = SkCanvas::kStrict_SrcRectConstraint;
+ }
+ else {
+ constraint = SkCanvas::kFast_SrcRectConstraint;
+ }
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_SRC)) {
+ SkRect src;
+ this->getRect(command, SKJSONCANVAS_ATTRIBUTE_SRC, &src);
+ target->drawImageRect(image, src, dst, paintPtr, constraint);
+ }
+ else {
+ target->drawImageRect(image, dst, paintPtr, constraint);
+ }
+ image->unref();
+}
+
+void Renderer::processBitmap(Json::Value& command, SkCanvas* target) {
+ SkImage* image = load_image(command[SKJSONCANVAS_ATTRIBUTE_BITMAP]);
+ if (image == nullptr) {
+ return;
+ }
+ Json::Value point = command[SKJSONCANVAS_ATTRIBUTE_COORDS];
+ SkPaint* paintPtr;
+ SkPaint paint;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_PAINT)) {
+ this->getPaint(command, &paint);
+ paintPtr = &paint;
+ }
+ else {
+ paintPtr = nullptr;
+ }
+ target->drawImage(image, point[0].asFloat(), point[1].asFloat(), paintPtr);
+ image->unref();
+}
+
+void Renderer::processBitmapRect(Json::Value& command, SkCanvas* target) {
+ SkBitmap* bitmap = load_bitmap(command[SKJSONCANVAS_ATTRIBUTE_BITMAP]);
+ if (bitmap == nullptr) {
+ return;
+ }
+ SkRect dst;
+ this->getRect(command, SKJSONCANVAS_ATTRIBUTE_DST, &dst);
+ SkPaint* paintPtr;
+ SkPaint paint;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_PAINT)) {
+ this->getPaint(command, &paint);
+ paintPtr = &paint;
+ }
+ else {
+ paintPtr = nullptr;
+ }
+ SkCanvas::SrcRectConstraint constraint;
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_STRICT) &&
+ command[SKJSONCANVAS_ATTRIBUTE_STRICT].asBool()) {
+ constraint = SkCanvas::kStrict_SrcRectConstraint;
+ }
+ else {
+ constraint = SkCanvas::kFast_SrcRectConstraint;
+ }
+ if (command.isMember(SKJSONCANVAS_ATTRIBUTE_SRC)) {
+ SkRect src;
+ this->getRect(command, SKJSONCANVAS_ATTRIBUTE_SRC, &src);
+ target->drawBitmapRect(*bitmap, src, dst, paintPtr, constraint);
+ }
+ else {
+ target->drawBitmapRect(*bitmap, dst, paintPtr, constraint);
+ }
+ free(bitmap);
+}
+
void render(const char* json, SkCanvas* target) {
Renderer renderer;
Json::Reader reader;