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/SkMiniRecorder.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 
SkPictureRecorder()22 SkPictureRecorder::SkPictureRecorder() {
23     fActivelyRecording = false;
24     fMiniRecorder = std::make_unique<SkMiniRecorder>();
25     fRecorder = std::make_unique<SkRecorder>(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get());
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, fMiniRecorder.get());
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 
finishRecordingAsPicture()53 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture() {
54     fActivelyRecording = false;
55     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
56 
57     if (fRecord->count() == 0) {
58         auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
59         if (fBBH) {
60             SkRect bounds = pic->cullRect();  // actually the computed bounds, not fCullRect.
61             SkBBoxHierarchy::Metadata meta;
62             meta.isDraw = true;               // All mini-recorder pictures are single draws.
63             fBBH->insert(&bounds, &meta, 1);
64         }
65         fBBH.reset(nullptr);
66         return pic;
67     }
68 
69     // TODO: delay as much of this work until just before first playback?
70     SkRecordOptimize(fRecord.get());
71 
72     SkDrawableList* drawableList = fRecorder->getDrawableList();
73     std::unique_ptr<SkBigPicture::SnapshotArray> pictList{
74         drawableList ? drawableList->newDrawableSnapshot() : nullptr
75     };
76 
77     if (fBBH) {
78         SkAutoTMalloc<SkRect> bounds(fRecord->count());
79         SkAutoTMalloc<SkBBoxHierarchy::Metadata> meta(fRecord->count());
80         SkRecordFillBounds(fCullRect, *fRecord, bounds, meta);
81 
82         fBBH->insert(bounds, meta, fRecord->count());
83 
84         // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
85         SkRect bbhBound = SkRect::MakeEmpty();
86         for (int i = 0; i < fRecord->count(); i++) {
87             bbhBound.join(bounds[i]);
88         }
89         SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
90               || (bbhBound.isEmpty() && fCullRect.isEmpty()));
91         fCullRect = bbhBound;
92     }
93 
94     size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
95     for (int i = 0; pictList && i < pictList->count(); i++) {
96         subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
97     }
98     return sk_make_sp<SkBigPicture>(fCullRect,
99                                     std::move(fRecord),
100                                     std::move(pictList),
101                                     std::move(fBBH),
102                                     subPictureBytes);
103 }
104 
finishRecordingAsPictureWithCull(const SkRect & cullRect)105 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect) {
106     fCullRect = cullRect;
107     return this->finishRecordingAsPicture();
108 }
109 
110 
partialReplay(SkCanvas * canvas) const111 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
112     if (nullptr == canvas) {
113         return;
114     }
115 
116     int drawableCount = 0;
117     SkDrawable* const* drawables = nullptr;
118     SkDrawableList* drawableList = fRecorder->getDrawableList();
119     if (drawableList) {
120         drawableCount = drawableList->count();
121         drawables = drawableList->begin();
122     }
123     SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
124 }
125 
finishRecordingAsDrawable()126 sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable() {
127     fActivelyRecording = false;
128     fRecorder->flushMiniRecorder();
129     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
130 
131     SkRecordOptimize(fRecord.get());
132 
133     if (fBBH) {
134         SkAutoTMalloc<SkRect> bounds(fRecord->count());
135         SkAutoTMalloc<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