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