blob: 140c6e82f5385851d04a4cbb4c8bae0cfd688274 [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
Chris Craikdeeda3d2014-05-05 19:09:33 -070017#define LOG_TAG "OpenGLRenderer"
18
Chris Craik14e51302013-12-30 15:32:54 -080019#include <SkCanvas.h>
20
21#include "StatefulBaseRenderer.h"
22
23namespace android {
24namespace uirenderer {
25
Chris Craik058fc642014-07-23 18:19:28 -070026StatefulBaseRenderer::StatefulBaseRenderer()
27 : mDirtyClip(false)
28 , mWidth(-1)
29 , mHeight(-1)
30 , mSaveCount(1)
31 , mFirstSnapshot(new Snapshot)
32 , mSnapshot(mFirstSnapshot) {
Chris Craik14e51302013-12-30 15:32:54 -080033}
34
35void StatefulBaseRenderer::initializeSaveStack(float clipLeft, float clipTop,
36 float clipRight, float clipBottom) {
37 mSnapshot = new Snapshot(mFirstSnapshot,
38 SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
39 mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
40 mSnapshot->fbo = getTargetFbo();
41 mSaveCount = 1;
42}
43
Chris Craik797b95b2014-05-20 18:10:25 -070044void StatefulBaseRenderer::setViewport(int width, int height) {
Chris Craik14e51302013-12-30 15:32:54 -080045 mWidth = width;
46 mHeight = height;
Chris Craika64a2be2014-05-14 14:17:01 -070047 mFirstSnapshot->initializeViewport(width, height);
Chris Craik797b95b2014-05-20 18:10:25 -070048 onViewportInitialized();
49}
50
Chris Craik14e51302013-12-30 15:32:54 -080051///////////////////////////////////////////////////////////////////////////////
52// Save (layer)
53///////////////////////////////////////////////////////////////////////////////
54
55/**
56 * Non-virtual implementation of save, guaranteed to save without side-effects
57 *
58 * The approach here and in restoreSnapshot(), allows subclasses to directly manipulate the save
59 * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
60 */
61int StatefulBaseRenderer::saveSnapshot(int flags) {
62 mSnapshot = new Snapshot(mSnapshot, flags);
63 return mSaveCount++;
64}
65
66int StatefulBaseRenderer::save(int flags) {
67 return saveSnapshot(flags);
68}
69
70/**
71 * Non-virtual implementation of restore, guaranteed to restore without side-effects.
72 */
73void StatefulBaseRenderer::restoreSnapshot() {
74 sp<Snapshot> toRemove = mSnapshot;
75 sp<Snapshot> toRestore = mSnapshot->previous;
76
77 mSaveCount--;
78 mSnapshot = toRestore;
79
80 // subclass handles restore implementation
81 onSnapshotRestored(*toRemove, *toRestore);
82}
83
84void StatefulBaseRenderer::restore() {
85 if (mSaveCount > 1) {
86 restoreSnapshot();
87 }
88}
89
90void StatefulBaseRenderer::restoreToCount(int saveCount) {
91 if (saveCount < 1) saveCount = 1;
92
93 while (mSaveCount > saveCount) {
94 restoreSnapshot();
95 }
96}
97
98///////////////////////////////////////////////////////////////////////////////
99// Matrix
100///////////////////////////////////////////////////////////////////////////////
101
Chris Craik05f3d6e2014-06-02 16:27:04 -0700102void StatefulBaseRenderer::getMatrix(Matrix4* matrix) const {
103 matrix->load(*(mSnapshot->transform));
104}
105
Chris Craik14e51302013-12-30 15:32:54 -0800106void StatefulBaseRenderer::getMatrix(SkMatrix* matrix) const {
107 mSnapshot->transform->copyTo(*matrix);
108}
109
110void StatefulBaseRenderer::translate(float dx, float dy, float dz) {
111 mSnapshot->transform->translate(dx, dy, dz);
112}
113
114void StatefulBaseRenderer::rotate(float degrees) {
115 mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
116}
117
118void StatefulBaseRenderer::scale(float sx, float sy) {
119 mSnapshot->transform->scale(sx, sy, 1.0f);
120}
121
122void StatefulBaseRenderer::skew(float sx, float sy) {
123 mSnapshot->transform->skew(sx, sy);
124}
125
Derek Sollenberger13908822013-12-10 12:28:58 -0500126void StatefulBaseRenderer::setMatrix(const SkMatrix& matrix) {
127 mSnapshot->transform->load(matrix);
Chris Craik14e51302013-12-30 15:32:54 -0800128}
129
130void StatefulBaseRenderer::setMatrix(const Matrix4& matrix) {
131 mSnapshot->transform->load(matrix);
132}
133
Derek Sollenberger13908822013-12-10 12:28:58 -0500134void StatefulBaseRenderer::concatMatrix(const SkMatrix& matrix) {
135 mat4 transform(matrix);
Chris Craik14e51302013-12-30 15:32:54 -0800136 mSnapshot->transform->multiply(transform);
137}
138
139void StatefulBaseRenderer::concatMatrix(const Matrix4& matrix) {
140 mSnapshot->transform->multiply(matrix);
141}
142
143///////////////////////////////////////////////////////////////////////////////
144// Clip
145///////////////////////////////////////////////////////////////////////////////
146
Chris Craikd6b65f62014-01-01 14:45:21 -0800147bool StatefulBaseRenderer::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
148 if (CC_LIKELY(currentTransform()->rectToRect())) {
149 mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
150 return !mSnapshot->clipRect->isEmpty();
151 }
152
153 SkPath path;
154 path.addRect(left, top, right, bottom);
155
156 return StatefulBaseRenderer::clipPath(&path, op);
157}
158
Chris Craikd218a922014-01-02 17:13:34 -0800159bool StatefulBaseRenderer::clipPath(const SkPath* path, SkRegion::Op op) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800160 SkMatrix transform;
161 currentTransform()->copyTo(transform);
162
163 SkPath transformed;
164 path->transform(transform, &transformed);
165
166 SkRegion clip;
167 if (!mSnapshot->previous->clipRegion->isEmpty()) {
168 clip.setRegion(*mSnapshot->previous->clipRegion);
169 } else {
170 if (mSnapshot->previous == firstSnapshot()) {
171 clip.setRect(0, 0, getWidth(), getHeight());
172 } else {
173 Rect* bounds = mSnapshot->previous->clipRect;
174 clip.setRect(bounds->left, bounds->top, bounds->right, bounds->bottom);
175 }
176 }
177
178 SkRegion region;
179 region.setPath(transformed, clip);
180
181 mDirtyClip |= mSnapshot->clipRegionTransformed(region, op);
182 return !mSnapshot->clipRect->isEmpty();
183}
184
Chris Craikd218a922014-01-02 17:13:34 -0800185bool StatefulBaseRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) {
Chris Craikd6b65f62014-01-01 14:45:21 -0800186 mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
187 return !mSnapshot->clipRect->isEmpty();
188}
Chris Craik14e51302013-12-30 15:32:54 -0800189
Chris Craikdeeda3d2014-05-05 19:09:33 -0700190void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
191 mSnapshot->setClippingOutline(allocator, outline);
192}
193
Chris Craik14e51302013-12-30 15:32:54 -0800194///////////////////////////////////////////////////////////////////////////////
195// Quick Rejection
196///////////////////////////////////////////////////////////////////////////////
197
198/**
199 * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
200 * the clipRect. Does not modify the scissor.
201 *
202 * @param clipRequired if not null, will be set to true if element intersects clip
203 * (and wasn't rejected)
204 *
205 * @param snapOut if set, the geometry will be treated as having an AA ramp.
206 * See Rect::snapGeometryToPixelBoundaries()
207 */
208bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
Chris Craikdeeda3d2014-05-05 19:09:33 -0700209 float right, float bottom,
210 bool* clipRequired, bool* roundRectClipRequired,
211 bool snapOut) const {
Chris Craik14e51302013-12-30 15:32:54 -0800212 if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
213 return true;
214 }
215
216 Rect r(left, top, right, bottom);
Chris Craikd6b65f62014-01-01 14:45:21 -0800217 currentTransform()->mapRect(r);
Chris Craik14e51302013-12-30 15:32:54 -0800218 r.snapGeometryToPixelBoundaries(snapOut);
219
Chris Craikd6b65f62014-01-01 14:45:21 -0800220 Rect clipRect(*currentClipRect());
Chris Craik14e51302013-12-30 15:32:54 -0800221 clipRect.snapToPixelBoundaries();
222
223 if (!clipRect.intersects(r)) return true;
224
225 // clip is required if geometry intersects clip rect
Chris Craikdeeda3d2014-05-05 19:09:33 -0700226 if (clipRequired) {
227 *clipRequired = !clipRect.contains(r);
228 }
229
230 // round rect clip is required if RR clip exists, and geometry intersects its corners
231 if (roundRectClipRequired) {
232 *roundRectClipRequired = mSnapshot->roundRectClipState != NULL
233 && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
234 }
Chris Craik14e51302013-12-30 15:32:54 -0800235 return false;
236}
237
238/**
239 * Returns false if drawing won't be clipped out.
240 *
241 * Makes the decision conservatively, by rounding out the mapped rect before comparing with the
242 * clipRect. To be used when perfect, pixel accuracy is not possible (esp. with tessellation) but
243 * rejection is still desired.
244 *
245 * This function, unlike quickRejectSetupScissor, should be used where precise geometry information
246 * isn't known (esp. when geometry adjusts based on scale). Generally, this will be first pass
247 * rejection where precise rejection isn't important, or precise information isn't available.
248 */
249bool StatefulBaseRenderer::quickRejectConservative(float left, float top,
250 float right, float bottom) const {
251 if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
252 return true;
253 }
254
255 Rect r(left, top, right, bottom);
Chris Craikd6b65f62014-01-01 14:45:21 -0800256 currentTransform()->mapRect(r);
Chris Craik14e51302013-12-30 15:32:54 -0800257 r.roundOut(); // rounded out to be conservative
258
Chris Craikd6b65f62014-01-01 14:45:21 -0800259 Rect clipRect(*currentClipRect());
Chris Craik14e51302013-12-30 15:32:54 -0800260 clipRect.snapToPixelBoundaries();
261
262 if (!clipRect.intersects(r)) return true;
263
264 return false;
265}
266
267}; // namespace uirenderer
268}; // namespace android