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 "SkLayerInfo.h" 12 #include "SkPictureRecorder.h" 13 #include "SkPictureUtils.h" 14 #include "SkRecord.h" 15 #include "SkRecordDraw.h" 16 #include "SkRecordOpts.h" 17 #include "SkRecorder.h" 18 #include "SkTypes.h" 19 20 SkPictureRecorder::SkPictureRecorder() { 21 fActivelyRecording = false; 22 fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeWH(0, 0), &fMiniRecorder)); 23 } 24 25 SkPictureRecorder::~SkPictureRecorder() {} 26 27 SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect, 28 SkBBHFactory* bbhFactory /* = nullptr */, 29 uint32_t recordFlags /* = 0 */) { 30 fCullRect = cullRect; 31 fFlags = recordFlags; 32 33 if (bbhFactory) { 34 fBBH.reset((*bbhFactory)(cullRect)); 35 SkASSERT(fBBH.get()); 36 } 37 38 if (!fRecord) { 39 fRecord.reset(new SkRecord); 40 } 41 SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag) 42 ? SkRecorder::Playback_DrawPictureMode 43 : SkRecorder::Record_DrawPictureMode; 44 fRecorder->reset(fRecord.get(), cullRect, dpm, &fMiniRecorder); 45 fActivelyRecording = true; 46 return this->getRecordingCanvas(); 47 } 48 49 SkCanvas* SkPictureRecorder::getRecordingCanvas() { 50 return fActivelyRecording ? fRecorder.get() : nullptr; 51 } 52 53 SkPicture* SkPictureRecorder::endRecordingAsPicture() { 54 fActivelyRecording = false; 55 fRecorder->restoreToCount(1); // If we were missing any restores, add them now. 56 57 if (fRecord->count() == 0) { 58 return fMiniRecorder.detachAsPicture(fCullRect); 59 } 60 61 // TODO: delay as much of this work until just before first playback? 62 SkRecordOptimize(fRecord); 63 64 SkAutoTUnref<SkLayerInfo> saveLayerData; 65 66 if (fBBH && (fFlags & kComputeSaveLayerInfo_RecordFlag)) { 67 saveLayerData.reset(new SkLayerInfo); 68 } 69 70 SkDrawableList* drawableList = fRecorder->getDrawableList(); 71 SkBigPicture::SnapshotArray* pictList = 72 drawableList ? drawableList->newDrawableSnapshot() : nullptr; 73 74 if (fBBH.get()) { 75 SkAutoTMalloc<SkRect> bounds(fRecord->count()); 76 if (saveLayerData) { 77 SkRecordComputeLayers(fCullRect, *fRecord, bounds, pictList, saveLayerData); 78 } else { 79 SkRecordFillBounds(fCullRect, *fRecord, bounds); 80 } 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 += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]); 94 } 95 return new SkBigPicture(fCullRect, fRecord.detach(), pictList, fBBH.detach(), 96 saveLayerData.detach(), subPictureBytes); 97 } 98 99 SkPicture* SkPictureRecorder::endRecordingAsPicture(const SkRect& cullRect) { 100 fCullRect = cullRect; 101 return this->endRecordingAsPicture(); 102 } 103 104 105 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const { 106 if (nullptr == canvas) { 107 return; 108 } 109 110 int drawableCount = 0; 111 SkDrawable* const* drawables = nullptr; 112 SkDrawableList* drawableList = fRecorder->getDrawableList(); 113 if (drawableList) { 114 drawableCount = drawableList->count(); 115 drawables = drawableList->begin(); 116 } 117 SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/); 118 } 119 120 /////////////////////////////////////////////////////////////////////////////////////////////////// 121 122 class SkRecordedDrawable : public SkDrawable { 123 SkAutoTUnref<SkRecord> fRecord; 124 SkAutoTUnref<SkBBoxHierarchy> fBBH; 125 SkAutoTDelete<SkDrawableList> fDrawableList; 126 const SkRect fBounds; 127 const bool fDoSaveLayerInfo; 128 129 public: 130 SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkDrawableList* drawableList, 131 const SkRect& bounds, bool doSaveLayerInfo) 132 : fRecord(SkRef(record)) 133 , fBBH(SkSafeRef(bbh)) 134 , fDrawableList(drawableList) // we take ownership 135 , fBounds(bounds) 136 , fDoSaveLayerInfo(doSaveLayerInfo) 137 {} 138 139 protected: 140 SkRect onGetBounds() override { return fBounds; } 141 142 void onDraw(SkCanvas* canvas) override { 143 SkDrawable* const* drawables = nullptr; 144 int drawableCount = 0; 145 if (fDrawableList) { 146 drawables = fDrawableList->begin(); 147 drawableCount = fDrawableList->count(); 148 } 149 SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, fBBH, nullptr/*callback*/); 150 } 151 152 SkPicture* onNewPictureSnapshot() override { 153 SkBigPicture::SnapshotArray* pictList = nullptr; 154 if (fDrawableList) { 155 // TODO: should we plumb-down the BBHFactory and recordFlags from our host 156 // PictureRecorder? 157 pictList = fDrawableList->newDrawableSnapshot(); 158 } 159 160 SkAutoTUnref<SkLayerInfo> saveLayerData; 161 if (fBBH && fDoSaveLayerInfo) { 162 // TODO: can we avoid work by not allocating / filling these bounds? 163 SkAutoTMalloc<SkRect> scratchBounds(fRecord->count()); 164 saveLayerData.reset(new SkLayerInfo); 165 166 SkRecordComputeLayers(fBounds, *fRecord, scratchBounds, pictList, saveLayerData); 167 } 168 169 size_t subPictureBytes = 0; 170 for (int i = 0; pictList && i < pictList->count(); i++) { 171 subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]); 172 } 173 // SkBigPicture will take ownership of a ref on both fRecord and fBBH. 174 // We're not willing to give up our ownership, so we must ref them for SkPicture. 175 return new SkBigPicture(fBounds, SkRef(fRecord.get()), pictList, SkSafeRef(fBBH.get()), 176 saveLayerData.detach(), subPictureBytes); 177 } 178 }; 179 180 SkDrawable* SkPictureRecorder::endRecordingAsDrawable() { 181 fActivelyRecording = false; 182 fRecorder->flushMiniRecorder(); 183 fRecorder->restoreToCount(1); // If we were missing any restores, add them now. 184 185 // TODO: delay as much of this work until just before first playback? 186 SkRecordOptimize(fRecord); 187 188 if (fBBH.get()) { 189 SkAutoTMalloc<SkRect> bounds(fRecord->count()); 190 SkRecordFillBounds(fCullRect, *fRecord, bounds); 191 fBBH->insert(bounds, fRecord->count()); 192 } 193 194 SkDrawable* drawable = 195 new SkRecordedDrawable(fRecord, fBBH, fRecorder->detachDrawableList(), fCullRect, 196 SkToBool(fFlags & kComputeSaveLayerInfo_RecordFlag)); 197 198 // release our refs now, so only the drawable will be the owner. 199 fRecord.reset(nullptr); 200 fBBH.reset(nullptr); 201 202 return drawable; 203 } 204