OSDN Git Service

[NAN] API cleanup - rename FLAGS. [DO NOT MERGE]
[android-x86/frameworks-base.git] / libs / hwui / CanvasState.cpp
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 "Canvas.h"
18 #include "CanvasState.h"
19 #include "utils/MathUtils.h"
20
21 namespace android {
22 namespace uirenderer {
23
24
25 CanvasState::CanvasState(CanvasStateClient& renderer)
26         : mDirtyClip(false)
27         , mWidth(-1)
28         , mHeight(-1)
29         , mSaveCount(1)
30         , mCanvas(renderer)
31         , mSnapshot(&mFirstSnapshot) {
32 }
33
34 CanvasState::~CanvasState() {
35     // First call freeSnapshot on all but mFirstSnapshot
36     // to invoke all the dtors
37     freeAllSnapshots();
38
39     // Now actually release the memory
40     while (mSnapshotPool) {
41         void* temp = mSnapshotPool;
42         mSnapshotPool = mSnapshotPool->previous;
43         free(temp);
44     }
45 }
46
47 void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) {
48     if (mWidth != viewportWidth || mHeight != viewportHeight) {
49         mWidth = viewportWidth;
50         mHeight = viewportHeight;
51         mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
52         mCanvas.onViewportInitialized();
53     }
54
55     freeAllSnapshots();
56     mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
57     mSnapshot->setRelativeLightCenter(Vector3());
58     mSaveCount = 1;
59 }
60
61 void CanvasState::initializeSaveStack(
62         int viewportWidth, int viewportHeight,
63         float clipLeft, float clipTop,
64         float clipRight, float clipBottom, const Vector3& lightCenter) {
65     if (mWidth != viewportWidth || mHeight != viewportHeight) {
66         mWidth = viewportWidth;
67         mHeight = viewportHeight;
68         mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
69         mCanvas.onViewportInitialized();
70     }
71
72     freeAllSnapshots();
73     mSnapshot = allocSnapshot(&mFirstSnapshot, SaveFlags::MatrixClip);
74     mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
75     mSnapshot->fbo = mCanvas.getTargetFbo();
76     mSnapshot->setRelativeLightCenter(lightCenter);
77     mSaveCount = 1;
78 }
79
80 Snapshot* CanvasState::allocSnapshot(Snapshot* previous, int savecount) {
81     void* memory;
82     if (mSnapshotPool) {
83         memory = mSnapshotPool;
84         mSnapshotPool = mSnapshotPool->previous;
85         mSnapshotPoolCount--;
86     } else {
87         memory = malloc(sizeof(Snapshot));
88     }
89     return new (memory) Snapshot(previous, savecount);
90 }
91
92 void CanvasState::freeSnapshot(Snapshot* snapshot) {
93     snapshot->~Snapshot();
94     // Arbitrary number, just don't let this grown unbounded
95     if (mSnapshotPoolCount > 10) {
96         free((void*) snapshot);
97     } else {
98         snapshot->previous = mSnapshotPool;
99         mSnapshotPool = snapshot;
100         mSnapshotPoolCount++;
101     }
102 }
103
104 void CanvasState::freeAllSnapshots() {
105     while (mSnapshot != &mFirstSnapshot) {
106         Snapshot* temp = mSnapshot;
107         mSnapshot = mSnapshot->previous;
108         freeSnapshot(temp);
109     }
110 }
111
112 ///////////////////////////////////////////////////////////////////////////////
113 // Save (layer)
114 ///////////////////////////////////////////////////////////////////////////////
115
116 /**
117  * Guaranteed to save without side-effects
118  *
119  * This approach, here and in restoreSnapshot(), allows subclasses to directly manipulate the save
120  * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
121  */
122 int CanvasState::saveSnapshot(int flags) {
123     mSnapshot = allocSnapshot(mSnapshot, flags);
124     return mSaveCount++;
125 }
126
127 int CanvasState::save(int flags) {
128     return saveSnapshot(flags);
129 }
130
131 /**
132  * Guaranteed to restore without side-effects.
133  */
134 void CanvasState::restoreSnapshot() {
135     Snapshot* toRemove = mSnapshot;
136     Snapshot* toRestore = mSnapshot->previous;
137
138     mSaveCount--;
139     mSnapshot = toRestore;
140
141     // subclass handles restore implementation
142     mCanvas.onSnapshotRestored(*toRemove, *toRestore);
143
144     freeSnapshot(toRemove);
145 }
146
147 void CanvasState::restore() {
148     if (mSaveCount > 1) {
149         restoreSnapshot();
150     }
151 }
152
153 void CanvasState::restoreToCount(int saveCount) {
154     if (saveCount < 1) saveCount = 1;
155
156     while (mSaveCount > saveCount) {
157         restoreSnapshot();
158     }
159 }
160
161 ///////////////////////////////////////////////////////////////////////////////
162 // Matrix
163 ///////////////////////////////////////////////////////////////////////////////
164
165 void CanvasState::getMatrix(SkMatrix* matrix) const {
166     mSnapshot->transform->copyTo(*matrix);
167 }
168
169 void CanvasState::translate(float dx, float dy, float dz) {
170     mSnapshot->transform->translate(dx, dy, dz);
171 }
172
173 void CanvasState::rotate(float degrees) {
174     mSnapshot->transform->rotate(degrees, 0.0f, 0.0f, 1.0f);
175 }
176
177 void CanvasState::scale(float sx, float sy) {
178     mSnapshot->transform->scale(sx, sy, 1.0f);
179 }
180
181 void CanvasState::skew(float sx, float sy) {
182     mSnapshot->transform->skew(sx, sy);
183 }
184
185 void CanvasState::setMatrix(const SkMatrix& matrix) {
186     mSnapshot->transform->load(matrix);
187 }
188
189 void CanvasState::setMatrix(const Matrix4& matrix) {
190     *(mSnapshot->transform) = matrix;
191 }
192
193 void CanvasState::concatMatrix(const SkMatrix& matrix) {
194     mat4 transform(matrix);
195     mSnapshot->transform->multiply(transform);
196 }
197
198 void CanvasState::concatMatrix(const Matrix4& matrix) {
199     mSnapshot->transform->multiply(matrix);
200 }
201
202 ///////////////////////////////////////////////////////////////////////////////
203 // Clip
204 ///////////////////////////////////////////////////////////////////////////////
205
206 bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
207     mSnapshot->clip(Rect(left, top, right, bottom), op);
208     mDirtyClip = true;
209     return !mSnapshot->clipIsEmpty();
210 }
211
212 bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
213     mSnapshot->clipPath(*path, op);
214     mDirtyClip = true;
215     return !mSnapshot->clipIsEmpty();
216 }
217
218 bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
219     mSnapshot->clipRegionTransformed(*region, op);
220     mDirtyClip = true;
221     return !mSnapshot->clipIsEmpty();
222 }
223
224 void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
225     Rect bounds;
226     float radius;
227     if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
228
229     bool outlineIsRounded = MathUtils::isPositive(radius);
230     if (!outlineIsRounded || currentTransform()->isSimple()) {
231         // TODO: consider storing this rect separately, so that this can't be replaced with clip ops
232         clipRect(bounds.left, bounds.top, bounds.right, bounds.bottom, SkRegion::kIntersect_Op);
233     }
234     if (outlineIsRounded) {
235         setClippingRoundRect(allocator, bounds, radius, false);
236     }
237 }
238
239 void CanvasState::setClippingRoundRect(LinearAllocator& allocator,
240         const Rect& rect, float radius, bool highPriority) {
241     mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
242 }
243
244 void CanvasState::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
245     mSnapshot->setProjectionPathMask(allocator, path);
246 }
247
248 ///////////////////////////////////////////////////////////////////////////////
249 // Quick Rejection
250 ///////////////////////////////////////////////////////////////////////////////
251
252 /**
253  * Calculates whether content drawn within the passed bounds would be outside of, or intersect with
254  * the clipRect. Does not modify the scissor.
255  *
256  * @param clipRequired if not null, will be set to true if element intersects clip
257  *         (and wasn't rejected)
258  *
259  * @param snapOut if set, the geometry will be treated as having an AA ramp.
260  *         See Rect::snapGeometryToPixelBoundaries()
261  */
262 bool CanvasState::calculateQuickRejectForScissor(float left, float top,
263         float right, float bottom,
264         bool* clipRequired, bool* roundRectClipRequired,
265         bool snapOut) const {
266     if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
267         return true;
268     }
269
270     Rect r(left, top, right, bottom);
271     currentTransform()->mapRect(r);
272     r.snapGeometryToPixelBoundaries(snapOut);
273
274     Rect clipRect(currentRenderTargetClip());
275     clipRect.snapToPixelBoundaries();
276
277     if (!clipRect.intersects(r)) return true;
278
279     // clip is required if geometry intersects clip rect
280     if (clipRequired) {
281         *clipRequired = !clipRect.contains(r);
282     }
283
284     // round rect clip is required if RR clip exists, and geometry intersects its corners
285     if (roundRectClipRequired) {
286         *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr
287                 && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
288     }
289     return false;
290 }
291
292 bool CanvasState::quickRejectConservative(float left, float top,
293         float right, float bottom) const {
294     if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
295         return true;
296     }
297
298     Rect r(left, top, right, bottom);
299     currentTransform()->mapRect(r);
300     r.roundOut(); // rounded out to be conservative
301
302     Rect clipRect(currentRenderTargetClip());
303     clipRect.snapToPixelBoundaries();
304
305     if (!clipRect.intersects(r)) return true;
306
307     return false;
308 }
309
310 } // namespace uirenderer
311 } // namespace android