• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tools/debugger/DebugCanvas.h"
9 
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkClipOp.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPath.h"
16 #include "include/core/SkPicture.h"
17 #include "include/core/SkPoint.h"
18 #include "include/core/SkRSXform.h"
19 #include "include/core/SkShader.h"
20 #include "include/core/SkString.h"
21 #include "include/core/SkTextBlob.h"
22 #include "include/core/SkVertices.h"
23 #include "include/gpu/GrDirectContext.h"
24 #include "include/gpu/GrRecordingContext.h"
25 #include "include/private/base/SkTArray.h"
26 #include "include/private/base/SkTo.h"
27 #include "include/utils/SkPaintFilterCanvas.h"
28 #include "src/core/SkCanvasPriv.h"
29 #include "src/core/SkRectPriv.h"
30 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
31 #include "src/gpu/ganesh/GrRenderTargetProxy.h"
32 #include "src/gpu/ganesh/GrSurfaceProxy.h"
33 #include "src/utils/SkJSONWriter.h"
34 #include "tools/debugger/DebugLayerManager.h"
35 #include "tools/debugger/DrawCommand.h"
36 
37 #include <string>
38 #include <utility>
39 
40 class SkDrawable;
41 class SkImage;
42 class SkRRect;
43 class SkRegion;
44 class UrlDataManager;
45 struct SkDrawShadowRec;
46 
47 #if defined(SK_GANESH)
48 #include "src/gpu/ganesh/GrAuditTrail.h"
49 #endif
50 
51 #define SKDEBUGCANVAS_VERSION 1
52 #define SKDEBUGCANVAS_ATTRIBUTE_VERSION "version"
53 #define SKDEBUGCANVAS_ATTRIBUTE_COMMANDS "commands"
54 #define SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL "auditTrail"
55 
56 namespace {
57     // Constants used in Annotations by Android for keeping track of layers
58     static constexpr char kOffscreenLayerDraw[] = "OffscreenLayerDraw";
59     static constexpr char kSurfaceID[] = "SurfaceID";
60     static constexpr char kAndroidClip[] = "AndroidDeviceClipRestriction";
61 
62     static SkPath arrowHead = SkPath::Polygon({
63         { 0,   0},
64         { 6, -15},
65         { 0,  -12},
66         {-6, -15},
67     }, true);
68 
drawArrow(SkCanvas * canvas,const SkPoint & a,const SkPoint & b,const SkPaint & paint)69     void drawArrow(SkCanvas* canvas, const SkPoint& a, const SkPoint& b, const SkPaint& paint) {
70         canvas->translate(0.5, 0.5);
71         canvas->drawLine(a, b, paint);
72         canvas->save();
73         canvas->translate(b.fX, b.fY);
74         SkScalar angle = SkScalarATan2((b.fY - a.fY), b.fX - a.fX);
75         canvas->rotate(angle * 180 / SK_ScalarPI - 90);
76         // arrow head
77         canvas->drawPath(arrowHead, paint);
78         canvas->restore();
79         canvas->restore();
80     }
81 } // namespace
82 
83 class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
84 public:
DebugPaintFilterCanvas(SkCanvas * canvas)85     DebugPaintFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) {}
86 
87 protected:
onFilter(SkPaint & paint) const88     bool onFilter(SkPaint& paint) const override {
89         paint.setColor(SK_ColorRED);
90         paint.setAlpha(0x08);
91         paint.setBlendMode(SkBlendMode::kSrcOver);
92         return true;
93     }
94 
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)95     void onDrawPicture(const SkPicture* picture,
96                        const SkMatrix*  matrix,
97                        const SkPaint*   paint) override {
98         // We need to replay the picture onto this canvas in order to filter its internal paints.
99         this->SkCanvas::onDrawPicture(picture, matrix, paint);
100     }
101 
102 private:
103 
104     using INHERITED = SkPaintFilterCanvas;
105 };
106 
DebugCanvas(int width,int height)107 DebugCanvas::DebugCanvas(int width, int height)
108         : INHERITED(width, height)
109         , fOverdrawViz(false)
110         , fClipVizColor(SK_ColorTRANSPARENT)
111         , fDrawGpuOpBounds(false)
112         , fShowAndroidClip(false)
113         , fShowOrigin(false)
114         , fnextDrawPictureLayerId(-1)
115         , fnextDrawImageRectLayerId(-1)
116         , fAndroidClip(SkRect::MakeEmpty()) {
117     // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
118     // operations. This can lead to problems in the debugger which expects all
119     // the operations in the captured skp to appear in the debug canvas. To
120     // circumvent this we create a wide open clip here (an empty clip rect
121     // is not sufficient).
122     // Internally, the SkRect passed to clipRect is converted to an SkIRect and
123     // rounded out. The following code creates a nearly maximal rect that will
124     // not get collapsed by the coming conversions (Due to precision loss the
125     // inset has to be surprisingly large).
126     SkIRect largeIRect = SkRectPriv::MakeILarge();
127     largeIRect.inset(1024, 1024);
128     SkRect large = SkRect::Make(largeIRect);
129 #ifdef SK_DEBUG
130     SkASSERT(!large.roundOut().isEmpty());
131 #endif
132     // call the base class' version to avoid adding a draw command
133     this->INHERITED::onClipRect(large, SkClipOp::kIntersect, kHard_ClipEdgeStyle);
134 }
135 
DebugCanvas(SkIRect bounds)136 DebugCanvas::DebugCanvas(SkIRect bounds)
137         : DebugCanvas(bounds.width(), bounds.height()) {}
138 
~DebugCanvas()139 DebugCanvas::~DebugCanvas() {
140     for (DrawCommand* p : fCommandVector) {
141         delete p;
142     }
143     fCommandVector.reset();
144 }
145 
addDrawCommand(DrawCommand * command)146 void DebugCanvas::addDrawCommand(DrawCommand* command) { fCommandVector.push_back(command); }
147 
draw(SkCanvas * canvas)148 void DebugCanvas::draw(SkCanvas* canvas) {
149     if (!fCommandVector.empty()) {
150         this->drawTo(canvas, fCommandVector.size() - 1);
151     }
152 }
153 
drawTo(SkCanvas * originalCanvas,int index,int m)154 void DebugCanvas::drawTo(SkCanvas* originalCanvas, int index, int m) {
155     SkASSERT(!fCommandVector.empty());
156     SkASSERT(index < fCommandVector.size());
157 
158     int saveCount = originalCanvas->save();
159 
160     originalCanvas->resetMatrix();
161     SkCanvasPriv::ResetClip(originalCanvas);
162 
163     DebugPaintFilterCanvas filterCanvas(originalCanvas);
164     SkCanvas* finalCanvas = fOverdrawViz ? &filterCanvas : originalCanvas;
165 
166 #if defined(SK_GANESH)
167     auto dContext = GrAsDirectContext(finalCanvas->recordingContext());
168 
169     // If we have a GPU backend we can also visualize the op information
170     GrAuditTrail* at = nullptr;
171     if (fDrawGpuOpBounds || m != -1) {
172         // The audit trail must be obtained from the original canvas.
173         at = this->getAuditTrail(originalCanvas);
174     }
175 #endif
176 
177     for (int i = 0; i <= index; i++) {
178 #if defined(SK_GANESH)
179         GrAuditTrail::AutoCollectOps* acb = nullptr;
180         if (at) {
181             // We need to flush any pending operations, or they might combine with commands below.
182             // Previous operations were not registered with the audit trail when they were
183             // created, so if we allow them to combine, the audit trail will fail to find them.
184             if (dContext) {
185                 dContext->flush();
186             }
187             acb = new GrAuditTrail::AutoCollectOps(at, i);
188         }
189 #endif
190         if (fCommandVector[i]->isVisible()) {
191             fCommandVector[i]->execute(finalCanvas);
192         }
193 #if defined(SK_GANESH)
194         if (at && acb) {
195             delete acb;
196         }
197 #endif
198     }
199 
200     if (SkColorGetA(fClipVizColor) != 0) {
201         finalCanvas->save();
202         SkPaint clipPaint;
203         clipPaint.setColor(fClipVizColor);
204         finalCanvas->drawPaint(clipPaint);
205         finalCanvas->restore();
206     }
207 
208     fMatrix = finalCanvas->getLocalToDevice();
209     fClip   = finalCanvas->getDeviceClipBounds();
210     if (fShowOrigin) {
211         const SkPaint originXPaint = SkPaint({1.0, 0, 0, 1.0});
212         const SkPaint originYPaint = SkPaint({0, 1.0, 0, 1.0});
213         // Draw an origin cross at the origin before restoring to assist in visualizing the
214         // current matrix.
215         drawArrow(finalCanvas, {-50, 0}, {50, 0}, originXPaint);
216         drawArrow(finalCanvas, {0, -50}, {0, 50}, originYPaint);
217     }
218     finalCanvas->restoreToCount(saveCount);
219 
220     if (fShowAndroidClip) {
221         // Draw visualization of android device clip restriction
222         SkPaint androidClipPaint;
223         androidClipPaint.setARGB(80, 255, 100, 0);
224         finalCanvas->drawRect(fAndroidClip, androidClipPaint);
225     }
226 
227 #if defined(SK_GANESH)
228     // draw any ops if required and issue a full reset onto GrAuditTrail
229     if (at) {
230         // just in case there is global reordering, we flush the canvas before querying
231         // GrAuditTrail
232         GrAuditTrail::AutoEnable ae(at);
233         if (dContext) {
234             dContext->flush();
235         }
236 
237         // we pick three colorblind-safe colors, 75% alpha
238         static const SkColor kTotalBounds     = SkColorSetARGB(0xC0, 0x6A, 0x3D, 0x9A);
239         static const SkColor kCommandOpBounds = SkColorSetARGB(0xC0, 0xE3, 0x1A, 0x1C);
240         static const SkColor kOtherOpBounds   = SkColorSetARGB(0xC0, 0xFF, 0x7F, 0x00);
241 
242         // get the render target of the top device (from the original canvas) so we can ignore ops
243         // drawn offscreen
244         GrRenderTargetProxy* rtp = SkCanvasPriv::TopDeviceTargetProxy(originalCanvas);
245         GrSurfaceProxy::UniqueID proxyID = rtp->uniqueID();
246 
247         // get the bounding boxes to draw
248         SkTArray<GrAuditTrail::OpInfo> childrenBounds;
249         if (m == -1) {
250             at->getBoundsByClientID(&childrenBounds, index);
251         } else {
252             // the client wants us to draw the mth op
253             at->getBoundsByOpsTaskID(&childrenBounds.push_back(), m);
254         }
255         // Shift the rects half a pixel, so they appear as exactly 1px thick lines.
256         finalCanvas->save();
257         finalCanvas->translate(0.5, -0.5);
258         SkPaint paint;
259         paint.setStyle(SkPaint::kStroke_Style);
260         paint.setStrokeWidth(1);
261         for (int i = 0; i < childrenBounds.size(); i++) {
262             if (childrenBounds[i].fProxyUniqueID != proxyID) {
263                 // offscreen draw, ignore for now
264                 continue;
265             }
266             paint.setColor(kTotalBounds);
267             finalCanvas->drawRect(childrenBounds[i].fBounds, paint);
268             for (int j = 0; j < childrenBounds[i].fOps.size(); j++) {
269                 const GrAuditTrail::OpInfo::Op& op = childrenBounds[i].fOps[j];
270                 if (op.fClientID != index) {
271                     paint.setColor(kOtherOpBounds);
272                 } else {
273                     paint.setColor(kCommandOpBounds);
274                 }
275                 finalCanvas->drawRect(op.fBounds, paint);
276             }
277         }
278         finalCanvas->restore();
279         this->cleanupAuditTrail(at);
280     }
281 #endif
282 }
283 
deleteDrawCommandAt(int index)284 void DebugCanvas::deleteDrawCommandAt(int index) {
285     SkASSERT(index < fCommandVector.size());
286     delete fCommandVector[index];
287     fCommandVector.remove(index);
288 }
289 
getDrawCommandAt(int index) const290 DrawCommand* DebugCanvas::getDrawCommandAt(int index) const {
291     SkASSERT(index < fCommandVector.size());
292     return fCommandVector[index];
293 }
294 
295 #if defined(SK_GANESH)
getAuditTrail(SkCanvas * canvas)296 GrAuditTrail* DebugCanvas::getAuditTrail(SkCanvas* canvas) {
297     GrAuditTrail* at  = nullptr;
298     auto ctx = canvas->recordingContext();
299     if (ctx) {
300         at = ctx->priv().auditTrail();
301     }
302     return at;
303 }
304 
drawAndCollectOps(SkCanvas * canvas)305 void DebugCanvas::drawAndCollectOps(SkCanvas* canvas) {
306     GrAuditTrail* at = this->getAuditTrail(canvas);
307     if (at) {
308         // loop over all of the commands and draw them, this is to collect reordering
309         // information
310         for (int i = 0; i < this->getSize(); i++) {
311             GrAuditTrail::AutoCollectOps enable(at, i);
312             fCommandVector[i]->execute(canvas);
313         }
314 
315         // in case there is some kind of global reordering
316         {
317             GrAuditTrail::AutoEnable ae(at);
318 
319             auto dContext = GrAsDirectContext(canvas->recordingContext());
320             if (dContext) {
321                 dContext->flush();
322             }
323         }
324     }
325 }
326 
cleanupAuditTrail(GrAuditTrail * at)327 void DebugCanvas::cleanupAuditTrail(GrAuditTrail* at) {
328     if (at) {
329         GrAuditTrail::AutoEnable ae(at);
330         at->fullReset();
331     }
332 }
333 #endif // defined(SK_GANESH)
334 
toJSON(SkJSONWriter & writer,UrlDataManager & urlDataManager,SkCanvas * canvas)335 void DebugCanvas::toJSON(SkJSONWriter&   writer,
336                          UrlDataManager& urlDataManager,
337                          SkCanvas*       canvas) {
338 #if defined(SK_GANESH)
339     this->drawAndCollectOps(canvas);
340 
341     // now collect json
342     GrAuditTrail* at = this->getAuditTrail(canvas);
343 #endif
344     writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_VERSION, SKDEBUGCANVAS_VERSION);
345     writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_COMMANDS);
346 
347     for (int i = 0; i < this->getSize(); i++) {
348         writer.beginObject();  // command
349         this->getDrawCommandAt(i)->toJSON(writer, urlDataManager);
350 
351 #if defined(SK_GANESH)
352         if (at) {
353             writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL);
354             at->toJson(writer, i);
355         }
356 #endif
357         writer.endObject();  // command
358     }
359 
360     writer.endArray();  // commands
361 #if defined(SK_GANESH)
362     this->cleanupAuditTrail(at);
363 #endif
364 }
365 
toJSONOpsTask(SkJSONWriter & writer,SkCanvas * canvas)366 void DebugCanvas::toJSONOpsTask(SkJSONWriter& writer, SkCanvas* canvas) {
367 #if defined(SK_GANESH)
368     this->drawAndCollectOps(canvas);
369 
370     GrAuditTrail* at = this->getAuditTrail(canvas);
371     if (at) {
372         GrAuditTrail::AutoManageOpsTask enable(at);
373         at->toJson(writer);
374         this->cleanupAuditTrail(at);
375         return;
376     }
377 #endif
378 
379     writer.beginObject();
380     writer.endObject();
381 }
382 
setOverdrawViz(bool overdrawViz)383 void DebugCanvas::setOverdrawViz(bool overdrawViz) { fOverdrawViz = overdrawViz; }
384 
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)385 void DebugCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
386     this->addDrawCommand(new ClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
387 }
388 
onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle edgeStyle)389 void DebugCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
390     this->addDrawCommand(new ClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
391 }
392 
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)393 void DebugCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
394     this->addDrawCommand(new ClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
395 }
396 
onClipRegion(const SkRegion & region,SkClipOp op)397 void DebugCanvas::onClipRegion(const SkRegion& region, SkClipOp op) {
398     this->addDrawCommand(new ClipRegionCommand(region, op));
399 }
400 
onClipShader(sk_sp<SkShader> cs,SkClipOp op)401 void DebugCanvas::onClipShader(sk_sp<SkShader> cs, SkClipOp op) {
402     this->addDrawCommand(new ClipShaderCommand(std::move(cs), op));
403 }
404 
onResetClip()405 void DebugCanvas::onResetClip() {
406     this->addDrawCommand(new ResetClipCommand());
407 }
408 
didConcat44(const SkM44 & m)409 void DebugCanvas::didConcat44(const SkM44& m) {
410     this->addDrawCommand(new Concat44Command(m));
411     this->INHERITED::didConcat44(m);
412 }
413 
didScale(SkScalar x,SkScalar y)414 void DebugCanvas::didScale(SkScalar x, SkScalar y) {
415     this->didConcat44(SkM44::Scale(x, y));
416 }
417 
didTranslate(SkScalar x,SkScalar y)418 void DebugCanvas::didTranslate(SkScalar x, SkScalar y) {
419     this->didConcat44(SkM44::Translate(x, y));
420 }
421 
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)422 void DebugCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
423     // Parse layer-releated annotations added in SkiaPipeline.cpp and RenderNodeDrawable.cpp
424     // the format of the annotations is <Indicator|RenderNodeId>
425     SkTArray<SkString> tokens;
426     SkStrSplit(key, "|", kStrict_SkStrSplitMode, &tokens);
427     if (tokens.size() == 2) {
428         if (tokens[0].equals(kOffscreenLayerDraw)) {
429             // Indicates that the next drawPicture command contains the SkPicture to render the
430             // node at this id in an offscreen buffer.
431             fnextDrawPictureLayerId = std::stoi(tokens[1].c_str());
432             fnextDrawPictureDirtyRect = rect.roundOut();
433             return; // don't record it
434         } else if (tokens[0].equals(kSurfaceID)) {
435             // Indicates that the following drawImageRect should draw the offscreen buffer.
436             fnextDrawImageRectLayerId = std::stoi(tokens[1].c_str());
437             return; // don't record it
438         }
439     }
440     if (strcmp(kAndroidClip, key) == 0) {
441         // Store this frame's android device clip restriction for visualization later.
442         // This annotation stands in place of the androidFramework_setDeviceClipRestriction
443         // which is unrecordable.
444         fAndroidClip = rect;
445     }
446     this->addDrawCommand(new DrawAnnotationCommand(rect, key, sk_ref_sp(value)));
447 }
448 
onDrawImage2(const SkImage * image,SkScalar left,SkScalar top,const SkSamplingOptions & sampling,const SkPaint * paint)449 void DebugCanvas::onDrawImage2(const SkImage*           image,
450                                SkScalar                 left,
451                                SkScalar                 top,
452                                const SkSamplingOptions& sampling,
453                                const SkPaint*           paint) {
454     this->addDrawCommand(new DrawImageCommand(image, left, top, sampling, paint));
455 }
456 
onDrawImageLattice2(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)457 void DebugCanvas::onDrawImageLattice2(const SkImage* image,
458                                       const Lattice& lattice,
459                                       const SkRect&  dst,
460                                       SkFilterMode filter,   // todo
461                                       const SkPaint* paint) {
462     this->addDrawCommand(new DrawImageLatticeCommand(image, lattice, dst, filter, paint));
463 }
464 
onDrawImageRect2(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)465 void DebugCanvas::onDrawImageRect2(const SkImage*           image,
466                                    const SkRect&            src,
467                                    const SkRect&            dst,
468                                    const SkSamplingOptions& sampling,
469                                    const SkPaint*           paint,
470                                    SrcRectConstraint        constraint) {
471     if (fnextDrawImageRectLayerId != -1 && fLayerManager) {
472         // This drawImageRect command would have drawn the offscreen buffer for a layer.
473         // On Android, we recorded an SkPicture of the commands that drew to the layer.
474         // To render the layer as it would have looked on the frame this DebugCanvas draws, we need
475         // to call fLayerManager->getLayerAsImage(id). This must be done just before
476         // drawTo(command), since it depends on the index into the layer's commands
477         // (managed by fLayerManager)
478         // Instead of adding a DrawImageRectCommand, we need a deferred command, that when
479         // executed, will call drawImageRect(fLayerManager->getLayerAsImage())
480         this->addDrawCommand(new DrawImageRectLayerCommand(
481             fLayerManager, fnextDrawImageRectLayerId, fFrame, src, dst, sampling,
482                                                            paint, constraint));
483     } else {
484         this->addDrawCommand(new DrawImageRectCommand(image, src, dst, sampling, paint, constraint));
485     }
486     // Reset expectation so next drawImageRect is not special.
487     fnextDrawImageRectLayerId = -1;
488 }
489 
onDrawOval(const SkRect & oval,const SkPaint & paint)490 void DebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
491     this->addDrawCommand(new DrawOvalCommand(oval, paint));
492 }
493 
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)494 void DebugCanvas::onDrawArc(const SkRect&  oval,
495                             SkScalar       startAngle,
496                             SkScalar       sweepAngle,
497                             bool           useCenter,
498                             const SkPaint& paint) {
499     this->addDrawCommand(new DrawArcCommand(oval, startAngle, sweepAngle, useCenter, paint));
500 }
501 
onDrawPaint(const SkPaint & paint)502 void DebugCanvas::onDrawPaint(const SkPaint& paint) {
503     this->addDrawCommand(new DrawPaintCommand(paint));
504 }
505 
onDrawBehind(const SkPaint & paint)506 void DebugCanvas::onDrawBehind(const SkPaint& paint) {
507     this->addDrawCommand(new DrawBehindCommand(paint));
508 }
509 
onDrawPath(const SkPath & path,const SkPaint & paint)510 void DebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
511     this->addDrawCommand(new DrawPathCommand(path, paint));
512 }
513 
onDrawRegion(const SkRegion & region,const SkPaint & paint)514 void DebugCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
515     this->addDrawCommand(new DrawRegionCommand(region, paint));
516 }
517 
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)518 void DebugCanvas::onDrawPicture(const SkPicture* picture,
519                                 const SkMatrix*  matrix,
520                                 const SkPaint*   paint) {
521     if (fnextDrawPictureLayerId != -1 && fLayerManager) {
522         fLayerManager->storeSkPicture(fnextDrawPictureLayerId, fFrame, sk_ref_sp(picture),
523            fnextDrawPictureDirtyRect);
524     } else {
525         this->addDrawCommand(new BeginDrawPictureCommand(picture, matrix, paint));
526         SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
527         picture->playback(this);
528         this->addDrawCommand(new EndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
529     }
530     fnextDrawPictureLayerId = -1;
531 }
532 
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)533 void DebugCanvas::onDrawPoints(PointMode      mode,
534                                size_t         count,
535                                const SkPoint  pts[],
536                                const SkPaint& paint) {
537     this->addDrawCommand(new DrawPointsCommand(mode, count, pts, paint));
538 }
539 
onDrawRect(const SkRect & rect,const SkPaint & paint)540 void DebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
541     // NOTE(chudy): Messing up when renamed to DrawRect... Why?
542     addDrawCommand(new DrawRectCommand(rect, paint));
543 }
544 
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)545 void DebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
546     this->addDrawCommand(new DrawRRectCommand(rrect, paint));
547 }
548 
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)549 void DebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
550     this->addDrawCommand(new DrawDRRectCommand(outer, inner, paint));
551 }
552 
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)553 void DebugCanvas::onDrawTextBlob(const SkTextBlob* blob,
554                                  SkScalar          x,
555                                  SkScalar          y,
556                                  const SkPaint&    paint) {
557     this->addDrawCommand(
558             new DrawTextBlobCommand(sk_ref_sp(const_cast<SkTextBlob*>(blob)), x, y, paint));
559 }
560 
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)561 void DebugCanvas::onDrawPatch(const SkPoint  cubics[12],
562                               const SkColor  colors[4],
563                               const SkPoint  texCoords[4],
564                               SkBlendMode    bmode,
565                               const SkPaint& paint) {
566     this->addDrawCommand(new DrawPatchCommand(cubics, colors, texCoords, bmode, paint));
567 }
568 
onDrawVerticesObject(const SkVertices * vertices,SkBlendMode bmode,const SkPaint & paint)569 void DebugCanvas::onDrawVerticesObject(const SkVertices*      vertices,
570                                        SkBlendMode            bmode,
571                                        const SkPaint&         paint) {
572     this->addDrawCommand(
573             new DrawVerticesCommand(sk_ref_sp(const_cast<SkVertices*>(vertices)), bmode, paint));
574 }
575 
onDrawAtlas2(const SkImage * image,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode bmode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)576 void DebugCanvas::onDrawAtlas2(const SkImage*           image,
577                                const SkRSXform          xform[],
578                                const SkRect             tex[],
579                                const SkColor            colors[],
580                                int                      count,
581                                SkBlendMode              bmode,
582                                const SkSamplingOptions& sampling,
583                                const SkRect*            cull,
584                                const SkPaint*           paint) {
585     this->addDrawCommand(
586             new DrawAtlasCommand(image, xform, tex, colors, count, bmode, sampling, cull, paint));
587 }
588 
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)589 void DebugCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
590     this->addDrawCommand(new DrawShadowCommand(path, rec));
591 }
592 
onDrawDrawable(SkDrawable * drawable,const SkMatrix * matrix)593 void DebugCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
594     this->addDrawCommand(new DrawDrawableCommand(drawable, matrix));
595 }
596 
onDrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],QuadAAFlags aa,const SkColor4f & color,SkBlendMode mode)597 void DebugCanvas::onDrawEdgeAAQuad(const SkRect&    rect,
598                                    const SkPoint    clip[4],
599                                    QuadAAFlags      aa,
600                                    const SkColor4f& color,
601                                    SkBlendMode      mode) {
602     this->addDrawCommand(new DrawEdgeAAQuadCommand(rect, clip, aa, color, mode));
603 }
604 
onDrawEdgeAAImageSet2(const ImageSetEntry set[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)605 void DebugCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry set[],
606                                         int                 count,
607                                         const SkPoint       dstClips[],
608                                         const SkMatrix      preViewMatrices[],
609                                         const SkSamplingOptions& sampling,
610                                         const SkPaint*      paint,
611                                         SrcRectConstraint   constraint) {
612     this->addDrawCommand(new DrawEdgeAAImageSetCommand(
613             set, count, dstClips, preViewMatrices, sampling, paint, constraint));
614 }
615 
willRestore()616 void DebugCanvas::willRestore() {
617     this->addDrawCommand(new RestoreCommand());
618     this->INHERITED::willRestore();
619 }
620 
willSave()621 void DebugCanvas::willSave() {
622     this->addDrawCommand(new SaveCommand());
623     this->INHERITED::willSave();
624 }
625 
getSaveLayerStrategy(const SaveLayerRec & rec)626 SkCanvas::SaveLayerStrategy DebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
627     this->addDrawCommand(new SaveLayerCommand(rec));
628     (void)this->INHERITED::getSaveLayerStrategy(rec);
629     // No need for a full layer.
630     return kNoLayer_SaveLayerStrategy;
631 }
632 
onDoSaveBehind(const SkRect * subset)633 bool DebugCanvas::onDoSaveBehind(const SkRect* subset) {
634     // TODO
635     return false;
636 }
637 
didSetM44(const SkM44 & matrix)638 void DebugCanvas::didSetM44(const SkM44& matrix) {
639     this->addDrawCommand(new SetM44Command(matrix));
640     this->INHERITED::didSetM44(matrix);
641 }
642 
toggleCommand(int index,bool toggle)643 void DebugCanvas::toggleCommand(int index, bool toggle) {
644     SkASSERT(index < fCommandVector.size());
645     fCommandVector[index]->setVisible(toggle);
646 }
647 
getImageIdToCommandMap(UrlDataManager & udm) const648 std::map<int, std::vector<int>> DebugCanvas::getImageIdToCommandMap(UrlDataManager& udm) const {
649     // map from image ids to list of commands that reference them.
650     std::map<int, std::vector<int>> m;
651 
652     for (int i = 0; i < this->getSize(); i++) {
653         const DrawCommand* command = this->getDrawCommandAt(i);
654         int imageIndex = -1;
655         // this is not an exaustive list of where images can be used, they show up in paints too.
656         switch (command->getOpType()) {
657             case DrawCommand::OpType::kDrawImage_OpType: {
658                 imageIndex = static_cast<const DrawImageCommand*>(command)->imageId(udm);
659                 break;
660             }
661             case DrawCommand::OpType::kDrawImageRect_OpType: {
662                 imageIndex = static_cast<const DrawImageRectCommand*>(command)->imageId(udm);
663                 break;
664             }
665             case DrawCommand::OpType::kDrawImageLattice_OpType: {
666                 imageIndex = static_cast<const DrawImageLatticeCommand*>(command)->imageId(udm);
667                 break;
668             }
669             default: break;
670         }
671         if (imageIndex >= 0) {
672             m[imageIndex].push_back(i);
673         }
674     }
675     return m;
676 }
677