|  | /* | 
|  | * Copyright 2021 Google LLC | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #ifndef MSKPPlayer_DEFINED | 
|  | #define MSKPPlayer_DEFINED | 
|  |  | 
|  | #include "include/core/SkRefCnt.h" | 
|  | #include "include/core/SkSize.h" | 
|  |  | 
|  | #include <unordered_map> | 
|  | #include <vector> | 
|  |  | 
|  | class SkCanvas; | 
|  | class SkImage; | 
|  | class SkStreamSeekable; | 
|  | class SkSurface; | 
|  |  | 
|  | /** | 
|  | * Plays frames/pages of a MSKP to a canvas. This class uses the term "frame" as though the MSKP | 
|  | * contains an animation, though it could indeed contain pages of a static document. | 
|  | */ | 
|  | class MSKPPlayer { | 
|  | public: | 
|  | ~MSKPPlayer(); | 
|  |  | 
|  | /** Make a player from a MSKP stream, or null if stream can't be read as MSKP. */ | 
|  | static std::unique_ptr<MSKPPlayer> Make(SkStreamSeekable* stream); | 
|  |  | 
|  | /** Maximum width and height across all frames. */ | 
|  | SkISize maxDimensions() const { return fMaxDimensions; } | 
|  |  | 
|  | /** Total number of frames. */ | 
|  | int numFrames() const { return static_cast<int>(fRootLayers.size()); } | 
|  |  | 
|  | /** Size of an individual frame. */ | 
|  | SkISize frameDimensions(int i) const; | 
|  |  | 
|  | /** | 
|  | * Plays a frame into the passed canvas. Frames can be randomly accessed. Offscreen layers are | 
|  | * incrementally updated from their current state to the state required for the frame | 
|  | * (redrawing from scratch if their current state is ahead of the passed frame index). | 
|  | */ | 
|  | bool playFrame(SkCanvas* canvas, int i); | 
|  |  | 
|  | /** Destroys any cached offscreen layers. */ | 
|  | void resetLayers(); | 
|  |  | 
|  | /** | 
|  | * Forces all offscreen layers to re-render the next time they're required for a frame but | 
|  | * preserves the backing stores for them if already allocated. | 
|  | */ | 
|  | void rewindLayers(); | 
|  |  | 
|  | /** | 
|  | * Creates backing stores for any offscreen layers using the passed canvas's makeSurface(). | 
|  | * Existing layers that match the canvas's recording context are not reallocated or rewound. | 
|  | */ | 
|  | void allocateLayers(SkCanvas*); | 
|  |  | 
|  | /** | 
|  | * A set of IDs of offscreen layers in no particular order. If frame value >= 0 is specified | 
|  | * then the layer set is filtered to layers used by that frame (or empty if >= numFrames). If | 
|  | * < 0 then gathers all the layers across all frames. | 
|  | */ | 
|  | std::vector<int> layerIDs(int frame = -1) const; | 
|  |  | 
|  | /** | 
|  | * Gets the contents of an offscreen layer. It's contents will depend on current playback state | 
|  | * (playFrame(), updateFrameLayers(), resetLayers()). If the layer currently has no backing | 
|  | * store because it hasn't been drawn or resetLayers() was called then this will return nullptr. | 
|  | * Layer contents are not affected by rewindLayers() as that simply lazily redraws the frame | 
|  | * contents the next time it is required by playFrame*() or updateFrameLayers(). | 
|  | */ | 
|  | sk_sp<SkImage> layerSnapshot(int layerID) const; | 
|  |  | 
|  | private: | 
|  | MSKPPlayer() = default; | 
|  | // noncopyable, nonmoveable. | 
|  | MSKPPlayer(const MSKPPlayer&) = delete; | 
|  | MSKPPlayer(MSKPPlayer&&) = delete; | 
|  | MSKPPlayer& operator=(const MSKPPlayer&) = delete; | 
|  | MSKPPlayer& operator=(MSKPPlayer&&) = delete; | 
|  |  | 
|  | // Cmds are used to draw content to the frame root layer and to offscreen layers. | 
|  | struct Cmd; | 
|  | // Draws a SkPicture. | 
|  | struct PicCmd; | 
|  | // Draws another layer. Stores the ID of the layer to draw and what command index on that | 
|  | // layer should be current when the layer is drawn. The layer contents are updated to the | 
|  | // stored command index before the layer is drawn. | 
|  | struct DrawLayerCmd; | 
|  |  | 
|  | // The commands for a root/offscreen layer and dimensions of the layer. | 
|  | struct LayerCmds { | 
|  | LayerCmds() = default; | 
|  | LayerCmds(LayerCmds&&) = default; | 
|  | SkISize fDimensions; | 
|  | std::vector<std::unique_ptr<Cmd>> fCmds; | 
|  | }; | 
|  |  | 
|  | // Playback state of layer: the last command index drawn to it and the SkSurface with contents. | 
|  | struct LayerState { | 
|  | size_t fCurrCmd = -1; | 
|  | sk_sp<SkSurface> fSurface; | 
|  | }; | 
|  |  | 
|  | static sk_sp<SkSurface> MakeSurfaceForLayer(const LayerCmds&, SkCanvas* rootCanvas); | 
|  |  | 
|  | void collectReferencedLayers(const LayerCmds& layer, std::vector<int>*) const; | 
|  |  | 
|  | // MSKP layer ID -> LayerCmds | 
|  | using LayerMap = std::unordered_map<int, LayerCmds>; | 
|  | // MSKP layer ID -> LayerState | 
|  | using LayerStateMap = std::unordered_map<int, LayerState>; | 
|  |  | 
|  | /** | 
|  | * A SkCanvas that consumes the SkPicture and records Cmds into a Layer. It will spawn | 
|  | * additional Layers and record nested SkPictures into those using additional CmdRecordCanvas | 
|  | * CmdRecordCanvas instances. It needs access to fOffscreenLayers to create and update LayerCmds | 
|  | * structs for offscreen layers. | 
|  | */ | 
|  | class CmdRecordCanvas; | 
|  |  | 
|  | SkISize            fMaxDimensions = {0, 0};  // Max dimensions across all frames. | 
|  | LayerMap           fOffscreenLayers;         // All the offscreen layers for all frames. | 
|  | LayerStateMap      fOffscreenLayerStates;    // Current surfaces and command idx for offscreen | 
|  | // layers | 
|  | std::vector<LayerCmds> fRootLayers;          // One root layer for each frame. | 
|  | }; | 
|  |  | 
|  | #endif |