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/SkData.h"
9#include "include/core/SkDrawable.h"
10#include "include/core/SkPictureRecorder.h"
11#include "include/core/SkTypes.h"
12#include "src/core/SkBigPicture.h"
13#include "src/core/SkMiniRecorder.h"
14#include "src/core/SkRecord.h"
15#include "src/core/SkRecordDraw.h"
16#include "src/core/SkRecordOpts.h"
17#include "src/core/SkRecordedDrawable.h"
18#include "src/core/SkRecorder.h"
19
20SkPictureRecorder::SkPictureRecorder() {
21 fActivelyRecording = false;
22 fMiniRecorder.reset(new SkMiniRecorder);
23 fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get()));
24}
25
26SkPictureRecorder::~SkPictureRecorder() {}
27
28SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
29 sk_sp<SkBBoxHierarchy> bbh,
30 uint32_t recordFlags /* = 0 */) {
31 const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect;
32
33 fCullRect = cullRect;
34 fFlags = recordFlags;
35 fBBH = std::move(bbh);
36
37 if (!fRecord) {
38 fRecord.reset(new SkRecord);
39 }
40 SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag)
41 ? SkRecorder::Playback_DrawPictureMode
42 : SkRecorder::Record_DrawPictureMode;
43 fRecorder->reset(fRecord.get(), cullRect, dpm, fMiniRecorder.get());
44 fActivelyRecording = true;
45 return this->getRecordingCanvas();
46}
47
48SkCanvas* SkPictureRecorder::beginRecording(const SkRect& bounds,
49 SkBBHFactory* factory,
50 uint32_t flags) {
51 return this->beginRecording(bounds, factory ? (*factory)() : nullptr, flags);
52}
53
54SkCanvas* SkPictureRecorder::getRecordingCanvas() {
55 return fActivelyRecording ? fRecorder.get() : nullptr;
56}
57
58sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) {
59 fActivelyRecording = false;
60 fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
61
62 if (fRecord->count() == 0) {
63 auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
64 if (fBBH) {
65 SkRect bounds = pic->cullRect(); // actually the computed bounds, not fCullRect.
66 SkBBoxHierarchy::Metadata meta;
67 meta.isDraw = true; // All mini-recorder pictures are single draws.
68 fBBH->insert(&bounds, &meta, 1);
69 }
70 fBBH.reset(nullptr);
71 return pic;
72 }
73
74 // TODO: delay as much of this work until just before first playback?
75 SkRecordOptimize(fRecord.get());
76
77 SkDrawableList* drawableList = fRecorder->getDrawableList();
78 std::unique_ptr<SkBigPicture::SnapshotArray> pictList{
79 drawableList ? drawableList->newDrawableSnapshot() : nullptr
80 };
81
82 if (fBBH.get()) {
83 SkAutoTMalloc<SkRect> bounds(fRecord->count());
84 SkAutoTMalloc<SkBBoxHierarchy::Metadata> meta(fRecord->count());
85 SkRecordFillBounds(fCullRect, *fRecord, bounds, meta);
86
87 fBBH->insert(bounds, meta, fRecord->count());
88
89 // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
90 SkRect bbhBound = SkRect::MakeEmpty();
91 for (int i = 0; i < fRecord->count(); i++) {
92 bbhBound.join(bounds[i]);
93 }
94 SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
95 || (bbhBound.isEmpty() && fCullRect.isEmpty()));
96 fCullRect = bbhBound;
97 }
98
99 size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
100 for (int i = 0; pictList && i < pictList->count(); i++) {
101 subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
102 }
103 return sk_make_sp<SkBigPicture>(fCullRect,
104 std::move(fRecord),
105 std::move(pictList),
106 std::move(fBBH),
107 subPictureBytes);
108}
109
110sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect,
111 uint32_t finishFlags) {
112 fCullRect = cullRect;
113 return this->finishRecordingAsPicture(finishFlags);
114}
115
116
117void 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
132sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) {
133 fActivelyRecording = false;
134 fRecorder->flushMiniRecorder();
135 fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
136
137 SkRecordOptimize(fRecord.get());
138
139 if (fBBH.get()) {
140 SkAutoTMalloc<SkRect> bounds(fRecord->count());
141 SkAutoTMalloc<SkBBoxHierarchy::Metadata> meta(fRecord->count());
142 SkRecordFillBounds(fCullRect, *fRecord, bounds, meta);
143 fBBH->insert(bounds, meta, fRecord->count());
144 }
145
146 sk_sp<SkDrawable> drawable =
147 sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH),
148 fRecorder->detachDrawableList(), fCullRect);
149
150 return drawable;
151}
152