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 "SkMiniRecorder.h"
12 #include "SkPictureRecorder.h"
13 #include "SkRecord.h"
14 #include "SkRecordDraw.h"
15 #include "SkRecordOpts.h"
16 #include "SkRecordedDrawable.h"
17 #include "SkRecorder.h"
18 #include "SkTypes.h"
19 
SkPictureRecorder()20 SkPictureRecorder::SkPictureRecorder() {
21     fActivelyRecording = false;
22     fMiniRecorder.reset(new SkMiniRecorder);
23     fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get()));
24 }
25 
~SkPictureRecorder()26 SkPictureRecorder::~SkPictureRecorder() {}
27 
beginRecording(const SkRect & userCullRect,SkBBHFactory * bbhFactory,uint32_t recordFlags)28 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
29                                             SkBBHFactory* bbhFactory /* = nullptr */,
30                                             uint32_t recordFlags /* = 0 */) {
31     const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect;
32 
33     fCullRect = cullRect;
34     fFlags = recordFlags;
35 
36     if (bbhFactory) {
37         fBBH.reset((*bbhFactory)(cullRect));
38         SkASSERT(fBBH.get());
39     }
40 
41     if (!fRecord) {
42         fRecord.reset(new SkRecord);
43     }
44     SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag)
45         ? SkRecorder::Playback_DrawPictureMode
46         : SkRecorder::Record_DrawPictureMode;
47     fRecorder->reset(fRecord.get(), cullRect, dpm, fMiniRecorder.get());
48     fActivelyRecording = true;
49     return this->getRecordingCanvas();
50 }
51 
getRecordingCanvas()52 SkCanvas* SkPictureRecorder::getRecordingCanvas() {
53     return fActivelyRecording ? fRecorder.get() : nullptr;
54 }
55 
finishRecordingAsPicture(uint32_t finishFlags)56 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) {
57     fActivelyRecording = false;
58     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
59 
60     if (fRecord->count() == 0) {
61         auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
62         fBBH.reset(nullptr);
63         return pic;
64     }
65 
66     // TODO: delay as much of this work until just before first playback?
67     SkRecordOptimize(fRecord.get());
68 
69     SkDrawableList* drawableList = fRecorder->getDrawableList();
70     SkBigPicture::SnapshotArray* pictList =
71         drawableList ? drawableList->newDrawableSnapshot() : nullptr;
72 
73     if (fBBH.get()) {
74         SkAutoTMalloc<SkRect> bounds(fRecord->count());
75         SkRecordFillBounds(fCullRect, *fRecord, bounds);
76         fBBH->insert(bounds, fRecord->count());
77 
78         // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
79         // TODO: get updated fCullRect from bounds instead of forcing the BBH to return it?
80         SkRect bbhBound = fBBH->getRootBound();
81         SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
82             || (bbhBound.isEmpty() && fCullRect.isEmpty()));
83         fCullRect = bbhBound;
84     }
85 
86     size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
87     for (int i = 0; pictList && i < pictList->count(); i++) {
88         subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
89     }
90     return sk_make_sp<SkBigPicture>(fCullRect, fRecord.release(), pictList, fBBH.release(),
91                                     subPictureBytes);
92 }
93 
finishRecordingAsPictureWithCull(const SkRect & cullRect,uint32_t finishFlags)94 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect,
95                                                                      uint32_t finishFlags) {
96     fCullRect = cullRect;
97     return this->finishRecordingAsPicture(finishFlags);
98 }
99 
100 
partialReplay(SkCanvas * canvas) const101 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
102     if (nullptr == canvas) {
103         return;
104     }
105 
106     int drawableCount = 0;
107     SkDrawable* const* drawables = nullptr;
108     SkDrawableList* drawableList = fRecorder->getDrawableList();
109     if (drawableList) {
110         drawableCount = drawableList->count();
111         drawables = drawableList->begin();
112     }
113     SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
114 }
115 
finishRecordingAsDrawable(uint32_t finishFlags)116 sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) {
117     fActivelyRecording = false;
118     fRecorder->flushMiniRecorder();
119     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
120 
121     SkRecordOptimize(fRecord.get());
122 
123     if (fBBH.get()) {
124         SkAutoTMalloc<SkRect> bounds(fRecord->count());
125         SkRecordFillBounds(fCullRect, *fRecord, bounds);
126         fBBH->insert(bounds, fRecord->count());
127     }
128 
129     sk_sp<SkDrawable> drawable =
130          sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH),
131                                         fRecorder->detachDrawableList(), fCullRect);
132 
133     return drawable;
134 }
135