blob: aa83e20cd8a57a86ec90ca9f5953d8998b0a82a5 [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() :
Chris Craikd6b65f62014-01-01 14:45:21 -080025 mDirtyClip(false), mWidth(-1), mHeight(-1),
Chris Craik14e51302013-12-30 15:32:54 -080026 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;
Chris Craika64a2be2014-05-14 14:17:01 -070041 mFirstSnapshot->initializeViewport(width, height);
Chris Craik14e51302013-12-30 15:32:54 -080042}
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
Chris Craikd218a922014-01-02 17:13:34 -0800115void StatefulBaseRenderer::setMatrix(const SkMatrix* matrix) {
Chris Craik14e51302013-12-30 15:32:54 -0800116 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
Chris Craikd218a922014-01-02 17:13:34 -0800127void StatefulBaseRenderer::concatMatrix(const SkMatrix* matrix) {
Chris Craik14e51302013-12-30 15:32:54 -0800128 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
Chris Craikd6b65f62014-01-01 14:45:21 -0800140bool 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
Chris Craikd218a922014-01-02 17:13:34 -0800152bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800153 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
Chris Craikd218a922014-01-02 17:13:34 -0800178bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800179 mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
180 return !mSnapshot->clipRect->isEmpty();
181}
Chris Craik14e51302013-12-30 15:32:54 -0800182
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);
Chris Craikd6b65f62014-01-01 14:45:21 -0800204 currentTransform()->mapRect(r);
Chris Craik14e51302013-12-30 15:32:54 -0800205 r.snapGeometryToPixelBoundaries(snapOut);
206
Chris Craikd6b65f62014-01-01 14:45:21 -0800207 Rect clipRect(*currentClipRect());
Chris Craik14e51302013-12-30 15:32:54 -0800208 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);
Chris Craikd6b65f62014-01-01 14:45:21 -0800235 currentTransform()->mapRect(r);
Chris Craik14e51302013-12-30 15:32:54 -0800236 r.roundOut(); // rounded out to be conservative
237
Chris Craikd6b65f62014-01-01 14:45:21 -0800238 Rect clipRect(*currentClipRect());
Chris Craik14e51302013-12-30 15:32:54 -0800239 clipRect.snapToPixelBoundaries();
240
241 if (!clipRect.intersects(r)) return true;
242
243 return false;
244}
245
246}; // namespace uirenderer
247}; // namespace android