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/SkPictureRecorder.h"
9
10 #include "include/core/SkBBHFactory.h"
11 #include "include/core/SkDrawable.h"
12 #include "include/core/SkPicture.h"
13 #include "include/core/SkTypes.h"
14 #include "include/private/base/SkTemplates.h"
15 #include "src/core/SkBigPicture.h"
16 #include "src/core/SkRecord.h"
17 #include "src/core/SkRecordDraw.h"
18 #include "src/core/SkRecordOpts.h"
19 #include "src/core/SkRecordedDrawable.h"
20 #include "src/core/SkRecorder.h"
21
22 #include <cstddef>
23 #include <memory>
24 #include <utility>
25
26 using namespace skia_private;
27
SkPictureRecorder()28 SkPictureRecorder::SkPictureRecorder() {
29 fActivelyRecording = false;
30 fRecorder = std::make_unique<SkRecorder>(nullptr, SkRect::MakeEmpty());
31 }
32
~SkPictureRecorder()33 SkPictureRecorder::~SkPictureRecorder() {}
34
beginRecording(const SkRect & userCullRect,sk_sp<SkBBoxHierarchy> bbh)35 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
36 sk_sp<SkBBoxHierarchy> bbh) {
37 const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect;
38
39 fCullRect = cullRect;
40 fBBH = std::move(bbh);
41
42 if (!fRecord) {
43 fRecord.reset(new SkRecord);
44 }
45 fRecorder->reset(fRecord.get(), cullRect);
46 fActivelyRecording = true;
47 return this->getRecordingCanvas();
48 }
49
beginRecording(const SkRect & bounds,SkBBHFactory * factory)50 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& bounds, SkBBHFactory* factory) {
51 return this->beginRecording(bounds, factory ? (*factory)() : nullptr);
52 }
53
getRecordingCanvas()54 SkCanvas* SkPictureRecorder::getRecordingCanvas() {
55 return fActivelyRecording ? fRecorder.get() : nullptr;
56 }
57
58 class SkEmptyPicture final : public SkPicture {
59 public:
playback(SkCanvas *,AbortCallback *) const60 void playback(SkCanvas*, AbortCallback*) const override { }
61
approximateBytesUsed() const62 size_t approximateBytesUsed() const override { return sizeof(*this); }
approximateOpCount(bool nested) const63 int approximateOpCount(bool nested) const override { return 0; }
cullRect() const64 SkRect cullRect() const override { return SkRect::MakeEmpty(); }
65 };
66
finishRecordingAsPicture()67 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture() {
68 fActivelyRecording = false;
69 fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
70
71 if (fRecord->count() == 0) {
72 return sk_make_sp<SkEmptyPicture>();
73 }
74
75 // TODO: delay as much of this work until just before first playback?
76 SkRecordOptimize(fRecord.get());
77
78 SkDrawableList* drawableList = fRecorder->getDrawableList();
79 std::unique_ptr<SkBigPicture::SnapshotArray> pictList{
80 drawableList ? drawableList->newDrawableSnapshot() : nullptr
81 };
82
83 if (fBBH) {
84 AutoTArray<SkRect> bounds(fRecord->count());
85 AutoTMalloc<SkBBoxHierarchy::Metadata> meta(fRecord->count());
86 SkRecordFillBounds(fCullRect, *fRecord, bounds.data(), meta);
87
88 fBBH->insert(bounds.data(), meta, fRecord->count());
89
90 // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
91 SkRect bbhBound = SkRect::MakeEmpty();
92 for (int i = 0; i < fRecord->count(); i++) {
93 bbhBound.join(bounds[i]);
94 }
95 SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
96 || (bbhBound.isEmpty() && fCullRect.isEmpty()));
97 fCullRect = bbhBound;
98 }
99
100 size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
101 for (int i = 0; pictList && i < pictList->count(); i++) {
102 subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
103 }
104 return sk_make_sp<SkBigPicture>(fCullRect,
105 std::move(fRecord),
106 std::move(pictList),
107 std::move(fBBH),
108 subPictureBytes);
109 }
110
finishRecordingAsPictureWithCull(const SkRect & cullRect)111 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect) {
112 fCullRect = cullRect;
113 return this->finishRecordingAsPicture();
114 }
115
116
partialReplay(SkCanvas * canvas) const117 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
118 if (nullptr == canvas) {
119 return;
120 }
121
122 int drawableCount = 0;
123 SkDrawable* const* drawables = nullptr;
124 SkDrawableList* drawableList = fRecorder->getDrawableList();
125 if (drawableList) {
126 drawableCount = drawableList->count();
127 drawables = drawableList->begin();
128 }
129 SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
130 }
131
finishRecordingAsDrawable()132 sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable() {
133 fActivelyRecording = false;
134 fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
135
136 SkRecordOptimize(fRecord.get());
137
138 if (fBBH) {
139 AutoTArray<SkRect> bounds(fRecord->count());
140 AutoTMalloc<SkBBoxHierarchy::Metadata> meta(fRecord->count());
141 SkRecordFillBounds(fCullRect, *fRecord, bounds.data(), meta);
142 fBBH->insert(bounds.data(), meta, fRecord->count());
143 }
144
145 sk_sp<SkDrawable> drawable =
146 sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH),
147 fRecorder->detachDrawableList(), fCullRect);
148
149 return drawable;
150 }
151