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