StatefulBaseRenderer.cpp revision a64a2bef1048db5a742843f1e3bea9e80d0defc5
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        mDirtyClip(false), mWidth(-1), mHeight(-1),
26        mSaveCount(1), mFirstSnapshot(new Snapshot), mSnapshot(mFirstSnapshot) {
27}
28
29void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
30        float clipRight, float clipBottom) {
31    mSnapshot = new Snapshot(mFirstSnapshot,
32            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
33    mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
34    mSnapshot->fbo = getTargetFbo();
35    mSaveCount = 1;
36}
37
38void StatefulBaseRenderer::initializeViewport(int width, int height) {
39    mWidth = width;
40    mHeight = height;
41    mFirstSnapshot->initializeViewport(width, height);
42}
43
44///////////////////////////////////////////////////////////////////////////////
45// Save (layer)
46///////////////////////////////////////////////////////////////////////////////
47
48/**
49 * Non-virtual implementation of save, guaranteed to save without side-effects
50 *
51 * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
52 * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
53 */
54int StatefulBaseRenderer::saveSnapshot(int flags) {
55    mSnapshot = new Snapshot(mSnapshot, flags);
56    return mSaveCount++;
57}
58
59int StatefulBaseRenderer::save(int flags) {
60    return saveSnapshot(flags);
61}
62
63/**
64 * Non-virtual implementation of restore, guaranteed to restore without side-effects.
65 */
66void StatefulBaseRenderer::restoreSnapshot() {
67    sp<Snapshot> toRemove = mSnapshot;
68    sp<Snapshot> toRestore = mSnapshot->previous;
69
70    mSaveCount--;
71    mSnapshot = toRestore;
72
73    // subclass handles restore implementation
74    onSnapshotRestored(*toRemove, *toRestore);
75}
76
77void StatefulBaseRenderer::restore() {
78    if (mSaveCount > 1) {
79        restoreSnapshot();
80    }
81}
82
83void StatefulBaseRenderer::restoreToCount(int saveCount) {
84    if (saveCount < 1) saveCount = 1;
85
86    while (mSaveCount > saveCount) {
87        restoreSnapshot();
88    }
89}
90
91///////////////////////////////////////////////////////////////////////////////
92// Matrix
93///////////////////////////////////////////////////////////////////////////////
94
95void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
96    mSnapshot->transform->copyTo(*matrix);
97}
98
99void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
100    mSnapshot->transform->translate(dx, dy, dz);
101}
102
103void StatefulBaseRenderer::rotate(float degrees) {
104    mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
105}
106
107void StatefulBaseRenderer::scale(float sx, float sy) {
108    mSnapshot->transform->scale(sx, sy, 1.0f);
109}
110
111void StatefulBaseRenderer::skew(float sx, float sy) {
112    mSnapshot->transform->skew(sx, sy);
113}
114
115void StatefulBaseRenderer::setMatrix(const SkMatrix* matrix) {
116    if (matrix) {
117        mSnapshot->transform->load(*matrix);
118    } else {
119        mSnapshot->transform->loadIdentity();
120    }
121}
122
123void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
124    mSnapshot->transform->load(matrix);
125}
126
127void StatefulBaseRenderer::concatMatrix(const SkMatrix* matrix) {
128    mat4 transform(*matrix);
129    mSnapshot->transform->multiply(transform);
130}
131
132void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
133    mSnapshot->transform->multiply(matrix);
134}
135
136///////////////////////////////////////////////////////////////////////////////
137// Clip
138///////////////////////////////////////////////////////////////////////////////
139
140bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
141    if (CC_LIKELY(currentTransform()->rectToRect())) {
142        mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
143        return !mSnapshot->clipRect->isEmpty();
144    }
145
146    SkPath path;
147    path.addRect(left, top, right, bottom);
148
149    return StatefulBaseRenderer::clipPath(&path, op);
150}
151
152bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
153    SkMatrix transform;
154    currentTransform()->copyTo(transform);
155
156    SkPath transformed;
157    path->transform(transform, &transformed);
158
159    SkRegion clip;
160    if (!mSnapshot->previous->clipRegion->isEmpty()) {
161        clip.setRegion(*mSnapshot->previous->clipRegion);
162    } else {
163        if (mSnapshot->previous == firstSnapshot()) {
164            clip.setRect(0, 0, getWidth(), getHeight());
165        } else {
166            Rect* bounds = mSnapshot->previous->clipRect;
167            clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
168        }
169    }
170
171    SkRegion region;
172    region.setPath(transformed, clip);
173
174    mDirtyClip |= mSnapshot->clipRegionTransformed(region, op);
175    return !mSnapshot->clipRect->isEmpty();
176}
177
178bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
179    mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
180    return !mSnapshot->clipRect->isEmpty();
181}
182
183///////////////////////////////////////////////////////////////////////////////
184// Quick Rejection
185///////////////////////////////////////////////////////////////////////////////
186
187/**
188 * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
189 * the clipRect. Does not modify the scissor.
190 *
191 * @param clipRequired if not null, will be set to true if element intersects clip
192 *         (and wasn't rejected)
193 *
194 * @param snapOut if set, the geometry will be treated as having an AA ramp.
195 *         See Rect::snapGeometryToPixelBoundaries()
196 */
197bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
198        float right, float bottom, bool* clipRequired, bool snapOut) const {
199    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
200        return true;
201    }
202
203    Rect r(left, top, right, bottom);
204    currentTransform()->mapRect(r);
205    r.snapGeometryToPixelBoundaries(snapOut);
206
207    Rect clipRect(*currentClipRect());
208    clipRect.snapToPixelBoundaries();
209
210    if (!clipRect.intersects(r)) return true;
211
212    // clip is required if geometry intersects clip rect
213    if (clipRequired) *clipRequired = !clipRect.contains(r);
214    return false;
215}
216
217/**
218 * Returns false if drawing won't be clipped out.
219 *
220 * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
221 * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
222 * rejection is still desired.
223 *
224 * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
225 * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
226 * rejection where precise rejection isn't important, or precise information isn't available.
227 */
228bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
229        float right, float bottom) const {
230    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
231        return true;
232    }
233
234    Rect r(left, top, right, bottom);
235    currentTransform()->mapRect(r);
236    r.roundOut(); // rounded out to be conservative
237
238    Rect clipRect(*currentClipRect());
239    clipRect.snapToPixelBoundaries();
240
241    if (!clipRect.intersects(r)) return true;
242
243    return false;
244}
245
246}; // namespace uirenderer
247}; // namespace android
248