Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / LoggingCanvas.cpp
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
54 AutoLogger::AutoLogger(LoggingCanvas* loggingCanvas) : m_canvas(loggingCanvas)
55 {
56     loggingCanvas->m_depthCount++;
57 }
58
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
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
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
82 LoggingCanvas::LoggingCanvas(int width, int height) : InterceptingCanvas(width, height)
83 {
84     m_log = JSONArray::create();
85 }
86
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
236 void LoggingCanvas::endCommentGroup()
237 {
238     AutoLogger logger(this);
239     logger.logItem("endCommentGroup");
240     this->SkCanvas::endCommentGroup();
241 }
242
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
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
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
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
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
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
306 void LoggingCanvas::onPopCull()
307 {
308     AutoLogger logger(this);
309     logger.logItem("popCull");
310     this->SkCanvas::onPopCull();
311 }
312
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
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
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
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
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
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
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
391 void LoggingCanvas::willSave()
392 {
393     AutoLogger logger(this);
394     RefPtr<JSONObject> params = logger.logItemWithParams("save");
395     this->SkCanvas::willSave();
396 }
397
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
409 void LoggingCanvas::willRestore()
410 {
411     AutoLogger logger(this);
412     logger.logItem("restore");
413     this->SkCanvas::willRestore();
414 }
415
416 PassRefPtr<JSONArray> LoggingCanvas::log()
417 {
418     return m_log;
419 }
420
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
656 String LoggingCanvas::stringForSkColor(const SkColor& color)
657 {
658     String colorString = "#";
659     appendUnsignedAsHex(color, colorString);
660     return colorString;
661 }
662
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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