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