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 "third_party/blink/renderer/platform/graphics/logging_canvas.h"
32
33 #include <unicode/unistr.h>
34
35 #include "base/stl_util.h"
36 #include "base/sys_byteorder.h"
37 #include "build/build_config.h"
38 #include "third_party/blink/renderer/platform/geometry/int_size.h"
39 #include "third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h"
40 #include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
41 #include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
42 #include "third_party/blink/renderer/platform/wtf/text/base64.h"
43 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
44 #include "third_party/skia/include/core/SkImage.h"
45 #include "third_party/skia/include/core/SkImageInfo.h"
46 #include "third_party/skia/include/core/SkPaint.h"
47 #include "third_party/skia/include/core/SkPath.h"
48 #include "third_party/skia/include/core/SkRRect.h"
49 #include "third_party/skia/include/core/SkRect.h"
50
51 namespace blink {
52
53 namespace {
54
55 struct VerbParams {
56 STACK_ALLOCATED();
57
58 public:
59 String name;
60 unsigned point_count;
61 unsigned point_offset;
62
VerbParamsblink::__anonef17afa80111::VerbParams63 VerbParams(const String& name, unsigned point_count, unsigned point_offset)
64 : name(name), point_count(point_count), point_offset(point_offset) {}
65 };
66
ObjectForSkRect(const SkRect & rect)67 std::unique_ptr<JSONObject> ObjectForSkRect(const SkRect& rect) {
68 auto rect_item = std::make_unique<JSONObject>();
69 rect_item->SetDouble("left", rect.left());
70 rect_item->SetDouble("top", rect.top());
71 rect_item->SetDouble("right", rect.right());
72 rect_item->SetDouble("bottom", rect.bottom());
73 return rect_item;
74 }
75
PointModeName(SkCanvas::PointMode mode)76 String PointModeName(SkCanvas::PointMode mode) {
77 switch (mode) {
78 case SkCanvas::kPoints_PointMode:
79 return "Points";
80 case SkCanvas::kLines_PointMode:
81 return "Lines";
82 case SkCanvas::kPolygon_PointMode:
83 return "Polygon";
84 default:
85 NOTREACHED();
86 return "?";
87 };
88 }
89
ObjectForSkPoint(const SkPoint & point)90 std::unique_ptr<JSONObject> ObjectForSkPoint(const SkPoint& point) {
91 auto point_item = std::make_unique<JSONObject>();
92 point_item->SetDouble("x", point.x());
93 point_item->SetDouble("y", point.y());
94 return point_item;
95 }
96
ArrayForSkPoints(size_t count,const SkPoint points[])97 std::unique_ptr<JSONArray> ArrayForSkPoints(size_t count,
98 const SkPoint points[]) {
99 auto points_array_item = std::make_unique<JSONArray>();
100 for (size_t i = 0; i < count; ++i)
101 points_array_item->PushObject(ObjectForSkPoint(points[i]));
102 return points_array_item;
103 }
104
ObjectForRadius(const SkRRect & rrect,SkRRect::Corner corner)105 std::unique_ptr<JSONObject> ObjectForRadius(const SkRRect& rrect,
106 SkRRect::Corner corner) {
107 auto radius_item = std::make_unique<JSONObject>();
108 SkVector radius = rrect.radii(corner);
109 radius_item->SetDouble("xRadius", radius.x());
110 radius_item->SetDouble("yRadius", radius.y());
111 return radius_item;
112 }
113
RrectTypeName(SkRRect::Type type)114 String RrectTypeName(SkRRect::Type type) {
115 switch (type) {
116 case SkRRect::kEmpty_Type:
117 return "Empty";
118 case SkRRect::kRect_Type:
119 return "Rect";
120 case SkRRect::kOval_Type:
121 return "Oval";
122 case SkRRect::kSimple_Type:
123 return "Simple";
124 case SkRRect::kNinePatch_Type:
125 return "Nine-patch";
126 case SkRRect::kComplex_Type:
127 return "Complex";
128 default:
129 NOTREACHED();
130 return "?";
131 };
132 }
133
RadiusName(SkRRect::Corner corner)134 String RadiusName(SkRRect::Corner corner) {
135 switch (corner) {
136 case SkRRect::kUpperLeft_Corner:
137 return "upperLeftRadius";
138 case SkRRect::kUpperRight_Corner:
139 return "upperRightRadius";
140 case SkRRect::kLowerRight_Corner:
141 return "lowerRightRadius";
142 case SkRRect::kLowerLeft_Corner:
143 return "lowerLeftRadius";
144 default:
145 NOTREACHED();
146 return "?";
147 }
148 }
149
ObjectForSkRRect(const SkRRect & rrect)150 std::unique_ptr<JSONObject> ObjectForSkRRect(const SkRRect& rrect) {
151 auto rrect_item = std::make_unique<JSONObject>();
152 rrect_item->SetString("type", RrectTypeName(rrect.type()));
153 rrect_item->SetDouble("left", rrect.rect().left());
154 rrect_item->SetDouble("top", rrect.rect().top());
155 rrect_item->SetDouble("right", rrect.rect().right());
156 rrect_item->SetDouble("bottom", rrect.rect().bottom());
157 for (int i = 0; i < 4; ++i)
158 rrect_item->SetObject(RadiusName((SkRRect::Corner)i),
159 ObjectForRadius(rrect, (SkRRect::Corner)i));
160 return rrect_item;
161 }
162
FillTypeName(SkPathFillType type)163 String FillTypeName(SkPathFillType type) {
164 switch (type) {
165 case SkPathFillType::kWinding:
166 return "Winding";
167 case SkPathFillType::kEvenOdd:
168 return "EvenOdd";
169 case SkPathFillType::kInverseWinding:
170 return "InverseWinding";
171 case SkPathFillType::kInverseEvenOdd:
172 return "InverseEvenOdd";
173 default:
174 NOTREACHED();
175 return "?";
176 };
177 }
178
ConvexityName(SkPathConvexityType convexity)179 String ConvexityName(SkPathConvexityType convexity) {
180 switch (convexity) {
181 case SkPathConvexityType::kUnknown:
182 return "Unknown";
183 case SkPathConvexityType::kConvex:
184 return "Convex";
185 case SkPathConvexityType::kConcave:
186 return "Concave";
187 default:
188 NOTREACHED();
189 return "?";
190 };
191 }
192
SegmentParams(SkPath::Verb verb)193 VerbParams SegmentParams(SkPath::Verb verb) {
194 switch (verb) {
195 case SkPath::kMove_Verb:
196 return VerbParams("Move", 1, 0);
197 case SkPath::kLine_Verb:
198 return VerbParams("Line", 1, 1);
199 case SkPath::kQuad_Verb:
200 return VerbParams("Quad", 2, 1);
201 case SkPath::kConic_Verb:
202 return VerbParams("Conic", 2, 1);
203 case SkPath::kCubic_Verb:
204 return VerbParams("Cubic", 3, 1);
205 case SkPath::kClose_Verb:
206 return VerbParams("Close", 0, 0);
207 case SkPath::kDone_Verb:
208 return VerbParams("Done", 0, 0);
209 default:
210 NOTREACHED();
211 return VerbParams("?", 0, 0);
212 };
213 }
214
ObjectForSkPath(const SkPath & path)215 std::unique_ptr<JSONObject> ObjectForSkPath(const SkPath& path) {
216 auto path_item = std::make_unique<JSONObject>();
217 path_item->SetString("fillType", FillTypeName(path.getFillType()));
218 path_item->SetString("convexity", ConvexityName(path.getConvexityType()));
219 path_item->SetBoolean("isRect", path.isRect(nullptr));
220 SkPath::Iter iter(path, false);
221 SkPoint points[4];
222 auto path_points_array = std::make_unique<JSONArray>();
223 for (SkPath::Verb verb = iter.next(points); verb != SkPath::kDone_Verb;
224 verb = iter.next(points)) {
225 VerbParams verb_params = SegmentParams(verb);
226 auto path_point_item = std::make_unique<JSONObject>();
227 path_point_item->SetString("verb", verb_params.name);
228 DCHECK_LE(verb_params.point_count + verb_params.point_offset,
229 base::size(points));
230 path_point_item->SetArray(
231 "points", ArrayForSkPoints(verb_params.point_count,
232 points + verb_params.point_offset));
233 if (SkPath::kConic_Verb == verb)
234 path_point_item->SetDouble("conicWeight", iter.conicWeight());
235 path_points_array->PushObject(std::move(path_point_item));
236 }
237 path_item->SetArray("pathPoints", std::move(path_points_array));
238 path_item->SetObject("bounds", ObjectForSkRect(path.getBounds()));
239 return path_item;
240 }
241
ObjectForSkImage(const SkImage * image)242 std::unique_ptr<JSONObject> ObjectForSkImage(const SkImage* image) {
243 auto image_item = std::make_unique<JSONObject>();
244 image_item->SetInteger("width", image->width());
245 image_item->SetInteger("height", image->height());
246 image_item->SetBoolean("opaque", image->isOpaque());
247 image_item->SetInteger("uniqueID", image->uniqueID());
248 return image_item;
249 }
250
ArrayForSkMatrix(const SkMatrix & matrix)251 std::unique_ptr<JSONArray> ArrayForSkMatrix(const SkMatrix& matrix) {
252 auto matrix_array = std::make_unique<JSONArray>();
253 for (int i = 0; i < 9; ++i)
254 matrix_array->PushDouble(matrix[i]);
255 return matrix_array;
256 }
257
ArrayForSkScalars(size_t count,const SkScalar array[])258 std::unique_ptr<JSONArray> ArrayForSkScalars(size_t count,
259 const SkScalar array[]) {
260 auto points_array_item = std::make_unique<JSONArray>();
261 for (size_t i = 0; i < count; ++i)
262 points_array_item->PushDouble(array[i]);
263 return points_array_item;
264 }
265
ObjectForSkShader(const SkShader & shader)266 std::unique_ptr<JSONObject> ObjectForSkShader(const SkShader& shader) {
267 return std::make_unique<JSONObject>();
268 }
269
StringForSkColor(SkColor color)270 String StringForSkColor(SkColor color) {
271 // #AARRGGBB.
272 return String::Format("#%08X", color);
273 }
274
AppendFlagToString(StringBuilder * flags_string,bool is_set,const StringView & name)275 void AppendFlagToString(StringBuilder* flags_string,
276 bool is_set,
277 const StringView& name) {
278 if (!is_set)
279 return;
280 if (flags_string->length())
281 flags_string->Append("|");
282 flags_string->Append(name);
283 }
284
StringForSkPaintFlags(const SkPaint & paint)285 String StringForSkPaintFlags(const SkPaint& paint) {
286 if (!paint.isAntiAlias() && !paint.isDither())
287 return "none";
288 StringBuilder flags_string;
289 AppendFlagToString(&flags_string, paint.isAntiAlias(), "AntiAlias");
290 AppendFlagToString(&flags_string, paint.isDither(), "Dither");
291 return flags_string.ToString();
292 }
293
FilterQualityName(SkFilterQuality filter_quality)294 String FilterQualityName(SkFilterQuality filter_quality) {
295 switch (filter_quality) {
296 case kNone_SkFilterQuality:
297 return "None";
298 case kLow_SkFilterQuality:
299 return "Low";
300 case kMedium_SkFilterQuality:
301 return "Medium";
302 case kHigh_SkFilterQuality:
303 return "High";
304 default:
305 NOTREACHED();
306 return "?";
307 };
308 }
309
StrokeCapName(SkPaint::Cap cap)310 String StrokeCapName(SkPaint::Cap cap) {
311 switch (cap) {
312 case SkPaint::kButt_Cap:
313 return "Butt";
314 case SkPaint::kRound_Cap:
315 return "Round";
316 case SkPaint::kSquare_Cap:
317 return "Square";
318 default:
319 NOTREACHED();
320 return "?";
321 };
322 }
323
StrokeJoinName(SkPaint::Join join)324 String StrokeJoinName(SkPaint::Join join) {
325 switch (join) {
326 case SkPaint::kMiter_Join:
327 return "Miter";
328 case SkPaint::kRound_Join:
329 return "Round";
330 case SkPaint::kBevel_Join:
331 return "Bevel";
332 default:
333 NOTREACHED();
334 return "?";
335 };
336 }
337
StyleName(SkPaint::Style style)338 String StyleName(SkPaint::Style style) {
339 switch (style) {
340 case SkPaint::kFill_Style:
341 return "Fill";
342 case SkPaint::kStroke_Style:
343 return "Stroke";
344 case SkPaint::kStrokeAndFill_Style:
345 return "StrokeAndFill";
346 default:
347 NOTREACHED();
348 return "?";
349 };
350 }
351
ObjectForSkPaint(const SkPaint & paint)352 std::unique_ptr<JSONObject> ObjectForSkPaint(const SkPaint& paint) {
353 auto paint_item = std::make_unique<JSONObject>();
354 if (SkShader* shader = paint.getShader())
355 paint_item->SetObject("shader", ObjectForSkShader(*shader));
356 paint_item->SetString("color", StringForSkColor(paint.getColor()));
357 paint_item->SetDouble("strokeWidth", paint.getStrokeWidth());
358 paint_item->SetDouble("strokeMiter", paint.getStrokeMiter());
359 paint_item->SetString("flags", StringForSkPaintFlags(paint));
360 paint_item->SetString("filterLevel",
361 FilterQualityName(paint.getFilterQuality()));
362 paint_item->SetString("strokeCap", StrokeCapName(paint.getStrokeCap()));
363 paint_item->SetString("strokeJoin", StrokeJoinName(paint.getStrokeJoin()));
364 paint_item->SetString("styleName", StyleName(paint.getStyle()));
365 if (paint.getBlendMode() != SkBlendMode::kSrcOver)
366 paint_item->SetString("blendMode", SkBlendMode_Name(paint.getBlendMode()));
367 if (paint.getImageFilter())
368 paint_item->SetString("imageFilter", "SkImageFilter");
369 return paint_item;
370 }
371
ClipOpName(SkClipOp op)372 String ClipOpName(SkClipOp op) {
373 switch (op) {
374 case SkClipOp::kDifference:
375 return "kDifference_Op";
376 case SkClipOp::kIntersect:
377 return "kIntersect_Op";
378 default:
379 return "Unknown type";
380 };
381 }
382
383 } // namespace
384
385 class AutoLogger
386 : InterceptingCanvasBase::CanvasInterceptorBase<LoggingCanvas> {
387 public:
AutoLogger(LoggingCanvas * canvas)388 explicit AutoLogger(LoggingCanvas* canvas)
389 : InterceptingCanvasBase::CanvasInterceptorBase<LoggingCanvas>(canvas) {}
390
391 JSONObject* LogItem(const String& name);
392 JSONObject* LogItemWithParams(const String& name);
~AutoLogger()393 ~AutoLogger() {
394 if (TopLevelCall())
395 Canvas()->log_->PushObject(std::move(log_item_));
396 }
397
398 private:
399 std::unique_ptr<JSONObject> log_item_;
400 };
401
LogItem(const String & name)402 JSONObject* AutoLogger::LogItem(const String& name) {
403 auto item = std::make_unique<JSONObject>();
404 item->SetString("method", name);
405 log_item_ = std::move(item);
406 return log_item_.get();
407 }
408
LogItemWithParams(const String & name)409 JSONObject* AutoLogger::LogItemWithParams(const String& name) {
410 JSONObject* item = LogItem(name);
411 auto params = std::make_unique<JSONObject>();
412 item->SetObject("params", std::move(params));
413 return item->GetJSONObject("params");
414 }
415
LoggingCanvas()416 LoggingCanvas::LoggingCanvas()
417 : InterceptingCanvasBase(999999, 999999),
418 log_(std::make_unique<JSONArray>()) {}
419
onDrawPaint(const SkPaint & paint)420 void LoggingCanvas::onDrawPaint(const SkPaint& paint) {
421 AutoLogger logger(this);
422 logger.LogItemWithParams("drawPaint")
423 ->SetObject("paint", ObjectForSkPaint(paint));
424 this->SkCanvas::onDrawPaint(paint);
425 }
426
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)427 void LoggingCanvas::onDrawPoints(PointMode mode,
428 size_t count,
429 const SkPoint pts[],
430 const SkPaint& paint) {
431 AutoLogger logger(this);
432 JSONObject* params = logger.LogItemWithParams("drawPoints");
433 params->SetString("pointMode", PointModeName(mode));
434 params->SetArray("points", ArrayForSkPoints(count, pts));
435 params->SetObject("paint", ObjectForSkPaint(paint));
436 this->SkCanvas::onDrawPoints(mode, count, pts, paint);
437 }
438
onDrawRect(const SkRect & rect,const SkPaint & paint)439 void LoggingCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
440 AutoLogger logger(this);
441 JSONObject* params = logger.LogItemWithParams("drawRect");
442 params->SetObject("rect", ObjectForSkRect(rect));
443 params->SetObject("paint", ObjectForSkPaint(paint));
444 this->SkCanvas::onDrawRect(rect, paint);
445 }
446
onDrawOval(const SkRect & oval,const SkPaint & paint)447 void LoggingCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
448 AutoLogger logger(this);
449 JSONObject* params = logger.LogItemWithParams("drawOval");
450 params->SetObject("oval", ObjectForSkRect(oval));
451 params->SetObject("paint", ObjectForSkPaint(paint));
452 this->SkCanvas::onDrawOval(oval, paint);
453 }
454
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)455 void LoggingCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
456 AutoLogger logger(this);
457 JSONObject* params = logger.LogItemWithParams("drawRRect");
458 params->SetObject("rrect", ObjectForSkRRect(rrect));
459 params->SetObject("paint", ObjectForSkPaint(paint));
460 this->SkCanvas::onDrawRRect(rrect, paint);
461 }
462
onDrawPath(const SkPath & path,const SkPaint & paint)463 void LoggingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
464 AutoLogger logger(this);
465 JSONObject* params = logger.LogItemWithParams("drawPath");
466 params->SetObject("path", ObjectForSkPath(path));
467 params->SetObject("paint", ObjectForSkPaint(paint));
468 this->SkCanvas::onDrawPath(path, paint);
469 }
470
onDrawImage(const SkImage * image,SkScalar left,SkScalar top,const SkPaint * paint)471 void LoggingCanvas::onDrawImage(const SkImage* image,
472 SkScalar left,
473 SkScalar top,
474 const SkPaint* paint) {
475 AutoLogger logger(this);
476 JSONObject* params = logger.LogItemWithParams("drawImage");
477 params->SetDouble("left", left);
478 params->SetDouble("top", top);
479 params->SetObject("image", ObjectForSkImage(image));
480 if (paint)
481 params->SetObject("paint", ObjectForSkPaint(*paint));
482 this->SkCanvas::onDrawImage(image, left, top, paint);
483 }
484
onDrawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)485 void LoggingCanvas::onDrawImageRect(const SkImage* image,
486 const SkRect* src,
487 const SkRect& dst,
488 const SkPaint* paint,
489 SrcRectConstraint constraint) {
490 AutoLogger logger(this);
491 JSONObject* params = logger.LogItemWithParams("drawImageRect");
492 params->SetObject("image", ObjectForSkImage(image));
493 if (src)
494 params->SetObject("src", ObjectForSkRect(*src));
495 params->SetObject("dst", ObjectForSkRect(dst));
496 if (paint)
497 params->SetObject("paint", ObjectForSkPaint(*paint));
498 this->SkCanvas::onDrawImageRect(image, src, dst, paint, constraint);
499 }
500
onDrawVerticesObject(const SkVertices * vertices,SkBlendMode bmode,const SkPaint & paint)501 void LoggingCanvas::onDrawVerticesObject(const SkVertices* vertices,
502 SkBlendMode bmode,
503 const SkPaint& paint) {
504 AutoLogger logger(this);
505 JSONObject* params = logger.LogItemWithParams("drawVertices");
506 params->SetObject("paint", ObjectForSkPaint(paint));
507 this->SkCanvas::onDrawVerticesObject(vertices, bmode, paint);
508 }
509
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)510 void LoggingCanvas::onDrawDRRect(const SkRRect& outer,
511 const SkRRect& inner,
512 const SkPaint& paint) {
513 AutoLogger logger(this);
514 JSONObject* params = logger.LogItemWithParams("drawDRRect");
515 params->SetObject("outer", ObjectForSkRRect(outer));
516 params->SetObject("inner", ObjectForSkRRect(inner));
517 params->SetObject("paint", ObjectForSkPaint(paint));
518 this->SkCanvas::onDrawDRRect(outer, inner, paint);
519 }
520
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)521 void LoggingCanvas::onDrawTextBlob(const SkTextBlob* blob,
522 SkScalar x,
523 SkScalar y,
524 const SkPaint& paint) {
525 AutoLogger logger(this);
526 JSONObject* params = logger.LogItemWithParams("drawTextBlob");
527 params->SetDouble("x", x);
528 params->SetDouble("y", y);
529 params->SetObject("paint", ObjectForSkPaint(paint));
530 this->SkCanvas::onDrawTextBlob(blob, x, y, paint);
531 }
532
onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle style)533 void LoggingCanvas::onClipRect(const SkRect& rect,
534 SkClipOp op,
535 ClipEdgeStyle style) {
536 AutoLogger logger(this);
537 JSONObject* params = logger.LogItemWithParams("clipRect");
538 params->SetObject("rect", ObjectForSkRect(rect));
539 params->SetString("SkRegion::Op", ClipOpName(op));
540 params->SetBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
541 this->SkCanvas::onClipRect(rect, op, style);
542 }
543
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle style)544 void LoggingCanvas::onClipRRect(const SkRRect& rrect,
545 SkClipOp op,
546 ClipEdgeStyle style) {
547 AutoLogger logger(this);
548 JSONObject* params = logger.LogItemWithParams("clipRRect");
549 params->SetObject("rrect", ObjectForSkRRect(rrect));
550 params->SetString("SkRegion::Op", ClipOpName(op));
551 params->SetBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
552 this->SkCanvas::onClipRRect(rrect, op, style);
553 }
554
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle style)555 void LoggingCanvas::onClipPath(const SkPath& path,
556 SkClipOp op,
557 ClipEdgeStyle style) {
558 AutoLogger logger(this);
559 JSONObject* params = logger.LogItemWithParams("clipPath");
560 params->SetObject("path", ObjectForSkPath(path));
561 params->SetString("SkRegion::Op", ClipOpName(op));
562 params->SetBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
563 this->SkCanvas::onClipPath(path, op, style);
564 }
565
onClipRegion(const SkRegion & region,SkClipOp op)566 void LoggingCanvas::onClipRegion(const SkRegion& region, SkClipOp op) {
567 AutoLogger logger(this);
568 JSONObject* params = logger.LogItemWithParams("clipRegion");
569 params->SetString("op", ClipOpName(op));
570 this->SkCanvas::onClipRegion(region, op);
571 }
572
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)573 void LoggingCanvas::onDrawPicture(const SkPicture* picture,
574 const SkMatrix* matrix,
575 const SkPaint* paint) {
576 this->UnrollDrawPicture(picture, matrix, paint, nullptr);
577 }
578
didSetMatrix(const SkMatrix & matrix)579 void LoggingCanvas::didSetMatrix(const SkMatrix& matrix) {
580 AutoLogger logger(this);
581 JSONObject* params = logger.LogItemWithParams("setMatrix");
582 params->SetArray("matrix", ArrayForSkMatrix(matrix));
583 }
584
didConcat44(const SkScalar m[16])585 void LoggingCanvas::didConcat44(const SkScalar m[16]) {
586 AutoLogger logger(this);
587 JSONObject* params = logger.LogItemWithParams("concat44");
588 params->SetArray("matrix44", ArrayForSkScalars(16, m));
589 }
590
didConcat(const SkMatrix & matrix)591 void LoggingCanvas::didConcat(const SkMatrix& matrix) {
592 AutoLogger logger(this);
593 JSONObject* params;
594
595 switch (matrix.getType()) {
596 case SkMatrix::kTranslate_Mask:
597 params = logger.LogItemWithParams("translate");
598 params->SetDouble("dx", matrix.getTranslateX());
599 params->SetDouble("dy", matrix.getTranslateY());
600 break;
601
602 case SkMatrix::kScale_Mask:
603 params = logger.LogItemWithParams("scale");
604 params->SetDouble("scaleX", matrix.getScaleX());
605 params->SetDouble("scaleY", matrix.getScaleY());
606 break;
607
608 default:
609 params = logger.LogItemWithParams("concat");
610 params->SetArray("matrix", ArrayForSkMatrix(matrix));
611 }
612 }
613
didScale(SkScalar x,SkScalar y)614 void LoggingCanvas::didScale(SkScalar x, SkScalar y) {
615 AutoLogger logger(this);
616 JSONObject* params = logger.LogItemWithParams("scale");
617 params->SetDouble("scaleX", x);
618 params->SetDouble("scaleY", y);
619 }
620
didTranslate(SkScalar x,SkScalar y)621 void LoggingCanvas::didTranslate(SkScalar x, SkScalar y) {
622 AutoLogger logger(this);
623 JSONObject* params = logger.LogItemWithParams("translate");
624 params->SetDouble("dx", x);
625 params->SetDouble("dy", y);
626 }
627
willSave()628 void LoggingCanvas::willSave() {
629 AutoLogger logger(this);
630 logger.LogItem("save");
631 this->SkCanvas::willSave();
632 }
633
getSaveLayerStrategy(const SaveLayerRec & rec)634 SkCanvas::SaveLayerStrategy LoggingCanvas::getSaveLayerStrategy(
635 const SaveLayerRec& rec) {
636 AutoLogger logger(this);
637 JSONObject* params = logger.LogItemWithParams("saveLayer");
638 if (rec.fBounds)
639 params->SetObject("bounds", ObjectForSkRect(*rec.fBounds));
640 if (rec.fPaint)
641 params->SetObject("paint", ObjectForSkPaint(*rec.fPaint));
642 params->SetInteger("saveFlags", static_cast<int>(rec.fSaveLayerFlags));
643 return this->SkCanvas::getSaveLayerStrategy(rec);
644 }
645
willRestore()646 void LoggingCanvas::willRestore() {
647 AutoLogger logger(this);
648 logger.LogItem("restore");
649 this->SkCanvas::willRestore();
650 }
651
Log()652 std::unique_ptr<JSONArray> LoggingCanvas::Log() {
653 return JSONArray::From(log_->Clone());
654 }
655
RecordAsJSON(const PaintRecord & record)656 std::unique_ptr<JSONArray> RecordAsJSON(const PaintRecord& record) {
657 LoggingCanvas canvas;
658 record.Playback(&canvas);
659 return canvas.Log();
660 }
661
RecordAsDebugString(const PaintRecord & record)662 String RecordAsDebugString(const PaintRecord& record) {
663 return RecordAsJSON(record)->ToPrettyJSONString();
664 }
665
ShowPaintRecord(const PaintRecord & record)666 void ShowPaintRecord(const PaintRecord& record) {
667 DLOG(INFO) << RecordAsDebugString(record).Utf8();
668 }
669
SkPictureAsJSON(const SkPicture & picture)670 std::unique_ptr<JSONArray> SkPictureAsJSON(const SkPicture& picture) {
671 LoggingCanvas canvas;
672 picture.playback(&canvas);
673 return canvas.Log();
674 }
675
SkPictureAsDebugString(const SkPicture & picture)676 String SkPictureAsDebugString(const SkPicture& picture) {
677 return SkPictureAsJSON(picture)->ToPrettyJSONString();
678 }
679
ShowSkPicture(const SkPicture & picture)680 void ShowSkPicture(const SkPicture& picture) {
681 DLOG(INFO) << SkPictureAsDebugString(picture).Utf8();
682 }
683
684 } // namespace blink
685