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