1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "platform/graphics/LoggingCanvas.h"
33
34 #include "platform/image-encoders/skia/PNGImageEncoder.h"
35 #include "third_party/skia/include/core/SkPicture.h"
36 #include "wtf/HexNumber.h"
37 #include "wtf/text/Base64.h"
38 #include "wtf/text/TextEncoding.h"
39
40 namespace blink {
41
42 class AutoLogger {
43 public:
44 explicit AutoLogger(LoggingCanvas*);
45 PassRefPtr<JSONObject> logItem(const String& name);
46 PassRefPtr<JSONObject> logItemWithParams(const String& name);
47 ~AutoLogger();
48
49 private:
50 LoggingCanvas* m_canvas;
51 RefPtr<JSONObject> m_logItem;
52 };
53
AutoLogger(LoggingCanvas * loggingCanvas)54 AutoLogger::AutoLogger(LoggingCanvas* loggingCanvas) : m_canvas(loggingCanvas)
55 {
56 loggingCanvas->m_depthCount++;
57 }
58
logItem(const String & name)59 PassRefPtr<JSONObject> AutoLogger::logItem(const String& name)
60 {
61 RefPtr<JSONObject> item = JSONObject::create();
62 item->setString("method", name);
63 m_logItem = item;
64 return item.release();
65 }
66
logItemWithParams(const String & name)67 PassRefPtr<JSONObject> AutoLogger::logItemWithParams(const String& name)
68 {
69 RefPtr<JSONObject> item = logItem(name);
70 RefPtr<JSONObject> params = JSONObject::create();
71 item->setObject("params", params);
72 return params.release();
73 }
74
~AutoLogger()75 AutoLogger::~AutoLogger()
76 {
77 m_canvas->m_depthCount--;
78 if (!m_canvas->m_depthCount)
79 m_canvas->m_log->pushObject(m_logItem);
80 }
81
LoggingCanvas(int width,int height)82 LoggingCanvas::LoggingCanvas(int width, int height) : InterceptingCanvas(width, height)
83 {
84 m_log = JSONArray::create();
85 }
86
clear(SkColor color)87 void LoggingCanvas::clear(SkColor color)
88 {
89 AutoLogger logger(this);
90 logger.logItemWithParams("clear")->setString("color", stringForSkColor(color));
91 this->SkCanvas::clear(color);
92 }
93
drawPaint(const SkPaint & paint)94 void LoggingCanvas::drawPaint(const SkPaint& paint)
95 {
96 AutoLogger logger(this);
97 logger.logItemWithParams("drawPaint")->setObject("paint", objectForSkPaint(paint));
98 this->SkCanvas::drawPaint(paint);
99 }
100
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)101 void LoggingCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint)
102 {
103 AutoLogger logger(this);
104 RefPtr<JSONObject> params = logger.logItemWithParams("drawPoints");
105 params->setString("pointMode", pointModeName(mode));
106 params->setArray("points", arrayForSkPoints(count, pts));
107 params->setObject("paint", objectForSkPaint(paint));
108 this->SkCanvas::drawPoints(mode, count, pts, paint);
109 }
110
drawRect(const SkRect & rect,const SkPaint & paint)111 void LoggingCanvas::drawRect(const SkRect& rect, const SkPaint& paint)
112 {
113 AutoLogger logger(this);
114 RefPtr<JSONObject> params = logger.logItemWithParams("drawRect");
115 params->setObject("rect", objectForSkRect(rect));
116 params->setObject("paint", objectForSkPaint(paint));
117 this->SkCanvas::drawRect(rect, paint);
118 }
119
drawOval(const SkRect & oval,const SkPaint & paint)120 void LoggingCanvas::drawOval(const SkRect& oval, const SkPaint& paint)
121 {
122 AutoLogger logger(this);
123 RefPtr<JSONObject> params = logger.logItemWithParams("drawOval");
124 params->setObject("oval", objectForSkRect(oval));
125 params->setObject("paint", objectForSkPaint(paint));
126 this->SkCanvas::drawOval(oval, paint);
127 }
128
drawRRect(const SkRRect & rrect,const SkPaint & paint)129 void LoggingCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint)
130 {
131 AutoLogger logger(this);
132 RefPtr<JSONObject> params = logger.logItemWithParams("drawRRect");
133 params->setObject("rrect", objectForSkRRect(rrect));
134 params->setObject("paint", objectForSkPaint(paint));
135 this->SkCanvas::drawRRect(rrect, paint);
136 }
137
drawPath(const SkPath & path,const SkPaint & paint)138 void LoggingCanvas::drawPath(const SkPath& path, const SkPaint& paint)
139 {
140 AutoLogger logger(this);
141 RefPtr<JSONObject> params = logger.logItemWithParams("drawPath");
142 params->setObject("path", objectForSkPath(path));
143 params->setObject("paint", objectForSkPaint(paint));
144 this->SkCanvas::drawPath(path, paint);
145 }
146
drawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint)147 void LoggingCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint)
148 {
149 AutoLogger logger(this);
150 RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmap");
151 params->setNumber("left", left);
152 params->setNumber("top", top);
153 params->setObject("bitmap", objectForSkBitmap(bitmap));
154 params->setObject("paint", objectForSkPaint(*paint));
155 this->SkCanvas::drawBitmap(bitmap, left, top, paint);
156 }
157
drawBitmapRectToRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,DrawBitmapRectFlags flags)158 void LoggingCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags flags)
159 {
160 AutoLogger logger(this);
161 RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapRectToRect");
162 params->setObject("bitmap", objectForSkBitmap(bitmap));
163 params->setObject("src", objectForSkRect(*src));
164 params->setObject("dst", objectForSkRect(dst));
165 params->setObject("paint", objectForSkPaint(*paint));
166 params->setNumber("flags", flags);
167 this->SkCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
168 }
169
drawBitmapMatrix(const SkBitmap & bitmap,const SkMatrix & m,const SkPaint * paint)170 void LoggingCanvas::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint* paint)
171 {
172 AutoLogger logger(this);
173 RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapMatrix");
174 params->setObject("bitmap", objectForSkBitmap(bitmap));
175 params->setArray("matrix", arrayForSkMatrix(m));
176 params->setObject("paint", objectForSkPaint(*paint));
177 this->SkCanvas::drawBitmapMatrix(bitmap, m, paint);
178 }
179
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)180 void LoggingCanvas::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint)
181 {
182 AutoLogger logger(this);
183 RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapNine");
184 params->setObject("bitmap", objectForSkBitmap(bitmap));
185 params->setObject("center", objectForSkIRect(center));
186 params->setObject("dst", objectForSkRect(dst));
187 params->setObject("paint", objectForSkPaint(*paint));
188 this->SkCanvas::drawBitmapNine(bitmap, center, dst, paint);
189 }
190
drawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint * paint)191 void LoggingCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint)
192 {
193 AutoLogger logger(this);
194 RefPtr<JSONObject> params = logger.logItemWithParams("drawSprite");
195 params->setObject("bitmap", objectForSkBitmap(bitmap));
196 params->setNumber("left", left);
197 params->setNumber("top", top);
198 params->setObject("paint", objectForSkPaint(*paint));
199 this->SkCanvas::drawSprite(bitmap, left, top, paint);
200 }
201
drawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint)202 void LoggingCanvas::drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
203 const uint16_t indices[], int indexCount, const SkPaint& paint)
204 {
205 AutoLogger logger(this);
206 RefPtr<JSONObject> params = logger.logItemWithParams("drawVertices");
207 params->setObject("paint", objectForSkPaint(paint));
208 this->SkCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, indexCount, paint);
209 }
210
drawData(const void * data,size_t length)211 void LoggingCanvas::drawData(const void* data, size_t length)
212 {
213 AutoLogger logger(this);
214 RefPtr<JSONObject> params = logger.logItemWithParams("drawData");
215 params->setNumber("length", length);
216 this->SkCanvas::drawData(data, length);
217 }
218
beginCommentGroup(const char * description)219 void LoggingCanvas::beginCommentGroup(const char* description)
220 {
221 AutoLogger logger(this);
222 RefPtr<JSONObject> params = logger.logItemWithParams("beginCommentGroup");
223 params->setString("description", description);
224 this->SkCanvas::beginCommentGroup(description);
225 }
226
addComment(const char * keyword,const char * value)227 void LoggingCanvas::addComment(const char* keyword, const char* value)
228 {
229 AutoLogger logger(this);
230 RefPtr<JSONObject> params = logger.logItemWithParams("addComment");
231 params->setString("key", keyword);
232 params->setString("value", value);
233 this->SkCanvas::addComment(keyword, value);
234 }
235
endCommentGroup()236 void LoggingCanvas::endCommentGroup()
237 {
238 AutoLogger logger(this);
239 logger.logItem("endCommentGroup");
240 this->SkCanvas::endCommentGroup();
241 }
242
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)243 void LoggingCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint)
244 {
245 AutoLogger logger(this);
246 RefPtr<JSONObject> params = logger.logItemWithParams("drawDRRect");
247 params->setObject("outer", objectForSkRRect(outer));
248 params->setObject("inner", objectForSkRRect(inner));
249 params->setObject("paint", objectForSkPaint(paint));
250 this->SkCanvas::onDrawDRRect(outer, inner, paint);
251 }
252
onDrawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)253 void LoggingCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint)
254 {
255 AutoLogger logger(this);
256 RefPtr<JSONObject> params = logger.logItemWithParams("drawText");
257 params->setString("text", stringForText(text, byteLength, paint));
258 params->setNumber("x", x);
259 params->setNumber("y", y);
260 params->setObject("paint", objectForSkPaint(paint));
261 this->SkCanvas::onDrawText(text, byteLength, x, y, paint);
262 }
263
onDrawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)264 void LoggingCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint)
265 {
266 AutoLogger logger(this);
267 RefPtr<JSONObject> params = logger.logItemWithParams("drawPosText");
268 params->setString("text", stringForText(text, byteLength, paint));
269 size_t pointsCount = paint.countText(text, byteLength);
270 params->setArray("pos", arrayForSkPoints(pointsCount, pos));
271 params->setObject("paint", objectForSkPaint(paint));
272 this->SkCanvas::onDrawPosText(text, byteLength, pos, paint);
273 }
274
onDrawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)275 void LoggingCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint)
276 {
277 AutoLogger logger(this);
278 RefPtr<JSONObject> params = logger.logItemWithParams("drawPosTextH");
279 params->setString("text", stringForText(text, byteLength, paint));
280 size_t pointsCount = paint.countText(text, byteLength);
281 params->setArray("xpos", arrayForSkScalars(pointsCount, xpos));
282 params->setNumber("constY", constY);
283 params->setObject("paint", objectForSkPaint(paint));
284 this->SkCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint);
285 }
286
onDrawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)287 void LoggingCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint)
288 {
289 AutoLogger logger(this);
290 RefPtr<JSONObject> params = logger.logItemWithParams("drawTextOnPath");
291 params->setString("text", stringForText(text, byteLength, paint));
292 params->setObject("path", objectForSkPath(path));
293 params->setArray("matrix", arrayForSkMatrix(*matrix));
294 params->setObject("paint", objectForSkPaint(paint));
295 this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint);
296 }
297
onPushCull(const SkRect & cullRect)298 void LoggingCanvas::onPushCull(const SkRect& cullRect)
299 {
300 AutoLogger logger(this);
301 RefPtr<JSONObject> params = logger.logItemWithParams("pushCull");
302 params->setObject("cullRect", objectForSkRect(cullRect));
303 this->SkCanvas::onPushCull(cullRect);
304 }
305
onPopCull()306 void LoggingCanvas::onPopCull()
307 {
308 AutoLogger logger(this);
309 logger.logItem("popCull");
310 this->SkCanvas::onPopCull();
311 }
312
onClipRect(const SkRect & rect,SkRegion::Op op,ClipEdgeStyle style)313 void LoggingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style)
314 {
315 AutoLogger logger(this);
316 RefPtr<JSONObject> params = logger.logItemWithParams("clipRect");
317 params->setObject("rect", objectForSkRect(rect));
318 params->setString("SkRegion::Op", regionOpName(op));
319 params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
320 this->SkCanvas::onClipRect(rect, op, style);
321 }
322
onClipRRect(const SkRRect & rrect,SkRegion::Op op,ClipEdgeStyle style)323 void LoggingCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle style)
324 {
325 AutoLogger logger(this);
326 RefPtr<JSONObject> params = logger.logItemWithParams("clipRRect");
327 params->setObject("rrect", objectForSkRRect(rrect));
328 params->setString("SkRegion::Op", regionOpName(op));
329 params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
330 this->SkCanvas::onClipRRect(rrect, op, style);
331 }
332
onClipPath(const SkPath & path,SkRegion::Op op,ClipEdgeStyle style)333 void LoggingCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle style)
334 {
335 AutoLogger logger(this);
336 RefPtr<JSONObject> params = logger.logItemWithParams("clipPath");
337 params->setObject("path", objectForSkPath(path));
338 params->setString("SkRegion::Op", regionOpName(op));
339 params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
340 this->SkCanvas::onClipPath(path, op, style);
341 }
342
onClipRegion(const SkRegion & region,SkRegion::Op op)343 void LoggingCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op)
344 {
345 AutoLogger logger(this);
346 RefPtr<JSONObject> params = logger.logItemWithParams("clipRegion");
347 params->setString("op", regionOpName(op));
348 this->SkCanvas::onClipRegion(region, op);
349 }
350
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)351 void LoggingCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint)
352 {
353 AutoLogger logger(this);
354 logger.logItemWithParams("drawPicture")->setObject("picture", objectForSkPicture(*picture));
355 this->SkCanvas::onDrawPicture(picture, matrix, paint);
356 }
357
didSetMatrix(const SkMatrix & matrix)358 void LoggingCanvas::didSetMatrix(const SkMatrix& matrix)
359 {
360 AutoLogger logger(this);
361 RefPtr<JSONObject> params = logger.logItemWithParams("setMatrix");
362 params->setArray("matrix", arrayForSkMatrix(matrix));
363 this->SkCanvas::didSetMatrix(matrix);
364 }
365
didConcat(const SkMatrix & matrix)366 void LoggingCanvas::didConcat(const SkMatrix& matrix)
367 {
368 AutoLogger logger(this);
369 RefPtr<JSONObject> params;
370
371 switch (matrix.getType()) {
372 case SkMatrix::kTranslate_Mask:
373 params = logger.logItemWithParams("translate");
374 params->setNumber("dx", matrix.getTranslateX());
375 params->setNumber("dy", matrix.getTranslateY());
376 break;
377
378 case SkMatrix::kScale_Mask:
379 params = logger.logItemWithParams("scale");
380 params->setNumber("scaleX", matrix.getScaleX());
381 params->setNumber("scaleY", matrix.getScaleY());
382 break;
383
384 default:
385 params = logger.logItemWithParams("concat");
386 params->setArray("matrix", arrayForSkMatrix(matrix));
387 }
388 this->SkCanvas::didConcat(matrix);
389 }
390
willSave()391 void LoggingCanvas::willSave()
392 {
393 AutoLogger logger(this);
394 RefPtr<JSONObject> params = logger.logItem("save");
395 this->SkCanvas::willSave();
396 }
397
willSaveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)398 SkCanvas::SaveLayerStrategy LoggingCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags)
399 {
400 AutoLogger logger(this);
401 RefPtr<JSONObject> params = logger.logItemWithParams("saveLayer");
402 if (bounds)
403 params->setObject("bounds", objectForSkRect(*bounds));
404 params->setObject("paint", objectForSkPaint(*paint));
405 params->setString("saveFlags", saveFlagsToString(flags));
406 return this->SkCanvas::willSaveLayer(bounds, paint, flags);
407 }
408
willRestore()409 void LoggingCanvas::willRestore()
410 {
411 AutoLogger logger(this);
412 logger.logItem("restore");
413 this->SkCanvas::willRestore();
414 }
415
log()416 PassRefPtr<JSONArray> LoggingCanvas::log()
417 {
418 return m_log;
419 }
420
objectForSkRect(const SkRect & rect)421 PassRefPtr<JSONObject> LoggingCanvas::objectForSkRect(const SkRect& rect)
422 {
423 RefPtr<JSONObject> rectItem = JSONObject::create();
424 rectItem->setNumber("left", rect.left());
425 rectItem->setNumber("top", rect.top());
426 rectItem->setNumber("right", rect.right());
427 rectItem->setNumber("bottom", rect.bottom());
428 return rectItem.release();
429 }
430
objectForSkIRect(const SkIRect & rect)431 PassRefPtr<JSONObject> LoggingCanvas::objectForSkIRect(const SkIRect& rect)
432 {
433 RefPtr<JSONObject> rectItem = JSONObject::create();
434 rectItem->setNumber("left", rect.left());
435 rectItem->setNumber("top", rect.top());
436 rectItem->setNumber("right", rect.right());
437 rectItem->setNumber("bottom", rect.bottom());
438 return rectItem.release();
439 }
440
pointModeName(PointMode mode)441 String LoggingCanvas::pointModeName(PointMode mode)
442 {
443 switch (mode) {
444 case SkCanvas::kPoints_PointMode: return "Points";
445 case SkCanvas::kLines_PointMode: return "Lines";
446 case SkCanvas::kPolygon_PointMode: return "Polygon";
447 default:
448 ASSERT_NOT_REACHED();
449 return "?";
450 };
451 }
452
objectForSkPoint(const SkPoint & point)453 PassRefPtr<JSONObject> LoggingCanvas::objectForSkPoint(const SkPoint& point)
454 {
455 RefPtr<JSONObject> pointItem = JSONObject::create();
456 pointItem->setNumber("x", point.x());
457 pointItem->setNumber("y", point.y());
458 return pointItem.release();
459 }
460
arrayForSkPoints(size_t count,const SkPoint points[])461 PassRefPtr<JSONArray> LoggingCanvas::arrayForSkPoints(size_t count, const SkPoint points[])
462 {
463 RefPtr<JSONArray> pointsArrayItem = JSONArray::create();
464 for (size_t i = 0; i < count; ++i)
465 pointsArrayItem->pushObject(objectForSkPoint(points[i]));
466 return pointsArrayItem.release();
467 }
468
objectForSkPicture(const SkPicture & picture)469 PassRefPtr<JSONObject> LoggingCanvas::objectForSkPicture(const SkPicture& picture)
470 {
471 RefPtr<JSONObject> pictureItem = JSONObject::create();
472 pictureItem->setNumber("width", picture.width());
473 pictureItem->setNumber("height", picture.height());
474 return pictureItem.release();
475 }
476
objectForRadius(const SkRRect & rrect,SkRRect::Corner corner)477 PassRefPtr<JSONObject> LoggingCanvas::objectForRadius(const SkRRect& rrect, SkRRect::Corner corner)
478 {
479 RefPtr<JSONObject> radiusItem = JSONObject::create();
480 SkVector radius = rrect.radii(corner);
481 radiusItem->setNumber("xRadius", radius.x());
482 radiusItem->setNumber("yRadius", radius.y());
483 return radiusItem.release();
484 }
485
rrectTypeName(SkRRect::Type type)486 String LoggingCanvas::rrectTypeName(SkRRect::Type type)
487 {
488 switch (type) {
489 case SkRRect::kEmpty_Type: return "Empty";
490 case SkRRect::kRect_Type: return "Rect";
491 case SkRRect::kOval_Type: return "Oval";
492 case SkRRect::kSimple_Type: return "Simple";
493 case SkRRect::kNinePatch_Type: return "Nine-patch";
494 case SkRRect::kComplex_Type: return "Complex";
495 default:
496 ASSERT_NOT_REACHED();
497 return "?";
498 };
499 }
500
radiusName(SkRRect::Corner corner)501 String LoggingCanvas::radiusName(SkRRect::Corner corner)
502 {
503 switch (corner) {
504 case SkRRect::kUpperLeft_Corner: return "upperLeftRadius";
505 case SkRRect::kUpperRight_Corner: return "upperRightRadius";
506 case SkRRect::kLowerRight_Corner: return "lowerRightRadius";
507 case SkRRect::kLowerLeft_Corner: return "lowerLeftRadius";
508 default:
509 ASSERT_NOT_REACHED();
510 return "?";
511 }
512 }
513
objectForSkRRect(const SkRRect & rrect)514 PassRefPtr<JSONObject> LoggingCanvas::objectForSkRRect(const SkRRect& rrect)
515 {
516 RefPtr<JSONObject> rrectItem = JSONObject::create();
517 rrectItem->setString("type", rrectTypeName(rrect.type()));
518 rrectItem->setNumber("left", rrect.rect().left());
519 rrectItem->setNumber("top", rrect.rect().top());
520 rrectItem->setNumber("right", rrect.rect().right());
521 rrectItem->setNumber("bottom", rrect.rect().bottom());
522 for (int i = 0; i < 4; ++i)
523 rrectItem->setObject(radiusName((SkRRect::Corner) i), objectForRadius(rrect, (SkRRect::Corner) i));
524 return rrectItem.release();
525 }
526
fillTypeName(SkPath::FillType type)527 String LoggingCanvas::fillTypeName(SkPath::FillType type)
528 {
529 switch (type) {
530 case SkPath::kWinding_FillType: return "Winding";
531 case SkPath::kEvenOdd_FillType: return "EvenOdd";
532 case SkPath::kInverseWinding_FillType: return "InverseWinding";
533 case SkPath::kInverseEvenOdd_FillType: return "InverseEvenOdd";
534 default:
535 ASSERT_NOT_REACHED();
536 return "?";
537 };
538 }
539
convexityName(SkPath::Convexity convexity)540 String LoggingCanvas::convexityName(SkPath::Convexity convexity)
541 {
542 switch (convexity) {
543 case SkPath::kUnknown_Convexity: return "Unknown";
544 case SkPath::kConvex_Convexity: return "Convex";
545 case SkPath::kConcave_Convexity: return "Concave";
546 default:
547 ASSERT_NOT_REACHED();
548 return "?";
549 };
550 }
551
verbName(SkPath::Verb verb)552 String LoggingCanvas::verbName(SkPath::Verb verb)
553 {
554 switch (verb) {
555 case SkPath::kMove_Verb: return "Move";
556 case SkPath::kLine_Verb: return "Line";
557 case SkPath::kQuad_Verb: return "Quad";
558 case SkPath::kConic_Verb: return "Conic";
559 case SkPath::kCubic_Verb: return "Cubic";
560 case SkPath::kClose_Verb: return "Close";
561 case SkPath::kDone_Verb: return "Done";
562 default:
563 ASSERT_NOT_REACHED();
564 return "?";
565 };
566 }
567
segmentParams(SkPath::Verb verb)568 LoggingCanvas::VerbParams LoggingCanvas::segmentParams(SkPath::Verb verb)
569 {
570 switch (verb) {
571 case SkPath::kMove_Verb: return VerbParams("Move", 1, 0);
572 case SkPath::kLine_Verb: return VerbParams("Line", 1, 1);
573 case SkPath::kQuad_Verb: return VerbParams("Quad", 2, 1);
574 case SkPath::kConic_Verb: return VerbParams("Conic", 2, 1);
575 case SkPath::kCubic_Verb: return VerbParams("Cubic", 3, 1);
576 case SkPath::kClose_Verb: return VerbParams("Close", 0, 0);
577 case SkPath::kDone_Verb: return VerbParams("Done", 0, 0);
578 default:
579 ASSERT_NOT_REACHED();
580 return VerbParams("?", 0, 0);
581 };
582 }
583
objectForSkPath(const SkPath & path)584 PassRefPtr<JSONObject> LoggingCanvas::objectForSkPath(const SkPath& path)
585 {
586 RefPtr<JSONObject> pathItem = JSONObject::create();
587 pathItem->setString("fillType", fillTypeName(path.getFillType()));
588 pathItem->setString("convexity", convexityName(path.getConvexity()));
589 pathItem->setBoolean("isRect", path.isRect(0));
590 SkPath::Iter iter(path, false);
591 SkPoint points[4];
592 RefPtr<JSONArray> pathPointsArray = JSONArray::create();
593 for (SkPath::Verb verb = iter.next(points, false); verb != SkPath::kDone_Verb; verb = iter.next(points, false)) {
594 VerbParams verbParams = segmentParams(verb);
595 RefPtr<JSONObject> pathPointItem = JSONObject::create();
596 pathPointItem->setString("verb", verbParams.name);
597 ASSERT(verbParams.pointCount + verbParams.pointOffset <= WTF_ARRAY_LENGTH(points));
598 pathPointItem->setArray("points", arrayForSkPoints(verbParams.pointCount, points + verbParams.pointOffset));
599 if (SkPath::kConic_Verb == verb)
600 pathPointItem->setNumber("conicWeight", iter.conicWeight());
601 pathPointsArray->pushObject(pathPointItem);
602 }
603 pathItem->setArray("pathPoints", pathPointsArray);
604 pathItem->setObject("bounds", objectForSkRect(path.getBounds()));
605 return pathItem.release();
606 }
607
colorTypeName(SkColorType colorType)608 String LoggingCanvas::colorTypeName(SkColorType colorType)
609 {
610 switch (colorType) {
611 case kUnknown_SkColorType: return "None";
612 case kAlpha_8_SkColorType: return "A8";
613 case kIndex_8_SkColorType: return "Index8";
614 case kRGB_565_SkColorType: return "RGB565";
615 case kARGB_4444_SkColorType: return "ARGB4444";
616 case kN32_SkColorType: return "ARGB8888";
617 default:
618 ASSERT_NOT_REACHED();
619 return "?";
620 };
621 }
622
objectForBitmapData(const SkBitmap & bitmap)623 PassRefPtr<JSONObject> LoggingCanvas::objectForBitmapData(const SkBitmap& bitmap)
624 {
625 RefPtr<JSONObject> dataItem = JSONObject::create();
626 Vector<unsigned char> output;
627 PNGImageEncoder::encode(bitmap, &output);
628 dataItem->setString("base64", WTF::base64Encode(reinterpret_cast<char*>(output.data()), output.size()));
629 dataItem->setString("mimeType", "image/png");
630 return dataItem.release();
631 }
632
objectForSkBitmap(const SkBitmap & bitmap)633 PassRefPtr<JSONObject> LoggingCanvas::objectForSkBitmap(const SkBitmap& bitmap)
634 {
635 RefPtr<JSONObject> bitmapItem = JSONObject::create();
636 bitmapItem->setNumber("width", bitmap.width());
637 bitmapItem->setNumber("height", bitmap.height());
638 bitmapItem->setString("config", colorTypeName(bitmap.colorType()));
639 bitmapItem->setBoolean("opaque", bitmap.isOpaque());
640 bitmapItem->setBoolean("immutable", bitmap.isImmutable());
641 bitmapItem->setBoolean("volatile", bitmap.isVolatile());
642 bitmapItem->setNumber("genID", bitmap.getGenerationID());
643 bitmapItem->setObject("data", objectForBitmapData(bitmap));
644 return bitmapItem.release();
645 }
646
objectForSkShader(const SkShader & shader)647 PassRefPtr<JSONObject> LoggingCanvas::objectForSkShader(const SkShader& shader)
648 {
649 RefPtr<JSONObject> shaderItem = JSONObject::create();
650 const SkMatrix localMatrix = shader.getLocalMatrix();
651 if (!localMatrix.isIdentity())
652 shaderItem->setArray("localMatrix", arrayForSkMatrix(localMatrix));
653 return shaderItem.release();
654 }
655
stringForSkColor(const SkColor & color)656 String LoggingCanvas::stringForSkColor(const SkColor& color)
657 {
658 String colorString = "#";
659 appendUnsignedAsHex(color, colorString);
660 return colorString;
661 }
662
appendFlagToString(String * flagsString,bool isSet,const String & name)663 void LoggingCanvas::appendFlagToString(String* flagsString, bool isSet, const String& name)
664 {
665 if (!isSet)
666 return;
667 if (flagsString->length())
668 flagsString->append("|");
669 flagsString->append(name);
670 }
671
stringForSkPaintFlags(const SkPaint & paint)672 String LoggingCanvas::stringForSkPaintFlags(const SkPaint& paint)
673 {
674 if (!paint.getFlags())
675 return "none";
676 String flagsString = "";
677 appendFlagToString(&flagsString, paint.isAntiAlias(), "AntiAlias");
678 appendFlagToString(&flagsString, paint.isDither(), "Dither");
679 appendFlagToString(&flagsString, paint.isUnderlineText(), "UnderlinText");
680 appendFlagToString(&flagsString, paint.isStrikeThruText(), "StrikeThruText");
681 appendFlagToString(&flagsString, paint.isFakeBoldText(), "FakeBoldText");
682 appendFlagToString(&flagsString, paint.isLinearText(), "LinearText");
683 appendFlagToString(&flagsString, paint.isSubpixelText(), "SubpixelText");
684 appendFlagToString(&flagsString, paint.isDevKernText(), "DevKernText");
685 appendFlagToString(&flagsString, paint.isLCDRenderText(), "LCDRenderText");
686 appendFlagToString(&flagsString, paint.isEmbeddedBitmapText(), "EmbeddedBitmapText");
687 appendFlagToString(&flagsString, paint.isAutohinted(), "Autohinted");
688 appendFlagToString(&flagsString, paint.isVerticalText(), "VerticalText");
689 appendFlagToString(&flagsString, paint.getFlags() & SkPaint::kGenA8FromLCD_Flag, "GenA8FromLCD");
690 return flagsString;
691 }
692
filterLevelName(SkPaint::FilterLevel filterLevel)693 String LoggingCanvas::filterLevelName(SkPaint::FilterLevel filterLevel)
694 {
695 switch (filterLevel) {
696 case SkPaint::kNone_FilterLevel: return "None";
697 case SkPaint::kLow_FilterLevel: return "Low";
698 case SkPaint::kMedium_FilterLevel: return "Medium";
699 case SkPaint::kHigh_FilterLevel: return "High";
700 default:
701 ASSERT_NOT_REACHED();
702 return "?";
703 };
704 }
705
textAlignName(SkPaint::Align align)706 String LoggingCanvas::textAlignName(SkPaint::Align align)
707 {
708 switch (align) {
709 case SkPaint::kLeft_Align: return "Left";
710 case SkPaint::kCenter_Align: return "Center";
711 case SkPaint::kRight_Align: return "Right";
712 default:
713 ASSERT_NOT_REACHED();
714 return "?";
715 };
716 }
717
strokeCapName(SkPaint::Cap cap)718 String LoggingCanvas::strokeCapName(SkPaint::Cap cap)
719 {
720 switch (cap) {
721 case SkPaint::kButt_Cap: return "Butt";
722 case SkPaint::kRound_Cap: return "Round";
723 case SkPaint::kSquare_Cap: return "Square";
724 default:
725 ASSERT_NOT_REACHED();
726 return "?";
727 };
728 }
729
strokeJoinName(SkPaint::Join join)730 String LoggingCanvas::strokeJoinName(SkPaint::Join join)
731 {
732 switch (join) {
733 case SkPaint::kMiter_Join: return "Miter";
734 case SkPaint::kRound_Join: return "Round";
735 case SkPaint::kBevel_Join: return "Bevel";
736 default:
737 ASSERT_NOT_REACHED();
738 return "?";
739 };
740 }
741
styleName(SkPaint::Style style)742 String LoggingCanvas::styleName(SkPaint::Style style)
743 {
744 switch (style) {
745 case SkPaint::kFill_Style: return "Fill";
746 case SkPaint::kStroke_Style: return "Stroke";
747 case SkPaint::kStrokeAndFill_Style: return "StrokeAndFill";
748 default:
749 ASSERT_NOT_REACHED();
750 return "?";
751 };
752 }
753
textEncodingName(SkPaint::TextEncoding encoding)754 String LoggingCanvas::textEncodingName(SkPaint::TextEncoding encoding)
755 {
756 switch (encoding) {
757 case SkPaint::kUTF8_TextEncoding: return "UTF-8";
758 case SkPaint::kUTF16_TextEncoding: return "UTF-16";
759 case SkPaint::kUTF32_TextEncoding: return "UTF-32";
760 case SkPaint::kGlyphID_TextEncoding: return "GlyphID";
761 default:
762 ASSERT_NOT_REACHED();
763 return "?";
764 };
765 }
766
hintingName(SkPaint::Hinting hinting)767 String LoggingCanvas::hintingName(SkPaint::Hinting hinting)
768 {
769 switch (hinting) {
770 case SkPaint::kNo_Hinting: return "None";
771 case SkPaint::kSlight_Hinting: return "Slight";
772 case SkPaint::kNormal_Hinting: return "Normal";
773 case SkPaint::kFull_Hinting: return "Full";
774 default:
775 ASSERT_NOT_REACHED();
776 return "?";
777 };
778 }
779
objectForSkPaint(const SkPaint & paint)780 PassRefPtr<JSONObject> LoggingCanvas::objectForSkPaint(const SkPaint& paint)
781 {
782 RefPtr<JSONObject> paintItem = JSONObject::create();
783 paintItem->setNumber("textSize", paint.getTextSize());
784 paintItem->setNumber("textScaleX", paint.getTextScaleX());
785 paintItem->setNumber("textSkewX", paint.getTextSkewX());
786 if (SkShader* shader = paint.getShader())
787 paintItem->setObject("shader", objectForSkShader(*shader));
788 paintItem->setString("color", stringForSkColor(paint.getColor()));
789 paintItem->setNumber("strokeWidth", paint.getStrokeWidth());
790 paintItem->setNumber("strokeMiter", paint.getStrokeMiter());
791 paintItem->setString("flags", stringForSkPaintFlags(paint));
792 paintItem->setString("filterLevel", filterLevelName(paint.getFilterLevel()));
793 paintItem->setString("textAlign", textAlignName(paint.getTextAlign()));
794 paintItem->setString("strokeCap", strokeCapName(paint.getStrokeCap()));
795 paintItem->setString("strokeJoin", strokeJoinName(paint.getStrokeJoin()));
796 paintItem->setString("styleName", styleName(paint.getStyle()));
797 paintItem->setString("textEncoding", textEncodingName(paint.getTextEncoding()));
798 paintItem->setString("hinting", hintingName(paint.getHinting()));
799 return paintItem.release();
800 }
801
arrayForSkMatrix(const SkMatrix & matrix)802 PassRefPtr<JSONArray> LoggingCanvas::arrayForSkMatrix(const SkMatrix& matrix)
803 {
804 RefPtr<JSONArray> matrixArray = JSONArray::create();
805 for (int i = 0; i < 9; ++i)
806 matrixArray->pushNumber(matrix[i]);
807 return matrixArray.release();
808 }
809
arrayForSkScalars(size_t n,const SkScalar scalars[])810 PassRefPtr<JSONArray> LoggingCanvas::arrayForSkScalars(size_t n, const SkScalar scalars[])
811 {
812 RefPtr<JSONArray> scalarsArray = JSONArray::create();
813 for (size_t i = 0; i < n; ++i)
814 scalarsArray->pushNumber(scalars[i]);
815 return scalarsArray.release();
816 }
817
regionOpName(SkRegion::Op op)818 String LoggingCanvas::regionOpName(SkRegion::Op op)
819 {
820 switch (op) {
821 case SkRegion::kDifference_Op: return "kDifference_Op";
822 case SkRegion::kIntersect_Op: return "kIntersect_Op";
823 case SkRegion::kUnion_Op: return "kUnion_Op";
824 case SkRegion::kXOR_Op: return "kXOR_Op";
825 case SkRegion::kReverseDifference_Op: return "kReverseDifference_Op";
826 case SkRegion::kReplace_Op: return "kReplace_Op";
827 default: return "Unknown type";
828 };
829 }
830
saveFlagsToString(SkCanvas::SaveFlags flags)831 String LoggingCanvas::saveFlagsToString(SkCanvas::SaveFlags flags)
832 {
833 String flagsString = "";
834 if (flags & SkCanvas::kHasAlphaLayer_SaveFlag)
835 flagsString.append("kHasAlphaLayer_SaveFlag ");
836 if (flags & SkCanvas::kFullColorLayer_SaveFlag)
837 flagsString.append("kFullColorLayer_SaveFlag ");
838 if (flags & SkCanvas::kClipToLayer_SaveFlag)
839 flagsString.append("kClipToLayer_SaveFlag ");
840 return flagsString;
841 }
842
textEncodingCanonicalName(SkPaint::TextEncoding encoding)843 String LoggingCanvas::textEncodingCanonicalName(SkPaint::TextEncoding encoding)
844 {
845 String name = textEncodingName(encoding);
846 if (encoding == SkPaint::kUTF16_TextEncoding || encoding == SkPaint::kUTF32_TextEncoding)
847 name.append("LE");
848 return name;
849 }
850
stringForUTFText(const void * text,size_t length,SkPaint::TextEncoding encoding)851 String LoggingCanvas::stringForUTFText(const void* text, size_t length, SkPaint::TextEncoding encoding)
852 {
853 return WTF::TextEncoding(textEncodingCanonicalName(encoding)).decode((const char*)text, length);
854 }
855
stringForText(const void * text,size_t byteLength,const SkPaint & paint)856 String LoggingCanvas::stringForText(const void* text, size_t byteLength, const SkPaint& paint)
857 {
858 SkPaint::TextEncoding encoding = paint.getTextEncoding();
859 switch (encoding) {
860 case SkPaint::kUTF8_TextEncoding:
861 case SkPaint::kUTF16_TextEncoding:
862 case SkPaint::kUTF32_TextEncoding:
863 return stringForUTFText(text, byteLength, encoding);
864 case SkPaint::kGlyphID_TextEncoding: {
865 WTF::Vector<SkUnichar> dataVector(byteLength / 2);
866 SkUnichar* textData = dataVector.data();
867 paint.glyphsToUnichars(static_cast<const uint16_t*>(text), byteLength / 2, textData);
868 return WTF::UTF32LittleEndianEncoding().decode(reinterpret_cast<const char*>(textData), byteLength * 2);
869 }
870 default:
871 ASSERT_NOT_REACHED();
872 return "?";
873 }
874 }
875
876 } // namespace blink
877