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