| /* | |
| * 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 "SkCanvasDrawable.h" | |
| #include "SkData.h" | |
| #include "SkLayerInfo.h" | |
| #include "SkPictureRecorder.h" | |
| #include "SkRecord.h" | |
| #include "SkRecordDraw.h" | |
| #include "SkRecorder.h" | |
| #include "SkRecordOpts.h" | |
| #include "SkTypes.h" | |
| SkPictureRecorder::SkPictureRecorder() {} | |
| SkPictureRecorder::~SkPictureRecorder() {} | |
| SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect, | |
| SkBBHFactory* bbhFactory /* = NULL */, | |
| uint32_t recordFlags /* = 0 */) { | |
| fCullRect = cullRect; | |
| fFlags = recordFlags; | |
| if (bbhFactory) { | |
| fBBH.reset((*bbhFactory)(cullRect)); | |
| SkASSERT(fBBH.get()); | |
| } | |
| fRecord.reset(SkNEW(SkRecord)); | |
| fRecorder.reset(SkNEW_ARGS(SkRecorder, (fRecord.get(), cullRect))); | |
| return this->getRecordingCanvas(); | |
| } | |
| SkCanvas* SkPictureRecorder::getRecordingCanvas() { | |
| return fRecorder.get(); | |
| } | |
| SkPicture* SkPictureRecorder::endRecordingAsPicture() { | |
| // TODO: delay as much of this work until just before first playback? | |
| SkRecordOptimize(fRecord); | |
| SkAutoTUnref<SkLayerInfo> saveLayerData; | |
| if (fBBH && (fFlags & kComputeSaveLayerInfo_RecordFlag)) { | |
| SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey(); | |
| saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key))); | |
| } | |
| SkCanvasDrawableList* drawableList = fRecorder->getDrawableList(); | |
| SkPicture::SnapshotArray* pictList = drawableList ? drawableList->newDrawableSnapshot() : NULL; | |
| if (fBBH.get()) { | |
| if (saveLayerData) { | |
| SkRecordComputeLayers(fCullRect, *fRecord, pictList, fBBH.get(), saveLayerData); | |
| } else { | |
| SkRecordFillBounds(fCullRect, *fRecord, fBBH.get()); | |
| } | |
| } | |
| SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord, pictList, fBBH)); | |
| if (saveLayerData) { | |
| pict->EXPERIMENTAL_addAccelData(saveLayerData); | |
| } | |
| // release our refs now, so only the picture will be the owner. | |
| fRecorder.reset(NULL); | |
| fRecord.reset(NULL); | |
| fBBH.reset(NULL); | |
| return pict; | |
| } | |
| void SkPictureRecorder::partialReplay(SkCanvas* canvas) const { | |
| if (NULL == canvas) { | |
| return; | |
| } | |
| int drawableCount = 0; | |
| SkCanvasDrawable* const* drawables = NULL; | |
| SkCanvasDrawableList* drawableList = fRecorder->getDrawableList(); | |
| if (drawableList) { | |
| drawableCount = drawableList->count(); | |
| drawables = drawableList->begin(); | |
| } | |
| SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, NULL/*bbh*/, NULL/*callback*/); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////////////////////////// | |
| class SkRecordedDrawable : public SkCanvasDrawable { | |
| SkAutoTUnref<SkRecord> fRecord; | |
| SkAutoTUnref<SkBBoxHierarchy> fBBH; | |
| SkAutoTDelete<SkCanvasDrawableList> fDrawableList; | |
| const SkRect fBounds; | |
| const bool fDoSaveLayerInfo; | |
| public: | |
| SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkCanvasDrawableList* drawableList, | |
| const SkRect& bounds, bool doSaveLayerInfo) | |
| : fRecord(SkRef(record)) | |
| , fBBH(SkSafeRef(bbh)) | |
| , fDrawableList(drawableList) // we take ownership | |
| , fBounds(bounds) | |
| , fDoSaveLayerInfo(doSaveLayerInfo) | |
| {} | |
| protected: | |
| SkRect onGetBounds() SK_OVERRIDE { return fBounds; } | |
| void onDraw(SkCanvas* canvas) SK_OVERRIDE { | |
| SkCanvasDrawable* const* drawables = NULL; | |
| int drawableCount = 0; | |
| if (fDrawableList) { | |
| drawables = fDrawableList->begin(); | |
| drawableCount = fDrawableList->count(); | |
| } | |
| SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, fBBH, NULL/*callback*/); | |
| } | |
| SkPicture* onNewPictureSnapshot() SK_OVERRIDE { | |
| SkPicture::SnapshotArray* pictList = NULL; | |
| if (fDrawableList) { | |
| // TODO: should we plumb-down the BBHFactory and recordFlags from our host | |
| // PictureRecorder? | |
| pictList = fDrawableList->newDrawableSnapshot(); | |
| } | |
| SkAutoTUnref<SkLayerInfo> saveLayerData; | |
| if (fBBH && fDoSaveLayerInfo) { | |
| SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey(); | |
| saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key))); | |
| SkBBoxHierarchy* bbh = NULL; // we've already computed fBBH (received in constructor) | |
| // TODO: update saveLayer info computation to reuse the already computed | |
| // bounds in 'fBBH' | |
| SkRecordComputeLayers(fBounds, *fRecord, pictList, bbh, saveLayerData); | |
| } | |
| SkPicture* pict = SkNEW_ARGS(SkPicture, (fBounds, fRecord, pictList, fBBH)); | |
| if (saveLayerData) { | |
| pict->EXPERIMENTAL_addAccelData(saveLayerData); | |
| } | |
| return pict; | |
| } | |
| }; | |
| SkCanvasDrawable* SkPictureRecorder::EXPERIMENTAL_endRecordingAsDrawable() { | |
| // TODO: delay as much of this work until just before first playback? | |
| SkRecordOptimize(fRecord); | |
| if (fBBH.get()) { | |
| SkRecordFillBounds(fCullRect, *fRecord, fBBH.get()); | |
| } | |
| SkCanvasDrawable* drawable = SkNEW_ARGS(SkRecordedDrawable, | |
| (fRecord, fBBH, fRecorder->detachDrawableList(), | |
| fCullRect, | |
| SkToBool(fFlags & kComputeSaveLayerInfo_RecordFlag))); | |
| // release our refs now, so only the drawable will be the owner. | |
| fRecorder.reset(NULL); | |
| fRecord.reset(NULL); | |
| fBBH.reset(NULL); | |
| return drawable; | |
| } |