blob: 1baf87dc65878209d657d52ceb3fcdb0450a0a22 [file] [log] [blame]
Mike Klein8f4e2242019-03-20 11:59:00 -05001/*
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
Brian Salomon8f7d9532020-12-23 09:16:59 -05008#include "tools/debugger/DebugCanvas.h"
9
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040010#include "include/core/SkPaint.h"
11#include "include/core/SkPath.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkPicture.h"
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040013#include "include/core/SkPoint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkTextBlob.h"
Robert Phillips2c21a112020-11-20 13:49:37 -050015#include "include/gpu/GrDirectContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/utils/SkPaintFilterCanvas.h"
17#include "src/core/SkCanvasPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/core/SkRectPriv.h"
Robert Phillipsb27b38b2020-07-10 16:23:47 -040019#include "src/gpu/GrRecordingContextPriv.h"
Brian Salomon8f7d9532020-12-23 09:16:59 -050020#include "src/utils/SkJSONWriter.h"
21#include "tools/debugger/DebugLayerManager.h"
22#include "tools/debugger/DrawCommand.h"
Mike Klein8f4e2242019-03-20 11:59:00 -050023
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050024#include <string>
25
Robert Phillipsa92913e2021-07-12 16:31:52 -040026#if SK_GPU_V1
27#include "src/gpu/GrAuditTrail.h"
28#endif
29
Mike Klein8f4e2242019-03-20 11:59:00 -050030#define SKDEBUGCANVAS_VERSION 1
31#define SKDEBUGCANVAS_ATTRIBUTE_VERSION "version"
32#define SKDEBUGCANVAS_ATTRIBUTE_COMMANDS "commands"
33#define SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL "auditTrail"
34
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050035namespace {
36 // Constants used in Annotations by Android for keeping track of layers
37 static constexpr char kOffscreenLayerDraw[] = "OffscreenLayerDraw";
38 static constexpr char kSurfaceID[] = "SurfaceID";
Nathaniel Nifong12b2c272020-01-10 14:38:00 -050039 static constexpr char kAndroidClip[] = "AndroidDeviceClipRestriction";
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040040
41 static SkPath arrowHead = SkPath::Polygon({
42 { 0, 0},
43 { 6, -15},
44 { 0, -12},
45 {-6, -15},
46 }, true);
47
48 void drawArrow(SkCanvas* canvas, const SkPoint& a, const SkPoint& b, const SkPaint& paint) {
Nathaniel Nifong0f7aa542020-09-02 15:40:37 -040049 canvas->translate(0.5, 0.5);
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040050 canvas->drawLine(a, b, paint);
51 canvas->save();
52 canvas->translate(b.fX, b.fY);
53 SkScalar angle = SkScalarATan2((b.fY - a.fY), b.fX - a.fX);
54 canvas->rotate(angle * 180 / SK_ScalarPI - 90);
55 // arrow head
56 canvas->drawPath(arrowHead, paint);
57 canvas->restore();
Nathaniel Nifong0f7aa542020-09-02 15:40:37 -040058 canvas->restore();
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040059 }
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050060} // namespace
61
Mike Klein8f4e2242019-03-20 11:59:00 -050062class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
63public:
Nathaniel Nifongc84ad832019-12-11 15:24:48 -050064 DebugPaintFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) {}
Mike Klein8f4e2242019-03-20 11:59:00 -050065
66protected:
Ben Wagnerf55fa0d2018-08-27 18:11:57 -040067 bool onFilter(SkPaint& paint) const override {
Nathaniel Nifongc84ad832019-12-11 15:24:48 -050068 paint.setColor(SK_ColorRED);
69 paint.setAlpha(0x08);
70 paint.setBlendMode(SkBlendMode::kSrcOver);
Mike Klein8f4e2242019-03-20 11:59:00 -050071 return true;
72 }
73
74 void onDrawPicture(const SkPicture* picture,
75 const SkMatrix* matrix,
76 const SkPaint* paint) override {
77 // We need to replay the picture onto this canvas in order to filter its internal paints.
78 this->SkCanvas::onDrawPicture(picture, matrix, paint);
79 }
80
81private:
Mike Klein8f4e2242019-03-20 11:59:00 -050082
John Stiles7571f9e2020-09-02 22:42:33 -040083 using INHERITED = SkPaintFilterCanvas;
Mike Klein8f4e2242019-03-20 11:59:00 -050084};
85
86DebugCanvas::DebugCanvas(int width, int height)
87 : INHERITED(width, height)
88 , fOverdrawViz(false)
89 , fClipVizColor(SK_ColorTRANSPARENT)
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050090 , fDrawGpuOpBounds(false)
Nathaniel Nifong12b2c272020-01-10 14:38:00 -050091 , fShowAndroidClip(false)
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040092 , fShowOrigin(false)
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050093 , fnextDrawPictureLayerId(-1)
Nathaniel Nifong12b2c272020-01-10 14:38:00 -050094 , fnextDrawImageRectLayerId(-1)
95 , fAndroidClip(SkRect::MakeEmpty()) {
Mike Klein8f4e2242019-03-20 11:59:00 -050096 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
97 // operations. This can lead to problems in the debugger which expects all
98 // the operations in the captured skp to appear in the debug canvas. To
99 // circumvent this we create a wide open clip here (an empty clip rect
100 // is not sufficient).
101 // Internally, the SkRect passed to clipRect is converted to an SkIRect and
102 // rounded out. The following code creates a nearly maximal rect that will
103 // not get collapsed by the coming conversions (Due to precision loss the
104 // inset has to be surprisingly large).
105 SkIRect largeIRect = SkRectPriv::MakeILarge();
106 largeIRect.inset(1024, 1024);
107 SkRect large = SkRect::Make(largeIRect);
108#ifdef SK_DEBUG
109 SkASSERT(!large.roundOut().isEmpty());
110#endif
111 // call the base class' version to avoid adding a draw command
Michael Ludwige4b79692020-09-16 13:55:05 -0400112 this->INHERITED::onClipRect(large, SkClipOp::kIntersect, kHard_ClipEdgeStyle);
Mike Klein8f4e2242019-03-20 11:59:00 -0500113}
114
John Stiles214de112020-07-29 17:26:28 -0400115DebugCanvas::DebugCanvas(SkIRect bounds)
116 : DebugCanvas(bounds.width(), bounds.height()) {}
Mike Klein8f4e2242019-03-20 11:59:00 -0500117
118DebugCanvas::~DebugCanvas() { fCommandVector.deleteAll(); }
119
120void DebugCanvas::addDrawCommand(DrawCommand* command) { fCommandVector.push_back(command); }
121
122void DebugCanvas::draw(SkCanvas* canvas) {
123 if (!fCommandVector.isEmpty()) {
124 this->drawTo(canvas, fCommandVector.count() - 1);
125 }
126}
127
128void DebugCanvas::drawTo(SkCanvas* originalCanvas, int index, int m) {
129 SkASSERT(!fCommandVector.isEmpty());
130 SkASSERT(index < fCommandVector.count());
131
132 int saveCount = originalCanvas->save();
133
Mike Klein8f4e2242019-03-20 11:59:00 -0500134 originalCanvas->resetMatrix();
Michael Ludwigcfd204a2021-07-23 11:48:34 -0400135 SkCanvasPriv::ResetClip(originalCanvas);
Mike Klein8f4e2242019-03-20 11:59:00 -0500136
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500137 DebugPaintFilterCanvas filterCanvas(originalCanvas);
138 SkCanvas* finalCanvas = fOverdrawViz ? &filterCanvas : originalCanvas;
Mike Klein8f4e2242019-03-20 11:59:00 -0500139
Robert Phillipsa92913e2021-07-12 16:31:52 -0400140#if SK_GPU_V1
Robert Phillips2c21a112020-11-20 13:49:37 -0500141 auto dContext = GrAsDirectContext(finalCanvas->recordingContext());
142
Mike Klein8f4e2242019-03-20 11:59:00 -0500143 // If we have a GPU backend we can also visualize the op information
144 GrAuditTrail* at = nullptr;
145 if (fDrawGpuOpBounds || m != -1) {
146 // The audit trail must be obtained from the original canvas.
147 at = this->getAuditTrail(originalCanvas);
148 }
Robert Phillipsa92913e2021-07-12 16:31:52 -0400149#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500150
151 for (int i = 0; i <= index; i++) {
Robert Phillipsa92913e2021-07-12 16:31:52 -0400152#if SK_GPU_V1
Mike Klein8f4e2242019-03-20 11:59:00 -0500153 GrAuditTrail::AutoCollectOps* acb = nullptr;
154 if (at) {
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500155 // We need to flush any pending operations, or they might combine with commands below.
156 // Previous operations were not registered with the audit trail when they were
157 // created, so if we allow them to combine, the audit trail will fail to find them.
Robert Phillips2c21a112020-11-20 13:49:37 -0500158 if (dContext) {
159 dContext->flush();
160 }
Mike Klein8f4e2242019-03-20 11:59:00 -0500161 acb = new GrAuditTrail::AutoCollectOps(at, i);
162 }
Robert Phillipsa92913e2021-07-12 16:31:52 -0400163#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500164 if (fCommandVector[i]->isVisible()) {
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500165 fCommandVector[i]->execute(finalCanvas);
Mike Klein8f4e2242019-03-20 11:59:00 -0500166 }
Robert Phillipsa92913e2021-07-12 16:31:52 -0400167#if SK_GPU_V1
Mike Klein8f4e2242019-03-20 11:59:00 -0500168 if (at && acb) {
169 delete acb;
170 }
Robert Phillipsa92913e2021-07-12 16:31:52 -0400171#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500172 }
173
174 if (SkColorGetA(fClipVizColor) != 0) {
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500175 finalCanvas->save();
Mike Klein8f4e2242019-03-20 11:59:00 -0500176 SkPaint clipPaint;
177 clipPaint.setColor(fClipVizColor);
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500178 finalCanvas->drawPaint(clipPaint);
179 finalCanvas->restore();
Mike Klein8f4e2242019-03-20 11:59:00 -0500180 }
181
Mike Reed1a4140e2020-12-03 11:21:31 -0500182 fMatrix = finalCanvas->getLocalToDevice();
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500183 fClip = finalCanvas->getDeviceClipBounds();
Nathaniel Nifong642a10b2020-08-20 12:33:46 -0400184 if (fShowOrigin) {
185 const SkPaint originXPaint = SkPaint({1.0, 0, 0, 1.0});
186 const SkPaint originYPaint = SkPaint({0, 1.0, 0, 1.0});
187 // Draw an origin cross at the origin before restoring to assist in visualizing the
188 // current matrix.
189 drawArrow(finalCanvas, {-50, 0}, {50, 0}, originXPaint);
190 drawArrow(finalCanvas, {0, -50}, {0, 50}, originYPaint);
191 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500192 finalCanvas->restoreToCount(saveCount);
Mike Klein8f4e2242019-03-20 11:59:00 -0500193
Nathaniel Nifong12b2c272020-01-10 14:38:00 -0500194 if (fShowAndroidClip) {
195 // Draw visualization of android device clip restriction
196 SkPaint androidClipPaint;
197 androidClipPaint.setARGB(80, 255, 100, 0);
198 finalCanvas->drawRect(fAndroidClip, androidClipPaint);
199 }
200
Robert Phillipsa92913e2021-07-12 16:31:52 -0400201#if SK_GPU_V1
Mike Klein8f4e2242019-03-20 11:59:00 -0500202 // draw any ops if required and issue a full reset onto GrAuditTrail
203 if (at) {
204 // just in case there is global reordering, we flush the canvas before querying
205 // GrAuditTrail
206 GrAuditTrail::AutoEnable ae(at);
Robert Phillips2c21a112020-11-20 13:49:37 -0500207 if (dContext) {
208 dContext->flush();
209 }
Mike Klein8f4e2242019-03-20 11:59:00 -0500210
211 // we pick three colorblind-safe colors, 75% alpha
212 static const SkColor kTotalBounds = SkColorSetARGB(0xC0, 0x6A, 0x3D, 0x9A);
213 static const SkColor kCommandOpBounds = SkColorSetARGB(0xC0, 0xE3, 0x1A, 0x1C);
214 static const SkColor kOtherOpBounds = SkColorSetARGB(0xC0, 0xFF, 0x7F, 0x00);
215
216 // get the render target of the top device (from the original canvas) so we can ignore ops
217 // drawn offscreen
Robert Phillipsfa8af0a2021-06-03 11:58:43 -0400218 GrRenderTargetProxy* rtp = SkCanvasPriv::TopDeviceTargetProxy(originalCanvas);
219 GrSurfaceProxy::UniqueID proxyID = rtp->uniqueID();
Mike Klein8f4e2242019-03-20 11:59:00 -0500220
221 // get the bounding boxes to draw
222 SkTArray<GrAuditTrail::OpInfo> childrenBounds;
223 if (m == -1) {
224 at->getBoundsByClientID(&childrenBounds, index);
225 } else {
226 // the client wants us to draw the mth op
Greg Danielf41b2bd2019-08-22 16:19:24 -0400227 at->getBoundsByOpsTaskID(&childrenBounds.push_back(), m);
Mike Klein8f4e2242019-03-20 11:59:00 -0500228 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500229 // Shift the rects half a pixel, so they appear as exactly 1px thick lines.
230 finalCanvas->save();
231 finalCanvas->translate(0.5, -0.5);
Mike Klein8f4e2242019-03-20 11:59:00 -0500232 SkPaint paint;
233 paint.setStyle(SkPaint::kStroke_Style);
234 paint.setStrokeWidth(1);
235 for (int i = 0; i < childrenBounds.count(); i++) {
236 if (childrenBounds[i].fProxyUniqueID != proxyID) {
237 // offscreen draw, ignore for now
238 continue;
239 }
240 paint.setColor(kTotalBounds);
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500241 finalCanvas->drawRect(childrenBounds[i].fBounds, paint);
Mike Klein8f4e2242019-03-20 11:59:00 -0500242 for (int j = 0; j < childrenBounds[i].fOps.count(); j++) {
243 const GrAuditTrail::OpInfo::Op& op = childrenBounds[i].fOps[j];
244 if (op.fClientID != index) {
245 paint.setColor(kOtherOpBounds);
246 } else {
247 paint.setColor(kCommandOpBounds);
248 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500249 finalCanvas->drawRect(op.fBounds, paint);
Mike Klein8f4e2242019-03-20 11:59:00 -0500250 }
251 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500252 finalCanvas->restore();
Robert Phillipsa92913e2021-07-12 16:31:52 -0400253 this->cleanupAuditTrail(at);
Mike Klein8f4e2242019-03-20 11:59:00 -0500254 }
Robert Phillipsa92913e2021-07-12 16:31:52 -0400255#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500256}
257
258void DebugCanvas::deleteDrawCommandAt(int index) {
259 SkASSERT(index < fCommandVector.count());
260 delete fCommandVector[index];
261 fCommandVector.remove(index);
262}
263
Nathaniel Nifong0b448da2020-09-16 10:35:22 -0400264DrawCommand* DebugCanvas::getDrawCommandAt(int index) const {
Mike Klein8f4e2242019-03-20 11:59:00 -0500265 SkASSERT(index < fCommandVector.count());
266 return fCommandVector[index];
267}
268
Robert Phillipsa92913e2021-07-12 16:31:52 -0400269#if SK_GPU_V1
Mike Klein8f4e2242019-03-20 11:59:00 -0500270GrAuditTrail* DebugCanvas::getAuditTrail(SkCanvas* canvas) {
271 GrAuditTrail* at = nullptr;
Robert Phillipsb27b38b2020-07-10 16:23:47 -0400272 auto ctx = canvas->recordingContext();
Mike Klein8f4e2242019-03-20 11:59:00 -0500273 if (ctx) {
274 at = ctx->priv().auditTrail();
275 }
276 return at;
277}
278
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500279void DebugCanvas::drawAndCollectOps(SkCanvas* canvas) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500280 GrAuditTrail* at = this->getAuditTrail(canvas);
281 if (at) {
282 // loop over all of the commands and draw them, this is to collect reordering
283 // information
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500284 for (int i = 0; i < this->getSize(); i++) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500285 GrAuditTrail::AutoCollectOps enable(at, i);
286 fCommandVector[i]->execute(canvas);
287 }
288
289 // in case there is some kind of global reordering
290 {
291 GrAuditTrail::AutoEnable ae(at);
Robert Phillips2c21a112020-11-20 13:49:37 -0500292
293 auto dContext = GrAsDirectContext(canvas->recordingContext());
294 if (dContext) {
295 dContext->flush();
296 }
Mike Klein8f4e2242019-03-20 11:59:00 -0500297 }
298 }
299}
300
Robert Phillipsa92913e2021-07-12 16:31:52 -0400301void DebugCanvas::cleanupAuditTrail(GrAuditTrail* at) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500302 if (at) {
303 GrAuditTrail::AutoEnable ae(at);
304 at->fullReset();
305 }
306}
Robert Phillipsa92913e2021-07-12 16:31:52 -0400307#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500308
309void DebugCanvas::toJSON(SkJSONWriter& writer,
310 UrlDataManager& urlDataManager,
Mike Klein8f4e2242019-03-20 11:59:00 -0500311 SkCanvas* canvas) {
Robert Phillipsa92913e2021-07-12 16:31:52 -0400312#if SK_GPU_V1
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500313 this->drawAndCollectOps(canvas);
Mike Klein8f4e2242019-03-20 11:59:00 -0500314
315 // now collect json
316 GrAuditTrail* at = this->getAuditTrail(canvas);
Robert Phillipsa92913e2021-07-12 16:31:52 -0400317#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500318 writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_VERSION, SKDEBUGCANVAS_VERSION);
319 writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_COMMANDS);
320
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500321 for (int i = 0; i < this->getSize(); i++) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500322 writer.beginObject(); // command
323 this->getDrawCommandAt(i)->toJSON(writer, urlDataManager);
324
Robert Phillipsa92913e2021-07-12 16:31:52 -0400325#if SK_GPU_V1
Mike Klein8f4e2242019-03-20 11:59:00 -0500326 if (at) {
327 writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL);
328 at->toJson(writer, i);
329 }
Robert Phillipsa92913e2021-07-12 16:31:52 -0400330#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500331 writer.endObject(); // command
332 }
333
334 writer.endArray(); // commands
Robert Phillipsa92913e2021-07-12 16:31:52 -0400335#if SK_GPU_V1
336 this->cleanupAuditTrail(at);
337#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500338}
339
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500340void DebugCanvas::toJSONOpsTask(SkJSONWriter& writer, SkCanvas* canvas) {
Robert Phillipsa92913e2021-07-12 16:31:52 -0400341#if SK_GPU_V1
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500342 this->drawAndCollectOps(canvas);
Mike Klein8f4e2242019-03-20 11:59:00 -0500343
344 GrAuditTrail* at = this->getAuditTrail(canvas);
345 if (at) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400346 GrAuditTrail::AutoManageOpsTask enable(at);
Mike Klein8f4e2242019-03-20 11:59:00 -0500347 at->toJson(writer);
Robert Phillipsa92913e2021-07-12 16:31:52 -0400348 this->cleanupAuditTrail(at);
349 return;
Mike Klein8f4e2242019-03-20 11:59:00 -0500350 }
Robert Phillipsa92913e2021-07-12 16:31:52 -0400351#endif
352
353 writer.beginObject();
354 writer.endObject();
Mike Klein8f4e2242019-03-20 11:59:00 -0500355}
356
357void DebugCanvas::setOverdrawViz(bool overdrawViz) { fOverdrawViz = overdrawViz; }
358
359void DebugCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
Mike Klein17428132019-03-20 13:02:32 -0500360 this->addDrawCommand(new ClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
Mike Klein8f4e2242019-03-20 11:59:00 -0500361}
362
363void DebugCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Mike Klein17428132019-03-20 13:02:32 -0500364 this->addDrawCommand(new ClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
Mike Klein8f4e2242019-03-20 11:59:00 -0500365}
366
367void DebugCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Mike Klein17428132019-03-20 13:02:32 -0500368 this->addDrawCommand(new ClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
Mike Klein8f4e2242019-03-20 11:59:00 -0500369}
370
371void DebugCanvas::onClipRegion(const SkRegion& region, SkClipOp op) {
Mike Klein17428132019-03-20 13:02:32 -0500372 this->addDrawCommand(new ClipRegionCommand(region, op));
Mike Klein8f4e2242019-03-20 11:59:00 -0500373}
374
Mike Reed121c2af2020-03-10 14:02:56 -0400375void DebugCanvas::onClipShader(sk_sp<SkShader> cs, SkClipOp op) {
376 this->addDrawCommand(new ClipShaderCommand(std::move(cs), op));
377}
378
Michael Ludwigcfd204a2021-07-23 11:48:34 -0400379void DebugCanvas::onResetClip() {
380 this->addDrawCommand(new ResetClipCommand());
381}
382
Mike Reed7d45a7a2020-04-18 10:27:52 -0400383void DebugCanvas::didConcat44(const SkM44& m) {
Nathaniel Nifong642a10b2020-08-20 12:33:46 -0400384 this->addDrawCommand(new Concat44Command(m));
Mike Reeda3a704a2020-01-10 17:21:40 -0500385 this->INHERITED::didConcat44(m);
386}
387
388void DebugCanvas::didScale(SkScalar x, SkScalar y) {
Mike Reed420a9ba2020-11-25 13:37:30 -0500389 this->didConcat44(SkM44::Scale(x, y));
Mike Reeda3a704a2020-01-10 17:21:40 -0500390}
391
392void DebugCanvas::didTranslate(SkScalar x, SkScalar y) {
Mike Reed420a9ba2020-11-25 13:37:30 -0500393 this->didConcat44(SkM44::Translate(x, y));
Mike Reeda3a704a2020-01-10 17:21:40 -0500394}
395
Mike Klein8f4e2242019-03-20 11:59:00 -0500396void DebugCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Nathaniel Nifong20b177a2019-12-12 11:05:10 -0500397 // Parse layer-releated annotations added in SkiaPipeline.cpp and RenderNodeDrawable.cpp
398 // the format of the annotations is <Indicator|RenderNodeId>
399 SkTArray<SkString> tokens;
400 SkStrSplit(key, "|", kStrict_SkStrSplitMode, &tokens);
401 if (tokens.size() == 2) {
402 if (tokens[0].equals(kOffscreenLayerDraw)) {
Nathaniel Nifong642a10b2020-08-20 12:33:46 -0400403 // Indicates that the next drawPicture command contains the SkPicture to render the
404 // node at this id in an offscreen buffer.
Nathaniel Nifong20b177a2019-12-12 11:05:10 -0500405 fnextDrawPictureLayerId = std::stoi(tokens[1].c_str());
406 fnextDrawPictureDirtyRect = rect.roundOut();
407 return; // don't record it
408 } else if (tokens[0].equals(kSurfaceID)) {
409 // Indicates that the following drawImageRect should draw the offscreen buffer.
410 fnextDrawImageRectLayerId = std::stoi(tokens[1].c_str());
411 return; // don't record it
412 }
413 }
Nathaniel Nifong12b2c272020-01-10 14:38:00 -0500414 if (strcmp(kAndroidClip, key) == 0) {
415 // Store this frame's android device clip restriction for visualization later.
416 // This annotation stands in place of the androidFramework_setDeviceClipRestriction
417 // which is unrecordable.
418 fAndroidClip = rect;
419 }
Mike Klein17428132019-03-20 13:02:32 -0500420 this->addDrawCommand(new DrawAnnotationCommand(rect, key, sk_ref_sp(value)));
Mike Klein8f4e2242019-03-20 11:59:00 -0500421}
422
Mike Reed4f23dec2020-12-30 14:22:42 +0000423void DebugCanvas::onDrawImage2(const SkImage* image,
424 SkScalar left,
425 SkScalar top,
Mike Reed18aeb572021-01-19 17:58:25 -0500426 const SkSamplingOptions& sampling,
Mike Reed4f23dec2020-12-30 14:22:42 +0000427 const SkPaint* paint) {
Mike Reed18aeb572021-01-19 17:58:25 -0500428 this->addDrawCommand(new DrawImageCommand(image, left, top, sampling, paint));
Mike Reed4f23dec2020-12-30 14:22:42 +0000429}
430
431void DebugCanvas::onDrawImageLattice2(const SkImage* image,
432 const Lattice& lattice,
433 const SkRect& dst,
434 SkFilterMode filter, // todo
435 const SkPaint* paint) {
Mike Reed99116302021-01-25 11:37:10 -0500436 this->addDrawCommand(new DrawImageLatticeCommand(image, lattice, dst, filter, paint));
Mike Reed4f23dec2020-12-30 14:22:42 +0000437}
438
439void DebugCanvas::onDrawImageRect2(const SkImage* image,
440 const SkRect& src,
441 const SkRect& dst,
Mike Reed18aeb572021-01-19 17:58:25 -0500442 const SkSamplingOptions& sampling,
Mike Reed4f23dec2020-12-30 14:22:42 +0000443 const SkPaint* paint,
444 SrcRectConstraint constraint) {
445 if (fnextDrawImageRectLayerId != -1 && fLayerManager) {
446 // This drawImageRect command would have drawn the offscreen buffer for a layer.
447 // On Android, we recorded an SkPicture of the commands that drew to the layer.
448 // To render the layer as it would have looked on the frame this DebugCanvas draws, we need
449 // to call fLayerManager->getLayerAsImage(id). This must be done just before
450 // drawTo(command), since it depends on the index into the layer's commands
451 // (managed by fLayerManager)
452 // Instead of adding a DrawImageRectCommand, we need a deferred command, that when
453 // executed, will call drawImageRect(fLayerManager->getLayerAsImage())
454 this->addDrawCommand(new DrawImageRectLayerCommand(
Mike Reede02d7f82021-01-21 22:25:21 -0500455 fLayerManager, fnextDrawImageRectLayerId, fFrame, src, dst, sampling,
456 paint, constraint));
Mike Reed4f23dec2020-12-30 14:22:42 +0000457 } else {
Mike Reed18aeb572021-01-19 17:58:25 -0500458 this->addDrawCommand(new DrawImageRectCommand(image, src, dst, sampling, paint, constraint));
Mike Reed4f23dec2020-12-30 14:22:42 +0000459 }
460 // Reset expectation so next drawImageRect is not special.
461 fnextDrawImageRectLayerId = -1;
462}
Mike Klein8f4e2242019-03-20 11:59:00 -0500463
Mike Klein8f4e2242019-03-20 11:59:00 -0500464void DebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500465 this->addDrawCommand(new DrawOvalCommand(oval, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500466}
467
468void DebugCanvas::onDrawArc(const SkRect& oval,
469 SkScalar startAngle,
470 SkScalar sweepAngle,
471 bool useCenter,
472 const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500473 this->addDrawCommand(new DrawArcCommand(oval, startAngle, sweepAngle, useCenter, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500474}
475
476void DebugCanvas::onDrawPaint(const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500477 this->addDrawCommand(new DrawPaintCommand(paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500478}
479
Mike Reedd5674082019-04-19 15:00:47 -0400480void DebugCanvas::onDrawBehind(const SkPaint& paint) {
481 this->addDrawCommand(new DrawBehindCommand(paint));
482}
483
Mike Klein8f4e2242019-03-20 11:59:00 -0500484void DebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500485 this->addDrawCommand(new DrawPathCommand(path, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500486}
487
488void DebugCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500489 this->addDrawCommand(new DrawRegionCommand(region, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500490}
491
492void DebugCanvas::onDrawPicture(const SkPicture* picture,
493 const SkMatrix* matrix,
494 const SkPaint* paint) {
Nathaniel Nifong20b177a2019-12-12 11:05:10 -0500495 if (fnextDrawPictureLayerId != -1 && fLayerManager) {
496 fLayerManager->storeSkPicture(fnextDrawPictureLayerId, fFrame, sk_ref_sp(picture),
497 fnextDrawPictureDirtyRect);
498 } else {
499 this->addDrawCommand(new BeginDrawPictureCommand(picture, matrix, paint));
500 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
501 picture->playback(this);
502 this->addDrawCommand(new EndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
503 }
504 fnextDrawPictureLayerId = -1;
Mike Klein8f4e2242019-03-20 11:59:00 -0500505}
506
507void DebugCanvas::onDrawPoints(PointMode mode,
508 size_t count,
509 const SkPoint pts[],
510 const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500511 this->addDrawCommand(new DrawPointsCommand(mode, count, pts, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500512}
513
514void DebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
515 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
Mike Klein17428132019-03-20 13:02:32 -0500516 addDrawCommand(new DrawRectCommand(rect, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500517}
518
519void DebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500520 this->addDrawCommand(new DrawRRectCommand(rrect, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500521}
522
523void DebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500524 this->addDrawCommand(new DrawDRRectCommand(outer, inner, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500525}
526
527void DebugCanvas::onDrawTextBlob(const SkTextBlob* blob,
528 SkScalar x,
529 SkScalar y,
530 const SkPaint& paint) {
531 this->addDrawCommand(
Mike Klein17428132019-03-20 13:02:32 -0500532 new DrawTextBlobCommand(sk_ref_sp(const_cast<SkTextBlob*>(blob)), x, y, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500533}
534
535void DebugCanvas::onDrawPatch(const SkPoint cubics[12],
536 const SkColor colors[4],
537 const SkPoint texCoords[4],
538 SkBlendMode bmode,
539 const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500540 this->addDrawCommand(new DrawPatchCommand(cubics, colors, texCoords, bmode, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500541}
542
Mike Reeda2cf8ae2020-03-02 17:08:01 -0500543void DebugCanvas::onDrawVerticesObject(const SkVertices* vertices,
544 SkBlendMode bmode,
545 const SkPaint& paint) {
546 this->addDrawCommand(
547 new DrawVerticesCommand(sk_ref_sp(const_cast<SkVertices*>(vertices)), bmode, paint));
548}
Mike Klein8f4e2242019-03-20 11:59:00 -0500549
Mike Reed4f23dec2020-12-30 14:22:42 +0000550void DebugCanvas::onDrawAtlas2(const SkImage* image,
551 const SkRSXform xform[],
552 const SkRect tex[],
553 const SkColor colors[],
554 int count,
555 SkBlendMode bmode,
556 const SkSamplingOptions& sampling,
557 const SkRect* cull,
558 const SkPaint* paint) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500559 this->addDrawCommand(
Mike Reed99116302021-01-25 11:37:10 -0500560 new DrawAtlasCommand(image, xform, tex, colors, count, bmode, sampling, cull, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500561}
562
563void DebugCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
Mike Klein17428132019-03-20 13:02:32 -0500564 this->addDrawCommand(new DrawShadowCommand(path, rec));
Mike Klein8f4e2242019-03-20 11:59:00 -0500565}
566
567void DebugCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
Mike Klein17428132019-03-20 13:02:32 -0500568 this->addDrawCommand(new DrawDrawableCommand(drawable, matrix));
Mike Klein8f4e2242019-03-20 11:59:00 -0500569}
570
Michael Ludwiga595f862019-08-27 15:25:49 -0400571void DebugCanvas::onDrawEdgeAAQuad(const SkRect& rect,
572 const SkPoint clip[4],
573 QuadAAFlags aa,
574 const SkColor4f& color,
575 SkBlendMode mode) {
Mike Klein17428132019-03-20 13:02:32 -0500576 this->addDrawCommand(new DrawEdgeAAQuadCommand(rect, clip, aa, color, mode));
Mike Klein8f4e2242019-03-20 11:59:00 -0500577}
578
Mike Reed4f509342021-01-05 12:03:47 -0500579void DebugCanvas::onDrawEdgeAAImageSet2(const ImageSetEntry set[],
580 int count,
581 const SkPoint dstClips[],
582 const SkMatrix preViewMatrices[],
583 const SkSamplingOptions& sampling,
584 const SkPaint* paint,
585 SrcRectConstraint constraint) {
Mike Klein17428132019-03-20 13:02:32 -0500586 this->addDrawCommand(new DrawEdgeAAImageSetCommand(
Mike Reed4f509342021-01-05 12:03:47 -0500587 set, count, dstClips, preViewMatrices, sampling, paint, constraint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500588}
589
590void DebugCanvas::willRestore() {
Mike Klein17428132019-03-20 13:02:32 -0500591 this->addDrawCommand(new RestoreCommand());
Mike Klein8f4e2242019-03-20 11:59:00 -0500592 this->INHERITED::willRestore();
593}
594
595void DebugCanvas::willSave() {
Mike Klein17428132019-03-20 13:02:32 -0500596 this->addDrawCommand(new SaveCommand());
Mike Klein8f4e2242019-03-20 11:59:00 -0500597 this->INHERITED::willSave();
598}
599
600SkCanvas::SaveLayerStrategy DebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
Mike Klein17428132019-03-20 13:02:32 -0500601 this->addDrawCommand(new SaveLayerCommand(rec));
Mike Klein8f4e2242019-03-20 11:59:00 -0500602 (void)this->INHERITED::getSaveLayerStrategy(rec);
603 // No need for a full layer.
604 return kNoLayer_SaveLayerStrategy;
605}
606
607bool DebugCanvas::onDoSaveBehind(const SkRect* subset) {
608 // TODO
609 return false;
610}
611
Mike Reed420a9ba2020-11-25 13:37:30 -0500612void DebugCanvas::didSetM44(const SkM44& matrix) {
613 this->addDrawCommand(new SetM44Command(matrix));
614 this->INHERITED::didSetM44(matrix);
615}
616
Mike Klein8f4e2242019-03-20 11:59:00 -0500617void DebugCanvas::toggleCommand(int index, bool toggle) {
618 SkASSERT(index < fCommandVector.count());
619 fCommandVector[index]->setVisible(toggle);
620}
Nathaniel Nifong0b448da2020-09-16 10:35:22 -0400621
622std::map<int, std::vector<int>> DebugCanvas::getImageIdToCommandMap(UrlDataManager& udm) const {
623 // map from image ids to list of commands that reference them.
624 std::map<int, std::vector<int>> m;
625
626 for (int i = 0; i < this->getSize(); i++) {
627 const DrawCommand* command = this->getDrawCommandAt(i);
628 int imageIndex = -1;
629 // this is not an exaustive list of where images can be used, they show up in paints too.
630 switch (command->getOpType()) {
631 case DrawCommand::OpType::kDrawImage_OpType: {
632 imageIndex = static_cast<const DrawImageCommand*>(command)->imageId(udm);
633 break;
634 }
635 case DrawCommand::OpType::kDrawImageRect_OpType: {
636 imageIndex = static_cast<const DrawImageRectCommand*>(command)->imageId(udm);
637 break;
638 }
Nathaniel Nifong0b448da2020-09-16 10:35:22 -0400639 case DrawCommand::OpType::kDrawImageLattice_OpType: {
640 imageIndex = static_cast<const DrawImageLatticeCommand*>(command)->imageId(udm);
641 break;
642 }
643 default: break;
644 }
645 if (imageIndex >= 0) {
646 m[imageIndex].push_back(i);
647 }
648 }
649 return m;
650}