Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / platform / graphics / LoggingCanvas.cpp
blobb3a153bf1c4f27e3aaaba46aa53336ad4a458f14
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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.
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.
31 #include "config.h"
32 #include "platform/graphics/LoggingCanvas.h"
34 #include "platform/geometry/IntSize.h"
35 #include "platform/graphics/ImageBuffer.h"
36 #include "platform/graphics/skia/ImagePixelLocker.h"
37 #include "platform/image-encoders/skia/PNGImageEncoder.h"
38 #include "third_party/skia/include/core/SkImage.h"
39 #include "third_party/skia/include/core/SkImageInfo.h"
40 #include "third_party/skia/include/core/SkPaint.h"
41 #include "third_party/skia/include/core/SkPath.h"
42 #include "third_party/skia/include/core/SkPicture.h"
43 #include "third_party/skia/include/core/SkRRect.h"
44 #include "third_party/skia/include/core/SkRect.h"
45 #include "wtf/HexNumber.h"
46 #include "wtf/text/Base64.h"
47 #include "wtf/text/TextEncoding.h"
49 namespace blink {
51 namespace {
53 struct VerbParams {
54 String name;
55 unsigned pointCount;
56 unsigned pointOffset;
58 VerbParams(const String& name, unsigned pointCount, unsigned pointOffset)
59 : name(name)
60 , pointCount(pointCount)
61 , pointOffset(pointOffset) { }
64 PassRefPtr<JSONObject> objectForSkRect(const SkRect& rect)
66 RefPtr<JSONObject> rectItem = JSONObject::create();
67 rectItem->setNumber("left", rect.left());
68 rectItem->setNumber("top", rect.top());
69 rectItem->setNumber("right", rect.right());
70 rectItem->setNumber("bottom", rect.bottom());
71 return rectItem.release();
74 PassRefPtr<JSONObject> objectForSkIRect(const SkIRect& rect)
76 RefPtr<JSONObject> rectItem = JSONObject::create();
77 rectItem->setNumber("left", rect.left());
78 rectItem->setNumber("top", rect.top());
79 rectItem->setNumber("right", rect.right());
80 rectItem->setNumber("bottom", rect.bottom());
81 return rectItem.release();
84 String pointModeName(SkCanvas::PointMode mode)
86 switch (mode) {
87 case SkCanvas::kPoints_PointMode: return "Points";
88 case SkCanvas::kLines_PointMode: return "Lines";
89 case SkCanvas::kPolygon_PointMode: return "Polygon";
90 default:
91 ASSERT_NOT_REACHED();
92 return "?";
96 PassRefPtr<JSONObject> objectForSkPoint(const SkPoint& point)
98 RefPtr<JSONObject> pointItem = JSONObject::create();
99 pointItem->setNumber("x", point.x());
100 pointItem->setNumber("y", point.y());
101 return pointItem.release();
104 PassRefPtr<JSONArray> arrayForSkPoints(size_t count, const SkPoint points[])
106 RefPtr<JSONArray> pointsArrayItem = JSONArray::create();
107 for (size_t i = 0; i < count; ++i)
108 pointsArrayItem->pushObject(objectForSkPoint(points[i]));
109 return pointsArrayItem.release();
112 PassRefPtr<JSONObject> objectForRadius(const SkRRect& rrect, SkRRect::Corner corner)
114 RefPtr<JSONObject> radiusItem = JSONObject::create();
115 SkVector radius = rrect.radii(corner);
116 radiusItem->setNumber("xRadius", radius.x());
117 radiusItem->setNumber("yRadius", radius.y());
118 return radiusItem.release();
121 String rrectTypeName(SkRRect::Type type)
123 switch (type) {
124 case SkRRect::kEmpty_Type: return "Empty";
125 case SkRRect::kRect_Type: return "Rect";
126 case SkRRect::kOval_Type: return "Oval";
127 case SkRRect::kSimple_Type: return "Simple";
128 case SkRRect::kNinePatch_Type: return "Nine-patch";
129 case SkRRect::kComplex_Type: return "Complex";
130 default:
131 ASSERT_NOT_REACHED();
132 return "?";
136 String radiusName(SkRRect::Corner corner)
138 switch (corner) {
139 case SkRRect::kUpperLeft_Corner: return "upperLeftRadius";
140 case SkRRect::kUpperRight_Corner: return "upperRightRadius";
141 case SkRRect::kLowerRight_Corner: return "lowerRightRadius";
142 case SkRRect::kLowerLeft_Corner: return "lowerLeftRadius";
143 default:
144 ASSERT_NOT_REACHED();
145 return "?";
149 PassRefPtr<JSONObject> objectForSkRRect(const SkRRect& rrect)
151 RefPtr<JSONObject> rrectItem = JSONObject::create();
152 rrectItem->setString("type", rrectTypeName(rrect.type()));
153 rrectItem->setNumber("left", rrect.rect().left());
154 rrectItem->setNumber("top", rrect.rect().top());
155 rrectItem->setNumber("right", rrect.rect().right());
156 rrectItem->setNumber("bottom", rrect.rect().bottom());
157 for (int i = 0; i < 4; ++i)
158 rrectItem->setObject(radiusName((SkRRect::Corner) i), objectForRadius(rrect, (SkRRect::Corner) i));
159 return rrectItem.release();
162 String fillTypeName(SkPath::FillType type)
164 switch (type) {
165 case SkPath::kWinding_FillType: return "Winding";
166 case SkPath::kEvenOdd_FillType: return "EvenOdd";
167 case SkPath::kInverseWinding_FillType: return "InverseWinding";
168 case SkPath::kInverseEvenOdd_FillType: return "InverseEvenOdd";
169 default:
170 ASSERT_NOT_REACHED();
171 return "?";
175 String convexityName(SkPath::Convexity convexity)
177 switch (convexity) {
178 case SkPath::kUnknown_Convexity: return "Unknown";
179 case SkPath::kConvex_Convexity: return "Convex";
180 case SkPath::kConcave_Convexity: return "Concave";
181 default:
182 ASSERT_NOT_REACHED();
183 return "?";
187 VerbParams segmentParams(SkPath::Verb verb)
189 switch (verb) {
190 case SkPath::kMove_Verb: return VerbParams("Move", 1, 0);
191 case SkPath::kLine_Verb: return VerbParams("Line", 1, 1);
192 case SkPath::kQuad_Verb: return VerbParams("Quad", 2, 1);
193 case SkPath::kConic_Verb: return VerbParams("Conic", 2, 1);
194 case SkPath::kCubic_Verb: return VerbParams("Cubic", 3, 1);
195 case SkPath::kClose_Verb: return VerbParams("Close", 0, 0);
196 case SkPath::kDone_Verb: return VerbParams("Done", 0, 0);
197 default:
198 ASSERT_NOT_REACHED();
199 return VerbParams("?", 0, 0);
203 PassRefPtr<JSONObject> objectForSkPath(const SkPath& path)
205 RefPtr<JSONObject> pathItem = JSONObject::create();
206 pathItem->setString("fillType", fillTypeName(path.getFillType()));
207 pathItem->setString("convexity", convexityName(path.getConvexity()));
208 pathItem->setBoolean("isRect", path.isRect(0));
209 SkPath::Iter iter(path, false);
210 SkPoint points[4];
211 RefPtr<JSONArray> pathPointsArray = JSONArray::create();
212 for (SkPath::Verb verb = iter.next(points, false); verb != SkPath::kDone_Verb; verb = iter.next(points, false)) {
213 VerbParams verbParams = segmentParams(verb);
214 RefPtr<JSONObject> pathPointItem = JSONObject::create();
215 pathPointItem->setString("verb", verbParams.name);
216 ASSERT(verbParams.pointCount + verbParams.pointOffset <= WTF_ARRAY_LENGTH(points));
217 pathPointItem->setArray("points", arrayForSkPoints(verbParams.pointCount, points + verbParams.pointOffset));
218 if (SkPath::kConic_Verb == verb)
219 pathPointItem->setNumber("conicWeight", iter.conicWeight());
220 pathPointsArray->pushObject(pathPointItem);
222 pathItem->setArray("pathPoints", pathPointsArray);
223 pathItem->setObject("bounds", objectForSkRect(path.getBounds()));
224 return pathItem.release();
227 String colorTypeName(SkColorType colorType)
229 switch (colorType) {
230 case kUnknown_SkColorType: return "None";
231 case kAlpha_8_SkColorType: return "A8";
232 case kIndex_8_SkColorType: return "Index8";
233 case kRGB_565_SkColorType: return "RGB565";
234 case kARGB_4444_SkColorType: return "ARGB4444";
235 case kN32_SkColorType: return "ARGB8888";
236 default:
237 ASSERT_NOT_REACHED();
238 return "?";
242 PassRefPtr<JSONObject> objectForBitmapData(const SkBitmap& bitmap)
244 Vector<unsigned char> output;
246 if (RefPtr<SkImage> image = adoptRef(SkImage::NewFromBitmap(bitmap))) {
247 ImagePixelLocker pixelLocker(image, kUnpremul_SkAlphaType);
248 ImageDataBuffer imageData(IntSize(image->width(), image->height()),
249 static_cast<const unsigned char*>(pixelLocker.pixels()));
251 PNGImageEncoder::encode(imageData, &output);
254 RefPtr<JSONObject> dataItem = JSONObject::create();
255 dataItem->setString("base64", WTF::base64Encode(reinterpret_cast<char*>(output.data()), output.size()));
256 dataItem->setString("mimeType", "image/png");
257 return dataItem.release();
260 PassRefPtr<JSONObject> objectForSkBitmap(const SkBitmap& bitmap)
262 RefPtr<JSONObject> bitmapItem = JSONObject::create();
263 bitmapItem->setNumber("width", bitmap.width());
264 bitmapItem->setNumber("height", bitmap.height());
265 bitmapItem->setString("config", colorTypeName(bitmap.colorType()));
266 bitmapItem->setBoolean("opaque", bitmap.isOpaque());
267 bitmapItem->setBoolean("immutable", bitmap.isImmutable());
268 bitmapItem->setBoolean("volatile", bitmap.isVolatile());
269 bitmapItem->setNumber("genID", bitmap.getGenerationID());
270 bitmapItem->setObject("data", objectForBitmapData(bitmap));
271 return bitmapItem.release();
274 PassRefPtr<JSONObject> objectForSkImage(const SkImage* image)
276 RefPtr<JSONObject> imageItem = JSONObject::create();
277 imageItem->setNumber("width", image->width());
278 imageItem->setNumber("height", image->height());
279 imageItem->setBoolean("opaque", image->isOpaque());
280 imageItem->setNumber("uniqueID", image->uniqueID());
281 return imageItem.release();
284 PassRefPtr<JSONArray> arrayForSkMatrix(const SkMatrix& matrix)
286 RefPtr<JSONArray> matrixArray = JSONArray::create();
287 for (int i = 0; i < 9; ++i)
288 matrixArray->pushNumber(matrix[i]);
289 return matrixArray.release();
292 PassRefPtr<JSONObject> objectForSkShader(const SkShader& shader)
294 RefPtr<JSONObject> shaderItem = JSONObject::create();
295 const SkMatrix localMatrix = shader.getLocalMatrix();
296 if (!localMatrix.isIdentity())
297 shaderItem->setArray("localMatrix", arrayForSkMatrix(localMatrix));
298 return shaderItem.release();
301 String stringForSkColor(const SkColor& color)
303 String colorString = "#";
304 appendUnsignedAsHex(color, colorString);
305 return colorString;
308 void appendFlagToString(String* flagsString, bool isSet, const String& name)
310 if (!isSet)
311 return;
312 if (flagsString->length())
313 flagsString->append("|");
314 flagsString->append(name);
317 String stringForSkPaintFlags(const SkPaint& paint)
319 if (!paint.getFlags())
320 return "none";
321 String flagsString = "";
322 appendFlagToString(&flagsString, paint.isAntiAlias(), "AntiAlias");
323 appendFlagToString(&flagsString, paint.isDither(), "Dither");
324 appendFlagToString(&flagsString, paint.isUnderlineText(), "UnderlinText");
325 appendFlagToString(&flagsString, paint.isStrikeThruText(), "StrikeThruText");
326 appendFlagToString(&flagsString, paint.isFakeBoldText(), "FakeBoldText");
327 appendFlagToString(&flagsString, paint.isLinearText(), "LinearText");
328 appendFlagToString(&flagsString, paint.isSubpixelText(), "SubpixelText");
329 appendFlagToString(&flagsString, paint.isDevKernText(), "DevKernText");
330 appendFlagToString(&flagsString, paint.isLCDRenderText(), "LCDRenderText");
331 appendFlagToString(&flagsString, paint.isEmbeddedBitmapText(), "EmbeddedBitmapText");
332 appendFlagToString(&flagsString, paint.isAutohinted(), "Autohinted");
333 appendFlagToString(&flagsString, paint.isVerticalText(), "VerticalText");
334 appendFlagToString(&flagsString, paint.getFlags() & SkPaint::kGenA8FromLCD_Flag, "GenA8FromLCD");
335 return flagsString;
338 String filterQualityName(SkFilterQuality filterQuality)
340 switch (filterQuality) {
341 case kNone_SkFilterQuality: return "None";
342 case kLow_SkFilterQuality: return "Low";
343 case kMedium_SkFilterQuality: return "Medium";
344 case kHigh_SkFilterQuality: return "High";
345 default:
346 ASSERT_NOT_REACHED();
347 return "?";
351 String textAlignName(SkPaint::Align align)
353 switch (align) {
354 case SkPaint::kLeft_Align: return "Left";
355 case SkPaint::kCenter_Align: return "Center";
356 case SkPaint::kRight_Align: return "Right";
357 default:
358 ASSERT_NOT_REACHED();
359 return "?";
363 String strokeCapName(SkPaint::Cap cap)
365 switch (cap) {
366 case SkPaint::kButt_Cap: return "Butt";
367 case SkPaint::kRound_Cap: return "Round";
368 case SkPaint::kSquare_Cap: return "Square";
369 default:
370 ASSERT_NOT_REACHED();
371 return "?";
375 String strokeJoinName(SkPaint::Join join)
377 switch (join) {
378 case SkPaint::kMiter_Join: return "Miter";
379 case SkPaint::kRound_Join: return "Round";
380 case SkPaint::kBevel_Join: return "Bevel";
381 default:
382 ASSERT_NOT_REACHED();
383 return "?";
387 String styleName(SkPaint::Style style)
389 switch (style) {
390 case SkPaint::kFill_Style: return "Fill";
391 case SkPaint::kStroke_Style: return "Stroke";
392 case SkPaint::kStrokeAndFill_Style: return "StrokeAndFill";
393 default:
394 ASSERT_NOT_REACHED();
395 return "?";
399 String textEncodingName(SkPaint::TextEncoding encoding)
401 switch (encoding) {
402 case SkPaint::kUTF8_TextEncoding: return "UTF-8";
403 case SkPaint::kUTF16_TextEncoding: return "UTF-16";
404 case SkPaint::kUTF32_TextEncoding: return "UTF-32";
405 case SkPaint::kGlyphID_TextEncoding: return "GlyphID";
406 default:
407 ASSERT_NOT_REACHED();
408 return "?";
412 String hintingName(SkPaint::Hinting hinting)
414 switch (hinting) {
415 case SkPaint::kNo_Hinting: return "None";
416 case SkPaint::kSlight_Hinting: return "Slight";
417 case SkPaint::kNormal_Hinting: return "Normal";
418 case SkPaint::kFull_Hinting: return "Full";
419 default:
420 ASSERT_NOT_REACHED();
421 return "?";
425 PassRefPtr<JSONObject> objectForSkPaint(const SkPaint& paint)
427 RefPtr<JSONObject> paintItem = JSONObject::create();
428 paintItem->setNumber("textSize", paint.getTextSize());
429 paintItem->setNumber("textScaleX", paint.getTextScaleX());
430 paintItem->setNumber("textSkewX", paint.getTextSkewX());
431 if (SkShader* shader = paint.getShader())
432 paintItem->setObject("shader", objectForSkShader(*shader));
433 paintItem->setString("color", stringForSkColor(paint.getColor()));
434 paintItem->setNumber("strokeWidth", paint.getStrokeWidth());
435 paintItem->setNumber("strokeMiter", paint.getStrokeMiter());
436 paintItem->setString("flags", stringForSkPaintFlags(paint));
437 paintItem->setString("filterLevel", filterQualityName(paint.getFilterQuality()));
438 paintItem->setString("textAlign", textAlignName(paint.getTextAlign()));
439 paintItem->setString("strokeCap", strokeCapName(paint.getStrokeCap()));
440 paintItem->setString("strokeJoin", strokeJoinName(paint.getStrokeJoin()));
441 paintItem->setString("styleName", styleName(paint.getStyle()));
442 paintItem->setString("textEncoding", textEncodingName(paint.getTextEncoding()));
443 paintItem->setString("hinting", hintingName(paint.getHinting()));
444 return paintItem.release();
447 PassRefPtr<JSONArray> arrayForSkScalars(size_t n, const SkScalar scalars[])
449 RefPtr<JSONArray> scalarsArray = JSONArray::create();
450 for (size_t i = 0; i < n; ++i)
451 scalarsArray->pushNumber(scalars[i]);
452 return scalarsArray.release();
455 String regionOpName(SkRegion::Op op)
457 switch (op) {
458 case SkRegion::kDifference_Op: return "kDifference_Op";
459 case SkRegion::kIntersect_Op: return "kIntersect_Op";
460 case SkRegion::kUnion_Op: return "kUnion_Op";
461 case SkRegion::kXOR_Op: return "kXOR_Op";
462 case SkRegion::kReverseDifference_Op: return "kReverseDifference_Op";
463 case SkRegion::kReplace_Op: return "kReplace_Op";
464 default: return "Unknown type";
468 String saveFlagsToString(SkCanvas::SaveFlags flags)
470 String flagsString = "";
471 if (flags & SkCanvas::kHasAlphaLayer_SaveFlag)
472 flagsString.append("kHasAlphaLayer_SaveFlag ");
473 if (flags & SkCanvas::kFullColorLayer_SaveFlag)
474 flagsString.append("kFullColorLayer_SaveFlag ");
475 if (flags & SkCanvas::kClipToLayer_SaveFlag)
476 flagsString.append("kClipToLayer_SaveFlag ");
477 return flagsString;
480 String textEncodingCanonicalName(SkPaint::TextEncoding encoding)
482 String name = textEncodingName(encoding);
483 if (encoding == SkPaint::kUTF16_TextEncoding || encoding == SkPaint::kUTF32_TextEncoding)
484 name.append("LE");
485 return name;
488 String stringForUTFText(const void* text, size_t length, SkPaint::TextEncoding encoding)
490 return WTF::TextEncoding(textEncodingCanonicalName(encoding)).decode((const char*)text, length);
493 String stringForText(const void* text, size_t byteLength, const SkPaint& paint)
495 SkPaint::TextEncoding encoding = paint.getTextEncoding();
496 switch (encoding) {
497 case SkPaint::kUTF8_TextEncoding:
498 case SkPaint::kUTF16_TextEncoding:
499 case SkPaint::kUTF32_TextEncoding:
500 return stringForUTFText(text, byteLength, encoding);
501 case SkPaint::kGlyphID_TextEncoding: {
502 WTF::Vector<SkUnichar> dataVector(byteLength / 2);
503 SkUnichar* textData = dataVector.data();
504 paint.glyphsToUnichars(static_cast<const uint16_t*>(text), byteLength / 2, textData);
505 return WTF::UTF32LittleEndianEncoding().decode(reinterpret_cast<const char*>(textData), byteLength * 2);
507 default:
508 ASSERT_NOT_REACHED();
509 return "?";
513 } // namespace
515 class AutoLogger : InterceptingCanvasBase::CanvasInterceptorBase<LoggingCanvas> {
516 public:
517 explicit AutoLogger(LoggingCanvas* canvas) : InterceptingCanvasBase::CanvasInterceptorBase<LoggingCanvas>(canvas) { }
519 PassRefPtr<JSONObject> logItem(const String& name);
520 PassRefPtr<JSONObject> logItemWithParams(const String& name);
521 ~AutoLogger()
523 if (topLevelCall())
524 canvas()->m_log->pushObject(m_logItem);
527 private:
528 RefPtr<JSONObject> m_logItem;
531 PassRefPtr<JSONObject> AutoLogger::logItem(const String& name)
533 RefPtr<JSONObject> item = JSONObject::create();
534 item->setString("method", name);
535 m_logItem = item;
536 return item.release();
539 PassRefPtr<JSONObject> AutoLogger::logItemWithParams(const String& name)
541 RefPtr<JSONObject> item = logItem(name);
542 RefPtr<JSONObject> params = JSONObject::create();
543 item->setObject("params", params);
544 return params.release();
547 LoggingCanvas::LoggingCanvas(int width, int height)
548 : InterceptingCanvasBase(width, height)
549 , m_log(JSONArray::create())
553 void LoggingCanvas::onDrawPaint(const SkPaint& paint)
555 AutoLogger logger(this);
556 logger.logItemWithParams("drawPaint")->setObject("paint", objectForSkPaint(paint));
557 this->SkCanvas::onDrawPaint(paint);
560 void LoggingCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint)
562 AutoLogger logger(this);
563 RefPtr<JSONObject> params = logger.logItemWithParams("drawPoints");
564 params->setString("pointMode", pointModeName(mode));
565 params->setArray("points", arrayForSkPoints(count, pts));
566 params->setObject("paint", objectForSkPaint(paint));
567 this->SkCanvas::onDrawPoints(mode, count, pts, paint);
570 void LoggingCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint)
572 AutoLogger logger(this);
573 RefPtr<JSONObject> params = logger.logItemWithParams("drawRect");
574 params->setObject("rect", objectForSkRect(rect));
575 params->setObject("paint", objectForSkPaint(paint));
576 this->SkCanvas::onDrawRect(rect, paint);
579 void LoggingCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint)
581 AutoLogger logger(this);
582 RefPtr<JSONObject> params = logger.logItemWithParams("drawOval");
583 params->setObject("oval", objectForSkRect(oval));
584 params->setObject("paint", objectForSkPaint(paint));
585 this->SkCanvas::onDrawOval(oval, paint);
588 void LoggingCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint)
590 AutoLogger logger(this);
591 RefPtr<JSONObject> params = logger.logItemWithParams("drawRRect");
592 params->setObject("rrect", objectForSkRRect(rrect));
593 params->setObject("paint", objectForSkPaint(paint));
594 this->SkCanvas::onDrawRRect(rrect, paint);
597 void LoggingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint)
599 AutoLogger logger(this);
600 RefPtr<JSONObject> params = logger.logItemWithParams("drawPath");
601 params->setObject("path", objectForSkPath(path));
602 params->setObject("paint", objectForSkPaint(paint));
603 this->SkCanvas::onDrawPath(path, paint);
606 void LoggingCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint)
608 AutoLogger logger(this);
609 RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmap");
610 params->setNumber("left", left);
611 params->setNumber("top", top);
612 params->setObject("bitmap", objectForSkBitmap(bitmap));
613 if (paint)
614 params->setObject("paint", objectForSkPaint(*paint));
615 this->SkCanvas::onDrawBitmap(bitmap, left, top, paint);
618 void LoggingCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint)
620 AutoLogger logger(this);
621 RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapRectToRect");
622 params->setObject("bitmap", objectForSkBitmap(bitmap));
623 if (src)
624 params->setObject("src", objectForSkRect(*src));
625 params->setObject("dst", objectForSkRect(dst));
626 if (paint)
627 params->setObject("paint", objectForSkPaint(*paint));
628 params->setNumber("flags", constraint);
629 this->SkCanvas::onDrawBitmapRect(bitmap, src, dst, paint, constraint);
632 void LoggingCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint)
634 AutoLogger logger(this);
635 RefPtr<JSONObject> params = logger.logItemWithParams("drawBitmapNine");
636 params->setObject("bitmap", objectForSkBitmap(bitmap));
637 params->setObject("center", objectForSkIRect(center));
638 params->setObject("dst", objectForSkRect(dst));
639 if (paint)
640 params->setObject("paint", objectForSkPaint(*paint));
641 this->SkCanvas::onDrawBitmapNine(bitmap, center, dst, paint);
644 void LoggingCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint)
646 AutoLogger logger(this);
647 RefPtr<JSONObject> params = logger.logItemWithParams("drawImage");
648 params->setNumber("left", left);
649 params->setNumber("top", top);
650 params->setObject("image", objectForSkImage(image));
651 if (paint)
652 params->setObject("paint", objectForSkPaint(*paint));
653 this->SkCanvas::onDrawImage(image, left, top, paint);
656 void LoggingCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, const SkPaint* paint, SrcRectConstraint constraint)
658 AutoLogger logger(this);
659 RefPtr<JSONObject> params = logger.logItemWithParams("drawImageRect");
660 params->setObject("image", objectForSkImage(image));
661 if (src)
662 params->setObject("src", objectForSkRect(*src));
663 params->setObject("dst", objectForSkRect(dst));
664 if (paint)
665 params->setObject("paint", objectForSkPaint(*paint));
666 this->SkCanvas::onDrawImageRect(image, src, dst, paint, constraint);
669 void LoggingCanvas::onDrawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint)
671 AutoLogger logger(this);
672 RefPtr<JSONObject> params = logger.logItemWithParams("drawSprite");
673 params->setObject("bitmap", objectForSkBitmap(bitmap));
674 params->setNumber("left", left);
675 params->setNumber("top", top);
676 if (paint)
677 params->setObject("paint", objectForSkPaint(*paint));
678 this->SkCanvas::onDrawSprite(bitmap, left, top, paint);
681 void LoggingCanvas::onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
682 const uint16_t indices[], int indexCount, const SkPaint& paint)
684 AutoLogger logger(this);
685 RefPtr<JSONObject> params = logger.logItemWithParams("drawVertices");
686 params->setObject("paint", objectForSkPaint(paint));
687 this->SkCanvas::onDrawVertices(vmode, vertexCount, vertices, texs, colors, xmode, indices, indexCount, paint);
690 void LoggingCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint)
692 AutoLogger logger(this);
693 RefPtr<JSONObject> params = logger.logItemWithParams("drawDRRect");
694 params->setObject("outer", objectForSkRRect(outer));
695 params->setObject("inner", objectForSkRRect(inner));
696 params->setObject("paint", objectForSkPaint(paint));
697 this->SkCanvas::onDrawDRRect(outer, inner, paint);
700 void LoggingCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint)
702 AutoLogger logger(this);
703 RefPtr<JSONObject> params = logger.logItemWithParams("drawText");
704 params->setString("text", stringForText(text, byteLength, paint));
705 params->setNumber("x", x);
706 params->setNumber("y", y);
707 params->setObject("paint", objectForSkPaint(paint));
708 this->SkCanvas::onDrawText(text, byteLength, x, y, paint);
711 void LoggingCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint)
713 AutoLogger logger(this);
714 RefPtr<JSONObject> params = logger.logItemWithParams("drawPosText");
715 params->setString("text", stringForText(text, byteLength, paint));
716 size_t pointsCount = paint.countText(text, byteLength);
717 params->setArray("pos", arrayForSkPoints(pointsCount, pos));
718 params->setObject("paint", objectForSkPaint(paint));
719 this->SkCanvas::onDrawPosText(text, byteLength, pos, paint);
722 void LoggingCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint)
724 AutoLogger logger(this);
725 RefPtr<JSONObject> params = logger.logItemWithParams("drawPosTextH");
726 params->setString("text", stringForText(text, byteLength, paint));
727 size_t pointsCount = paint.countText(text, byteLength);
728 params->setArray("xpos", arrayForSkScalars(pointsCount, xpos));
729 params->setNumber("constY", constY);
730 params->setObject("paint", objectForSkPaint(paint));
731 this->SkCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint);
734 void LoggingCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint)
736 AutoLogger logger(this);
737 RefPtr<JSONObject> params = logger.logItemWithParams("drawTextOnPath");
738 params->setString("text", stringForText(text, byteLength, paint));
739 params->setObject("path", objectForSkPath(path));
740 if (matrix)
741 params->setArray("matrix", arrayForSkMatrix(*matrix));
742 params->setObject("paint", objectForSkPaint(paint));
743 this->SkCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint);
746 void LoggingCanvas::onDrawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
748 AutoLogger logger(this);
749 RefPtr<JSONObject> params = logger.logItemWithParams("drawTextBlob");
750 params->setNumber("x", x);
751 params->setNumber("y", y);
752 params->setObject("paint", objectForSkPaint(paint));
753 this->SkCanvas::onDrawTextBlob(blob, x, y, paint);
756 void LoggingCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style)
758 AutoLogger logger(this);
759 RefPtr<JSONObject> params = logger.logItemWithParams("clipRect");
760 params->setObject("rect", objectForSkRect(rect));
761 params->setString("SkRegion::Op", regionOpName(op));
762 params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
763 this->SkCanvas::onClipRect(rect, op, style);
766 void LoggingCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle style)
768 AutoLogger logger(this);
769 RefPtr<JSONObject> params = logger.logItemWithParams("clipRRect");
770 params->setObject("rrect", objectForSkRRect(rrect));
771 params->setString("SkRegion::Op", regionOpName(op));
772 params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
773 this->SkCanvas::onClipRRect(rrect, op, style);
776 void LoggingCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle style)
778 AutoLogger logger(this);
779 RefPtr<JSONObject> params = logger.logItemWithParams("clipPath");
780 params->setObject("path", objectForSkPath(path));
781 params->setString("SkRegion::Op", regionOpName(op));
782 params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
783 this->SkCanvas::onClipPath(path, op, style);
786 void LoggingCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op)
788 AutoLogger logger(this);
789 RefPtr<JSONObject> params = logger.logItemWithParams("clipRegion");
790 params->setString("op", regionOpName(op));
791 this->SkCanvas::onClipRegion(region, op);
794 void LoggingCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint)
796 this->unrollDrawPicture(picture, matrix, paint, nullptr);
799 void LoggingCanvas::didSetMatrix(const SkMatrix& matrix)
801 AutoLogger logger(this);
802 RefPtr<JSONObject> params = logger.logItemWithParams("setMatrix");
803 params->setArray("matrix", arrayForSkMatrix(matrix));
804 this->SkCanvas::didSetMatrix(matrix);
807 void LoggingCanvas::didConcat(const SkMatrix& matrix)
809 AutoLogger logger(this);
810 RefPtr<JSONObject> params;
812 switch (matrix.getType()) {
813 case SkMatrix::kTranslate_Mask:
814 params = logger.logItemWithParams("translate");
815 params->setNumber("dx", matrix.getTranslateX());
816 params->setNumber("dy", matrix.getTranslateY());
817 break;
819 case SkMatrix::kScale_Mask:
820 params = logger.logItemWithParams("scale");
821 params->setNumber("scaleX", matrix.getScaleX());
822 params->setNumber("scaleY", matrix.getScaleY());
823 break;
825 default:
826 params = logger.logItemWithParams("concat");
827 params->setArray("matrix", arrayForSkMatrix(matrix));
829 this->SkCanvas::didConcat(matrix);
832 void LoggingCanvas::willSave()
834 AutoLogger logger(this);
835 RefPtr<JSONObject> params = logger.logItem("save");
836 this->SkCanvas::willSave();
839 SkCanvas::SaveLayerStrategy LoggingCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags)
841 AutoLogger logger(this);
842 RefPtr<JSONObject> params = logger.logItemWithParams("saveLayer");
843 if (bounds)
844 params->setObject("bounds", objectForSkRect(*bounds));
845 if (paint)
846 params->setObject("paint", objectForSkPaint(*paint));
847 params->setString("saveFlags", saveFlagsToString(flags));
848 return this->SkCanvas::willSaveLayer(bounds, paint, flags);
851 void LoggingCanvas::willRestore()
853 AutoLogger logger(this);
854 logger.logItem("restore");
855 this->SkCanvas::willRestore();
858 PassRefPtr<JSONArray> LoggingCanvas::log()
860 return m_log;
863 #ifndef NDEBUG
864 String pictureAsDebugString(const SkPicture* picture)
866 const SkIRect bounds = picture->cullRect().roundOut();
867 LoggingCanvas canvas(bounds.width(), bounds.height());
868 picture->playback(&canvas);
869 RefPtr<JSONObject> pictureAsJSON = JSONObject::create();
870 pictureAsJSON->setObject("cullRect", objectForSkRect(picture->cullRect()));
871 pictureAsJSON->setArray("operations", canvas.log());
872 RefPtr<JSONArray> operationsInJson = canvas.log();
873 return pictureAsJSON->toPrettyJSONString();
876 void showSkPicture(const SkPicture* picture)
878 WTFLogAlways("%s\n", pictureAsDebugString(picture).utf8().data());
880 #endif
882 } // namespace blink