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