OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/animation/transform_operations.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "ui/gfx/animation/tween.h" | |
10 #include "ui/gfx/geometry/box_f.h" | |
11 #include "ui/gfx/geometry/vector3d_f.h" | |
12 #include "ui/gfx/transform_util.h" | |
13 | |
14 namespace cc { | |
15 | |
16 TransformOperations::TransformOperations() | |
17 : decomposed_transform_dirty_(true) { | |
18 } | |
19 | |
20 TransformOperations::TransformOperations(const TransformOperations& other) { | |
21 operations_ = other.operations_; | |
22 decomposed_transform_dirty_ = other.decomposed_transform_dirty_; | |
23 if (!decomposed_transform_dirty_) { | |
24 decomposed_transform_.reset( | |
25 new gfx::DecomposedTransform(*other.decomposed_transform_.get())); | |
26 } | |
27 } | |
28 | |
29 TransformOperations::~TransformOperations() { | |
30 } | |
31 | |
32 gfx::Transform TransformOperations::Apply() const { | |
33 gfx::Transform to_return; | |
34 for (size_t i = 0; i < operations_.size(); ++i) | |
35 to_return.PreconcatTransform(operations_[i].matrix); | |
36 return to_return; | |
37 } | |
38 | |
39 gfx::Transform TransformOperations::Blend(const TransformOperations& from, | |
40 SkMScalar progress) const { | |
41 gfx::Transform to_return; | |
42 BlendInternal(from, progress, &to_return); | |
43 return to_return; | |
44 } | |
45 | |
46 bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box, | |
47 const TransformOperations& from, | |
48 SkMScalar min_progress, | |
49 SkMScalar max_progress, | |
50 gfx::BoxF* bounds) const { | |
51 *bounds = box; | |
52 | |
53 bool from_identity = from.IsIdentity(); | |
54 bool to_identity = IsIdentity(); | |
55 if (from_identity && to_identity) | |
56 return true; | |
57 | |
58 if (!MatchesTypes(from)) | |
59 return false; | |
60 | |
61 size_t num_operations = | |
62 std::max(from_identity ? 0 : from.operations_.size(), | |
63 to_identity ? 0 : operations_.size()); | |
64 | |
65 // Because we are squashing all of the matrices together when applying | |
66 // them to the animation, we must apply them in reverse order when | |
67 // not squashing them. | |
68 for (int i = num_operations - 1; i >= 0; --i) { | |
69 gfx::BoxF bounds_for_operation; | |
70 const TransformOperation* from_op = | |
71 from_identity ? nullptr : &from.operations_[i]; | |
72 const TransformOperation* to_op = to_identity ? nullptr : &operations_[i]; | |
73 if (!TransformOperation::BlendedBoundsForBox(*bounds, | |
74 from_op, | |
75 to_op, | |
76 min_progress, | |
77 max_progress, | |
78 &bounds_for_operation)) | |
79 return false; | |
80 *bounds = bounds_for_operation; | |
81 } | |
82 | |
83 return true; | |
84 } | |
85 | |
86 bool TransformOperations::AffectsScale() const { | |
87 for (size_t i = 0; i < operations_.size(); ++i) { | |
88 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_SCALE) | |
89 return true; | |
90 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_MATRIX && | |
91 !operations_[i].matrix.IsIdentityOrTranslation()) | |
92 return true; | |
93 } | |
94 return false; | |
95 } | |
96 | |
97 bool TransformOperations::PreservesAxisAlignment() const { | |
98 for (size_t i = 0; i < operations_.size(); ++i) { | |
99 switch (operations_[i].type) { | |
100 case TransformOperation::TRANSFORM_OPERATION_IDENTITY: | |
101 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: | |
102 case TransformOperation::TRANSFORM_OPERATION_SCALE: | |
103 continue; | |
104 case TransformOperation::TRANSFORM_OPERATION_MATRIX: | |
105 if (!operations_[i].matrix.IsIdentity() && | |
106 !operations_[i].matrix.IsScaleOrTranslation()) | |
107 return false; | |
108 continue; | |
109 case TransformOperation::TRANSFORM_OPERATION_ROTATE: | |
110 case TransformOperation::TRANSFORM_OPERATION_SKEW: | |
111 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: | |
112 return false; | |
113 } | |
114 } | |
115 return true; | |
116 } | |
117 | |
118 bool TransformOperations::IsTranslation() const { | |
119 for (size_t i = 0; i < operations_.size(); ++i) { | |
120 switch (operations_[i].type) { | |
121 case TransformOperation::TRANSFORM_OPERATION_IDENTITY: | |
122 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: | |
123 continue; | |
124 case TransformOperation::TRANSFORM_OPERATION_MATRIX: | |
125 if (!operations_[i].matrix.IsIdentityOrTranslation()) | |
126 return false; | |
127 continue; | |
128 case TransformOperation::TRANSFORM_OPERATION_ROTATE: | |
129 case TransformOperation::TRANSFORM_OPERATION_SCALE: | |
130 case TransformOperation::TRANSFORM_OPERATION_SKEW: | |
131 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: | |
132 return false; | |
133 } | |
134 } | |
135 return true; | |
136 } | |
137 | |
138 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const { | |
139 *scale = gfx::Vector3dF(1.f, 1.f, 1.f); | |
140 bool has_scale_component = false; | |
141 for (size_t i = 0; i < operations_.size(); ++i) { | |
142 switch (operations_[i].type) { | |
143 case TransformOperation::TRANSFORM_OPERATION_IDENTITY: | |
144 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: | |
145 continue; | |
146 case TransformOperation::TRANSFORM_OPERATION_MATRIX: | |
147 if (!operations_[i].matrix.IsIdentityOrTranslation()) | |
148 return false; | |
149 continue; | |
150 case TransformOperation::TRANSFORM_OPERATION_ROTATE: | |
151 case TransformOperation::TRANSFORM_OPERATION_SKEW: | |
152 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: | |
153 return false; | |
154 case TransformOperation::TRANSFORM_OPERATION_SCALE: | |
155 if (has_scale_component) | |
156 return false; | |
157 has_scale_component = true; | |
158 scale->Scale(operations_[i].scale.x, | |
159 operations_[i].scale.y, | |
160 operations_[i].scale.z); | |
161 } | |
162 } | |
163 return true; | |
164 } | |
165 | |
166 bool TransformOperations::MatchesTypes(const TransformOperations& other) const { | |
167 if (IsIdentity() || other.IsIdentity()) | |
168 return true; | |
169 | |
170 if (operations_.size() != other.operations_.size()) | |
171 return false; | |
172 | |
173 for (size_t i = 0; i < operations_.size(); ++i) { | |
174 if (operations_[i].type != other.operations_[i].type | |
175 && !operations_[i].IsIdentity() | |
176 && !other.operations_[i].IsIdentity()) | |
177 return false; | |
178 } | |
179 | |
180 return true; | |
181 } | |
182 | |
183 bool TransformOperations::CanBlendWith( | |
184 const TransformOperations& other) const { | |
185 gfx::Transform dummy; | |
186 return BlendInternal(other, 0.5, &dummy); | |
187 } | |
188 | |
189 void TransformOperations::AppendTranslate(SkMScalar x, | |
190 SkMScalar y, | |
191 SkMScalar z) { | |
192 TransformOperation to_add; | |
193 to_add.matrix.Translate3d(x, y, z); | |
194 to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE; | |
195 to_add.translate.x = x; | |
196 to_add.translate.y = y; | |
197 to_add.translate.z = z; | |
198 operations_.push_back(to_add); | |
199 decomposed_transform_dirty_ = true; | |
200 } | |
201 | |
202 void TransformOperations::AppendRotate(SkMScalar x, | |
203 SkMScalar y, | |
204 SkMScalar z, | |
205 SkMScalar degrees) { | |
206 TransformOperation to_add; | |
207 to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees); | |
208 to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE; | |
209 to_add.rotate.axis.x = x; | |
210 to_add.rotate.axis.y = y; | |
211 to_add.rotate.axis.z = z; | |
212 to_add.rotate.angle = degrees; | |
213 operations_.push_back(to_add); | |
214 decomposed_transform_dirty_ = true; | |
215 } | |
216 | |
217 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) { | |
218 TransformOperation to_add; | |
219 to_add.matrix.Scale3d(x, y, z); | |
220 to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE; | |
221 to_add.scale.x = x; | |
222 to_add.scale.y = y; | |
223 to_add.scale.z = z; | |
224 operations_.push_back(to_add); | |
225 decomposed_transform_dirty_ = true; | |
226 } | |
227 | |
228 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) { | |
229 TransformOperation to_add; | |
230 to_add.matrix.SkewX(x); | |
231 to_add.matrix.SkewY(y); | |
232 to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW; | |
233 to_add.skew.x = x; | |
234 to_add.skew.y = y; | |
235 operations_.push_back(to_add); | |
236 decomposed_transform_dirty_ = true; | |
237 } | |
238 | |
239 void TransformOperations::AppendPerspective(SkMScalar depth) { | |
240 TransformOperation to_add; | |
241 to_add.matrix.ApplyPerspectiveDepth(depth); | |
242 to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE; | |
243 to_add.perspective_depth = depth; | |
244 operations_.push_back(to_add); | |
245 decomposed_transform_dirty_ = true; | |
246 } | |
247 | |
248 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) { | |
249 TransformOperation to_add; | |
250 to_add.matrix = matrix; | |
251 to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX; | |
252 operations_.push_back(to_add); | |
253 decomposed_transform_dirty_ = true; | |
254 } | |
255 | |
256 void TransformOperations::AppendIdentity() { | |
257 operations_.push_back(TransformOperation()); | |
258 } | |
259 | |
260 bool TransformOperations::IsIdentity() const { | |
261 for (size_t i = 0; i < operations_.size(); ++i) { | |
262 if (!operations_[i].IsIdentity()) | |
263 return false; | |
264 } | |
265 return true; | |
266 } | |
267 | |
268 bool TransformOperations::BlendInternal(const TransformOperations& from, | |
269 SkMScalar progress, | |
270 gfx::Transform* result) const { | |
271 bool from_identity = from.IsIdentity(); | |
272 bool to_identity = IsIdentity(); | |
273 if (from_identity && to_identity) | |
274 return true; | |
275 | |
276 if (MatchesTypes(from)) { | |
277 size_t num_operations = | |
278 std::max(from_identity ? 0 : from.operations_.size(), | |
279 to_identity ? 0 : operations_.size()); | |
280 for (size_t i = 0; i < num_operations; ++i) { | |
281 gfx::Transform blended; | |
282 if (!TransformOperation::BlendTransformOperations( | |
283 from_identity ? 0 : &from.operations_[i], | |
284 to_identity ? 0 : &operations_[i], | |
285 progress, | |
286 &blended)) | |
287 return false; | |
288 result->PreconcatTransform(blended); | |
289 } | |
290 return true; | |
291 } | |
292 | |
293 if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform()) | |
294 return false; | |
295 | |
296 gfx::DecomposedTransform to_return; | |
297 if (!gfx::BlendDecomposedTransforms(&to_return, | |
298 *decomposed_transform_.get(), | |
299 *from.decomposed_transform_.get(), | |
300 progress)) | |
301 return false; | |
302 | |
303 *result = ComposeTransform(to_return); | |
304 return true; | |
305 } | |
306 | |
307 bool TransformOperations::ComputeDecomposedTransform() const { | |
308 if (decomposed_transform_dirty_) { | |
309 if (!decomposed_transform_) | |
310 decomposed_transform_.reset(new gfx::DecomposedTransform()); | |
311 gfx::Transform transform = Apply(); | |
312 if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform)) | |
313 return false; | |
314 decomposed_transform_dirty_ = false; | |
315 } | |
316 return true; | |
317 } | |
318 | |
319 } // namespace cc | |
OLD | NEW |