2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
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"
22 SkPictureRecorder::SkPictureRecorder() {
23 fActivelyRecording = false;
24 fMiniRecorder = std::make_unique<SkMiniRecorder>();
25 fRecorder = std::make_unique<SkRecorder>(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get());
28 SkPictureRecorder::~SkPictureRecorder() {}
30 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
31 sk_sp<SkBBoxHierarchy> bbh) {
32 const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect;
35 fBBH = std::move(bbh);
38 fRecord.reset(new SkRecord);
40 fRecorder->reset(fRecord.get(), cullRect, fMiniRecorder.get());
41 fActivelyRecording = true;
42 return this->getRecordingCanvas();
45 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& bounds, SkBBHFactory* factory) {
46 return this->beginRecording(bounds, factory ? (*factory)() : nullptr);
49 SkCanvas* SkPictureRecorder::getRecordingCanvas() {
50 return fActivelyRecording ? fRecorder.get() : nullptr;
53 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture() {
54 fActivelyRecording = false;
55 fRecorder->restoreToCount(1); // If we were missing any restores, add them now.
57 if (fRecord->count() == 0) {
58 auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
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);
69 // TODO: delay as much of this work until just before first playback?
70 SkRecordOptimize(fRecord.get());
72 SkDrawableList* drawableList = fRecorder->getDrawableList();
73 std::unique_ptr<SkBigPicture::SnapshotArray> pictList{
74 drawableList ? drawableList->newDrawableSnapshot() : nullptr
78 SkAutoTMalloc<SkRect> bounds(fRecord->count());
79 SkAutoTMalloc<SkBBoxHierarchy::Metadata> meta(fRecord->count());
80 SkRecordFillBounds(fCullRect, *fRecord, bounds, meta);
82 fBBH->insert(bounds, meta, fRecord->count());
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]);
89 SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
90 || (bbhBound.isEmpty() && fCullRect.isEmpty()));
94 size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
95 for (int i = 0; pictList && i < pictList->count(); i++) {
96 subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
98 return sk_make_sp<SkBigPicture>(fCullRect,
105 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect) {
106 fCullRect = cullRect;
107 return this->finishRecordingAsPicture();
111 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
112 if (nullptr == canvas) {
116 int drawableCount = 0;
117 SkDrawable* const* drawables = nullptr;
118 SkDrawableList* drawableList = fRecorder->getDrawableList();
120 drawableCount = drawableList->count();
121 drawables = drawableList->begin();
123 SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
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.
131 SkRecordOptimize(fRecord.get());
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());
140 sk_sp<SkDrawable> drawable =
141 sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH),
142 fRecorder->detachDrawableList(), fCullRect);