skia2/tools/MSKPPlayer.h
Brian Osman 68556bc798 Move canvas helper structs to header
This is necessary cleanup before changing the type of the matrix and
clip stack. That work has landed and reverted several times, so landing
this piece separately, first.

Change-Id: I147e4cc4260fa5e07a0712503f879da120f8466a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/435278
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2021-08-10 17:53:16 +00:00

136 lines
5.0 KiB
C++

/*
* 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