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