xref: /aosp_15_r20/external/skia/tools/MSKPPlayer.h (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 #ifndef MSKPPlayer_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define MSKPPlayer_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
15*c8dee2aaSAndroid Build Coastguard Worker #include <unordered_map>
16*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
17*c8dee2aaSAndroid Build Coastguard Worker 
18*c8dee2aaSAndroid Build Coastguard Worker class SkCanvas;
19*c8dee2aaSAndroid Build Coastguard Worker class SkImage;
20*c8dee2aaSAndroid Build Coastguard Worker class SkStreamSeekable;
21*c8dee2aaSAndroid Build Coastguard Worker class SkSurface;
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker /**
24*c8dee2aaSAndroid Build Coastguard Worker  * Plays frames/pages of a MSKP to a canvas. This class uses the term "frame" as though the MSKP
25*c8dee2aaSAndroid Build Coastguard Worker  * contains an animation, though it could indeed contain pages of a static document.
26*c8dee2aaSAndroid Build Coastguard Worker  */
27*c8dee2aaSAndroid Build Coastguard Worker class MSKPPlayer {
28*c8dee2aaSAndroid Build Coastguard Worker public:
29*c8dee2aaSAndroid Build Coastguard Worker     ~MSKPPlayer();
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker     /** Make a player from a MSKP stream, or null if stream can't be read as MSKP. */
32*c8dee2aaSAndroid Build Coastguard Worker     static std::unique_ptr<MSKPPlayer> Make(SkStreamSeekable* stream);
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker     /** Maximum width and height across all frames. */
maxDimensions()35*c8dee2aaSAndroid Build Coastguard Worker     SkISize maxDimensions() const { return fMaxDimensions; }
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker     /** Total number of frames. */
numFrames()38*c8dee2aaSAndroid Build Coastguard Worker     int numFrames() const { return static_cast<int>(fRootLayers.size()); }
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker     /** Size of an individual frame. */
41*c8dee2aaSAndroid Build Coastguard Worker     SkISize frameDimensions(int i) const;
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker     /**
44*c8dee2aaSAndroid Build Coastguard Worker      * Plays a frame into the passed canvas. Frames can be randomly accessed. Offscreen layers are
45*c8dee2aaSAndroid Build Coastguard Worker      * incrementally updated from their current state to the state required for the frame
46*c8dee2aaSAndroid Build Coastguard Worker      * (redrawing from scratch if their current state is ahead of the passed frame index).
47*c8dee2aaSAndroid Build Coastguard Worker      */
48*c8dee2aaSAndroid Build Coastguard Worker     bool playFrame(SkCanvas* canvas, int i);
49*c8dee2aaSAndroid Build Coastguard Worker 
50*c8dee2aaSAndroid Build Coastguard Worker     /** Destroys any cached offscreen layers. */
51*c8dee2aaSAndroid Build Coastguard Worker     void resetLayers();
52*c8dee2aaSAndroid Build Coastguard Worker 
53*c8dee2aaSAndroid Build Coastguard Worker     /**
54*c8dee2aaSAndroid Build Coastguard Worker      * Forces all offscreen layers to re-render the next time they're required for a frame but
55*c8dee2aaSAndroid Build Coastguard Worker      * preserves the backing stores for them if already allocated.
56*c8dee2aaSAndroid Build Coastguard Worker      */
57*c8dee2aaSAndroid Build Coastguard Worker     void rewindLayers();
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker     /**
60*c8dee2aaSAndroid Build Coastguard Worker      * Creates backing stores for any offscreen layers using the passed canvas's makeSurface().
61*c8dee2aaSAndroid Build Coastguard Worker      * Existing layers that match the canvas's recording context are not reallocated or rewound.
62*c8dee2aaSAndroid Build Coastguard Worker      */
63*c8dee2aaSAndroid Build Coastguard Worker     void allocateLayers(SkCanvas*);
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker     /**
66*c8dee2aaSAndroid Build Coastguard Worker      * A set of IDs of offscreen layers in no particular order. If frame value >= 0 is specified
67*c8dee2aaSAndroid Build Coastguard Worker      * then the layer set is filtered to layers used by that frame (or empty if >= numFrames). If
68*c8dee2aaSAndroid Build Coastguard Worker      * < 0 then gathers all the layers across all frames.
69*c8dee2aaSAndroid Build Coastguard Worker      */
70*c8dee2aaSAndroid Build Coastguard Worker     std::vector<int> layerIDs(int frame = -1) const;
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     /**
73*c8dee2aaSAndroid Build Coastguard Worker      * Gets the contents of an offscreen layer. It's contents will depend on current playback state
74*c8dee2aaSAndroid Build Coastguard Worker      * (playFrame(), updateFrameLayers(), resetLayers()). If the layer currently has no backing
75*c8dee2aaSAndroid Build Coastguard Worker      * store because it hasn't been drawn or resetLayers() was called then this will return nullptr.
76*c8dee2aaSAndroid Build Coastguard Worker      * Layer contents are not affected by rewindLayers() as that simply lazily redraws the frame
77*c8dee2aaSAndroid Build Coastguard Worker      * contents the next time it is required by playFrame*() or updateFrameLayers().
78*c8dee2aaSAndroid Build Coastguard Worker      */
79*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> layerSnapshot(int layerID) const;
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker private:
82*c8dee2aaSAndroid Build Coastguard Worker     MSKPPlayer() = default;
83*c8dee2aaSAndroid Build Coastguard Worker     // noncopyable, nonmoveable.
84*c8dee2aaSAndroid Build Coastguard Worker     MSKPPlayer(const MSKPPlayer&) = delete;
85*c8dee2aaSAndroid Build Coastguard Worker     MSKPPlayer(MSKPPlayer&&) = delete;
86*c8dee2aaSAndroid Build Coastguard Worker     MSKPPlayer& operator=(const MSKPPlayer&) = delete;
87*c8dee2aaSAndroid Build Coastguard Worker     MSKPPlayer& operator=(MSKPPlayer&&) = delete;
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker     // Cmds are used to draw content to the frame root layer and to offscreen layers.
90*c8dee2aaSAndroid Build Coastguard Worker     struct Cmd;
91*c8dee2aaSAndroid Build Coastguard Worker     // Draws a SkPicture.
92*c8dee2aaSAndroid Build Coastguard Worker     struct PicCmd;
93*c8dee2aaSAndroid Build Coastguard Worker     // Draws another layer. Stores the ID of the layer to draw and what command index on that
94*c8dee2aaSAndroid Build Coastguard Worker     // layer should be current when the layer is drawn. The layer contents are updated to the
95*c8dee2aaSAndroid Build Coastguard Worker     // stored command index before the layer is drawn.
96*c8dee2aaSAndroid Build Coastguard Worker     struct DrawLayerCmd;
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker     // The commands for a root/offscreen layer and dimensions of the layer.
99*c8dee2aaSAndroid Build Coastguard Worker     struct LayerCmds {
100*c8dee2aaSAndroid Build Coastguard Worker         LayerCmds() = default;
101*c8dee2aaSAndroid Build Coastguard Worker         LayerCmds(LayerCmds&&) = default;
102*c8dee2aaSAndroid Build Coastguard Worker         SkISize fDimensions;
103*c8dee2aaSAndroid Build Coastguard Worker         std::vector<std::unique_ptr<Cmd>> fCmds;
104*c8dee2aaSAndroid Build Coastguard Worker     };
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker     // Playback state of layer: the last command index drawn to it and the SkSurface with contents.
107*c8dee2aaSAndroid Build Coastguard Worker     struct LayerState {
108*c8dee2aaSAndroid Build Coastguard Worker         size_t fCurrCmd = -1;
109*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkSurface> fSurface;
110*c8dee2aaSAndroid Build Coastguard Worker     };
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker     static sk_sp<SkSurface> MakeSurfaceForLayer(const LayerCmds&, SkCanvas* rootCanvas);
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     void collectReferencedLayers(const LayerCmds& layer, std::vector<int>*) const;
115*c8dee2aaSAndroid Build Coastguard Worker 
116*c8dee2aaSAndroid Build Coastguard Worker     // MSKP layer ID -> LayerCmds
117*c8dee2aaSAndroid Build Coastguard Worker     using LayerMap = std::unordered_map<int, LayerCmds>;
118*c8dee2aaSAndroid Build Coastguard Worker     // MSKP layer ID -> LayerState
119*c8dee2aaSAndroid Build Coastguard Worker     using LayerStateMap = std::unordered_map<int, LayerState>;
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker     /**
122*c8dee2aaSAndroid Build Coastguard Worker      * A SkCanvas that consumes the SkPicture and records Cmds into a Layer. It will spawn
123*c8dee2aaSAndroid Build Coastguard Worker      * additional Layers and record nested SkPictures into those using additional CmdRecordCanvas
124*c8dee2aaSAndroid Build Coastguard Worker      * CmdRecordCanvas instances. It needs access to fOffscreenLayers to create and update LayerCmds
125*c8dee2aaSAndroid Build Coastguard Worker      * structs for offscreen layers.
126*c8dee2aaSAndroid Build Coastguard Worker      */
127*c8dee2aaSAndroid Build Coastguard Worker     class CmdRecordCanvas;
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker     SkISize            fMaxDimensions = {0, 0};  // Max dimensions across all frames.
130*c8dee2aaSAndroid Build Coastguard Worker     LayerMap           fOffscreenLayers;         // All the offscreen layers for all frames.
131*c8dee2aaSAndroid Build Coastguard Worker     LayerStateMap      fOffscreenLayerStates;    // Current surfaces and command idx for offscreen
132*c8dee2aaSAndroid Build Coastguard Worker                                                  // layers
133*c8dee2aaSAndroid Build Coastguard Worker     std::vector<LayerCmds> fRootLayers;          // One root layer for each frame.
134*c8dee2aaSAndroid Build Coastguard Worker };
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker #endif
137