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