1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2014 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBigPicture.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkData.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDrawable.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMiniRecorder.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPictureRecorder.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRecord.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRecordDraw.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRecordOpts.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRecordedDrawable.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRecorder.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypes.h"
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkPictureRecorder::SkPictureRecorder() {
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fActivelyRecording = false;
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fMiniRecorder.reset(new SkMiniRecorder);
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRecorder.reset(new SkRecorder(nullptr, SkRect::MakeEmpty(), fMiniRecorder.get()));
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkPictureRecorder::~SkPictureRecorder() {}
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkCanvas* SkPictureRecorder::beginRecording(const SkRect& userCullRect,
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            SkBBHFactory* bbhFactory /* = nullptr */,
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            uint32_t recordFlags /* = 0 */) {
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkRect cullRect = userCullRect.isEmpty() ? SkRect::MakeEmpty() : userCullRect;
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCullRect = cullRect;
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fFlags = recordFlags;
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (bbhFactory) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBBH.reset((*bbhFactory)(cullRect));
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT(fBBH.get());
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!fRecord) {
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fRecord.reset(new SkRecord);
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRecorder::DrawPictureMode dpm = (recordFlags & kPlaybackDrawPicture_RecordFlag)
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ? SkRecorder::Playback_DrawPictureMode
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        : SkRecorder::Record_DrawPictureMode;
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRecorder->reset(fRecord.get(), cullRect, dpm, fMiniRecorder.get());
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fActivelyRecording = true;
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return this->getRecordingCanvas();
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkCanvas* SkPictureRecorder::getRecordingCanvas() {
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fActivelyRecording ? fRecorder.get() : nullptr;
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPicture(uint32_t finishFlags) {
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fActivelyRecording = false;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fRecord->count() == 0) {
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        auto pic = fMiniRecorder->detachAsPicture(fBBH ? nullptr : &fCullRect);
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBBH.reset(nullptr);
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return pic;
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // TODO: delay as much of this work until just before first playback?
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRecordOptimize(fRecord.get());
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDrawableList* drawableList = fRecorder->getDrawableList();
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBigPicture::SnapshotArray* pictList =
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        drawableList ? drawableList->newDrawableSnapshot() : nullptr;
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fBBH.get()) {
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkAutoTMalloc<SkRect> bounds(fRecord->count());
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkRecordFillBounds(fCullRect, *fRecord, bounds);
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBBH->insert(bounds, fRecord->count());
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Now that we've calculated content bounds, we can update fCullRect, often trimming it.
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // TODO: get updated fCullRect from bounds instead of forcing the BBH to return it?
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkRect bbhBound = fBBH->getRootBound();
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            || (bbhBound.isEmpty() && fCullRect.isEmpty()));
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fCullRect = bbhBound;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t subPictureBytes = fRecorder->approxBytesUsedBySubPictures();
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; pictList && i < pictList->count(); i++) {
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        subPictureBytes += pictList->begin()[i]->approximateBytesUsed();
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return sk_make_sp<SkBigPicture>(fCullRect, fRecord.release(), pictList, fBBH.release(),
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                    subPictureBytes);
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkPicture> SkPictureRecorder::finishRecordingAsPictureWithCull(const SkRect& cullRect,
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                     uint32_t finishFlags) {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fCullRect = cullRect;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return this->finishRecordingAsPicture(finishFlags);
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == canvas) {
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int drawableCount = 0;
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDrawable* const* drawables = nullptr;
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDrawableList* drawableList = fRecorder->getDrawableList();
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (drawableList) {
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        drawableCount = drawableList->count();
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        drawables = drawableList->begin();
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRecordDraw(*fRecord, canvas, nullptr, drawables, drawableCount, nullptr/*bbh*/, nullptr/*callback*/);
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsk_sp<SkDrawable> SkPictureRecorder::finishRecordingAsDrawable(uint32_t finishFlags) {
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fActivelyRecording = false;
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRecorder->flushMiniRecorder();
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRecordOptimize(fRecord.get());
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fBBH.get()) {
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkAutoTMalloc<SkRect> bounds(fRecord->count());
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkRecordFillBounds(fCullRect, *fRecord, bounds);
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fBBH->insert(bounds, fRecord->count());
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkDrawable> drawable =
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         sk_make_sp<SkRecordedDrawable>(std::move(fRecord), std::move(fBBH),
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                        fRecorder->detachDrawableList(), fCullRect);
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return drawable;
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
135