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