StatefulBaseRenderer.cpp revision 14e513058ed4168c94e015638d16f5f87fd8063a
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <SkCanvas.h>
18
19#include "StatefulBaseRenderer.h"
20
21namespace android {
22namespace uirenderer {
23
24StatefulBaseRenderer::StatefulBaseRenderer() :
25        mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot) {
26}
27
28void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
29        float clipRight, float clipBottom) {
30    mSnapshot = new Snapshot(mFirstSnapshot,
31            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
32    mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
33    mSnapshot->fbo = getTargetFbo();
34    mSaveCount = 1;
35}
36
37void StatefulBaseRenderer::initializeViewport(int width, int height) {
38    mWidth = width;
39    mHeight = height;
40
41    mFirstSnapshot->height = height;
42    mFirstSnapshot->viewport.set(0, 0, width, height);
43}
44
45///////////////////////////////////////////////////////////////////////////////
46// Save (layer)
47///////////////////////////////////////////////////////////////////////////////
48
49/**
50 * Non-virtual implementation of save, guaranteed to save without side-effects
51 *
52 * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
53 * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
54 */
55int StatefulBaseRenderer::saveSnapshot(int flags) {
56    mSnapshot = new Snapshot(mSnapshot, flags);
57    return mSaveCount++;
58}
59
60int StatefulBaseRenderer::save(int flags) {
61    return saveSnapshot(flags);
62}
63
64/**
65 * Non-virtual implementation of restore, guaranteed to restore without side-effects.
66 */
67void StatefulBaseRenderer::restoreSnapshot() {
68    sp<Snapshot> toRemove = mSnapshot;
69    sp<Snapshot> toRestore = mSnapshot->previous;
70
71    mSaveCount--;
72    mSnapshot = toRestore;
73
74    // subclass handles restore implementation
75    onSnapshotRestored(*toRemove, *toRestore);
76}
77
78void StatefulBaseRenderer::restore() {
79    if (mSaveCount > 1) {
80        restoreSnapshot();
81    }
82}
83
84void StatefulBaseRenderer::restoreToCount(int saveCount) {
85    if (saveCount < 1) saveCount = 1;
86
87    while (mSaveCount > saveCount) {
88        restoreSnapshot();
89    }
90}
91
92///////////////////////////////////////////////////////////////////////////////
93// Matrix
94///////////////////////////////////////////////////////////////////////////////
95
96void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
97    mSnapshot->transform->copyTo(*matrix);
98}
99
100void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
101    mSnapshot->transform->translate(dx, dy, dz);
102}
103
104void StatefulBaseRenderer::rotate(float degrees) {
105    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
106}
107
108void StatefulBaseRenderer::scale(float sx, float sy) {
109    mSnapshot->transform->scale(sx, sy, 1.0f);
110}
111
112void StatefulBaseRenderer::skew(float sx, float sy) {
113    mSnapshot->transform->skew(sx, sy);
114}
115
116void StatefulBaseRenderer::setMatrix(SkMatrix* matrix) {
117    if (matrix) {
118        mSnapshot->transform->load(*matrix);
119    } else {
120        mSnapshot->transform->loadIdentity();
121    }
122}
123
124void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
125    mSnapshot->transform->load(matrix);
126}
127
128void StatefulBaseRenderer::concatMatrix(SkMatrix* matrix) {
129    mat4 transform(*matrix);
130    mSnapshot->transform->multiply(transform);
131}
132
133void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
134    mSnapshot->transform->multiply(matrix);
135}
136
137///////////////////////////////////////////////////////////////////////////////
138// Clip
139///////////////////////////////////////////////////////////////////////////////
140
141
142///////////////////////////////////////////////////////////////////////////////
143// Quick Rejection
144///////////////////////////////////////////////////////////////////////////////
145
146/**
147 * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
148 * the clipRect. Does not modify the scissor.
149 *
150 * @param clipRequired if not null, will be set to true if element intersects clip
151 *         (and wasn't rejected)
152 *
153 * @param snapOut if set, the geometry will be treated as having an AA ramp.
154 *         See Rect::snapGeometryToPixelBoundaries()
155 */
156bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
157        float right, float bottom, bool* clipRequired, bool snapOut) const {
158    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
159        return true;
160    }
161
162    Rect r(left, top, right, bottom);
163    currentTransform().mapRect(r);
164    r.snapGeometryToPixelBoundaries(snapOut);
165
166    Rect clipRect(currentClipRect());
167    clipRect.snapToPixelBoundaries();
168
169    if (!clipRect.intersects(r)) return true;
170
171    // clip is required if geometry intersects clip rect
172    if (clipRequired) *clipRequired = !clipRect.contains(r);
173    return false;
174}
175
176/**
177 * Returns false if drawing won't be clipped out.
178 *
179 * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
180 * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
181 * rejection is still desired.
182 *
183 * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
184 * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
185 * rejection where precise rejection isn't important, or precise information isn't available.
186 */
187bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
188        float right, float bottom) const {
189    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
190        return true;
191    }
192
193    Rect r(left, top, right, bottom);
194    currentTransform().mapRect(r);
195    r.roundOut(); // rounded out to be conservative
196
197    Rect clipRect(currentClipRect());
198    clipRect.snapToPixelBoundaries();
199
200    if (!clipRect.intersects(r)) return true;
201
202    return false;
203}
204
205}; // namespace uirenderer
206}; // namespace android
207