From: ethannicholas Date: Tue, 26 Jan 2016 15:47:57 +0000 (-0800) Subject: Initial support for turning Skia draws into a JSON document and vice versa. X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~129^2~2386 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=978d08a4a90d69961bd53811ed3ab222b88e2d30;p=platform%2Fupstream%2FlibSkiaSharp.git Initial support for turning Skia draws into a JSON document and vice versa. GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1636563002 Committed: https://skia.googlesource.com/skia/+/3cb582f688822461efa5a034e18008bf2f11e4f8 Review URL: https://codereview.chromium.org/1636563002 --- diff --git a/gyp/json.gyp b/gyp/json.gyp new file mode 100644 index 0000000..6c12b7c --- /dev/null +++ b/gyp/json.gyp @@ -0,0 +1,26 @@ +# Copyright 2015 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'targets': [ + { + 'target_name': 'json', + 'product_name': 'skia_json', + 'type': 'static_library', + 'standalone_static_library': 1, + 'dependencies': [ + 'core.gyp:core', + 'jsoncpp.gyp:jsoncpp', + ], + 'include_dirs': [ + '../include/utils', + '../src/core', + ], + 'sources': [ + '../tools/json/SkJSONCanvas.cpp', + '../tools/json/SkJSONRenderer.cpp', + ], + }, + ], +} diff --git a/gyp/most.gyp b/gyp/most.gyp index dac0685..22be29b 100644 --- a/gyp/most.gyp +++ b/gyp/most.gyp @@ -82,6 +82,7 @@ [ 'skia_build_server', { 'dependencies': [ 'skiaserve.gyp:skiaserve', + 'json.gyp:json', ], }], ], diff --git a/tools/json/SkJSONCanvas.cpp b/tools/json/SkJSONCanvas.cpp new file mode 100644 index 0000000..f60ee27 --- /dev/null +++ b/tools/json/SkJSONCanvas.cpp @@ -0,0 +1,428 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkJSONCanvas.h" +#include "SkPath.h" +#include "SkRRect.h" +#include "stdio.h" +#include "stdlib.h" + +SkJSONCanvas::SkJSONCanvas(int width, int height, SkWStream& out) + : INHERITED(width, height) + , fOut(out) + , fFirstCommand(true) { + fOut.writeText("{\"" SKJSONCANVAS_VERSION "\":1, \"" SKJSONCANVAS_COMMANDS + "\":["); +} + +void SkJSONCanvas::finish() { + fOut.writeText("]}"); +} + +void SkJSONCanvas::writef(const char* format, ...) { + va_list args; + va_start(args, format); + SkString s; + s.appendVAList(format, args); + fOut.writeText(s.c_str()); +} + +void SkJSONCanvas::open(const char* name) { + if (fFirstCommand) { + fFirstCommand = false; + } + else { + fOut.writeText(","); + } + this->writef("{\"" SKJSONCANVAS_COMMAND "\":\"%s\"", name); +} + +void SkJSONCanvas::close() { + fOut.writeText("}"); +} + +void SkJSONCanvas::writeString(const char* name, const char* text) { + this->writeString(name, text, strlen(text)); +} + +void SkJSONCanvas::writeString(const char* name, const void* text, size_t length) { + // TODO: escaping + this->writef(",\"%s\":\"", name); + fOut.write(text, length); + fOut.writeText("\""); +} + +void SkJSONCanvas::writePoint(const char* name, const SkPoint& point) { + this->writef(",\"%s\":[%f, %f]", name, point.x(), point.y()); +} + +void SkJSONCanvas::writeRect(const char* name, const SkRect& rect) { + this->writef(",\"%s\":[%f, %f, %f, %f]", name, rect.left(), rect.top(), rect.right(), + rect.bottom()); +} + +void SkJSONCanvas::writeRRect(const char* name, const SkRRect& rrect) { + SkRect rect = rrect.rect(); + SkVector corner1 = rrect.radii(SkRRect::kUpperLeft_Corner); + SkVector corner2 = rrect.radii(SkRRect::kUpperRight_Corner); + SkVector corner3 = rrect.radii(SkRRect::kLowerLeft_Corner); + SkVector corner4 = rrect.radii(SkRRect::kLowerRight_Corner); + this->writef(",\"%s\":[[%f, %f, %f, %f],[%f, %f],[%f, %f],[%f, %f],[%f, %f]]", name, + rect.left(), rect.top(), rect.right(), rect.bottom(), corner1.x(), corner1.y(), + corner2.x(), corner2.y(), corner3.x(), corner3.y(), corner4.x(), corner4.y()); +} + +void SkJSONCanvas::writePath(const char* name, const SkPath& path) { + SkString text("["); + SkPath::Iter iter(path, false); + SkPoint pts[4]; + bool first = true; + SkPath::Verb verb; + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + if (first) { + first = false; + } + else { + text.append(","); + } + switch (verb) { + case SkPath::kLine_Verb: + text.appendf("{\"" SKJSONCANVAS_VERB_LINE "\":[%f,%f]}", pts[1].x(), pts[1].y()); + break; + case SkPath::kQuad_Verb: + text.appendf("{\"" SKJSONCANVAS_VERB_QUAD "\":[[%f,%f],[%f,%f]]}", pts[1].x(), + pts[1].y(), pts[2].x(), pts[2].y()); + break; + case SkPath::kCubic_Verb: + text.appendf("{\"" SKJSONCANVAS_VERB_CUBIC "\":[[%f,%f],[%f,%f],[%f,%f]]}", + pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(), pts[3].x(), + pts[3].y()); + break; + case SkPath::kConic_Verb: + text.appendf("{\"" SKJSONCANVAS_VERB_CONIC "\":[[%f,%f],[%f,%f],%f]}", pts[1].x(), + pts[1].y(), pts[2].x(), pts[2].y(), iter.conicWeight()); + break; + case SkPath::kMove_Verb: + text.appendf("{\"" SKJSONCANVAS_VERB_MOVE "\":[%f,%f]}", pts[0].x(), pts[0].y()); + break; + case SkPath::kClose_Verb: + text.appendf("\"" SKJSONCANVAS_VERB_CLOSE "\""); + break; + case SkPath::kDone_Verb: + break; + } + } + text.appendf("]"); + this->writef(",\"" SKJSONCANVAS_ATTRIBUTE_PATH "\":%s", text.c_str()); +} + +void SkJSONCanvas::writeRegion(const char* name, const SkRegion& region) { + this->writef(",\"%s\":\"\"", name); +} + +void SkJSONCanvas::writePaint(const SkPaint& paint) { + this->writef(",\"" SKJSONCANVAS_ATTRIBUTE_PAINT "\":{"); + SkColor color = paint.getColor(); + bool first = true; + if (color != SK_ColorBLACK) { + this->writef("\"" SKJSONCANVAS_ATTRIBUTE_COLOR "\":[%d,%d,%d,%d]", SkColorGetA(color), + SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); + first = false; + } + SkPaint::Style style = paint.getStyle(); + if (style != SkPaint::kFill_Style) { + if (first) { + first = false; + } + else { + fOut.writeText(","); + } + switch (style) { + case SkPaint::kStroke_Style: + fOut.writeText("\"" SKJSONCANVAS_ATTRIBUTE_STYLE "\":\"" + SKJSONCANVAS_STYLE_STROKE "\""); + break; + case SkPaint::kStrokeAndFill_Style: + fOut.writeText("\"" SKJSONCANVAS_ATTRIBUTE_STYLE "\":\"" + SKJSONCANVAS_STYLE_STROKEANDFILL "\""); + break; + default: SkASSERT(false); + } + } + SkScalar strokeWidth = paint.getStrokeWidth(); + if (strokeWidth != 0.0f) { + if (first) { + first = false; + } + else { + fOut.writeText(","); + } + this->writef("\"" SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH "\":%f", strokeWidth); + } + if (paint.isAntiAlias()) { + if (first) { + first = false; + } + else { + fOut.writeText(","); + } + fOut.writeText("\"" SKJSONCANVAS_ATTRIBUTE_ANTIALIAS "\":true"); + } + fOut.writeText("}"); +} + +void SkJSONCanvas::writeMatrix(const char* name, const SkMatrix& matrix) { + this->writef(",\"%s\":[[%f,%f,%f],[%f,%f,%f],[%f,%f,%f]]", name, + matrix[0], matrix[1], matrix[2], + matrix[3], matrix[4], matrix[5], + matrix[6], matrix[7], matrix[8]); +} + +void SkJSONCanvas::writeRegionOp(const char* name, SkRegion::Op op) { + this->writef(",\"%s\":\"", name); + switch (op) { + case SkRegion::kDifference_Op: + fOut.writeText(SKJSONCANVAS_REGIONOP_DIFFERENCE); + break; + case SkRegion::kIntersect_Op: + fOut.writeText(SKJSONCANVAS_REGIONOP_INTERSECT); + break; + case SkRegion::kUnion_Op: + fOut.writeText(SKJSONCANVAS_REGIONOP_UNION); + break; + case SkRegion::kXOR_Op: + fOut.writeText(SKJSONCANVAS_REGIONOP_XOR); + break; + case SkRegion::kReverseDifference_Op: + fOut.writeText(SKJSONCANVAS_REGIONOP_REVERSE_DIFFERENCE); + break; + case SkRegion::kReplace_Op: + fOut.writeText(SKJSONCANVAS_REGIONOP_REPLACE); + break; + default: + SkASSERT(false); + }; + fOut.writeText("\""); +} + +void SkJSONCanvas::writeEdgeStyle(const char* name, SkCanvas::ClipEdgeStyle edgeStyle) { + this->writef(",\"%s\":\"", name); + switch (edgeStyle) { + case SkCanvas::kHard_ClipEdgeStyle: fOut.writeText(SKJSONCANVAS_EDGESTYLE_HARD); break; + case SkCanvas::kSoft_ClipEdgeStyle: fOut.writeText(SKJSONCANVAS_EDGESTYLE_SOFT); break; + default: SkASSERT(false); + }; + fOut.writeText("\""); +} + +void SkJSONCanvas::writePointMode(const char* name, SkCanvas::PointMode mode) { + this->writef(",\"%s\":\"", name); + switch (mode) { + case SkCanvas::kPoints_PointMode: fOut.writeText(SKJSONCANVAS_POINTMODE_POINTS); break; + case SkCanvas::kLines_PointMode: fOut.writeText(SKJSONCANVAS_POINTMODE_LINES); break; + case SkCanvas::kPolygon_PointMode: fOut.writeText(SKJSONCANVAS_POINTMODE_POLYGON); break; + default: SkASSERT(false); + }; + fOut.writeText("\""); +} + +void SkJSONCanvas::updateMatrix() { + const SkMatrix& matrix = this->getTotalMatrix(); + if (matrix != fLastMatrix) { + this->open(SKJSONCANVAS_COMMAND_MATRIX); + this->writeMatrix(SKJSONCANVAS_ATTRIBUTE_MATRIX, matrix); + fLastMatrix = matrix; + this->close(); + } +} + +void SkJSONCanvas::onDrawPaint(const SkPaint& paint) { + this->open(SKJSONCANVAS_COMMAND_PAINT); + this->writePaint(paint); + this->close(); +} + +void SkJSONCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_RECT); + this->writeRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rect); + this->writePaint(paint); + this->close(); +} + +void SkJSONCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_OVAL); + this->writeRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rect); + this->writePaint(paint); + this->close(); +} + +void SkJSONCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_RRECT); + this->writeRRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rrect); + this->writePaint(paint); + this->close();} + +void SkJSONCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_DRRECT); + this->writeRRect(SKJSONCANVAS_ATTRIBUTE_OUTER, outer); + this->writeRRect(SKJSONCANVAS_ATTRIBUTE_INNER, inner); + this->writePaint(paint); + this->close(); +} + +void SkJSONCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_POINTS); + this->writePointMode(SKJSONCANVAS_ATTRIBUTE_MODE, mode); + fOut.writeText(",\"" SKJSONCANVAS_ATTRIBUTE_POINTS "\":["); + for (size_t i = 0; i < count; i++) { + if (i != 0) { + fOut.writeText(","); + } + this->writef("[%f,%f]", pts[i].x(), pts[i].y()); + } + fOut.writeText("]"); + this->writePaint(paint); + this->close(); +} + +void SkJSONCanvas::onDrawVertices(SkCanvas::VertexMode, int vertexCount, const SkPoint vertices[], + const SkPoint texs[], const SkColor colors[], SkXfermode*, + const uint16_t indices[], int indexCount, const SkPaint&) { + SkDebugf("unsupported: drawVertices\n"); +} + +void SkJSONCanvas::onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], + int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) { + SkDebugf("unsupported: drawAtlas\n"); +} + +void SkJSONCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_PATH); + this->writePath(SKJSONCANVAS_ATTRIBUTE_PATH, path); + this->writePaint(paint); + this->close();} + +void SkJSONCanvas::onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) { + SkDebugf("unsupported: drawImage\n"); +} + +void SkJSONCanvas::onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, + SkCanvas::SrcRectConstraint) { + SkDebugf("unsupported: drawImageRect\n"); +} + +void SkJSONCanvas::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, + const SkPaint*) { + SkDebugf("unsupported: drawImageNine\n"); +} + +void SkJSONCanvas::onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) { + SkDebugf("unsupported: drawBitmap\n"); +} + +void SkJSONCanvas::onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, + SkCanvas::SrcRectConstraint) { + SkDebugf("unsupported: drawBitmapRect\n"); +} + +void SkJSONCanvas::onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) { + SkDebugf("unsupported: drawBitmapNine\n"); +} + +void SkJSONCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_TEXT); + this->writeString(SKJSONCANVAS_ATTRIBUTE_TEXT, text, byteLength); + this->writePoint(SKJSONCANVAS_ATTRIBUTE_COORDS, { x, y }); + this->writePaint(paint); + this->close(); +} + +void SkJSONCanvas::onDrawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) { + SkDebugf("unsupported: drawPosText\n"); +} + +void SkJSONCanvas::onDrawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) { + SkDebugf("unsupported: drawPosTextH\n"); +} + +void SkJSONCanvas::onDrawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) { + SkDebugf("unsupported: drawTextOnPath\n"); +} + +void SkJSONCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) { + SkDebugf("unsupported: drawTextBlob\n"); +} + +void SkJSONCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkXfermode* xmode, + const SkPaint& paint) { + SkDebugf("unsupported: drawPatch\n"); +} + +void SkJSONCanvas::onDrawDrawable(SkDrawable*, const SkMatrix*) { + SkDebugf("unsupported: drawDrawable\n"); +} + +void SkJSONCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_CLIPRECT); + this->writeRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rect); + this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op); + this->writeEdgeStyle(SKJSONCANVAS_ATTRIBUTE_EDGESTYLE, edgeStyle); + this->close(); +} + +void SkJSONCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { + this->updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_CLIPRRECT); + this->writeRRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rrect); + this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op); + this->writeEdgeStyle(SKJSONCANVAS_ATTRIBUTE_EDGESTYLE, edgeStyle); + this->close(); +} + +void SkJSONCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { + updateMatrix(); + this->open(SKJSONCANVAS_COMMAND_CLIPPATH); + this->writePath(SKJSONCANVAS_ATTRIBUTE_PATH, path); + this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op); + this->writeEdgeStyle(SKJSONCANVAS_ATTRIBUTE_EDGESTYLE, edgeStyle); + this->close(); +} + +void SkJSONCanvas::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) { + this->open(SKJSONCANVAS_COMMAND_CLIPREGION); + this->writeRegion(SKJSONCANVAS_ATTRIBUTE_DEVICEREGION, deviceRgn); + this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op); + this->close(); +} + +void SkJSONCanvas::willSave() { + this->open(SKJSONCANVAS_COMMAND_SAVE); + this->close(); +} + +void SkJSONCanvas::willRestore() { + this->open(SKJSONCANVAS_COMMAND_RESTORE); + this->close(); +} diff --git a/tools/json/SkJSONCanvas.h b/tools/json/SkJSONCanvas.h new file mode 100644 index 0000000..fcf7c37 --- /dev/null +++ b/tools/json/SkJSONCanvas.h @@ -0,0 +1,217 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJSONCanvas_DEFINED +#define SkJSONCanvas_DEFINED + +#include "SkCanvas.h" +#include "SkStream.h" + +#define SKJSONCANVAS_VERSION "version" +#define SKJSONCANVAS_COMMANDS "commands" +#define SKJSONCANVAS_COMMAND "command" + +#define SKJSONCANVAS_COMMAND_MATRIX "Matrix" +#define SKJSONCANVAS_COMMAND_PAINT "Paint" +#define SKJSONCANVAS_COMMAND_RECT "Rect" +#define SKJSONCANVAS_COMMAND_OVAL "Oval" +#define SKJSONCANVAS_COMMAND_RRECT "RRect" +#define SKJSONCANVAS_COMMAND_DRRECT "DRRect" +#define SKJSONCANVAS_COMMAND_POINTS "Points" +#define SKJSONCANVAS_COMMAND_VERTICES "Vertices" +#define SKJSONCANVAS_COMMAND_ATLAS "Atlas" +#define SKJSONCANVAS_COMMAND_PATH "Path" +#define SKJSONCANVAS_COMMAND_IMAGE "Image" +#define SKJSONCANVAS_COMMAND_IMAGERECT "ImageRect" +#define SKJSONCANVAS_COMMAND_IMAGENINE "ImageNine" +#define SKJSONCANVAS_COMMAND_BITMAP "Bitmap" +#define SKJSONCANVAS_COMMAND_BITMAPRECT "BitmapRect" +#define SKJSONCANVAS_COMMAND_BITMAPNINE "BitmapNine" +#define SKJSONCANVAS_COMMAND_TEXT "Text" +#define SKJSONCANVAS_COMMAND_POSTEXT "PosText" +#define SKJSONCANVAS_COMMAND_POSTEXTH "PosTextH" +#define SKJSONCANVAS_COMMAND_TEXTONPATH "TextOnPath" +#define SKJSONCANVAS_COMMAND_TEXTBLOB "TextBlob" +#define SKJSONCANVAS_COMMAND_PATCH "Patch" +#define SKJSONCANVAS_COMMAND_DRAWABLE "Drawable" +#define SKJSONCANVAS_COMMAND_CLIPRECT "ClipRect" +#define SKJSONCANVAS_COMMAND_CLIPRRECT "ClipRRect" +#define SKJSONCANVAS_COMMAND_CLIPPATH "ClipPath" +#define SKJSONCANVAS_COMMAND_CLIPREGION "ClipRegion" +#define SKJSONCANVAS_COMMAND_SAVE "Save" +#define SKJSONCANVAS_COMMAND_RESTORE "Restore" + +#define SKJSONCANVAS_ATTRIBUTE_MATRIX "matrix" +#define SKJSONCANVAS_ATTRIBUTE_COORDS "coords" +#define SKJSONCANVAS_ATTRIBUTE_PAINT "paint" +#define SKJSONCANVAS_ATTRIBUTE_OUTER "outer" +#define SKJSONCANVAS_ATTRIBUTE_INNER "inner" +#define SKJSONCANVAS_ATTRIBUTE_MODE "mode" +#define SKJSONCANVAS_ATTRIBUTE_POINTS "points" +#define SKJSONCANVAS_ATTRIBUTE_PATH "path" +#define SKJSONCANVAS_ATTRIBUTE_TEXT "text" +#define SKJSONCANVAS_ATTRIBUTE_COLOR "color" +#define SKJSONCANVAS_ATTRIBUTE_STYLE "style" +#define SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH "strokeWidth" +#define SKJSONCANVAS_ATTRIBUTE_ANTIALIAS "antiAlias" +#define SKJSONCANVAS_ATTRIBUTE_REGIONOP "op" +#define SKJSONCANVAS_ATTRIBUTE_EDGESTYLE "edgeStyle" +#define SKJSONCANVAS_ATTRIBUTE_DEVICEREGION "deviceRegion" + +#define SKJSONCANVAS_VERB_MOVE "move" +#define SKJSONCANVAS_VERB_LINE "line" +#define SKJSONCANVAS_VERB_QUAD "quad" +#define SKJSONCANVAS_VERB_CUBIC "cubic" +#define SKJSONCANVAS_VERB_CONIC "conic" +#define SKJSONCANVAS_VERB_CLOSE "close" + +#define SKJSONCANVAS_STYLE_FILL "fill" +#define SKJSONCANVAS_STYLE_STROKE "stroke" +#define SKJSONCANVAS_STYLE_STROKEANDFILL "strokeAndFill" + +#define SKJSONCANVAS_EDGESTYLE_HARD "hard" +#define SKJSONCANVAS_EDGESTYLE_SOFT "soft" + +#define SKJSONCANVAS_POINTMODE_POINTS "points" +#define SKJSONCANVAS_POINTMODE_LINES "lines" +#define SKJSONCANVAS_POINTMODE_POLYGON "polygon" + +#define SKJSONCANVAS_REGIONOP_DIFFERENCE "difference" +#define SKJSONCANVAS_REGIONOP_INTERSECT "intersect" +#define SKJSONCANVAS_REGIONOP_UNION "union" +#define SKJSONCANVAS_REGIONOP_XOR "xor" +#define SKJSONCANVAS_REGIONOP_REVERSE_DIFFERENCE "reverseDifference" +#define SKJSONCANVAS_REGIONOP_REPLACE "replace" + +/* + * 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 + * SkJSONRenderer. Be sure to call finish() when you are done drawing. + */ +class SkJSONCanvas : public SkCanvas { +public: + /* Create a canvas which writes to the specified output stream. */ + SkJSONCanvas(int width, int height, SkWStream& out); + + /* Complete the JSON document. */ + void finish(); + + // overridden SkCanvas API + + void onDrawPaint(const SkPaint&) override; + + void onDrawRect(const SkRect&, const SkPaint&) override; + + void onDrawOval(const SkRect&, const SkPaint&) override; + + void onDrawRRect(const SkRRect&, const SkPaint&) override; + + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + + void onDrawPoints(SkCanvas::PointMode, size_t count, const SkPoint pts[], + const SkPaint&) override; + + void onDrawVertices(SkCanvas::VertexMode, int vertexCount, const SkPoint vertices[], + const SkPoint texs[], const SkColor colors[], SkXfermode*, + const uint16_t indices[], int indexCount, const SkPaint&) override; + + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], + int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) override; + + void onDrawPath(const SkPath&, const SkPaint&) override; + + void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override; + + void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override; + + void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + + void onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) override; + + void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, + SkCanvas::SrcRectConstraint) override; + + void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst, + const SkPaint*) override; + + void onDrawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) override; + + void onDrawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) override; + + void onDrawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, + const SkPaint& paint) override; + + void onDrawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint& paint) override; + + void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) override; + + void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], + const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) override; + + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + + void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override; + + void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) override; + + void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) override; + + void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override; + + void willSave() override; + + void willRestore() override; + +private: + void writef(const char* fmt, ...); + + void open(const char* name); + + void close(); + + void writeString(const char* name, const char* text); + + void writeString(const char* name, const void* text, size_t length); + + void writePoint(const char* name, const SkPoint& point); + + void writeRect(const char* name, const SkRect& rect); + + void writeRRect(const char* name, const SkRRect& rrect); + + void writePath(const char* name, const SkPath& path); + + void writeRegion(const char* name, const SkRegion& region); + + void writePaint(const SkPaint& paint); + + void writeRegionOp(const char* name, SkRegion::Op op); + + void writeEdgeStyle(const char* name, SkCanvas::ClipEdgeStyle edgeStyle); + + void writePointMode(const char* name, SkCanvas::PointMode mode); + + void writeMatrix(const char* name, const SkMatrix& matrix); + + void updateMatrix(); + + SkWStream& fOut; + SkMatrix fLastMatrix; + bool fFirstCommand; + + typedef SkCanvas INHERITED; +}; + +#endif diff --git a/tools/json/SkJSONRenderer.cpp b/tools/json/SkJSONRenderer.cpp new file mode 100644 index 0000000..f9bb6ee --- /dev/null +++ b/tools/json/SkJSONRenderer.cpp @@ -0,0 +1,289 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkJSONRenderer.h" +#include "SkJSONCanvas.h" +#include "SkJSONCPP.h" +#include "SkPath.h" + +namespace SkJSONRenderer { + +class Renderer { +public: + void getPaint(Json::Value& command, SkPaint* paint); + + void getRect(Json::Value& command, const char* name, SkRect* rect); + + void getRRect(Json::Value& command, const char* name, SkRRect* rrect); + + void processCommand(Json::Value& command, SkCanvas* target); + + void processMatrix(Json::Value& command, SkCanvas* target); + + void processSave(Json::Value& command, SkCanvas* target); + + void processRestore(Json::Value& command, SkCanvas* target); + + void processPaint(Json::Value& command, SkCanvas* target); + + void processRect(Json::Value& command, SkCanvas* target); + + void processRRect(Json::Value& command, SkCanvas* target); + + void processOval(Json::Value& command, SkCanvas* target); + + void processPath(Json::Value& command, SkCanvas* target); + + void processText(Json::Value& command, SkCanvas* target); + + void processPoints(Json::Value& command, SkCanvas* target); + + void processClipRect(Json::Value& command, SkCanvas* target); +}; + +void Renderer::processCommand(Json::Value& command, SkCanvas* target) { + const char* name = command[SKJSONCANVAS_COMMAND].asCString(); + // TODO speed this up with a hash + if (!strcmp(name, SKJSONCANVAS_COMMAND_MATRIX)) { + this->processMatrix(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_SAVE)) { + this->processSave(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_RESTORE)) { + this->processRestore(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_PAINT)) { + this->processPaint(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_RECT)) { + this->processRect(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_RRECT)) { + this->processRRect(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_OVAL)) { + this->processOval(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_PATH)) { + this->processPath(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_TEXT)) { + this->processText(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_POINTS)) { + this->processPoints(command, target); + } + else if (!strcmp(name, SKJSONCANVAS_COMMAND_CLIPRECT)) { + this->processClipRect(command, target); + } + else { + SkDebugf("unsupported JSON command: %s\n", name); + } +} + +void Renderer::getPaint(Json::Value& command, SkPaint* result) { + Json::Value jsonPaint = command[SKJSONCANVAS_ATTRIBUTE_PAINT]; + 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(), + color[3].asInt())); + } + 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); + } + else if (!strcmp(style, SKJSONCANVAS_STYLE_STROKE)) { + result->setStyle(SkPaint::kStroke_Style); + } + else if (!strcmp(style, SKJSONCANVAS_STYLE_STROKEANDFILL)) { + result->setStyle(SkPaint::kStrokeAndFill_Style); + } + } + if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH)) { + float strokeWidth = jsonPaint[SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH].asFloat(); + result->setStrokeWidth(strokeWidth); + } + if (jsonPaint.isMember(SKJSONCANVAS_ATTRIBUTE_ANTIALIAS)) { + result->setAntiAlias(jsonPaint[SKJSONCANVAS_ATTRIBUTE_ANTIALIAS].asBool()); + } +} + +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()); +} + +void Renderer::getRRect(Json::Value& command, const char* name, SkRRect* result) { + Json::Value rrect = command[name]; + SkVector radii[4] = { + { rrect[1][0].asFloat(), rrect[1][1].asFloat() }, + { rrect[2][0].asFloat(), rrect[2][1].asFloat() }, + { rrect[3][0].asFloat(), rrect[3][1].asFloat() }, + { rrect[4][0].asFloat(), rrect[4][1].asFloat() } + }; + result->setRectRadii(SkRect::MakeLTRB(rrect[0][0].asFloat(), rrect[0][1].asFloat(), + rrect[0][2].asFloat(), rrect[0][3].asFloat()), + radii); +} + +void Renderer::processMatrix(Json::Value& command, SkCanvas* target) { + Json::Value jsonMatrix = command[SKJSONCANVAS_ATTRIBUTE_MATRIX]; + SkMatrix matrix; + SkScalar values[] = { + jsonMatrix[0][0].asFloat(), jsonMatrix[0][1].asFloat(), jsonMatrix[0][2].asFloat(), + jsonMatrix[1][0].asFloat(), jsonMatrix[1][1].asFloat(), jsonMatrix[1][2].asFloat(), + jsonMatrix[2][0].asFloat(), jsonMatrix[2][1].asFloat(), jsonMatrix[2][2].asFloat() + }; + matrix.set9(values); + target->setMatrix(matrix); +} + +void Renderer::processSave(Json::Value& command, SkCanvas* target) { + target->save(); +} + +void Renderer::processRestore(Json::Value& command, SkCanvas* target) { + target->restore(); +} + +void Renderer::processPaint(Json::Value& command, SkCanvas* target) { + SkPaint paint; + this->getPaint(command, &paint); + target->drawPaint(paint); +} + +void Renderer::processRect(Json::Value& command, SkCanvas* target) { + SkRect rect; + this->getRect(command, SKJSONCANVAS_ATTRIBUTE_COORDS, &rect); + SkPaint paint; + this->getPaint(command, &paint); + target->drawRect(rect, paint); +} + +void Renderer::processRRect(Json::Value& command, SkCanvas* target) { + SkRRect rrect; + this->getRRect(command, SKJSONCANVAS_ATTRIBUTE_COORDS, &rrect); + SkPaint paint; + this->getPaint(command, &paint); + target->drawRRect(rrect, paint); +} + +void Renderer::processOval(Json::Value& command, SkCanvas* target) { + SkRect rect; + this->getRect(command, SKJSONCANVAS_ATTRIBUTE_COORDS, &rect); + SkPaint paint; + this->getPaint(command, &paint); + target->drawOval(rect, paint); +} + +void Renderer::processPath(Json::Value& command, SkCanvas* target) { + Json::Value jsonPath = command[SKJSONCANVAS_ATTRIBUTE_PATH]; + SkPath path; + for (Json::ArrayIndex i = 0; i < jsonPath.size(); i++) { + Json::Value verb = jsonPath[i]; + if (verb.isString()) { + SkASSERT(!strcmp(verb.asCString(), SKJSONCANVAS_VERB_CLOSE)); + path.close(); + } + else { + if (verb.isMember(SKJSONCANVAS_VERB_MOVE)) { + Json::Value move = verb[SKJSONCANVAS_VERB_MOVE]; + path.moveTo(move[0].asFloat(), move[1].asFloat()); + } + else if (verb.isMember(SKJSONCANVAS_VERB_LINE)) { + Json::Value line = verb[SKJSONCANVAS_VERB_LINE]; + path.lineTo(line[0].asFloat(), line[1].asFloat()); + } + else if (verb.isMember(SKJSONCANVAS_VERB_QUAD)) { + Json::Value quad = verb[SKJSONCANVAS_VERB_QUAD]; + path.quadTo(quad[0][0].asFloat(), quad[0][1].asFloat(), + quad[1][0].asFloat(), quad[1][1].asFloat()); + } + else if (verb.isMember(SKJSONCANVAS_VERB_CUBIC)) { + Json::Value cubic = verb[SKJSONCANVAS_VERB_CUBIC]; + path.cubicTo(cubic[0][0].asFloat(), cubic[0][1].asFloat(), + cubic[1][0].asFloat(), cubic[1][1].asFloat(), + cubic[2][0].asFloat(), cubic[2][1].asFloat()); + } + else if (verb.isMember(SKJSONCANVAS_VERB_CONIC)) { + Json::Value conic = verb[SKJSONCANVAS_VERB_CONIC]; + path.conicTo(conic[0][0].asFloat(), conic[0][1].asFloat(), + conic[1][0].asFloat(), conic[1][1].asFloat(), + conic[2].asFloat()); + } + else { + SkASSERT(false); + } + } + } + SkPaint paint; + this->getPaint(command, &paint); + target->drawPath(path, paint); +} + +void Renderer::processText(Json::Value& command, SkCanvas* target) { + const char* text = command[SKJSONCANVAS_ATTRIBUTE_TEXT].asCString(); + SkPaint paint; + this->getPaint(command, &paint); + Json::Value coords = command[SKJSONCANVAS_ATTRIBUTE_COORDS]; + target->drawText(text, strlen(text), coords[0].asFloat(), coords[1].asFloat(), paint); +} + +void Renderer::processPoints(Json::Value& command, SkCanvas* target) { + SkCanvas::PointMode mode; + const char* jsonMode = command[SKJSONCANVAS_ATTRIBUTE_MODE].asCString(); + if (!strcmp(jsonMode, SKJSONCANVAS_POINTMODE_POINTS)) { + mode = SkCanvas::kPoints_PointMode; + } + else if (!strcmp(jsonMode, SKJSONCANVAS_POINTMODE_LINES)) { + mode = SkCanvas::kLines_PointMode; + } + else if (!strcmp(jsonMode, SKJSONCANVAS_POINTMODE_POLYGON)) { + mode = SkCanvas::kPolygon_PointMode; + } + else { + SkASSERT(false); + return; + } + Json::Value jsonPoints = command[SKJSONCANVAS_ATTRIBUTE_POINTS]; + int count = (int) jsonPoints.size(); + SkPoint* points = (SkPoint*) sk_malloc_throw(count * sizeof(SkPoint)); + for (int i = 0; i < count; i++) { + points[i] = SkPoint::Make(jsonPoints[i][0].asFloat(), jsonPoints[i][1].asFloat()); + } + SkPaint paint; + this->getPaint(command, &paint); + target->drawPoints(mode, count, points, paint); + free(points); +} + +void Renderer::processClipRect(Json::Value& command, SkCanvas* target) { + SkRect rect; + this->getRect(command, SKJSONCANVAS_ATTRIBUTE_COORDS, &rect); + target->clipRect(rect); +} + +void render(const char* json, SkCanvas* target) { + Renderer renderer; + Json::Reader reader; + Json::Value root; + if (reader.parse(std::string(json), root)) { + SkASSERT(root[SKJSONCANVAS_VERSION].asInt() == 1); + Json::Value commands = root[SKJSONCANVAS_COMMANDS]; + for (Json::ArrayIndex i = 0; i < commands.size(); i++) { + renderer.processCommand(commands[i], target); + } + } + else { + SkDebugf(json); + SkFAIL("json parse failure"); + } +} + +} // namespace diff --git a/tools/json/SkJSONRenderer.h b/tools/json/SkJSONRenderer.h new file mode 100644 index 0000000..d92edf2 --- /dev/null +++ b/tools/json/SkJSONRenderer.h @@ -0,0 +1,22 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkJSONRenderer_DEFINED +#define SkJSONRenderer_DEFINED + + +#include "SkCanvas.h" + +namespace SkJSONRenderer { + /* + * Takes a JSON document produced by SkJSONCanvas and issues its draw commands to the target + * canvas. + */ + void render(const char* json, SkCanvas* target); +} + +#endif