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