blob: cc8b14fafb9264785bf32c9e5d93edb8edc9bf78 [file] [log] [blame]
Chris Craik14e51302013-12-30 15:32:54 -08001/*
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