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