1 /*
2 * Copyright 2014 Google Inc.
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 "include/core/SkData.h"
9 #include "include/core/SkDrawable.h"
10 #include "include/core/SkPictureRecorder.h"
11 #include "include/core/SkTypes.h"
12 #include "src/core/SkBigPicture.h"
13 #include "src/core/SkMiniRecorder.h"
14 #include "src/core/SkRecord.h"
15 #include "src/core/SkRecordDraw.h"
16 #include "src/core/SkRecordOpts.h"
17 #include "src/core/SkRecordedDrawable.h"
18 #include "src/core/SkRecorder.h"
19
SkPictureRecorder()20 SkPictureRecorder::SkPictureRecorder() {
21 fActivelyRecording = false;
22 fMiniRecorder.reset(new SkMiniRecorder);
23 fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get()));
24 }
25
~SkPictureRecorder()26 SkPictureRecorder::~SkPictureRecorder() {}
27
beginRecording(const SkRect & userCullRect,SkBBHFactory * bbhFactory,uint32_t recordFlags)28 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
29 SkBBHFactory* bbhFactory /* = nullptr */,
30 uint32_t recordFlags /* = 0 */) {
31 const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect;
32
33 fCullRect = cullRect;
34 fFlags = recordFlags;
35
36 if (bbhFactory) {
37 fBBH.reset((*bbhFactory)());
38 SkASSERT(fBBH.get());
39 }
40
41 if (!fRecord) {
42 fRecord.reset(new SkRecord);
43 }
44 SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag)
45 ? SkRecorder::Playback_DrawPictureMode
46 : SkRecorder::Record_DrawPictureMode;
47 fRecorder->reset(fRecord.get(), cullRect, dpm, fMiniRecorder.get());
48 fActivelyRecording = true;
49 return this->getRecordingCanvas();
50 }
51
getRecordingCanvas()52 SkCanvas* SkPictureRecorder::getRecordingCanvas() {
53 return fActivelyRecording ? fRecorder.get() : nullptr;
54 }
55
finishRecordingAsPicture(uint32_t finishFlags)56 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) {
57 fActivelyRecording = false;
58 fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
59
60 if (fRecord->count() == 0) {
61 auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
62 fBBH.reset(nullptr);
63 return pic;
64 }
65
66 // TODO: delay as much of this work until just before first playback?
67 SkRecordOptimize(fRecord.get());
68
69 SkDrawableList* drawableList = fRecorder->getDrawableList();
70 SkBigPicture::SnapshotArray* pictList =
71 drawableList ? drawableList->newDrawableSnapshot() : nullptr;
72
73 if (fBBH.get()) {
74 SkAutoTMalloc<SkRect> bounds(fRecord->count());
75 SkRecordFillBounds(fCullRect, *fRecord, bounds);
76 fBBH->insert(bounds, fRecord->count());
77
78 // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
79 // TODO: get updated fCullRect from bounds instead of forcing the BBH to return it?
80 SkRect bbhBound = fBBH->getRootBound();
81 SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
82 || (bbhBound.isEmpty() && fCullRect.isEmpty()));
83 fCullRect = bbhBound;
84 }
85
86 size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
87 for (int i = 0; pictList && i < pictList->count(); i++) {
88 subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
89 }
90 return sk_make_sp<SkBigPicture>(fCullRect, fRecord.release(), pictList, fBBH.release(),
91 subPictureBytes);
92 }
93
finishRecordingAsPictureWithCull(const SkRect & cullRect,uint32_t finishFlags)94 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect,
95 uint32_t finishFlags) {
96 fCullRect = cullRect;
97 return this->finishRecordingAsPicture(finishFlags);
98 }
99
100
partialReplay(SkCanvas * canvas) const101 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
102 if (nullptr == canvas) {
103 return;
104 }
105
106 int drawableCount = 0;
107 SkDrawable* const* drawables = nullptr;
108 SkDrawableList* drawableList = fRecorder->getDrawableList();
109 if (drawableList) {
110 drawableCount = drawableList->count();
111 drawables = drawableList->begin();
112 }
113 SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
114 }
115
finishRecordingAsDrawable(uint32_t finishFlags)116 sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) {
117 fActivelyRecording = false;
118 fRecorder->flushMiniRecorder();
119 fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
120
121 SkRecordOptimize(fRecord.get());
122
123 if (fBBH.get()) {
124 SkAutoTMalloc<SkRect> bounds(fRecord->count());
125 SkRecordFillBounds(fCullRect, *fRecord, bounds);
126 fBBH->insert(bounds, fRecord->count());
127 }
128
129 sk_sp<SkDrawable> drawable =
130 sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH),
131 fRecorder->detachDrawableList(), fCullRect);
132
133 return drawable;
134 }
135