blob: fadc256555d9f1375ec28ae80a3736079acc72da [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
Nathaniel Nifong642a10b2020-08-20 12:33:46 -04008#include "include/core/SkPaint.h"
9#include "include/core/SkPath.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkPicture.h"
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040011#include "include/core/SkPoint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkTextBlob.h"
Robert Phillips2c21a112020-11-20 13:49:37 -050013#include "include/gpu/GrDirectContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/utils/SkPaintFilterCanvas.h"
15#include "src/core/SkCanvasPriv.h"
16#include "src/core/SkClipOpPriv.h"
17#include "src/core/SkRectPriv.h"
18#include "src/utils/SkJSONWriter.h"
19#include "tools/debugger/DebugCanvas.h"
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050020#include "tools/debugger/DebugLayerManager.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "tools/debugger/DrawCommand.h"
Mike Klein8f4e2242019-03-20 11:59:00 -050022
Greg Danielf91aeb22019-06-18 09:58:02 -040023#include "src/gpu/GrAuditTrail.h"
Robert Phillipsb27b38b2020-07-10 16:23:47 -040024#include "src/gpu/GrRecordingContextPriv.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050025#include "src/gpu/GrSurfaceDrawContext.h"
Mike Klein8f4e2242019-03-20 11:59:00 -050026
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050027#include <string>
28
Mike Klein8f4e2242019-03-20 11:59:00 -050029#define SKDEBUGCANVAS_VERSION 1
30#define SKDEBUGCANVAS_ATTRIBUTE_VERSION "version"
31#define SKDEBUGCANVAS_ATTRIBUTE_COMMANDS "commands"
32#define SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL "auditTrail"
33
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050034namespace {
35 // Constants used in Annotations by Android for keeping track of layers
36 static constexpr char kOffscreenLayerDraw[] = "OffscreenLayerDraw";
37 static constexpr char kSurfaceID[] = "SurfaceID";
Nathaniel Nifong12b2c272020-01-10 14:38:00 -050038 static constexpr char kAndroidClip[] = "AndroidDeviceClipRestriction";
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040039
40 static SkPath arrowHead = SkPath::Polygon({
41 { 0, 0},
42 { 6, -15},
43 { 0, -12},
44 {-6, -15},
45 }, true);
46
47 void drawArrow(SkCanvas* canvas, const SkPoint& a, const SkPoint& b, const SkPaint& paint) {
Nathaniel Nifong0f7aa542020-09-02 15:40:37 -040048 canvas->translate(0.5, 0.5);
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040049 canvas->drawLine(a, b, paint);
50 canvas->save();
51 canvas->translate(b.fX, b.fY);
52 SkScalar angle = SkScalarATan2((b.fY - a.fY), b.fX - a.fX);
53 canvas->rotate(angle * 180 / SK_ScalarPI - 90);
54 // arrow head
55 canvas->drawPath(arrowHead, paint);
56 canvas->restore();
Nathaniel Nifong0f7aa542020-09-02 15:40:37 -040057 canvas->restore();
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040058 }
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050059} // namespace
60
Mike Klein8f4e2242019-03-20 11:59:00 -050061class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
62public:
Nathaniel Nifongc84ad832019-12-11 15:24:48 -050063 DebugPaintFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) {}
Mike Klein8f4e2242019-03-20 11:59:00 -050064
65protected:
Ben Wagnerf55fa0d2018-08-27 18:11:57 -040066 bool onFilter(SkPaint& paint) const override {
Nathaniel Nifongc84ad832019-12-11 15:24:48 -050067 paint.setColor(SK_ColorRED);
68 paint.setAlpha(0x08);
69 paint.setBlendMode(SkBlendMode::kSrcOver);
Mike Klein8f4e2242019-03-20 11:59:00 -050070 return true;
71 }
72
73 void onDrawPicture(const SkPicture* picture,
74 const SkMatrix* matrix,
75 const SkPaint* paint) override {
76 // We need to replay the picture onto this canvas in order to filter its internal paints.
77 this->SkCanvas::onDrawPicture(picture, matrix, paint);
78 }
79
80private:
Mike Klein8f4e2242019-03-20 11:59:00 -050081
John Stiles7571f9e2020-09-02 22:42:33 -040082 using INHERITED = SkPaintFilterCanvas;
Mike Klein8f4e2242019-03-20 11:59:00 -050083};
84
85DebugCanvas::DebugCanvas(int width, int height)
86 : INHERITED(width, height)
87 , fOverdrawViz(false)
88 , fClipVizColor(SK_ColorTRANSPARENT)
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050089 , fDrawGpuOpBounds(false)
Nathaniel Nifong12b2c272020-01-10 14:38:00 -050090 , fShowAndroidClip(false)
Nathaniel Nifong642a10b2020-08-20 12:33:46 -040091 , fShowOrigin(false)
Nathaniel Nifong20b177a2019-12-12 11:05:10 -050092 , fnextDrawPictureLayerId(-1)
Nathaniel Nifong12b2c272020-01-10 14:38:00 -050093 , fnextDrawImageRectLayerId(-1)
94 , fAndroidClip(SkRect::MakeEmpty()) {
Mike Klein8f4e2242019-03-20 11:59:00 -050095 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
96 // operations. This can lead to problems in the debugger which expects all
97 // the operations in the captured skp to appear in the debug canvas. To
98 // circumvent this we create a wide open clip here (an empty clip rect
99 // is not sufficient).
100 // Internally, the SkRect passed to clipRect is converted to an SkIRect and
101 // rounded out. The following code creates a nearly maximal rect that will
102 // not get collapsed by the coming conversions (Due to precision loss the
103 // inset has to be surprisingly large).
104 SkIRect largeIRect = SkRectPriv::MakeILarge();
105 largeIRect.inset(1024, 1024);
106 SkRect large = SkRect::Make(largeIRect);
107#ifdef SK_DEBUG
108 SkASSERT(!large.roundOut().isEmpty());
109#endif
110 // call the base class' version to avoid adding a draw command
Michael Ludwige4b79692020-09-16 13:55:05 -0400111 this->INHERITED::onClipRect(large, SkClipOp::kIntersect, kHard_ClipEdgeStyle);
Mike Klein8f4e2242019-03-20 11:59:00 -0500112}
113
John Stiles214de112020-07-29 17:26:28 -0400114DebugCanvas::DebugCanvas(SkIRect bounds)
115 : DebugCanvas(bounds.width(), bounds.height()) {}
Mike Klein8f4e2242019-03-20 11:59:00 -0500116
117DebugCanvas::~DebugCanvas() { fCommandVector.deleteAll(); }
118
119void DebugCanvas::addDrawCommand(DrawCommand* command) { fCommandVector.push_back(command); }
120
121void DebugCanvas::draw(SkCanvas* canvas) {
122 if (!fCommandVector.isEmpty()) {
123 this->drawTo(canvas, fCommandVector.count() - 1);
124 }
125}
126
127void DebugCanvas::drawTo(SkCanvas* originalCanvas, int index, int m) {
128 SkASSERT(!fCommandVector.isEmpty());
129 SkASSERT(index < fCommandVector.count());
130
131 int saveCount = originalCanvas->save();
132
133 SkRect windowRect = SkRect::MakeWH(SkIntToScalar(originalCanvas->getBaseLayerSize().width()),
134 SkIntToScalar(originalCanvas->getBaseLayerSize().height()));
135
Mike Klein8f4e2242019-03-20 11:59:00 -0500136 originalCanvas->resetMatrix();
137 if (!windowRect.isEmpty()) {
138 originalCanvas->clipRect(windowRect, kReplace_SkClipOp);
139 }
140
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500141 DebugPaintFilterCanvas filterCanvas(originalCanvas);
142 SkCanvas* finalCanvas = fOverdrawViz ? &filterCanvas : originalCanvas;
Mike Klein8f4e2242019-03-20 11:59:00 -0500143
Robert Phillips2c21a112020-11-20 13:49:37 -0500144 auto dContext = GrAsDirectContext(finalCanvas->recordingContext());
145
Mike Klein8f4e2242019-03-20 11:59:00 -0500146 // If we have a GPU backend we can also visualize the op information
147 GrAuditTrail* at = nullptr;
148 if (fDrawGpuOpBounds || m != -1) {
149 // The audit trail must be obtained from the original canvas.
150 at = this->getAuditTrail(originalCanvas);
151 }
152
153 for (int i = 0; i <= index; i++) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500154 GrAuditTrail::AutoCollectOps* acb = nullptr;
155 if (at) {
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500156 // We need to flush any pending operations, or they might combine with commands below.
157 // Previous operations were not registered with the audit trail when they were
158 // created, so if we allow them to combine, the audit trail will fail to find them.
Robert Phillips2c21a112020-11-20 13:49:37 -0500159 if (dContext) {
160 dContext->flush();
161 }
Mike Klein8f4e2242019-03-20 11:59:00 -0500162 acb = new GrAuditTrail::AutoCollectOps(at, i);
163 }
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 }
167 if (at && acb) {
168 delete acb;
169 }
170 }
171
172 if (SkColorGetA(fClipVizColor) != 0) {
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500173 finalCanvas->save();
Mike Klein8f4e2242019-03-20 11:59:00 -0500174 SkPaint clipPaint;
175 clipPaint.setColor(fClipVizColor);
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500176 finalCanvas->drawPaint(clipPaint);
177 finalCanvas->restore();
Mike Klein8f4e2242019-03-20 11:59:00 -0500178 }
179
Mike Reed1a4140e2020-12-03 11:21:31 -0500180 fMatrix = finalCanvas->getLocalToDevice();
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500181 fClip = finalCanvas->getDeviceClipBounds();
Nathaniel Nifong642a10b2020-08-20 12:33:46 -0400182 if (fShowOrigin) {
183 const SkPaint originXPaint = SkPaint({1.0, 0, 0, 1.0});
184 const SkPaint originYPaint = SkPaint({0, 1.0, 0, 1.0});
185 // Draw an origin cross at the origin before restoring to assist in visualizing the
186 // current matrix.
187 drawArrow(finalCanvas, {-50, 0}, {50, 0}, originXPaint);
188 drawArrow(finalCanvas, {0, -50}, {0, 50}, originYPaint);
189 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500190 finalCanvas->restoreToCount(saveCount);
Mike Klein8f4e2242019-03-20 11:59:00 -0500191
Nathaniel Nifong12b2c272020-01-10 14:38:00 -0500192 if (fShowAndroidClip) {
193 // Draw visualization of android device clip restriction
194 SkPaint androidClipPaint;
195 androidClipPaint.setARGB(80, 255, 100, 0);
196 finalCanvas->drawRect(fAndroidClip, androidClipPaint);
197 }
198
Mike Klein8f4e2242019-03-20 11:59:00 -0500199 // draw any ops if required and issue a full reset onto GrAuditTrail
200 if (at) {
201 // just in case there is global reordering, we flush the canvas before querying
202 // GrAuditTrail
203 GrAuditTrail::AutoEnable ae(at);
Robert Phillips2c21a112020-11-20 13:49:37 -0500204 if (dContext) {
205 dContext->flush();
206 }
Mike Klein8f4e2242019-03-20 11:59:00 -0500207
208 // we pick three colorblind-safe colors, 75% alpha
209 static const SkColor kTotalBounds = SkColorSetARGB(0xC0, 0x6A, 0x3D, 0x9A);
210 static const SkColor kCommandOpBounds = SkColorSetARGB(0xC0, 0xE3, 0x1A, 0x1C);
211 static const SkColor kOtherOpBounds = SkColorSetARGB(0xC0, 0xFF, 0x7F, 0x00);
212
213 // get the render target of the top device (from the original canvas) so we can ignore ops
214 // drawn offscreen
Brian Salomoneebe7352020-12-09 16:37:04 -0500215 GrSurfaceDrawContext* rtc =
Mike Klein8f4e2242019-03-20 11:59:00 -0500216 originalCanvas->internal_private_accessTopLayerRenderTargetContext();
217 GrSurfaceProxy::UniqueID proxyID = rtc->asSurfaceProxy()->uniqueID();
218
219 // get the bounding boxes to draw
220 SkTArray<GrAuditTrail::OpInfo> childrenBounds;
221 if (m == -1) {
222 at->getBoundsByClientID(&childrenBounds, index);
223 } else {
224 // the client wants us to draw the mth op
Greg Danielf41b2bd2019-08-22 16:19:24 -0400225 at->getBoundsByOpsTaskID(&childrenBounds.push_back(), m);
Mike Klein8f4e2242019-03-20 11:59:00 -0500226 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500227 // Shift the rects half a pixel, so they appear as exactly 1px thick lines.
228 finalCanvas->save();
229 finalCanvas->translate(0.5, -0.5);
Mike Klein8f4e2242019-03-20 11:59:00 -0500230 SkPaint paint;
231 paint.setStyle(SkPaint::kStroke_Style);
232 paint.setStrokeWidth(1);
233 for (int i = 0; i < childrenBounds.count(); i++) {
234 if (childrenBounds[i].fProxyUniqueID != proxyID) {
235 // offscreen draw, ignore for now
236 continue;
237 }
238 paint.setColor(kTotalBounds);
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500239 finalCanvas->drawRect(childrenBounds[i].fBounds, paint);
Mike Klein8f4e2242019-03-20 11:59:00 -0500240 for (int j = 0; j < childrenBounds[i].fOps.count(); j++) {
241 const GrAuditTrail::OpInfo::Op& op = childrenBounds[i].fOps[j];
242 if (op.fClientID != index) {
243 paint.setColor(kOtherOpBounds);
244 } else {
245 paint.setColor(kCommandOpBounds);
246 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500247 finalCanvas->drawRect(op.fBounds, paint);
Mike Klein8f4e2242019-03-20 11:59:00 -0500248 }
249 }
Nathaniel Nifongc84ad832019-12-11 15:24:48 -0500250 finalCanvas->restore();
Mike Klein8f4e2242019-03-20 11:59:00 -0500251 }
252 this->cleanupAuditTrail(originalCanvas);
253}
254
255void DebugCanvas::deleteDrawCommandAt(int index) {
256 SkASSERT(index < fCommandVector.count());
257 delete fCommandVector[index];
258 fCommandVector.remove(index);
259}
260
Nathaniel Nifong0b448da2020-09-16 10:35:22 -0400261DrawCommand* DebugCanvas::getDrawCommandAt(int index) const {
Mike Klein8f4e2242019-03-20 11:59:00 -0500262 SkASSERT(index < fCommandVector.count());
263 return fCommandVector[index];
264}
265
266GrAuditTrail* DebugCanvas::getAuditTrail(SkCanvas* canvas) {
267 GrAuditTrail* at = nullptr;
Robert Phillipsb27b38b2020-07-10 16:23:47 -0400268 auto ctx = canvas->recordingContext();
Mike Klein8f4e2242019-03-20 11:59:00 -0500269 if (ctx) {
270 at = ctx->priv().auditTrail();
271 }
272 return at;
273}
274
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500275void DebugCanvas::drawAndCollectOps(SkCanvas* canvas) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500276 GrAuditTrail* at = this->getAuditTrail(canvas);
277 if (at) {
278 // loop over all of the commands and draw them, this is to collect reordering
279 // information
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500280 for (int i = 0; i < this->getSize(); i++) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500281 GrAuditTrail::AutoCollectOps enable(at, i);
282 fCommandVector[i]->execute(canvas);
283 }
284
285 // in case there is some kind of global reordering
286 {
287 GrAuditTrail::AutoEnable ae(at);
Robert Phillips2c21a112020-11-20 13:49:37 -0500288
289 auto dContext = GrAsDirectContext(canvas->recordingContext());
290 if (dContext) {
291 dContext->flush();
292 }
Mike Klein8f4e2242019-03-20 11:59:00 -0500293 }
294 }
295}
296
297void DebugCanvas::cleanupAuditTrail(SkCanvas* canvas) {
298 GrAuditTrail* at = this->getAuditTrail(canvas);
299 if (at) {
300 GrAuditTrail::AutoEnable ae(at);
301 at->fullReset();
302 }
303}
304
305void DebugCanvas::toJSON(SkJSONWriter& writer,
306 UrlDataManager& urlDataManager,
Mike Klein8f4e2242019-03-20 11:59:00 -0500307 SkCanvas* canvas) {
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500308 this->drawAndCollectOps(canvas);
Mike Klein8f4e2242019-03-20 11:59:00 -0500309
310 // now collect json
311 GrAuditTrail* at = this->getAuditTrail(canvas);
312 writer.appendS32(SKDEBUGCANVAS_ATTRIBUTE_VERSION, SKDEBUGCANVAS_VERSION);
313 writer.beginArray(SKDEBUGCANVAS_ATTRIBUTE_COMMANDS);
314
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500315 for (int i = 0; i < this->getSize(); i++) {
Mike Klein8f4e2242019-03-20 11:59:00 -0500316 writer.beginObject(); // command
317 this->getDrawCommandAt(i)->toJSON(writer, urlDataManager);
318
319 if (at) {
320 writer.appendName(SKDEBUGCANVAS_ATTRIBUTE_AUDITTRAIL);
321 at->toJson(writer, i);
322 }
323 writer.endObject(); // command
324 }
325
326 writer.endArray(); // commands
327 this->cleanupAuditTrail(canvas);
328}
329
Nathaniel Nifonga072b7b2019-12-13 13:51:14 -0500330void DebugCanvas::toJSONOpsTask(SkJSONWriter& writer, SkCanvas* canvas) {
331 this->drawAndCollectOps(canvas);
Mike Klein8f4e2242019-03-20 11:59:00 -0500332
333 GrAuditTrail* at = this->getAuditTrail(canvas);
334 if (at) {
Greg Danielf41b2bd2019-08-22 16:19:24 -0400335 GrAuditTrail::AutoManageOpsTask enable(at);
Mike Klein8f4e2242019-03-20 11:59:00 -0500336 at->toJson(writer);
337 } else {
338 writer.beginObject();
339 writer.endObject();
340 }
341 this->cleanupAuditTrail(canvas);
342}
343
344void DebugCanvas::setOverdrawViz(bool overdrawViz) { fOverdrawViz = overdrawViz; }
345
346void DebugCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
Mike Klein17428132019-03-20 13:02:32 -0500347 this->addDrawCommand(new ClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
Mike Klein8f4e2242019-03-20 11:59:00 -0500348}
349
350void DebugCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Mike Klein17428132019-03-20 13:02:32 -0500351 this->addDrawCommand(new ClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
Mike Klein8f4e2242019-03-20 11:59:00 -0500352}
353
354void DebugCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
Mike Klein17428132019-03-20 13:02:32 -0500355 this->addDrawCommand(new ClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
Mike Klein8f4e2242019-03-20 11:59:00 -0500356}
357
358void DebugCanvas::onClipRegion(const SkRegion& region, SkClipOp op) {
Mike Klein17428132019-03-20 13:02:32 -0500359 this->addDrawCommand(new ClipRegionCommand(region, op));
Mike Klein8f4e2242019-03-20 11:59:00 -0500360}
361
Mike Reed121c2af2020-03-10 14:02:56 -0400362void DebugCanvas::onClipShader(sk_sp<SkShader> cs, SkClipOp op) {
363 this->addDrawCommand(new ClipShaderCommand(std::move(cs), op));
364}
365
Mike Reed7d45a7a2020-04-18 10:27:52 -0400366void DebugCanvas::didConcat44(const SkM44& m) {
Nathaniel Nifong642a10b2020-08-20 12:33:46 -0400367 this->addDrawCommand(new Concat44Command(m));
Mike Reeda3a704a2020-01-10 17:21:40 -0500368 this->INHERITED::didConcat44(m);
369}
370
371void DebugCanvas::didScale(SkScalar x, SkScalar y) {
Mike Reed420a9ba2020-11-25 13:37:30 -0500372#ifdef SK_SUPPORT_LEGACY_CANVASMATRIX33
Mike Reed1f607332020-05-21 12:11:27 -0400373 this->didConcat(SkMatrix::Scale(x, y));
Mike Reed420a9ba2020-11-25 13:37:30 -0500374#else
375 this->didConcat44(SkM44::Scale(x, y));
376#endif
Mike Reeda3a704a2020-01-10 17:21:40 -0500377}
378
379void DebugCanvas::didTranslate(SkScalar x, SkScalar y) {
Mike Reed420a9ba2020-11-25 13:37:30 -0500380#ifdef SK_SUPPORT_LEGACY_CANVASMATRIX33
Mike Reed1f607332020-05-21 12:11:27 -0400381 this->didConcat(SkMatrix::Translate(x, y));
Mike Reed420a9ba2020-11-25 13:37:30 -0500382#else
383 this->didConcat44(SkM44::Translate(x, y));
384#endif
Mike Reeda3a704a2020-01-10 17:21:40 -0500385}
386
Mike Reed420a9ba2020-11-25 13:37:30 -0500387#ifdef SK_SUPPORT_LEGACY_CANVASMATRIX33
Mike Klein8f4e2242019-03-20 11:59:00 -0500388void DebugCanvas::didConcat(const SkMatrix& matrix) {
Mike Klein17428132019-03-20 13:02:32 -0500389 this->addDrawCommand(new ConcatCommand(matrix));
Mike Klein8f4e2242019-03-20 11:59:00 -0500390 this->INHERITED::didConcat(matrix);
391}
Mike Reed420a9ba2020-11-25 13:37:30 -0500392#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500393
394void DebugCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
Nathaniel Nifong20b177a2019-12-12 11:05:10 -0500395 // Parse layer-releated annotations added in SkiaPipeline.cpp and RenderNodeDrawable.cpp
396 // the format of the annotations is <Indicator|RenderNodeId>
397 SkTArray<SkString> tokens;
398 SkStrSplit(key, "|", kStrict_SkStrSplitMode, &tokens);
399 if (tokens.size() == 2) {
400 if (tokens[0].equals(kOffscreenLayerDraw)) {
Nathaniel Nifong642a10b2020-08-20 12:33:46 -0400401 // Indicates that the next drawPicture command contains the SkPicture to render the
402 // node at this id in an offscreen buffer.
Nathaniel Nifong20b177a2019-12-12 11:05:10 -0500403 fnextDrawPictureLayerId = std::stoi(tokens[1].c_str());
404 fnextDrawPictureDirtyRect = rect.roundOut();
405 return; // don't record it
406 } else if (tokens[0].equals(kSurfaceID)) {
407 // Indicates that the following drawImageRect should draw the offscreen buffer.
408 fnextDrawImageRectLayerId = std::stoi(tokens[1].c_str());
409 return; // don't record it
410 }
411 }
Nathaniel Nifong12b2c272020-01-10 14:38:00 -0500412 if (strcmp(kAndroidClip, key) == 0) {
413 // Store this frame's android device clip restriction for visualization later.
414 // This annotation stands in place of the androidFramework_setDeviceClipRestriction
415 // which is unrecordable.
416 fAndroidClip = rect;
417 }
Mike Klein17428132019-03-20 13:02:32 -0500418 this->addDrawCommand(new DrawAnnotationCommand(rect, key, sk_ref_sp(value)));
Mike Klein8f4e2242019-03-20 11:59:00 -0500419}
420
Mike Klein8f4e2242019-03-20 11:59:00 -0500421void DebugCanvas::onDrawImage(const SkImage* image,
422 SkScalar left,
423 SkScalar top,
424 const SkPaint* paint) {
Mike Klein17428132019-03-20 13:02:32 -0500425 this->addDrawCommand(new DrawImageCommand(image, left, top, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500426}
427
428void DebugCanvas::onDrawImageLattice(const SkImage* image,
429 const Lattice& lattice,
430 const SkRect& dst,
431 const SkPaint* paint) {
Mike Klein17428132019-03-20 13:02:32 -0500432 this->addDrawCommand(new DrawImageLatticeCommand(image, lattice, dst, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500433}
434
435void DebugCanvas::onDrawImageRect(const SkImage* image,
436 const SkRect* src,
437 const SkRect& dst,
438 const SkPaint* paint,
439 SrcRectConstraint constraint) {
Nathaniel Nifong20b177a2019-12-12 11:05:10 -0500440 if (fnextDrawImageRectLayerId != -1 && fLayerManager) {
441 // This drawImageRect command would have drawn the offscreen buffer for a layer.
442 // On Android, we recorded an SkPicture of the commands that drew to the layer.
443 // To render the layer as it would have looked on the frame this DebugCanvas draws, we need
444 // to call fLayerManager->getLayerAsImage(id). This must be done just before
445 // drawTo(command), since it depends on the index into the layer's commands
446 // (managed by fLayerManager)
447 // Instead of adding a DrawImageRectCommand, we need a deferred command, that when
448 // executed, will call drawImageRect(fLayerManager->getLayerAsImage())
449 this->addDrawCommand(new DrawImageRectLayerCommand(
450 fLayerManager, fnextDrawImageRectLayerId, fFrame, src, dst, paint, constraint));
451 } else {
452 this->addDrawCommand(new DrawImageRectCommand(image, src, dst, paint, constraint));
453 }
454 // Reset expectation so next drawImageRect is not special.
455 fnextDrawImageRectLayerId = -1;
Mike Klein8f4e2242019-03-20 11:59:00 -0500456}
457
458void DebugCanvas::onDrawImageNine(const SkImage* image,
459 const SkIRect& center,
460 const SkRect& dst,
461 const SkPaint* paint) {
Mike Klein17428132019-03-20 13:02:32 -0500462 this->addDrawCommand(new DrawImageNineCommand(image, center, dst, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500463}
464
465void DebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500466 this->addDrawCommand(new DrawOvalCommand(oval, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500467}
468
469void DebugCanvas::onDrawArc(const SkRect& oval,
470 SkScalar startAngle,
471 SkScalar sweepAngle,
472 bool useCenter,
473 const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500474 this->addDrawCommand(new DrawArcCommand(oval, startAngle, sweepAngle, useCenter, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500475}
476
477void DebugCanvas::onDrawPaint(const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500478 this->addDrawCommand(new DrawPaintCommand(paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500479}
480
Mike Reedd5674082019-04-19 15:00:47 -0400481void DebugCanvas::onDrawBehind(const SkPaint& paint) {
482 this->addDrawCommand(new DrawBehindCommand(paint));
483}
484
Mike Klein8f4e2242019-03-20 11:59:00 -0500485void DebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500486 this->addDrawCommand(new DrawPathCommand(path, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500487}
488
489void DebugCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500490 this->addDrawCommand(new DrawRegionCommand(region, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500491}
492
493void DebugCanvas::onDrawPicture(const SkPicture* picture,
494 const SkMatrix* matrix,
495 const SkPaint* paint) {
Nathaniel Nifong20b177a2019-12-12 11:05:10 -0500496 if (fnextDrawPictureLayerId != -1 && fLayerManager) {
497 fLayerManager->storeSkPicture(fnextDrawPictureLayerId, fFrame, sk_ref_sp(picture),
498 fnextDrawPictureDirtyRect);
499 } else {
500 this->addDrawCommand(new BeginDrawPictureCommand(picture, matrix, paint));
501 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
502 picture->playback(this);
503 this->addDrawCommand(new EndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
504 }
505 fnextDrawPictureLayerId = -1;
Mike Klein8f4e2242019-03-20 11:59:00 -0500506}
507
508void DebugCanvas::onDrawPoints(PointMode mode,
509 size_t count,
510 const SkPoint pts[],
511 const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500512 this->addDrawCommand(new DrawPointsCommand(mode, count, pts, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500513}
514
515void DebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
516 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
Mike Klein17428132019-03-20 13:02:32 -0500517 addDrawCommand(new DrawRectCommand(rect, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500518}
519
520void DebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500521 this->addDrawCommand(new DrawRRectCommand(rrect, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500522}
523
524void DebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500525 this->addDrawCommand(new DrawDRRectCommand(outer, inner, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500526}
527
528void DebugCanvas::onDrawTextBlob(const SkTextBlob* blob,
529 SkScalar x,
530 SkScalar y,
531 const SkPaint& paint) {
532 this->addDrawCommand(
Mike Klein17428132019-03-20 13:02:32 -0500533 new DrawTextBlobCommand(sk_ref_sp(const_cast<SkTextBlob*>(blob)), x, y, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500534}
535
536void DebugCanvas::onDrawPatch(const SkPoint cubics[12],
537 const SkColor colors[4],
538 const SkPoint texCoords[4],
539 SkBlendMode bmode,
540 const SkPaint& paint) {
Mike Klein17428132019-03-20 13:02:32 -0500541 this->addDrawCommand(new DrawPatchCommand(cubics, colors, texCoords, bmode, paint));
Mike Klein8f4e2242019-03-20 11:59:00 -0500542}
543
Mike Reeda2cf8ae2020-03-02 17:08:01 -0500544void DebugCanvas::onDrawVerticesObject(const SkVertices* vertices,
545 SkBlendMode bmode,
546 const SkPaint& paint) {
547 this->addDrawCommand(
548 new DrawVerticesCommand(sk_ref_sp(const_cast<SkVertices*>(vertices)), bmode, paint));
549}
Mike Klein8f4e2242019-03-20 11:59:00 -0500550
551void DebugCanvas::onDrawAtlas(const SkImage* image,
552 const SkRSXform xform[],
553 const SkRect tex[],
554 const SkColor colors[],
555 int count,
556 SkBlendMode bmode,
557 const SkRect* cull,
558 const SkPaint* paint) {
559 this->addDrawCommand(
Mike Klein17428132019-03-20 13:02:32 -0500560 new DrawAtlasCommand(image, xform, tex, colors, count, bmode, 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
579void DebugCanvas::onDrawEdgeAAImageSet(const ImageSetEntry set[],
580 int count,
581 const SkPoint dstClips[],
582 const SkMatrix preViewMatrices[],
583 const SkPaint* paint,
584 SrcRectConstraint constraint) {
Mike Klein17428132019-03-20 13:02:32 -0500585 this->addDrawCommand(new DrawEdgeAAImageSetCommand(
Mike Klein8f4e2242019-03-20 11:59:00 -0500586 set, count, dstClips, preViewMatrices, paint, constraint));
587}
588
589void DebugCanvas::willRestore() {
Mike Klein17428132019-03-20 13:02:32 -0500590 this->addDrawCommand(new RestoreCommand());
Mike Klein8f4e2242019-03-20 11:59:00 -0500591 this->INHERITED::willRestore();
592}
593
594void DebugCanvas::willSave() {
Mike Klein17428132019-03-20 13:02:32 -0500595 this->addDrawCommand(new SaveCommand());
Mike Klein8f4e2242019-03-20 11:59:00 -0500596 this->INHERITED::willSave();
597}
598
599SkCanvas::SaveLayerStrategy DebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
Mike Klein17428132019-03-20 13:02:32 -0500600 this->addDrawCommand(new SaveLayerCommand(rec));
Mike Klein8f4e2242019-03-20 11:59:00 -0500601 (void)this->INHERITED::getSaveLayerStrategy(rec);
602 // No need for a full layer.
603 return kNoLayer_SaveLayerStrategy;
604}
605
606bool DebugCanvas::onDoSaveBehind(const SkRect* subset) {
607 // TODO
608 return false;
609}
610
Mike Reed420a9ba2020-11-25 13:37:30 -0500611void DebugCanvas::didSetM44(const SkM44& matrix) {
612 this->addDrawCommand(new SetM44Command(matrix));
613 this->INHERITED::didSetM44(matrix);
614}
615
616#ifdef SK_SUPPORT_LEGACY_CANVASMATRIX33
Mike Klein8f4e2242019-03-20 11:59:00 -0500617void DebugCanvas::didSetMatrix(const SkMatrix& matrix) {
Mike Klein17428132019-03-20 13:02:32 -0500618 this->addDrawCommand(new SetMatrixCommand(matrix));
Mike Klein8f4e2242019-03-20 11:59:00 -0500619 this->INHERITED::didSetMatrix(matrix);
620}
Mike Reed420a9ba2020-11-25 13:37:30 -0500621#endif
Mike Klein8f4e2242019-03-20 11:59:00 -0500622
623void DebugCanvas::toggleCommand(int index, bool toggle) {
624 SkASSERT(index < fCommandVector.count());
625 fCommandVector[index]->setVisible(toggle);
626}
Nathaniel Nifong0b448da2020-09-16 10:35:22 -0400627
628std::map<int, std::vector<int>> DebugCanvas::getImageIdToCommandMap(UrlDataManager& udm) const {
629 // map from image ids to list of commands that reference them.
630 std::map<int, std::vector<int>> m;
631
632 for (int i = 0; i < this->getSize(); i++) {
633 const DrawCommand* command = this->getDrawCommandAt(i);
634 int imageIndex = -1;
635 // this is not an exaustive list of where images can be used, they show up in paints too.
636 switch (command->getOpType()) {
637 case DrawCommand::OpType::kDrawImage_OpType: {
638 imageIndex = static_cast<const DrawImageCommand*>(command)->imageId(udm);
639 break;
640 }
641 case DrawCommand::OpType::kDrawImageRect_OpType: {
642 imageIndex = static_cast<const DrawImageRectCommand*>(command)->imageId(udm);
643 break;
644 }
645 case DrawCommand::OpType::kDrawImageNine_OpType: {
646 imageIndex = static_cast<const DrawImageNineCommand*>(command)->imageId(udm);
647 break;
648 }
649 case DrawCommand::OpType::kDrawImageLattice_OpType: {
650 imageIndex = static_cast<const DrawImageLatticeCommand*>(command)->imageId(udm);
651 break;
652 }
653 default: break;
654 }
655 if (imageIndex >= 0) {
656 m[imageIndex].push_back(i);
657 }
658 }
659 return m;
660}