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