Coverage Report

Created: 2024-05-20 07:14

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