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