blob: f60ee27a277a105b1635fc060d1e0b9bf1706126 [file] [log] [blame]
ethannicholas978d08a2016-01-26 07:47:57 -08001/*
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 "SkPath.h"
10#include "SkRRect.h"
11#include "stdio.h"
12#include "stdlib.h"
13
14SkJSONCanvas::SkJSONCanvas(int width, int height, SkWStream& out)
15 : INHERITED(width, height)
16 , fOut(out)
17 , fFirstCommand(true) {
18 fOut.writeText("{\"" SKJSONCANVAS_VERSION "\":1, \"" SKJSONCANVAS_COMMANDS
19 "\":[");
20}
21
22void SkJSONCanvas::finish() {
23 fOut.writeText("]}");
24}
25
26void SkJSONCanvas::writef(const char* format, ...) {
27 va_list args;
28 va_start(args, format);
29 SkString s;
30 s.appendVAList(format, args);
31 fOut.writeText(s.c_str());
32}
33
34void SkJSONCanvas::open(const char* name) {
35 if (fFirstCommand) {
36 fFirstCommand = false;
37 }
38 else {
39 fOut.writeText(",");
40 }
41 this->writef("{\"" SKJSONCANVAS_COMMAND "\":\"%s\"", name);
42}
43
44void SkJSONCanvas::close() {
45 fOut.writeText("}");
46}
47
48void SkJSONCanvas::writeString(const char* name, const char* text) {
49 this->writeString(name, text, strlen(text));
50}
51
52void SkJSONCanvas::writeString(const char* name, const void* text, size_t length) {
53 // TODO: escaping
54 this->writef(",\"%s\":\"", name);
55 fOut.write(text, length);
56 fOut.writeText("\"");
57}
58
59void SkJSONCanvas::writePoint(const char* name, const SkPoint& point) {
60 this->writef(",\"%s\":[%f, %f]", name, point.x(), point.y());
61}
62
63void SkJSONCanvas::writeRect(const char* name, const SkRect& rect) {
64 this->writef(",\"%s\":[%f, %f, %f, %f]", name, rect.left(), rect.top(), rect.right(),
65 rect.bottom());
66}
67
68void SkJSONCanvas::writeRRect(const char* name, const SkRRect& rrect) {
69 SkRect rect = rrect.rect();
70 SkVector corner1 = rrect.radii(SkRRect::kUpperLeft_Corner);
71 SkVector corner2 = rrect.radii(SkRRect::kUpperRight_Corner);
72 SkVector corner3 = rrect.radii(SkRRect::kLowerLeft_Corner);
73 SkVector corner4 = rrect.radii(SkRRect::kLowerRight_Corner);
74 this->writef(",\"%s\":[[%f, %f, %f, %f],[%f, %f],[%f, %f],[%f, %f],[%f, %f]]", name,
75 rect.left(), rect.top(), rect.right(), rect.bottom(), corner1.x(), corner1.y(),
76 corner2.x(), corner2.y(), corner3.x(), corner3.y(), corner4.x(), corner4.y());
77}
78
79void SkJSONCanvas::writePath(const char* name, const SkPath& path) {
80 SkString text("[");
81 SkPath::Iter iter(path, false);
82 SkPoint pts[4];
83 bool first = true;
84 SkPath::Verb verb;
85 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
86 if (first) {
87 first = false;
88 }
89 else {
90 text.append(",");
91 }
92 switch (verb) {
93 case SkPath::kLine_Verb:
94 text.appendf("{\"" SKJSONCANVAS_VERB_LINE "\":[%f,%f]}", pts[1].x(), pts[1].y());
95 break;
96 case SkPath::kQuad_Verb:
97 text.appendf("{\"" SKJSONCANVAS_VERB_QUAD "\":[[%f,%f],[%f,%f]]}", pts[1].x(),
98 pts[1].y(), pts[2].x(), pts[2].y());
99 break;
100 case SkPath::kCubic_Verb:
101 text.appendf("{\"" SKJSONCANVAS_VERB_CUBIC "\":[[%f,%f],[%f,%f],[%f,%f]]}",
102 pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(), pts[3].x(),
103 pts[3].y());
104 break;
105 case SkPath::kConic_Verb:
106 text.appendf("{\"" SKJSONCANVAS_VERB_CONIC "\":[[%f,%f],[%f,%f],%f]}", pts[1].x(),
107 pts[1].y(), pts[2].x(), pts[2].y(), iter.conicWeight());
108 break;
109 case SkPath::kMove_Verb:
110 text.appendf("{\"" SKJSONCANVAS_VERB_MOVE "\":[%f,%f]}", pts[0].x(), pts[0].y());
111 break;
112 case SkPath::kClose_Verb:
113 text.appendf("\"" SKJSONCANVAS_VERB_CLOSE "\"");
114 break;
115 case SkPath::kDone_Verb:
116 break;
117 }
118 }
119 text.appendf("]");
120 this->writef(",\"" SKJSONCANVAS_ATTRIBUTE_PATH "\":%s", text.c_str());
121}
122
123void SkJSONCanvas::writeRegion(const char* name, const SkRegion& region) {
124 this->writef(",\"%s\":\"<unimplemented>\"", name);
125}
126
127void SkJSONCanvas::writePaint(const SkPaint& paint) {
128 this->writef(",\"" SKJSONCANVAS_ATTRIBUTE_PAINT "\":{");
129 SkColor color = paint.getColor();
130 bool first = true;
131 if (color != SK_ColorBLACK) {
132 this->writef("\"" SKJSONCANVAS_ATTRIBUTE_COLOR "\":[%d,%d,%d,%d]", SkColorGetA(color),
133 SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
134 first = false;
135 }
136 SkPaint::Style style = paint.getStyle();
137 if (style != SkPaint::kFill_Style) {
138 if (first) {
139 first = false;
140 }
141 else {
142 fOut.writeText(",");
143 }
144 switch (style) {
145 case SkPaint::kStroke_Style:
146 fOut.writeText("\"" SKJSONCANVAS_ATTRIBUTE_STYLE "\":\""
147 SKJSONCANVAS_STYLE_STROKE "\"");
148 break;
149 case SkPaint::kStrokeAndFill_Style:
150 fOut.writeText("\"" SKJSONCANVAS_ATTRIBUTE_STYLE "\":\""
151 SKJSONCANVAS_STYLE_STROKEANDFILL "\"");
152 break;
153 default: SkASSERT(false);
154 }
155 }
156 SkScalar strokeWidth = paint.getStrokeWidth();
157 if (strokeWidth != 0.0f) {
158 if (first) {
159 first = false;
160 }
161 else {
162 fOut.writeText(",");
163 }
164 this->writef("\"" SKJSONCANVAS_ATTRIBUTE_STROKEWIDTH "\":%f", strokeWidth);
165 }
166 if (paint.isAntiAlias()) {
167 if (first) {
168 first = false;
169 }
170 else {
171 fOut.writeText(",");
172 }
173 fOut.writeText("\"" SKJSONCANVAS_ATTRIBUTE_ANTIALIAS "\":true");
174 }
175 fOut.writeText("}");
176}
177
178void SkJSONCanvas::writeMatrix(const char* name, const SkMatrix& matrix) {
179 this->writef(",\"%s\":[[%f,%f,%f],[%f,%f,%f],[%f,%f,%f]]", name,
180 matrix[0], matrix[1], matrix[2],
181 matrix[3], matrix[4], matrix[5],
182 matrix[6], matrix[7], matrix[8]);
183}
184
185void SkJSONCanvas::writeRegionOp(const char* name, SkRegion::Op op) {
186 this->writef(",\"%s\":\"", name);
187 switch (op) {
188 case SkRegion::kDifference_Op:
189 fOut.writeText(SKJSONCANVAS_REGIONOP_DIFFERENCE);
190 break;
191 case SkRegion::kIntersect_Op:
192 fOut.writeText(SKJSONCANVAS_REGIONOP_INTERSECT);
193 break;
194 case SkRegion::kUnion_Op:
195 fOut.writeText(SKJSONCANVAS_REGIONOP_UNION);
196 break;
197 case SkRegion::kXOR_Op:
198 fOut.writeText(SKJSONCANVAS_REGIONOP_XOR);
199 break;
200 case SkRegion::kReverseDifference_Op:
201 fOut.writeText(SKJSONCANVAS_REGIONOP_REVERSE_DIFFERENCE);
202 break;
203 case SkRegion::kReplace_Op:
204 fOut.writeText(SKJSONCANVAS_REGIONOP_REPLACE);
205 break;
206 default:
207 SkASSERT(false);
208 };
209 fOut.writeText("\"");
210}
211
212void SkJSONCanvas::writeEdgeStyle(const char* name, SkCanvas::ClipEdgeStyle edgeStyle) {
213 this->writef(",\"%s\":\"", name);
214 switch (edgeStyle) {
215 case SkCanvas::kHard_ClipEdgeStyle: fOut.writeText(SKJSONCANVAS_EDGESTYLE_HARD); break;
216 case SkCanvas::kSoft_ClipEdgeStyle: fOut.writeText(SKJSONCANVAS_EDGESTYLE_SOFT); break;
217 default: SkASSERT(false);
218 };
219 fOut.writeText("\"");
220}
221
222void SkJSONCanvas::writePointMode(const char* name, SkCanvas::PointMode mode) {
223 this->writef(",\"%s\":\"", name);
224 switch (mode) {
225 case SkCanvas::kPoints_PointMode: fOut.writeText(SKJSONCANVAS_POINTMODE_POINTS); break;
226 case SkCanvas::kLines_PointMode: fOut.writeText(SKJSONCANVAS_POINTMODE_LINES); break;
227 case SkCanvas::kPolygon_PointMode: fOut.writeText(SKJSONCANVAS_POINTMODE_POLYGON); break;
228 default: SkASSERT(false);
229 };
230 fOut.writeText("\"");
231}
232
233void SkJSONCanvas::updateMatrix() {
234 const SkMatrix& matrix = this->getTotalMatrix();
235 if (matrix != fLastMatrix) {
236 this->open(SKJSONCANVAS_COMMAND_MATRIX);
237 this->writeMatrix(SKJSONCANVAS_ATTRIBUTE_MATRIX, matrix);
238 fLastMatrix = matrix;
239 this->close();
240 }
241}
242
243void SkJSONCanvas::onDrawPaint(const SkPaint& paint) {
244 this->open(SKJSONCANVAS_COMMAND_PAINT);
245 this->writePaint(paint);
246 this->close();
247}
248
249void SkJSONCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
250 this->updateMatrix();
251 this->open(SKJSONCANVAS_COMMAND_RECT);
252 this->writeRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rect);
253 this->writePaint(paint);
254 this->close();
255}
256
257void SkJSONCanvas::onDrawOval(const SkRect& rect, const SkPaint& paint) {
258 this->updateMatrix();
259 this->open(SKJSONCANVAS_COMMAND_OVAL);
260 this->writeRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rect);
261 this->writePaint(paint);
262 this->close();
263}
264
265void SkJSONCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
266 this->updateMatrix();
267 this->open(SKJSONCANVAS_COMMAND_RRECT);
268 this->writeRRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rrect);
269 this->writePaint(paint);
270 this->close();}
271
272void SkJSONCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
273 this->updateMatrix();
274 this->open(SKJSONCANVAS_COMMAND_DRRECT);
275 this->writeRRect(SKJSONCANVAS_ATTRIBUTE_OUTER, outer);
276 this->writeRRect(SKJSONCANVAS_ATTRIBUTE_INNER, inner);
277 this->writePaint(paint);
278 this->close();
279}
280
281void SkJSONCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
282 const SkPaint& paint) {
283 this->updateMatrix();
284 this->open(SKJSONCANVAS_COMMAND_POINTS);
285 this->writePointMode(SKJSONCANVAS_ATTRIBUTE_MODE, mode);
286 fOut.writeText(",\"" SKJSONCANVAS_ATTRIBUTE_POINTS "\":[");
287 for (size_t i = 0; i < count; i++) {
288 if (i != 0) {
289 fOut.writeText(",");
290 }
291 this->writef("[%f,%f]", pts[i].x(), pts[i].y());
292 }
293 fOut.writeText("]");
294 this->writePaint(paint);
295 this->close();
296}
297
298void SkJSONCanvas::onDrawVertices(SkCanvas::VertexMode, int vertexCount, const SkPoint vertices[],
299 const SkPoint texs[], const SkColor colors[], SkXfermode*,
300 const uint16_t indices[], int indexCount, const SkPaint&) {
301 SkDebugf("unsupported: drawVertices\n");
302}
303
304void SkJSONCanvas::onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[],
305 int count, SkXfermode::Mode, const SkRect* cull, const SkPaint*) {
306 SkDebugf("unsupported: drawAtlas\n");
307}
308
309void SkJSONCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
310 this->updateMatrix();
311 this->open(SKJSONCANVAS_COMMAND_PATH);
312 this->writePath(SKJSONCANVAS_ATTRIBUTE_PATH, path);
313 this->writePaint(paint);
314 this->close();}
315
316void SkJSONCanvas::onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) {
317 SkDebugf("unsupported: drawImage\n");
318}
319
320void SkJSONCanvas::onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
321 SkCanvas::SrcRectConstraint) {
322 SkDebugf("unsupported: drawImageRect\n");
323}
324
325void SkJSONCanvas::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
326 const SkPaint*) {
327 SkDebugf("unsupported: drawImageNine\n");
328}
329
330void SkJSONCanvas::onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) {
331 SkDebugf("unsupported: drawBitmap\n");
332}
333
334void SkJSONCanvas::onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
335 SkCanvas::SrcRectConstraint) {
336 SkDebugf("unsupported: drawBitmapRect\n");
337}
338
339void SkJSONCanvas::onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
340 const SkPaint*) {
341 SkDebugf("unsupported: drawBitmapNine\n");
342}
343
344void SkJSONCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x,
345 SkScalar y, const SkPaint& paint) {
346 this->updateMatrix();
347 this->open(SKJSONCANVAS_COMMAND_TEXT);
348 this->writeString(SKJSONCANVAS_ATTRIBUTE_TEXT, text, byteLength);
349 this->writePoint(SKJSONCANVAS_ATTRIBUTE_COORDS, { x, y });
350 this->writePaint(paint);
351 this->close();
352}
353
354void SkJSONCanvas::onDrawPosText(const void* text, size_t byteLength,
355 const SkPoint pos[], const SkPaint& paint) {
356 SkDebugf("unsupported: drawPosText\n");
357}
358
359void SkJSONCanvas::onDrawPosTextH(const void* text, size_t byteLength,
360 const SkScalar xpos[], SkScalar constY,
361 const SkPaint& paint) {
362 SkDebugf("unsupported: drawPosTextH\n");
363}
364
365void SkJSONCanvas::onDrawTextOnPath(const void* text, size_t byteLength,
366 const SkPath& path, const SkMatrix* matrix,
367 const SkPaint& paint) {
368 SkDebugf("unsupported: drawTextOnPath\n");
369}
370
371void SkJSONCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
372 const SkPaint& paint) {
373 SkDebugf("unsupported: drawTextBlob\n");
374}
375
376void SkJSONCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
377 const SkPoint texCoords[4], SkXfermode* xmode,
378 const SkPaint& paint) {
379 SkDebugf("unsupported: drawPatch\n");
380}
381
382void SkJSONCanvas::onDrawDrawable(SkDrawable*, const SkMatrix*) {
383 SkDebugf("unsupported: drawDrawable\n");
384}
385
386void SkJSONCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
387 this->updateMatrix();
388 this->open(SKJSONCANVAS_COMMAND_CLIPRECT);
389 this->writeRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rect);
390 this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op);
391 this->writeEdgeStyle(SKJSONCANVAS_ATTRIBUTE_EDGESTYLE, edgeStyle);
392 this->close();
393}
394
395void SkJSONCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
396 this->updateMatrix();
397 this->open(SKJSONCANVAS_COMMAND_CLIPRRECT);
398 this->writeRRect(SKJSONCANVAS_ATTRIBUTE_COORDS, rrect);
399 this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op);
400 this->writeEdgeStyle(SKJSONCANVAS_ATTRIBUTE_EDGESTYLE, edgeStyle);
401 this->close();
402}
403
404void SkJSONCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
405 updateMatrix();
406 this->open(SKJSONCANVAS_COMMAND_CLIPPATH);
407 this->writePath(SKJSONCANVAS_ATTRIBUTE_PATH, path);
408 this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op);
409 this->writeEdgeStyle(SKJSONCANVAS_ATTRIBUTE_EDGESTYLE, edgeStyle);
410 this->close();
411}
412
413void SkJSONCanvas::onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) {
414 this->open(SKJSONCANVAS_COMMAND_CLIPREGION);
415 this->writeRegion(SKJSONCANVAS_ATTRIBUTE_DEVICEREGION, deviceRgn);
416 this->writeRegionOp(SKJSONCANVAS_ATTRIBUTE_REGIONOP, op);
417 this->close();
418}
419
420void SkJSONCanvas::willSave() {
421 this->open(SKJSONCANVAS_COMMAND_SAVE);
422 this->close();
423}
424
425void SkJSONCanvas::willRestore() {
426 this->open(SKJSONCANVAS_COMMAND_RESTORE);
427 this->close();
428}