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