blob: 89bae48c0cf12f56e664223c1a8b9eab8eabc6f9 [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#include "tools/MSKPPlayer.h"
9
10#include "include/core/SkCanvas.h"
11#include "include/core/SkCanvasVirtualEnforcer.h"
12#include "include/core/SkPicture.h"
13#include "include/core/SkPictureRecorder.h"
14#include "include/core/SkSurface.h"
15#include "include/private/SkTArray.h"
16#include "include/utils/SkNoDrawCanvas.h"
17#include "src/core/SkCanvasPriv.h"
18#include "src/core/SkTLazy.h"
19#include "src/utils/SkMultiPictureDocument.h"
20#include "tools/SkSharingProc.h"
21
22
23///////////////////////////////////////////////////////////////////////////////
24
25// Base Cmd struct.
26struct MSKPPlayer::Cmd {
27 virtual ~Cmd() = default;
28 virtual void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const = 0;
29};
30
31// Draws a SkPicture.
32struct MSKPPlayer::PicCmd : Cmd {
33 sk_sp<SkPicture> fContent;
34
35 void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const override {
36 canvas->drawPicture(fContent.get());
37 }
38};
39
40// Draws another layer. Stores the ID of the layer to draw and what command index on that
41// layer should be current when the layer is drawn. The layer contents are updated to the
42// stored command index before the layer is drawn.
43struct MSKPPlayer::DrawLayerCmd : Cmd {
44 int fLayerId;
45 size_t fLayerCmdCnt;
46 SkRect fSrcRect;
47 SkRect fDstRect;
48 SkSamplingOptions fSampling;
49 SkCanvas::SrcRectConstraint fConstraint;
50 SkTLazy<SkPaint> fPaint;
51
52 void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const override;
53};
54
55void MSKPPlayer::DrawLayerCmd::draw(SkCanvas* canvas,
56 const LayerMap& layerMap,
57 LayerStateMap* layerStateMap) const {
58 const Layer& layer = layerMap.at(fLayerId);
59 LayerState* layerState = &(*layerStateMap)[fLayerId];
60 if (!layerState->fSurface) {
61 layerState->fCurrCmd = 0;
62 // Assume layer has same surface props and info as this (mskp doesn't currently record this
63 // data).
64 SkSurfaceProps props;
65 canvas->getProps(&props);
66 layerState->fSurface =
67 canvas->makeSurface(canvas->imageInfo().makeDimensions(layer.fDimensions), &props);
68 if (!layerState->fSurface) {
69 SkDebugf("Couldn't create surface for layer");
70 return;
71 }
72 }
73 size_t cmd = layerState->fCurrCmd;
74 if (cmd > fLayerCmdCnt) {
75 // If the layer contains contents from later commands then replay from the beginning.
76 cmd = 0;
77 }
78 SkCanvas* layerCanvas = layerState->fSurface->getCanvas();
79 for (; cmd < fLayerCmdCnt; ++cmd) {
80 layer.fCmds[cmd]->draw(layerCanvas, layerMap, layerStateMap);
81 }
82 const SkPaint* paint = fPaint.isValid() ? fPaint.get() : nullptr;
83 canvas->drawImageRect(layerState->fSurface->makeImageSnapshot(),
84 fSrcRect,
85 fDstRect,
86 fSampling,
87 paint,
88 fConstraint);
89}
90
91///////////////////////////////////////////////////////////////////////////////
92
93class MSKPPlayer::CmdRecordCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
94public:
95 CmdRecordCanvas(Layer* dst, LayerMap* offscreenLayers)
96 : fDst(dst), fOffscreenLayers(offscreenLayers) {
97 fRecorder.beginRecording(SkRect::Make(dst->fDimensions));
98 }
99 ~CmdRecordCanvas() override { this->recordPicCmd(); }
100
101protected:
102 void onDrawPaint(const SkPaint& paint) override {
103 fRecorder.getRecordingCanvas()->drawPaint(paint);
104 }
105
106 void onDrawBehind(const SkPaint& paint) override {
107 SkCanvasPriv::DrawBehind(fRecorder.getRecordingCanvas(), paint);
108 }
109
110 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
111 fRecorder.getRecordingCanvas()->drawRect(rect, paint);
112 }
113
114 void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
115 fRecorder.getRecordingCanvas()->drawRRect(rrect, paint);
116 }
117
118 void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
119 fRecorder.getRecordingCanvas()->drawDRRect(outer, inner, paint);
120 }
121
122 void onDrawOval(const SkRect& rect, const SkPaint& paint) override {
123 fRecorder.getRecordingCanvas()->drawOval(rect, paint);
124 }
125
126 void onDrawArc(const SkRect& rect,
127 SkScalar startAngle,
128 SkScalar sweepAngle,
129 bool useCenter,
130 const SkPaint& paint) override {
131 fRecorder.getRecordingCanvas()->drawArc(rect, startAngle, sweepAngle, useCenter, paint);
132 }
133
134 void onDrawPath(const SkPath& path, const SkPaint& paint) override {
135 fRecorder.getRecordingCanvas()->drawPath(path, paint);
136 }
137
138 void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
139 fRecorder.getRecordingCanvas()->drawRegion(region, paint);
140 }
141
142 void onDrawTextBlob(const SkTextBlob* blob,
143 SkScalar x,
144 SkScalar y,
145 const SkPaint& paint) override {
146 fRecorder.getRecordingCanvas()->drawTextBlob(blob, x, y, paint);
147 }
148
149 void onDrawPatch(const SkPoint cubics[12],
150 const SkColor colors[4],
151 const SkPoint texCoords[4],
152 SkBlendMode mode,
153 const SkPaint& paint) override {
154 fRecorder.getRecordingCanvas()->drawPatch(cubics, colors, texCoords, mode, paint);
155 }
156
157 void onDrawPoints(SkCanvas::PointMode mode,
158 size_t count,
159 const SkPoint pts[],
160 const SkPaint& paint) override {
161 fRecorder.getRecordingCanvas()->drawPoints(mode, count, pts, paint);
162 }
163
164 void onDrawImage2(const SkImage* image,
165 SkScalar dx,
166 SkScalar dy,
167 const SkSamplingOptions& sampling,
168 const SkPaint* paint) override {
169 fRecorder.getRecordingCanvas()->drawImage(image, dx, dy, sampling, paint);
170 }
171
172 void onDrawImageRect2(const SkImage* image,
173 const SkRect& src,
174 const SkRect& dst,
175 const SkSamplingOptions& sampling,
176 const SkPaint* paint,
177 SrcRectConstraint constraint) override {
178 if (fNextDrawImageFromLayerID != -1) {
179 this->recordPicCmd();
180 auto drawLayer = std::make_unique<DrawLayerCmd>();
181 drawLayer->fLayerId = fNextDrawImageFromLayerID;
182 drawLayer->fLayerCmdCnt = fOffscreenLayers->at(fNextDrawImageFromLayerID).fCmds.size();
183 drawLayer->fSrcRect = src;
184 drawLayer->fDstRect = dst;
185 drawLayer->fSampling = sampling;
186 drawLayer->fConstraint = constraint;
187 if (paint) {
188 drawLayer->fPaint.init(*paint);
189 }
190 fDst->fCmds.push_back(std::move(drawLayer));
191 fNextDrawImageFromLayerID = -1;
192 return;
193 }
194 fRecorder.getRecordingCanvas()->drawImageRect(image, src, dst, sampling, paint, constraint);
195 }
196
197 void onDrawImageLattice2(const SkImage* image,
198 const Lattice& lattice,
199 const SkRect& dst,
200 SkFilterMode mode,
201 const SkPaint* paint) override {
202 fRecorder.getRecordingCanvas()->drawImageLattice(image, lattice, dst, mode, paint);
203 }
204
205 void onDrawAtlas2(const SkImage* image,
206 const SkRSXform rsxForms[],
207 const SkRect src[],
208 const SkColor colors[],
209 int count,
210 SkBlendMode mode,
211 const SkSamplingOptions& sampling,
212 const SkRect* cull,
213 const SkPaint* paint) override {
214 fRecorder.getRecordingCanvas()->drawAtlas(image,
215 rsxForms,
216 src,
217 colors,
218 count,
219 mode,
220 sampling,
221 cull,
222 paint);
223 }
224
225 void onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[],
226 int count,
227 const SkPoint dstClips[],
228 const SkMatrix preViewMatrices[],
229 const SkSamplingOptions& sampling,
230 const SkPaint* paint,
231 SrcRectConstraint constraint) override {
232 fRecorder.getRecordingCanvas()->experimental_DrawEdgeAAImageSet(imageSet,
233 count,
234 dstClips,
235 preViewMatrices,
236 sampling,
237 paint,
238 constraint);
239 }
240
241#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
242 void onDrawEdgeAAQuad(const SkRect& rect,
243 const SkPoint clip[4],
244 SkCanvas::QuadAAFlags aaFlags,
245 const SkColor4f& color,
246 SkBlendMode mode) override {}
247#else
248 void onDrawEdgeAAQuad(const SkRect& rect,
249 const SkPoint clip[4],
250 SkCanvas::QuadAAFlags aaFlags,
251 const SkColor4f& color,
252 SkBlendMode mode) override {
253 fRecorder.getRecordingCanvas()->experimental_DrawEdgeAAQuad(rect,
254 clip,
255 aaFlags,
256 color,
257 mode);
258 }
259#endif
260
261 void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override {
262 static constexpr char kOffscreenLayerDraw[] = "OffscreenLayerDraw";
263 static constexpr char kSurfaceID[] = "SurfaceID";
264 SkTArray<SkString> tokens;
265 SkStrSplit(key, "|", kStrict_SkStrSplitMode, &tokens);
266 if (tokens.size() == 2) {
267 if (tokens[0].equals(kOffscreenLayerDraw)) {
268 // Indicates that the next drawPicture command contains the SkPicture to render
269 // to the layer identified by the ID. 'rect' indicates the dirty area to update
270 // (and indicates the layer size if this command is introducing a new layer id).
271 fNextDrawToLayerID = std::stoi(tokens[1].c_str());
272 if (fOffscreenLayers->find(fNextDrawToLayerID) == fOffscreenLayers->end()) {
273 SkASSERT(rect.left() == 0 && rect.top() == 0);
274 SkISize size = {SkScalarCeilToInt(rect.right()),
275 SkScalarCeilToInt(rect.bottom())};
276 (*fOffscreenLayers)[fNextDrawToLayerID].fDimensions = size;
277 }
278 // The next draw picture will notice that fNextDrawLayerID is set and redirect
279 // the picture to the offscreen layer.
280 return;
281 } else if (tokens[0].equals(kSurfaceID)) {
282 // Indicates that the following drawImageRect should draw an offscreen layer
283 // to this layer.
284 fNextDrawImageFromLayerID = std::stoi(tokens[1].c_str());
285 return;
286 }
287 }
288 }
289
290 void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override {
291 fRecorder.getRecordingCanvas()->private_draw_shadow_rec(path, rec);
292 }
293
294 void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
295 fRecorder.getRecordingCanvas()->drawDrawable(drawable, matrix);
296 }
297
298 void onDrawPicture(const SkPicture* picture,
299 const SkMatrix* matrix,
300 const SkPaint* paint) override {
301 if (fNextDrawToLayerID != -1) {
302 SkASSERT(!matrix);
303 SkASSERT(!paint);
304 CmdRecordCanvas sc(&fOffscreenLayers->at(fNextDrawToLayerID), fOffscreenLayers);
305 picture->playback(&sc);
306 fNextDrawToLayerID = -1;
307 return;
308 }
309 if (paint) {
310 this->saveLayer(nullptr, paint);
311 }
312 if (matrix) {
313 this->save();
314 this->concat(*matrix);
315 }
316
317 picture->playback(this);
318
319 if (matrix) {
320 this->restore();
321 }
322 if (paint) {
323 this->restore();
324 }
325 fRecorder.getRecordingCanvas()->drawPicture(picture, matrix, paint);
326 }
327
328private:
329 void recordPicCmd() {
330 auto cmd = std::make_unique<PicCmd>();
331 cmd->fContent = fRecorder.finishRecordingAsPicture();
332 if (cmd->fContent) {
333 fDst->fCmds.push_back(std::move(cmd));
334 }
335 // Set up to accumulate again.
336 fRecorder.beginRecording(SkRect::Make(fDst->fDimensions));
337 }
338
339 SkPictureRecorder fRecorder; // accumulates draws until we draw an offscreen into this layer.
340 Layer* fDst = nullptr;
341 int fNextDrawToLayerID = -1;
342 int fNextDrawImageFromLayerID = -1;
343 LayerMap* fOffscreenLayers = nullptr;
344};
345
346///////////////////////////////////////////////////////////////////////////////
347
348std::unique_ptr<MSKPPlayer> MSKPPlayer::Make(SkStreamSeekable* stream) {
349 auto deserialContext = std::make_unique<SkSharingDeserialContext>();
350 SkDeserialProcs procs;
351 procs.fImageProc = SkSharingDeserialContext::deserializeImage;
352 procs.fImageCtx = deserialContext.get();
353
354 int pageCount = SkMultiPictureDocumentReadPageCount(stream);
355 if (!pageCount) {
356 return nullptr;
357 }
358 std::vector<SkDocumentPage> pages(pageCount);
359 if (!SkMultiPictureDocumentRead(stream, pages.data(), pageCount, &procs)) {
360 return nullptr;
361 }
362 std::unique_ptr<MSKPPlayer> result(new MSKPPlayer);
363 result->fRootLayers.reserve(pages.size());
364 for (const auto& page : pages) {
365 SkISize dims = {SkScalarCeilToInt(page.fSize.width()),
366 SkScalarCeilToInt(page.fSize.height())};
367 result->fRootLayers.emplace_back();
368 result->fRootLayers.back().fDimensions = dims;
369 result->fMaxDimensions.fWidth = std::max(dims.width() , result->fMaxDimensions.width() );
370 result->fMaxDimensions.fHeight = std::max(dims.height(), result->fMaxDimensions.height());
371 CmdRecordCanvas sc(&result->fRootLayers.back(), &result->fOffscreenLayers);
372 page.fPicture->playback(&sc);
373 }
374 return result;
375}
376
377MSKPPlayer::~MSKPPlayer() = default;
378
379SkISize MSKPPlayer::frameDimensions(int i) const {
380 if (i < 0 || i >= this->numFrames()) {
381 return {-1, -1};
382 }
383 return fRootLayers[i].fDimensions;
384}
385
386bool MSKPPlayer::playFrame(SkCanvas* canvas, int i) {
387 if (i < 0 || i >= this->numFrames()) {
388 return false;
389 }
390
391 // Find the first offscreen layer that has a valid surface. If it's recording context
392 // differs from the passed canvas's then reset all the layers. Playback will
393 // automatically allocate new surfaces for offscreen layers as they're encountered.
394 for (const auto& ols : fOffscreenLayerStates) {
395 const LayerState& state = ols.second;
396 if (state.fSurface) {
397 if (state.fSurface->recordingContext() != canvas->recordingContext()) {
398 this->resetLayers();
399 }
400 break;
401 }
402 }
403
404 // Replay all the commands for this frame to the caller's canvas.
405 const Layer& layer = fRootLayers[i];
406 for (const auto& cmd : layer.fCmds) {
407 cmd->draw(canvas, fOffscreenLayers, &fOffscreenLayerStates);
408 }
409 return true;
410}
411
412void MSKPPlayer::resetLayers() { fOffscreenLayerStates.clear(); }