xref: /aosp_15_r20/external/skia/tools/MSKPPlayer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "tools/MSKPPlayer.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvasVirtualEnforcer.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/docs/SkMultiPictureDocument.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkNoDrawCanvas.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTLazy.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCanvasPriv.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStringUtils.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "tools/SkSharingProc.h"
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker // Base Cmd struct.
29*c8dee2aaSAndroid Build Coastguard Worker struct MSKPPlayer::Cmd {
30*c8dee2aaSAndroid Build Coastguard Worker     virtual ~Cmd() = default;
31*c8dee2aaSAndroid Build Coastguard Worker     virtual bool isFullRedraw(SkCanvas*) const = 0;
32*c8dee2aaSAndroid Build Coastguard Worker     virtual void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const = 0;
33*c8dee2aaSAndroid Build Coastguard Worker     // If this command draws another layer, return it's ID. Otherwise, -1.
layerIDMSKPPlayer::Cmd34*c8dee2aaSAndroid Build Coastguard Worker     virtual int layerID() const { return -1; }
35*c8dee2aaSAndroid Build Coastguard Worker };
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker // Draws a SkPicture.
38*c8dee2aaSAndroid Build Coastguard Worker struct MSKPPlayer::PicCmd : Cmd {
39*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPicture> fContent;
40*c8dee2aaSAndroid Build Coastguard Worker     SkIRect fClipRect = SkIRect::MakeEmpty(); // clip for picture (no clip if empty).
41*c8dee2aaSAndroid Build Coastguard Worker 
isFullRedrawMSKPPlayer::PicCmd42*c8dee2aaSAndroid Build Coastguard Worker     bool isFullRedraw(SkCanvas* canvas) const override {
43*c8dee2aaSAndroid Build Coastguard Worker         if (fClipRect.isEmpty()) {
44*c8dee2aaSAndroid Build Coastguard Worker             return false;
45*c8dee2aaSAndroid Build Coastguard Worker         }
46*c8dee2aaSAndroid Build Coastguard Worker         return fClipRect.contains(SkIRect::MakeSize(canvas->getBaseLayerSize()));
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker 
drawMSKPPlayer::PicCmd49*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const override {
50*c8dee2aaSAndroid Build Coastguard Worker         if (!fClipRect.isEmpty()) {
51*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
52*c8dee2aaSAndroid Build Coastguard Worker             canvas->clipIRect(fClipRect);
53*c8dee2aaSAndroid Build Coastguard Worker         }
54*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPicture(fContent.get());
55*c8dee2aaSAndroid Build Coastguard Worker         if (!fClipRect.isEmpty()) {
56*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
57*c8dee2aaSAndroid Build Coastguard Worker         }
58*c8dee2aaSAndroid Build Coastguard Worker     }
59*c8dee2aaSAndroid Build Coastguard Worker };
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker // Draws another layer. Stores the ID of the layer to draw and what command index on that
62*c8dee2aaSAndroid Build Coastguard Worker // layer should be current when the layer is drawn. The layer contents are updated to the
63*c8dee2aaSAndroid Build Coastguard Worker // stored command index before the layer is drawn.
64*c8dee2aaSAndroid Build Coastguard Worker struct MSKPPlayer::DrawLayerCmd : Cmd {
65*c8dee2aaSAndroid Build Coastguard Worker     int                         fLayerId;
66*c8dee2aaSAndroid Build Coastguard Worker     size_t                      fLayerCmdCnt;
67*c8dee2aaSAndroid Build Coastguard Worker     SkRect                      fSrcRect;
68*c8dee2aaSAndroid Build Coastguard Worker     SkRect                      fDstRect;
69*c8dee2aaSAndroid Build Coastguard Worker     SkSamplingOptions           fSampling;
70*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas::SrcRectConstraint fConstraint;
71*c8dee2aaSAndroid Build Coastguard Worker     SkTLazy<SkPaint>            fPaint;
72*c8dee2aaSAndroid Build Coastguard Worker 
isFullRedrawMSKPPlayer::DrawLayerCmd73*c8dee2aaSAndroid Build Coastguard Worker     bool isFullRedraw(SkCanvas* canvas) const override { return false; }
74*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const override;
layerIDMSKPPlayer::DrawLayerCmd75*c8dee2aaSAndroid Build Coastguard Worker     int layerID() const override { return fLayerId; }
76*c8dee2aaSAndroid Build Coastguard Worker };
77*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas,const LayerMap & layerMap,LayerStateMap * layerStateMap) const78*c8dee2aaSAndroid Build Coastguard Worker void MSKPPlayer::DrawLayerCmd::draw(SkCanvas* canvas,
79*c8dee2aaSAndroid Build Coastguard Worker                                     const LayerMap& layerMap,
80*c8dee2aaSAndroid Build Coastguard Worker                                     LayerStateMap* layerStateMap) const {
81*c8dee2aaSAndroid Build Coastguard Worker     const LayerCmds& layer = layerMap.at(fLayerId);
82*c8dee2aaSAndroid Build Coastguard Worker     LayerState* layerState = &(*layerStateMap)[fLayerId];
83*c8dee2aaSAndroid Build Coastguard Worker     if (!layerState->fSurface) {
84*c8dee2aaSAndroid Build Coastguard Worker         layerState->fCurrCmd = 0;
85*c8dee2aaSAndroid Build Coastguard Worker         layerState->fSurface = MSKPPlayer::MakeSurfaceForLayer(layer, canvas);
86*c8dee2aaSAndroid Build Coastguard Worker         if (!layerState->fSurface) {
87*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Couldn't create surface for layer");
88*c8dee2aaSAndroid Build Coastguard Worker             return;
89*c8dee2aaSAndroid Build Coastguard Worker         }
90*c8dee2aaSAndroid Build Coastguard Worker     }
91*c8dee2aaSAndroid Build Coastguard Worker     size_t cmd = layerState->fCurrCmd;
92*c8dee2aaSAndroid Build Coastguard Worker     if (cmd > fLayerCmdCnt) {
93*c8dee2aaSAndroid Build Coastguard Worker         // If the layer contains contents from later commands then replay from the beginning.
94*c8dee2aaSAndroid Build Coastguard Worker         cmd = 0;
95*c8dee2aaSAndroid Build Coastguard Worker     }
96*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* layerCanvas = layerState->fSurface->getCanvas();
97*c8dee2aaSAndroid Build Coastguard Worker     // Check if there is a full redraw between cmd and fLayerCmdCnt and if so jump to it and ensure
98*c8dee2aaSAndroid Build Coastguard Worker     // we clear the canvas if starting from a full redraw.
99*c8dee2aaSAndroid Build Coastguard Worker     for (size_t checkCmd = fLayerCmdCnt - 1; checkCmd > cmd; --checkCmd) {
100*c8dee2aaSAndroid Build Coastguard Worker         if (layer.fCmds[checkCmd]->isFullRedraw(layerCanvas)) {
101*c8dee2aaSAndroid Build Coastguard Worker             cmd = checkCmd;
102*c8dee2aaSAndroid Build Coastguard Worker             break;
103*c8dee2aaSAndroid Build Coastguard Worker         }
104*c8dee2aaSAndroid Build Coastguard Worker     }
105*c8dee2aaSAndroid Build Coastguard Worker     for (; cmd < fLayerCmdCnt; ++cmd) {
106*c8dee2aaSAndroid Build Coastguard Worker         if (cmd == 0 || layer.fCmds[cmd]->isFullRedraw(layerCanvas)) {
107*c8dee2aaSAndroid Build Coastguard Worker             layerState->fSurface->getCanvas()->clear(SK_ColorTRANSPARENT);
108*c8dee2aaSAndroid Build Coastguard Worker         }
109*c8dee2aaSAndroid Build Coastguard Worker         layer.fCmds[cmd]->draw(layerCanvas, layerMap, layerStateMap);
110*c8dee2aaSAndroid Build Coastguard Worker     }
111*c8dee2aaSAndroid Build Coastguard Worker     layerState->fCurrCmd = fLayerCmdCnt;
112*c8dee2aaSAndroid Build Coastguard Worker     const SkPaint* paint = fPaint.isValid() ? fPaint.get() : nullptr;
113*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawImageRect(layerState->fSurface->makeImageSnapshot(),
114*c8dee2aaSAndroid Build Coastguard Worker                           fSrcRect,
115*c8dee2aaSAndroid Build Coastguard Worker                           fDstRect,
116*c8dee2aaSAndroid Build Coastguard Worker                           fSampling,
117*c8dee2aaSAndroid Build Coastguard Worker                           paint,
118*c8dee2aaSAndroid Build Coastguard Worker                           fConstraint);
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker class MSKPPlayer::CmdRecordCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
124*c8dee2aaSAndroid Build Coastguard Worker public:
CmdRecordCanvas(LayerCmds * dst,LayerMap * offscreenLayers,const SkIRect * clipRect=nullptr)125*c8dee2aaSAndroid Build Coastguard Worker     CmdRecordCanvas(LayerCmds* dst, LayerMap* offscreenLayers, const SkIRect* clipRect = nullptr)
126*c8dee2aaSAndroid Build Coastguard Worker             : fDst(dst), fOffscreenLayers(offscreenLayers) {
127*c8dee2aaSAndroid Build Coastguard Worker         if (clipRect) {
128*c8dee2aaSAndroid Build Coastguard Worker             fClipRect = *clipRect;
129*c8dee2aaSAndroid Build Coastguard Worker         }
130*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.beginRecording(SkRect::Make(dst->fDimensions));
131*c8dee2aaSAndroid Build Coastguard Worker     }
~CmdRecordCanvas()132*c8dee2aaSAndroid Build Coastguard Worker     ~CmdRecordCanvas() override { this->recordPicCmd(); }
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker protected:
onDrawPaint(const SkPaint & paint)135*c8dee2aaSAndroid Build Coastguard Worker     void onDrawPaint(const SkPaint& paint) override {
136*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawPaint(paint);
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
onDrawBehind(const SkPaint & paint)139*c8dee2aaSAndroid Build Coastguard Worker     void onDrawBehind(const SkPaint& paint) override {
140*c8dee2aaSAndroid Build Coastguard Worker         SkCanvasPriv::DrawBehind(fRecorder.getRecordingCanvas(), paint);
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker 
onDrawRect(const SkRect & rect,const SkPaint & paint)143*c8dee2aaSAndroid Build Coastguard Worker     void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
144*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawRect(rect, paint);
145*c8dee2aaSAndroid Build Coastguard Worker     }
146*c8dee2aaSAndroid Build Coastguard Worker 
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)147*c8dee2aaSAndroid Build Coastguard Worker     void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
148*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawRRect(rrect, paint);
149*c8dee2aaSAndroid Build Coastguard Worker     }
150*c8dee2aaSAndroid Build Coastguard Worker 
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)151*c8dee2aaSAndroid Build Coastguard Worker     void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
152*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawDRRect(outer, inner, paint);
153*c8dee2aaSAndroid Build Coastguard Worker     }
154*c8dee2aaSAndroid Build Coastguard Worker 
onDrawOval(const SkRect & rect,const SkPaint & paint)155*c8dee2aaSAndroid Build Coastguard Worker     void onDrawOval(const SkRect& rect, const SkPaint& paint) override {
156*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawOval(rect, paint);
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker 
onDrawArc(const SkRect & rect,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)159*c8dee2aaSAndroid Build Coastguard Worker     void onDrawArc(const SkRect& rect,
160*c8dee2aaSAndroid Build Coastguard Worker                    SkScalar startAngle,
161*c8dee2aaSAndroid Build Coastguard Worker                    SkScalar sweepAngle,
162*c8dee2aaSAndroid Build Coastguard Worker                    bool useCenter,
163*c8dee2aaSAndroid Build Coastguard Worker                    const SkPaint& paint) override {
164*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawArc(rect, startAngle, sweepAngle, useCenter, paint);
165*c8dee2aaSAndroid Build Coastguard Worker     }
166*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPath(const SkPath & path,const SkPaint & paint)167*c8dee2aaSAndroid Build Coastguard Worker     void onDrawPath(const SkPath& path, const SkPaint& paint) override {
168*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawPath(path, paint);
169*c8dee2aaSAndroid Build Coastguard Worker     }
170*c8dee2aaSAndroid Build Coastguard Worker 
onDrawRegion(const SkRegion & region,const SkPaint & paint)171*c8dee2aaSAndroid Build Coastguard Worker     void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
172*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawRegion(region, paint);
173*c8dee2aaSAndroid Build Coastguard Worker     }
174*c8dee2aaSAndroid Build Coastguard Worker 
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)175*c8dee2aaSAndroid Build Coastguard Worker     void onDrawTextBlob(const SkTextBlob* blob,
176*c8dee2aaSAndroid Build Coastguard Worker                         SkScalar x,
177*c8dee2aaSAndroid Build Coastguard Worker                         SkScalar y,
178*c8dee2aaSAndroid Build Coastguard Worker                         const SkPaint& paint) override {
179*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawTextBlob(blob, x, y, paint);
180*c8dee2aaSAndroid Build Coastguard Worker     }
181*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode mode,const SkPaint & paint)182*c8dee2aaSAndroid Build Coastguard Worker     void onDrawPatch(const SkPoint cubics[12],
183*c8dee2aaSAndroid Build Coastguard Worker                      const SkColor colors[4],
184*c8dee2aaSAndroid Build Coastguard Worker                      const SkPoint texCoords[4],
185*c8dee2aaSAndroid Build Coastguard Worker                      SkBlendMode mode,
186*c8dee2aaSAndroid Build Coastguard Worker                      const SkPaint& paint) override {
187*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawPatch(cubics, colors, texCoords, mode, paint);
188*c8dee2aaSAndroid Build Coastguard Worker     }
189*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)190*c8dee2aaSAndroid Build Coastguard Worker     void onDrawPoints(SkCanvas::PointMode mode,
191*c8dee2aaSAndroid Build Coastguard Worker                       size_t count,
192*c8dee2aaSAndroid Build Coastguard Worker                       const SkPoint pts[],
193*c8dee2aaSAndroid Build Coastguard Worker                       const SkPaint& paint) override {
194*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawPoints(mode, count, pts, paint);
195*c8dee2aaSAndroid Build Coastguard Worker     }
196*c8dee2aaSAndroid Build Coastguard Worker 
onDrawImage2(const SkImage * image,SkScalar dx,SkScalar dy,const SkSamplingOptions & sampling,const SkPaint * paint)197*c8dee2aaSAndroid Build Coastguard Worker     void onDrawImage2(const SkImage* image,
198*c8dee2aaSAndroid Build Coastguard Worker                       SkScalar dx,
199*c8dee2aaSAndroid Build Coastguard Worker                       SkScalar dy,
200*c8dee2aaSAndroid Build Coastguard Worker                       const SkSamplingOptions& sampling,
201*c8dee2aaSAndroid Build Coastguard Worker                       const SkPaint* paint) override {
202*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawImage(image, dx, dy, sampling, paint);
203*c8dee2aaSAndroid Build Coastguard Worker     }
204*c8dee2aaSAndroid Build Coastguard Worker 
onDrawImageRect2(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)205*c8dee2aaSAndroid Build Coastguard Worker     void onDrawImageRect2(const SkImage* image,
206*c8dee2aaSAndroid Build Coastguard Worker                           const SkRect& src,
207*c8dee2aaSAndroid Build Coastguard Worker                           const SkRect& dst,
208*c8dee2aaSAndroid Build Coastguard Worker                           const SkSamplingOptions& sampling,
209*c8dee2aaSAndroid Build Coastguard Worker                           const SkPaint* paint,
210*c8dee2aaSAndroid Build Coastguard Worker                           SrcRectConstraint constraint) override {
211*c8dee2aaSAndroid Build Coastguard Worker         if (fNextDrawImageFromLayerID != -1) {
212*c8dee2aaSAndroid Build Coastguard Worker             this->recordPicCmd();
213*c8dee2aaSAndroid Build Coastguard Worker             auto drawLayer = std::make_unique<DrawLayerCmd>();
214*c8dee2aaSAndroid Build Coastguard Worker             drawLayer->fLayerId = fNextDrawImageFromLayerID;
215*c8dee2aaSAndroid Build Coastguard Worker             drawLayer->fLayerCmdCnt = fOffscreenLayers->at(fNextDrawImageFromLayerID).fCmds.size();
216*c8dee2aaSAndroid Build Coastguard Worker             drawLayer->fSrcRect = src;
217*c8dee2aaSAndroid Build Coastguard Worker             drawLayer->fDstRect = dst;
218*c8dee2aaSAndroid Build Coastguard Worker             drawLayer->fSampling = sampling;
219*c8dee2aaSAndroid Build Coastguard Worker             drawLayer->fConstraint = constraint;
220*c8dee2aaSAndroid Build Coastguard Worker             if (paint) {
221*c8dee2aaSAndroid Build Coastguard Worker                 drawLayer->fPaint.init(*paint);
222*c8dee2aaSAndroid Build Coastguard Worker             }
223*c8dee2aaSAndroid Build Coastguard Worker             fDst->fCmds.push_back(std::move(drawLayer));
224*c8dee2aaSAndroid Build Coastguard Worker             fNextDrawImageFromLayerID = -1;
225*c8dee2aaSAndroid Build Coastguard Worker             return;
226*c8dee2aaSAndroid Build Coastguard Worker         }
227*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawImageRect(image, src, dst, sampling, paint, constraint);
228*c8dee2aaSAndroid Build Coastguard Worker     }
229*c8dee2aaSAndroid Build Coastguard Worker 
onDrawImageLattice2(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode mode,const SkPaint * paint)230*c8dee2aaSAndroid Build Coastguard Worker     void onDrawImageLattice2(const SkImage* image,
231*c8dee2aaSAndroid Build Coastguard Worker                              const Lattice& lattice,
232*c8dee2aaSAndroid Build Coastguard Worker                              const SkRect& dst,
233*c8dee2aaSAndroid Build Coastguard Worker                              SkFilterMode mode,
234*c8dee2aaSAndroid Build Coastguard Worker                              const SkPaint* paint) override {
235*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawImageLattice(image, lattice, dst, mode, paint);
236*c8dee2aaSAndroid Build Coastguard Worker     }
237*c8dee2aaSAndroid Build Coastguard Worker 
onDrawAtlas2(const SkImage * image,const SkRSXform rsxForms[],const SkRect src[],const SkColor colors[],int count,SkBlendMode mode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)238*c8dee2aaSAndroid Build Coastguard Worker     void onDrawAtlas2(const SkImage* image,
239*c8dee2aaSAndroid Build Coastguard Worker                       const SkRSXform rsxForms[],
240*c8dee2aaSAndroid Build Coastguard Worker                       const SkRect src[],
241*c8dee2aaSAndroid Build Coastguard Worker                       const SkColor colors[],
242*c8dee2aaSAndroid Build Coastguard Worker                       int count,
243*c8dee2aaSAndroid Build Coastguard Worker                       SkBlendMode mode,
244*c8dee2aaSAndroid Build Coastguard Worker                       const SkSamplingOptions& sampling,
245*c8dee2aaSAndroid Build Coastguard Worker                       const SkRect* cull,
246*c8dee2aaSAndroid Build Coastguard Worker                       const SkPaint* paint) override {
247*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawAtlas(image,
248*c8dee2aaSAndroid Build Coastguard Worker                                                   rsxForms,
249*c8dee2aaSAndroid Build Coastguard Worker                                                   src,
250*c8dee2aaSAndroid Build Coastguard Worker                                                   colors,
251*c8dee2aaSAndroid Build Coastguard Worker                                                   count,
252*c8dee2aaSAndroid Build Coastguard Worker                                                   mode,
253*c8dee2aaSAndroid Build Coastguard Worker                                                   sampling,
254*c8dee2aaSAndroid Build Coastguard Worker                                                   cull,
255*c8dee2aaSAndroid Build Coastguard Worker                                                   paint);
256*c8dee2aaSAndroid Build Coastguard Worker     }
257*c8dee2aaSAndroid Build Coastguard Worker 
onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)258*c8dee2aaSAndroid Build Coastguard Worker     void onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[],
259*c8dee2aaSAndroid Build Coastguard Worker                                int count,
260*c8dee2aaSAndroid Build Coastguard Worker                                const SkPoint dstClips[],
261*c8dee2aaSAndroid Build Coastguard Worker                                const SkMatrix preViewMatrices[],
262*c8dee2aaSAndroid Build Coastguard Worker                                const SkSamplingOptions& sampling,
263*c8dee2aaSAndroid Build Coastguard Worker                                const SkPaint* paint,
264*c8dee2aaSAndroid Build Coastguard Worker                                SrcRectConstraint constraint) override {
265*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->experimental_DrawEdgeAAImageSet(imageSet,
266*c8dee2aaSAndroid Build Coastguard Worker                                                                         count,
267*c8dee2aaSAndroid Build Coastguard Worker                                                                         dstClips,
268*c8dee2aaSAndroid Build Coastguard Worker                                                                         preViewMatrices,
269*c8dee2aaSAndroid Build Coastguard Worker                                                                         sampling,
270*c8dee2aaSAndroid Build Coastguard Worker                                                                         paint,
271*c8dee2aaSAndroid Build Coastguard Worker                                                                         constraint);
272*c8dee2aaSAndroid Build Coastguard Worker     }
273*c8dee2aaSAndroid Build Coastguard Worker 
274*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
onDrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)275*c8dee2aaSAndroid Build Coastguard Worker     void onDrawEdgeAAQuad(const SkRect& rect,
276*c8dee2aaSAndroid Build Coastguard Worker                           const SkPoint clip[4],
277*c8dee2aaSAndroid Build Coastguard Worker                           SkCanvas::QuadAAFlags aaFlags,
278*c8dee2aaSAndroid Build Coastguard Worker                           const SkColor4f& color,
279*c8dee2aaSAndroid Build Coastguard Worker                           SkBlendMode mode) override {}
280*c8dee2aaSAndroid Build Coastguard Worker #else
onDrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aaFlags,const SkColor4f & color,SkBlendMode mode)281*c8dee2aaSAndroid Build Coastguard Worker     void onDrawEdgeAAQuad(const SkRect& rect,
282*c8dee2aaSAndroid Build Coastguard Worker                           const SkPoint clip[4],
283*c8dee2aaSAndroid Build Coastguard Worker                           SkCanvas::QuadAAFlags aaFlags,
284*c8dee2aaSAndroid Build Coastguard Worker                           const SkColor4f& color,
285*c8dee2aaSAndroid Build Coastguard Worker                           SkBlendMode mode) override {
286*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->experimental_DrawEdgeAAQuad(rect,
287*c8dee2aaSAndroid Build Coastguard Worker                                                                     clip,
288*c8dee2aaSAndroid Build Coastguard Worker                                                                     aaFlags,
289*c8dee2aaSAndroid Build Coastguard Worker                                                                     color,
290*c8dee2aaSAndroid Build Coastguard Worker                                                                     mode);
291*c8dee2aaSAndroid Build Coastguard Worker     }
292*c8dee2aaSAndroid Build Coastguard Worker #endif
293*c8dee2aaSAndroid Build Coastguard Worker 
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)294*c8dee2aaSAndroid Build Coastguard Worker     void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override {
295*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kOffscreenLayerDraw[] = "OffscreenLayerDraw";
296*c8dee2aaSAndroid Build Coastguard Worker         static constexpr char kSurfaceID[] = "SurfaceID";
297*c8dee2aaSAndroid Build Coastguard Worker         TArray<SkString> tokens;
298*c8dee2aaSAndroid Build Coastguard Worker         SkStrSplit(key, "|", kStrict_SkStrSplitMode, &tokens);
299*c8dee2aaSAndroid Build Coastguard Worker         if (tokens.size() == 2) {
300*c8dee2aaSAndroid Build Coastguard Worker             if (tokens[0].equals(kOffscreenLayerDraw)) {
301*c8dee2aaSAndroid Build Coastguard Worker                 // Indicates that the next drawPicture command contains the SkPicture to render
302*c8dee2aaSAndroid Build Coastguard Worker                 // to the layer identified by the ID. 'rect' indicates the dirty area to update
303*c8dee2aaSAndroid Build Coastguard Worker                 // (and indicates the layer size if this command is introducing a new layer id).
304*c8dee2aaSAndroid Build Coastguard Worker                 fNextDrawPictureToLayerID = std::stoi(tokens[1].c_str());
305*c8dee2aaSAndroid Build Coastguard Worker                 fNextDrawPictureToLayerClipRect = rect.roundOut();
306*c8dee2aaSAndroid Build Coastguard Worker                 if (fOffscreenLayers->find(fNextDrawPictureToLayerID) == fOffscreenLayers->end()) {
307*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(fNextDrawPictureToLayerClipRect.left() == 0 &&
308*c8dee2aaSAndroid Build Coastguard Worker                              fNextDrawPictureToLayerClipRect.top()  == 0);
309*c8dee2aaSAndroid Build Coastguard Worker                     (*fOffscreenLayers)[fNextDrawPictureToLayerID].fDimensions =
310*c8dee2aaSAndroid Build Coastguard Worker                             fNextDrawPictureToLayerClipRect.size();
311*c8dee2aaSAndroid Build Coastguard Worker                 }
312*c8dee2aaSAndroid Build Coastguard Worker                 // The next draw picture will notice that fNextDrawPictureToLayerID is set and
313*c8dee2aaSAndroid Build Coastguard Worker                 // redirect the picture to the offscreen layer.
314*c8dee2aaSAndroid Build Coastguard Worker                 return;
315*c8dee2aaSAndroid Build Coastguard Worker             } else if (tokens[0].equals(kSurfaceID)) {
316*c8dee2aaSAndroid Build Coastguard Worker                 // Indicates that the following drawImageRect should draw an offscreen layer
317*c8dee2aaSAndroid Build Coastguard Worker                 // to this layer.
318*c8dee2aaSAndroid Build Coastguard Worker                 fNextDrawImageFromLayerID = std::stoi(tokens[1].c_str());
319*c8dee2aaSAndroid Build Coastguard Worker                 return;
320*c8dee2aaSAndroid Build Coastguard Worker             }
321*c8dee2aaSAndroid Build Coastguard Worker         }
322*c8dee2aaSAndroid Build Coastguard Worker     }
323*c8dee2aaSAndroid Build Coastguard Worker 
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)324*c8dee2aaSAndroid Build Coastguard Worker     void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override {
325*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->private_draw_shadow_rec(path, rec);
326*c8dee2aaSAndroid Build Coastguard Worker     }
327*c8dee2aaSAndroid Build Coastguard Worker 
onDrawDrawable(SkDrawable * drawable,const SkMatrix * matrix)328*c8dee2aaSAndroid Build Coastguard Worker     void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
329*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.getRecordingCanvas()->drawDrawable(drawable, matrix);
330*c8dee2aaSAndroid Build Coastguard Worker     }
331*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)332*c8dee2aaSAndroid Build Coastguard Worker     void onDrawPicture(const SkPicture* picture,
333*c8dee2aaSAndroid Build Coastguard Worker                        const SkMatrix* matrix,
334*c8dee2aaSAndroid Build Coastguard Worker                        const SkPaint* paint) override {
335*c8dee2aaSAndroid Build Coastguard Worker         if (fNextDrawPictureToLayerID != -1) {
336*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!matrix);
337*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!paint);
338*c8dee2aaSAndroid Build Coastguard Worker             LayerCmds* layer = &fOffscreenLayers->at(fNextDrawPictureToLayerID);
339*c8dee2aaSAndroid Build Coastguard Worker             CmdRecordCanvas sc(layer, fOffscreenLayers, &fNextDrawPictureToLayerClipRect);
340*c8dee2aaSAndroid Build Coastguard Worker             picture->playback(&sc);
341*c8dee2aaSAndroid Build Coastguard Worker             fNextDrawPictureToLayerID = -1;
342*c8dee2aaSAndroid Build Coastguard Worker             fNextDrawPictureToLayerClipRect = SkIRect::MakeEmpty();
343*c8dee2aaSAndroid Build Coastguard Worker             return;
344*c8dee2aaSAndroid Build Coastguard Worker         }
345*c8dee2aaSAndroid Build Coastguard Worker         if (paint) {
346*c8dee2aaSAndroid Build Coastguard Worker             this->saveLayer(nullptr, paint);
347*c8dee2aaSAndroid Build Coastguard Worker         }
348*c8dee2aaSAndroid Build Coastguard Worker         if (matrix) {
349*c8dee2aaSAndroid Build Coastguard Worker             this->save();
350*c8dee2aaSAndroid Build Coastguard Worker             this->concat(*matrix);
351*c8dee2aaSAndroid Build Coastguard Worker         }
352*c8dee2aaSAndroid Build Coastguard Worker 
353*c8dee2aaSAndroid Build Coastguard Worker         picture->playback(this);
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker         if (matrix) {
356*c8dee2aaSAndroid Build Coastguard Worker             this->restore();
357*c8dee2aaSAndroid Build Coastguard Worker         }
358*c8dee2aaSAndroid Build Coastguard Worker         if (paint) {
359*c8dee2aaSAndroid Build Coastguard Worker             this->restore();
360*c8dee2aaSAndroid Build Coastguard Worker         }
361*c8dee2aaSAndroid Build Coastguard Worker     }
362*c8dee2aaSAndroid Build Coastguard Worker 
363*c8dee2aaSAndroid Build Coastguard Worker private:
recordPicCmd()364*c8dee2aaSAndroid Build Coastguard Worker     void recordPicCmd() {
365*c8dee2aaSAndroid Build Coastguard Worker         auto cmd = std::make_unique<PicCmd>();
366*c8dee2aaSAndroid Build Coastguard Worker         cmd->fContent = fRecorder.finishRecordingAsPicture();
367*c8dee2aaSAndroid Build Coastguard Worker         cmd->fClipRect = fClipRect;
368*c8dee2aaSAndroid Build Coastguard Worker         if (cmd->fContent) {
369*c8dee2aaSAndroid Build Coastguard Worker             fDst->fCmds.push_back(std::move(cmd));
370*c8dee2aaSAndroid Build Coastguard Worker         }
371*c8dee2aaSAndroid Build Coastguard Worker         // Set up to accumulate again.
372*c8dee2aaSAndroid Build Coastguard Worker         fRecorder.beginRecording(SkRect::Make(fDst->fDimensions));
373*c8dee2aaSAndroid Build Coastguard Worker     }
374*c8dee2aaSAndroid Build Coastguard Worker 
375*c8dee2aaSAndroid Build Coastguard Worker     SkPictureRecorder fRecorder; // accumulates draws until we draw an offscreen into this layer.
376*c8dee2aaSAndroid Build Coastguard Worker     LayerCmds*        fDst                            = nullptr;
377*c8dee2aaSAndroid Build Coastguard Worker     SkIRect           fClipRect                       = SkIRect::MakeEmpty();
378*c8dee2aaSAndroid Build Coastguard Worker     int               fNextDrawPictureToLayerID       = -1;
379*c8dee2aaSAndroid Build Coastguard Worker     SkIRect           fNextDrawPictureToLayerClipRect = SkIRect::MakeEmpty();
380*c8dee2aaSAndroid Build Coastguard Worker     int               fNextDrawImageFromLayerID       = -1;
381*c8dee2aaSAndroid Build Coastguard Worker     LayerMap*         fOffscreenLayers                = nullptr;
382*c8dee2aaSAndroid Build Coastguard Worker };
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
385*c8dee2aaSAndroid Build Coastguard Worker 
Make(SkStreamSeekable * stream)386*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<MSKPPlayer> MSKPPlayer::Make(SkStreamSeekable* stream) {
387*c8dee2aaSAndroid Build Coastguard Worker     auto deserialContext = std::make_unique<SkSharingDeserialContext>();
388*c8dee2aaSAndroid Build Coastguard Worker     SkDeserialProcs procs;
389*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageProc = SkSharingDeserialContext::deserializeImage;
390*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageCtx = deserialContext.get();
391*c8dee2aaSAndroid Build Coastguard Worker 
392*c8dee2aaSAndroid Build Coastguard Worker     int pageCount = SkMultiPictureDocument::ReadPageCount(stream);
393*c8dee2aaSAndroid Build Coastguard Worker     if (!pageCount) {
394*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
395*c8dee2aaSAndroid Build Coastguard Worker     }
396*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkDocumentPage> pages(pageCount);
397*c8dee2aaSAndroid Build Coastguard Worker     if (!SkMultiPictureDocument::Read(stream, pages.data(), pageCount, &procs)) {
398*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
399*c8dee2aaSAndroid Build Coastguard Worker     }
400*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<MSKPPlayer> result(new MSKPPlayer);
401*c8dee2aaSAndroid Build Coastguard Worker     result->fRootLayers.reserve(pages.size());
402*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& page : pages) {
403*c8dee2aaSAndroid Build Coastguard Worker         SkISize dims = {SkScalarCeilToInt(page.fSize.width()),
404*c8dee2aaSAndroid Build Coastguard Worker                         SkScalarCeilToInt(page.fSize.height())};
405*c8dee2aaSAndroid Build Coastguard Worker         result->fRootLayers.emplace_back();
406*c8dee2aaSAndroid Build Coastguard Worker         result->fRootLayers.back().fDimensions = dims;
407*c8dee2aaSAndroid Build Coastguard Worker         result->fMaxDimensions.fWidth  = std::max(dims.width() , result->fMaxDimensions.width() );
408*c8dee2aaSAndroid Build Coastguard Worker         result->fMaxDimensions.fHeight = std::max(dims.height(), result->fMaxDimensions.height());
409*c8dee2aaSAndroid Build Coastguard Worker         CmdRecordCanvas sc(&result->fRootLayers.back(), &result->fOffscreenLayers);
410*c8dee2aaSAndroid Build Coastguard Worker         page.fPicture->playback(&sc);
411*c8dee2aaSAndroid Build Coastguard Worker     }
412*c8dee2aaSAndroid Build Coastguard Worker     return result;
413*c8dee2aaSAndroid Build Coastguard Worker }
414*c8dee2aaSAndroid Build Coastguard Worker 
415*c8dee2aaSAndroid Build Coastguard Worker MSKPPlayer::~MSKPPlayer() = default;
416*c8dee2aaSAndroid Build Coastguard Worker 
frameDimensions(int i) const417*c8dee2aaSAndroid Build Coastguard Worker SkISize MSKPPlayer::frameDimensions(int i) const {
418*c8dee2aaSAndroid Build Coastguard Worker     if (i < 0 || i >= this->numFrames()) {
419*c8dee2aaSAndroid Build Coastguard Worker         return {-1, -1};
420*c8dee2aaSAndroid Build Coastguard Worker     }
421*c8dee2aaSAndroid Build Coastguard Worker     return fRootLayers[i].fDimensions;
422*c8dee2aaSAndroid Build Coastguard Worker }
423*c8dee2aaSAndroid Build Coastguard Worker 
playFrame(SkCanvas * canvas,int i)424*c8dee2aaSAndroid Build Coastguard Worker bool MSKPPlayer::playFrame(SkCanvas* canvas, int i) {
425*c8dee2aaSAndroid Build Coastguard Worker     if (i < 0 || i >= this->numFrames()) {
426*c8dee2aaSAndroid Build Coastguard Worker         return false;
427*c8dee2aaSAndroid Build Coastguard Worker     }
428*c8dee2aaSAndroid Build Coastguard Worker 
429*c8dee2aaSAndroid Build Coastguard Worker     // Find the first offscreen layer that has a valid surface. If it's recording context
430*c8dee2aaSAndroid Build Coastguard Worker     // differs from the passed canvas's then reset all the layers. Playback will
431*c8dee2aaSAndroid Build Coastguard Worker     // automatically allocate new surfaces for offscreen layers as they're encountered.
432*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& ols : fOffscreenLayerStates) {
433*c8dee2aaSAndroid Build Coastguard Worker         const LayerState& state = ols.second;
434*c8dee2aaSAndroid Build Coastguard Worker         if (state.fSurface) {
435*c8dee2aaSAndroid Build Coastguard Worker             if (state.fSurface->recordingContext() != canvas->recordingContext()) {
436*c8dee2aaSAndroid Build Coastguard Worker                 this->resetLayers();
437*c8dee2aaSAndroid Build Coastguard Worker             }
438*c8dee2aaSAndroid Build Coastguard Worker             break;
439*c8dee2aaSAndroid Build Coastguard Worker         }
440*c8dee2aaSAndroid Build Coastguard Worker     }
441*c8dee2aaSAndroid Build Coastguard Worker 
442*c8dee2aaSAndroid Build Coastguard Worker     // Replay all the commands for this frame to the caller's canvas.
443*c8dee2aaSAndroid Build Coastguard Worker     const LayerCmds& layer = fRootLayers[i];
444*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& cmd : layer.fCmds) {
445*c8dee2aaSAndroid Build Coastguard Worker         cmd->draw(canvas, fOffscreenLayers, &fOffscreenLayerStates);
446*c8dee2aaSAndroid Build Coastguard Worker     }
447*c8dee2aaSAndroid Build Coastguard Worker     return true;
448*c8dee2aaSAndroid Build Coastguard Worker }
449*c8dee2aaSAndroid Build Coastguard Worker 
MakeSurfaceForLayer(const LayerCmds & layer,SkCanvas * rootCanvas)450*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkSurface> MSKPPlayer::MakeSurfaceForLayer(const LayerCmds& layer, SkCanvas* rootCanvas) {
451*c8dee2aaSAndroid Build Coastguard Worker     // Assume layer has same surface props and info as this (mskp doesn't currently record this
452*c8dee2aaSAndroid Build Coastguard Worker     // data).
453*c8dee2aaSAndroid Build Coastguard Worker     SkSurfaceProps props;
454*c8dee2aaSAndroid Build Coastguard Worker     rootCanvas->getProps(&props);
455*c8dee2aaSAndroid Build Coastguard Worker     return rootCanvas->makeSurface(rootCanvas->imageInfo().makeDimensions(layer.fDimensions),
456*c8dee2aaSAndroid Build Coastguard Worker                                    &props);
457*c8dee2aaSAndroid Build Coastguard Worker }
458*c8dee2aaSAndroid Build Coastguard Worker 
resetLayers()459*c8dee2aaSAndroid Build Coastguard Worker void MSKPPlayer::resetLayers() { fOffscreenLayerStates.clear(); }
460*c8dee2aaSAndroid Build Coastguard Worker 
rewindLayers()461*c8dee2aaSAndroid Build Coastguard Worker void MSKPPlayer::rewindLayers() {
462*c8dee2aaSAndroid Build Coastguard Worker     for (auto& [id, state] : fOffscreenLayerStates) {
463*c8dee2aaSAndroid Build Coastguard Worker         state.fCurrCmd = -1;
464*c8dee2aaSAndroid Build Coastguard Worker     }
465*c8dee2aaSAndroid Build Coastguard Worker }
466*c8dee2aaSAndroid Build Coastguard Worker 
allocateLayers(SkCanvas * canvas)467*c8dee2aaSAndroid Build Coastguard Worker void MSKPPlayer::allocateLayers(SkCanvas* canvas) {
468*c8dee2aaSAndroid Build Coastguard Worker     // Iterate over layers not states as states are lazily created in playback but here we want to
469*c8dee2aaSAndroid Build Coastguard Worker     // create any that don't already exist.
470*c8dee2aaSAndroid Build Coastguard Worker     for (auto& [id, layer] : fOffscreenLayers) {
471*c8dee2aaSAndroid Build Coastguard Worker         LayerState& state = fOffscreenLayerStates[id];
472*c8dee2aaSAndroid Build Coastguard Worker         if (!state.fSurface || state.fSurface->recordingContext() != canvas->recordingContext()) {
473*c8dee2aaSAndroid Build Coastguard Worker             state.fCurrCmd = -1;
474*c8dee2aaSAndroid Build Coastguard Worker             state.fSurface = MakeSurfaceForLayer(fOffscreenLayers[id], canvas);
475*c8dee2aaSAndroid Build Coastguard Worker         }
476*c8dee2aaSAndroid Build Coastguard Worker     }
477*c8dee2aaSAndroid Build Coastguard Worker }
478*c8dee2aaSAndroid Build Coastguard Worker 
layerIDs(int frame) const479*c8dee2aaSAndroid Build Coastguard Worker std::vector<int> MSKPPlayer::layerIDs(int frame) const {
480*c8dee2aaSAndroid Build Coastguard Worker     std::vector<int> result;
481*c8dee2aaSAndroid Build Coastguard Worker     if (frame < 0) {
482*c8dee2aaSAndroid Build Coastguard Worker         result.reserve(fOffscreenLayers.size());
483*c8dee2aaSAndroid Build Coastguard Worker         for (auto& [id, _] : fOffscreenLayers) {
484*c8dee2aaSAndroid Build Coastguard Worker             result.push_back(id);
485*c8dee2aaSAndroid Build Coastguard Worker         }
486*c8dee2aaSAndroid Build Coastguard Worker         return result;
487*c8dee2aaSAndroid Build Coastguard Worker     }
488*c8dee2aaSAndroid Build Coastguard Worker     if (frame < static_cast<int>(fRootLayers.size())) {
489*c8dee2aaSAndroid Build Coastguard Worker         this->collectReferencedLayers(fRootLayers[frame], &result);
490*c8dee2aaSAndroid Build Coastguard Worker     }
491*c8dee2aaSAndroid Build Coastguard Worker     return result;
492*c8dee2aaSAndroid Build Coastguard Worker }
493*c8dee2aaSAndroid Build Coastguard Worker 
layerSnapshot(int layerID) const494*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> MSKPPlayer::layerSnapshot(int layerID) const {
495*c8dee2aaSAndroid Build Coastguard Worker     auto iter = fOffscreenLayerStates.find(layerID);
496*c8dee2aaSAndroid Build Coastguard Worker     if (iter == fOffscreenLayerStates.end() || !iter->second.fSurface) {
497*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
498*c8dee2aaSAndroid Build Coastguard Worker     }
499*c8dee2aaSAndroid Build Coastguard Worker     return iter->second.fSurface->makeImageSnapshot();
500*c8dee2aaSAndroid Build Coastguard Worker }
501*c8dee2aaSAndroid Build Coastguard Worker 
collectReferencedLayers(const LayerCmds & layer,std::vector<int> * out) const502*c8dee2aaSAndroid Build Coastguard Worker void MSKPPlayer::collectReferencedLayers(const LayerCmds& layer, std::vector<int>* out) const {
503*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& cmd : layer.fCmds) {
504*c8dee2aaSAndroid Build Coastguard Worker         if (int id = cmd->layerID(); id >= 0) {
505*c8dee2aaSAndroid Build Coastguard Worker             // Linear, but we'd need to have a lot of layers to actually care.
506*c8dee2aaSAndroid Build Coastguard Worker             if (std::find(out->begin(), out->end(), id) == out->end()) {
507*c8dee2aaSAndroid Build Coastguard Worker                 out->push_back(id);
508*c8dee2aaSAndroid Build Coastguard Worker                 auto iter = fOffscreenLayers.find(id);
509*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(iter != fOffscreenLayers.end());
510*c8dee2aaSAndroid Build Coastguard Worker                 this->collectReferencedLayers(iter->second, out);
511*c8dee2aaSAndroid Build Coastguard Worker             }
512*c8dee2aaSAndroid Build Coastguard Worker         }
513*c8dee2aaSAndroid Build Coastguard Worker     }
514*c8dee2aaSAndroid Build Coastguard Worker }
515