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