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 22SkPictureRecorder::SkPictureRecorder() { 23 fActivelyRecording = false; 24 fMiniRecorder = std::make_unique<SkMiniRecorder>(); 25 fRecorder = std::make_unique<SkRecorder>(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get()); 26} 27 28SkPictureRecorder::~SkPictureRecorder() {} 29 30SkCanvas* 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 45SkCanvas* SkPictureRecorder::beginRecording(const SkRect& bounds, SkBBHFactory* factory) { 46 return this->beginRecording(bounds, factory ? (*factory)() : nullptr); 47} 48 49SkCanvas* SkPictureRecorder::getRecordingCanvas() { 50 return fActivelyRecording ? fRecorder.get() : nullptr; 51} 52 53sk_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 105sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect) { 106 fCullRect = cullRect; 107 return this->finishRecordingAsPicture(); 108} 109 110 111void 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 126sk_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