xref: /aosp_15_r20/external/skia/src/core/SkPictureRecorder.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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