/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkBigPicture.h" #include "SkData.h" #include "SkDrawable.h" #include "SkMiniRecorder.h" #include "SkPictureRecorder.h" #include "SkRecord.h" #include "SkRecordDraw.h" #include "SkRecordOpts.h" #include "SkRecordedDrawable.h" #include "SkRecorder.h" #include "SkTypes.h" SkPictureRecorder::SkPictureRecorder() { fActivelyRecording = false; fMiniRecorder.reset(new SkMiniRecorder); fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get())); } SkPictureRecorder::~SkPictureRecorder() {} SkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect, SkBBHFactory* bbhFactory /* = nullptr */, uint32_t recordFlags /* = 0 */) { const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect; fCullRect = cullRect; fFlags = recordFlags; if (bbhFactory) { fBBH.reset((*bbhFactory)(cullRect)); SkASSERT(fBBH.get()); } if (!fRecord) { fRecord.reset(new SkRecord); } SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag) ? SkRecorder::Playback_DrawPictureMode : SkRecorder::Record_DrawPictureMode; fRecorder->reset(fRecord.get(), cullRect, dpm, fMiniRecorder.get()); fActivelyRecording = true; return this->getRecordingCanvas(); } SkCanvas* SkPictureRecorder::getRecordingCanvas() { return fActivelyRecording ? fRecorder.get() : nullptr; } sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) { fActivelyRecording = false; fRecorder->restoreToCount(1); // If we were missing any restores, add them now. if (fRecord->count() == 0) { auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect); fBBH.reset(nullptr); return pic; } // TODO: delay as much of this work until just before first playback? SkRecordOptimize(fRecord.get()); SkDrawableList* drawableList = fRecorder->getDrawableList(); SkBigPicture::SnapshotArray* pictList = drawableList ? drawableList->newDrawableSnapshot() : nullptr; if (fBBH.get()) { SkAutoTMalloc<SkRect> bounds(fRecord->count()); SkRecordFillBounds(fCullRect, *fRecord, bounds); fBBH->insert(bounds, fRecord->count()); // Now that we've calculated content bounds, we can update fCullRect, often trimming it. // TODO: get updated fCullRect from bounds instead of forcing the BBH to return it? SkRect bbhBound = fBBH->getRootBound(); SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound)) || (bbhBound.isEmpty() && fCullRect.isEmpty())); fCullRect = bbhBound; } size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures(); for (int i = 0; pictList && i < pictList->count(); i++) { subPictureBytes += pictList->begin()[i]->approximateBytesUsed(); } return sk_make_sp<SkBigPicture>(fCullRect, fRecord.release(), pictList, fBBH.release(), subPictureBytes); } sk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect, uint32_t finishFlags) { fCullRect = cullRect; return this->finishRecordingAsPicture(finishFlags); } void SkPictureRecorder::partialReplay(SkCanvas* canvas) const { if (nullptr == canvas) { return; } int drawableCount = 0; SkDrawable* const* drawables = nullptr; SkDrawableList* drawableList = fRecorder->getDrawableList(); if (drawableList) { drawableCount = drawableList->count(); drawables = drawableList->begin(); } SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/); } sk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) { fActivelyRecording = false; fRecorder->flushMiniRecorder(); fRecorder->restoreToCount(1); // If we were missing any restores, add them now. SkRecordOptimize(fRecord.get()); if (fBBH.get()) { SkAutoTMalloc<SkRect> bounds(fRecord->count()); SkRecordFillBounds(fCullRect, *fRecord, bounds); fBBH->insert(bounds, fRecord->count()); } sk_sp<SkDrawable> drawable = sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH), fRecorder->detachDrawableList(), fCullRect); return drawable; }