1 /*
2 * Copyright (C) 2012 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 "Snapshot.h"
18
19 #include <SkCanvas.h>
20
21 namespace android {
22 namespace uirenderer {
23
24 ///////////////////////////////////////////////////////////////////////////////
25 // Constructors
26 ///////////////////////////////////////////////////////////////////////////////
27
Snapshot()28 Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
29 invisible(false), empty(false), alpha(1.0f) {
30
31 transform = &mTransformRoot;
32 clipRect = &mClipRectRoot;
33 region = NULL;
34 clipRegion = NULL;
35 }
36
37 /**
38 * Copies the specified snapshot/ The specified snapshot is stored as
39 * the previous snapshot.
40 */
Snapshot(const sp<Snapshot> & s,int saveFlags)41 Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
42 flags(0), previous(s), layer(NULL), fbo(s->fbo),
43 invisible(s->invisible), empty(false),
44 viewport(s->viewport), height(s->height), alpha(s->alpha) {
45
46 clipRegion = NULL;
47
48 if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
49 mTransformRoot.load(*s->transform);
50 transform = &mTransformRoot;
51 } else {
52 transform = s->transform;
53 }
54
55 if (saveFlags & SkCanvas::kClip_SaveFlag) {
56 mClipRectRoot.set(*s->clipRect);
57 clipRect = &mClipRectRoot;
58 #if STENCIL_BUFFER_SIZE
59 if (s->clipRegion) {
60 mClipRegionRoot.merge(*s->clipRegion);
61 clipRegion = &mClipRegionRoot;
62 }
63 #endif
64 } else {
65 clipRect = s->clipRect;
66 #if STENCIL_BUFFER_SIZE
67 clipRegion = s->clipRegion;
68 #endif
69 }
70
71 if (s->flags & Snapshot::kFlagFboTarget) {
72 flags |= Snapshot::kFlagFboTarget;
73 region = s->region;
74 } else {
75 region = NULL;
76 }
77 }
78
79 ///////////////////////////////////////////////////////////////////////////////
80 // Clipping
81 ///////////////////////////////////////////////////////////////////////////////
82
ensureClipRegion()83 void Snapshot::ensureClipRegion() {
84 #if STENCIL_BUFFER_SIZE
85 if (!clipRegion) {
86 clipRegion = &mClipRegionRoot;
87 android::Rect tmp(clipRect->left, clipRect->top, clipRect->right, clipRect->bottom);
88 clipRegion->set(tmp);
89 }
90 #endif
91 }
92
copyClipRectFromRegion()93 void Snapshot::copyClipRectFromRegion() {
94 #if STENCIL_BUFFER_SIZE
95 if (!clipRegion->isEmpty()) {
96 android::Rect bounds(clipRegion->bounds());
97 clipRect->set(bounds.left, bounds.top, bounds.right, bounds.bottom);
98
99 if (clipRegion->isRect()) {
100 clipRegion->clear();
101 clipRegion = NULL;
102 }
103 } else {
104 clipRect->setEmpty();
105 clipRegion = NULL;
106 }
107 #endif
108 }
109
clipRegionOr(float left,float top,float right,float bottom)110 bool Snapshot::clipRegionOr(float left, float top, float right, float bottom) {
111 #if STENCIL_BUFFER_SIZE
112 android::Rect tmp(left, top, right, bottom);
113 clipRegion->orSelf(tmp);
114 copyClipRectFromRegion();
115 return true;
116 #else
117 return false;
118 #endif
119 }
120
clipRegionXor(float left,float top,float right,float bottom)121 bool Snapshot::clipRegionXor(float left, float top, float right, float bottom) {
122 #if STENCIL_BUFFER_SIZE
123 android::Rect tmp(left, top, right, bottom);
124 clipRegion->xorSelf(tmp);
125 copyClipRectFromRegion();
126 return true;
127 #else
128 return false;
129 #endif
130 }
131
clipRegionAnd(float left,float top,float right,float bottom)132 bool Snapshot::clipRegionAnd(float left, float top, float right, float bottom) {
133 #if STENCIL_BUFFER_SIZE
134 android::Rect tmp(left, top, right, bottom);
135 clipRegion->andSelf(tmp);
136 copyClipRectFromRegion();
137 return true;
138 #else
139 return false;
140 #endif
141 }
142
clipRegionNand(float left,float top,float right,float bottom)143 bool Snapshot::clipRegionNand(float left, float top, float right, float bottom) {
144 #if STENCIL_BUFFER_SIZE
145 android::Rect tmp(left, top, right, bottom);
146 clipRegion->subtractSelf(tmp);
147 copyClipRectFromRegion();
148 return true;
149 #else
150 return false;
151 #endif
152 }
153
clip(float left,float top,float right,float bottom,SkRegion::Op op)154 bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
155 Rect r(left, top, right, bottom);
156 transform->mapRect(r);
157 return clipTransformed(r, op);
158 }
159
clipTransformed(const Rect & r,SkRegion::Op op)160 bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
161 bool clipped = false;
162
163 switch (op) {
164 case SkRegion::kDifference_Op: {
165 ensureClipRegion();
166 clipped = clipRegionNand(r.left, r.top, r.right, r.bottom);
167 break;
168 }
169 case SkRegion::kIntersect_Op: {
170 if (CC_UNLIKELY(clipRegion)) {
171 clipped = clipRegionOr(r.left, r.top, r.right, r.bottom);
172 } else {
173 clipped = clipRect->intersect(r);
174 if (!clipped) {
175 clipRect->setEmpty();
176 clipped = true;
177 }
178 }
179 break;
180 }
181 case SkRegion::kUnion_Op: {
182 if (CC_UNLIKELY(clipRegion)) {
183 clipped = clipRegionAnd(r.left, r.top, r.right, r.bottom);
184 } else {
185 clipped = clipRect->unionWith(r);
186 }
187 break;
188 }
189 case SkRegion::kXOR_Op: {
190 ensureClipRegion();
191 clipped = clipRegionXor(r.left, r.top, r.right, r.bottom);
192 break;
193 }
194 case SkRegion::kReverseDifference_Op: {
195 // TODO!!!!!!!
196 break;
197 }
198 case SkRegion::kReplace_Op: {
199 setClip(r.left, r.top, r.right, r.bottom);
200 clipped = true;
201 break;
202 }
203 }
204
205 if (clipped) {
206 flags |= Snapshot::kFlagClipSet;
207 }
208
209 return clipped;
210 }
211
setClip(float left,float top,float right,float bottom)212 void Snapshot::setClip(float left, float top, float right, float bottom) {
213 clipRect->set(left, top, right, bottom);
214 #if STENCIL_BUFFER_SIZE
215 if (clipRegion) {
216 clipRegion->clear();
217 clipRegion = NULL;
218 }
219 #endif
220 flags |= Snapshot::kFlagClipSet;
221 }
222
getLocalClip()223 const Rect& Snapshot::getLocalClip() {
224 mat4 inverse;
225 inverse.loadInverse(*transform);
226
227 mLocalClip.set(*clipRect);
228 inverse.mapRect(mLocalClip);
229
230 return mLocalClip;
231 }
232
resetClip(float left,float top,float right,float bottom)233 void Snapshot::resetClip(float left, float top, float right, float bottom) {
234 clipRect = &mClipRectRoot;
235 setClip(left, top, right, bottom);
236 }
237
238 ///////////////////////////////////////////////////////////////////////////////
239 // Transforms
240 ///////////////////////////////////////////////////////////////////////////////
241
resetTransform(float x,float y,float z)242 void Snapshot::resetTransform(float x, float y, float z) {
243 transform = &mTransformRoot;
244 transform->loadTranslate(x, y, z);
245 }
246
247 ///////////////////////////////////////////////////////////////////////////////
248 // Queries
249 ///////////////////////////////////////////////////////////////////////////////
250
isIgnored() const251 bool Snapshot::isIgnored() const {
252 return invisible || empty;
253 }
254
255 }; // namespace uirenderer
256 }; // namespace android
257