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 20 SkPictureRecorder::SkPictureRecorder() { 21 fActivelyRecording = false; 22 fMiniRecorder.reset(new SkMiniRecorder); 23 fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get())); 24 } 25 26 SkPictureRecorder::~SkPictureRecorder() {} 27 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 52 SkCanvas* SkPictureRecorder::getRecordingCanvas() { 53 return fActivelyRecording ? fRecorder.get() : nullptr; 54 } 55 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 94 sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect, 95 uint32_t finishFlags) { 96 fCullRect = cullRect; 97 return this->finishRecordingAsPicture(finishFlags); 98 } 99 100 101 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 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