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