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.
5 #include "cc/animation/transform_operations.h"
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"
16 TransformOperations::TransformOperations()
17 : decomposed_transform_dirty_(true) {
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()));
29 TransformOperations::~TransformOperations() {
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
);
39 gfx::Transform
TransformOperations::Blend(const TransformOperations
& from
,
40 SkMScalar progress
) const {
41 gfx::Transform to_return
;
42 BlendInternal(from
, progress
, &to_return
);
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 {
53 bool from_identity
= from
.IsIdentity();
54 bool to_identity
= IsIdentity();
55 if (from_identity
&& to_identity
)
58 if (!MatchesTypes(from
))
61 size_t num_operations
= std::max(from_identity
? 0 : from
.operations_
.size(),
62 to_identity
? 0 : operations_
.size());
64 // Because we are squashing all of the matrices together when applying
65 // them to the animation, we must apply them in reverse order when
66 // not squashing them.
67 for (size_t i
= 0; i
< num_operations
; ++i
) {
68 size_t operation_index
= num_operations
- 1 - i
;
69 gfx::BoxF bounds_for_operation
;
70 const TransformOperation
* from_op
=
71 from_identity
? nullptr : &from
.operations_
[operation_index
];
72 const TransformOperation
* to_op
=
73 to_identity
? nullptr : &operations_
[operation_index
];
74 if (!TransformOperation::BlendedBoundsForBox(*bounds
, from_op
, to_op
,
75 min_progress
, max_progress
,
76 &bounds_for_operation
)) {
79 *bounds
= bounds_for_operation
;
85 bool TransformOperations::AffectsScale() const {
86 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
87 if (operations_
[i
].type
== TransformOperation::TRANSFORM_OPERATION_SCALE
)
89 if (operations_
[i
].type
== TransformOperation::TRANSFORM_OPERATION_MATRIX
&&
90 !operations_
[i
].matrix
.IsIdentityOrTranslation())
96 bool TransformOperations::PreservesAxisAlignment() const {
97 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
98 switch (operations_
[i
].type
) {
99 case TransformOperation::TRANSFORM_OPERATION_IDENTITY
:
100 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE
:
101 case TransformOperation::TRANSFORM_OPERATION_SCALE
:
103 case TransformOperation::TRANSFORM_OPERATION_MATRIX
:
104 if (!operations_
[i
].matrix
.IsIdentity() &&
105 !operations_
[i
].matrix
.IsScaleOrTranslation())
108 case TransformOperation::TRANSFORM_OPERATION_ROTATE
:
109 case TransformOperation::TRANSFORM_OPERATION_SKEW
:
110 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
:
117 bool TransformOperations::IsTranslation() const {
118 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
119 switch (operations_
[i
].type
) {
120 case TransformOperation::TRANSFORM_OPERATION_IDENTITY
:
121 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE
:
123 case TransformOperation::TRANSFORM_OPERATION_MATRIX
:
124 if (!operations_
[i
].matrix
.IsIdentityOrTranslation())
127 case TransformOperation::TRANSFORM_OPERATION_ROTATE
:
128 case TransformOperation::TRANSFORM_OPERATION_SCALE
:
129 case TransformOperation::TRANSFORM_OPERATION_SKEW
:
130 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
:
137 bool TransformOperations::ScaleComponent(gfx::Vector3dF
* scale
) const {
138 *scale
= gfx::Vector3dF(1.f
, 1.f
, 1.f
);
139 bool has_scale_component
= false;
140 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
141 switch (operations_
[i
].type
) {
142 case TransformOperation::TRANSFORM_OPERATION_IDENTITY
:
143 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE
:
145 case TransformOperation::TRANSFORM_OPERATION_MATRIX
:
146 if (!operations_
[i
].matrix
.IsIdentityOrTranslation())
149 case TransformOperation::TRANSFORM_OPERATION_ROTATE
:
150 case TransformOperation::TRANSFORM_OPERATION_SKEW
:
151 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
:
153 case TransformOperation::TRANSFORM_OPERATION_SCALE
:
154 if (has_scale_component
)
156 has_scale_component
= true;
157 scale
->Scale(operations_
[i
].scale
.x
,
158 operations_
[i
].scale
.y
,
159 operations_
[i
].scale
.z
);
165 bool TransformOperations::MatchesTypes(const TransformOperations
& other
) const {
166 if (operations_
.size() == 0 || other
.operations_
.size() == 0)
169 if (operations_
.size() != other
.operations_
.size())
172 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
173 if (operations_
[i
].type
!= other
.operations_
[i
].type
)
180 bool TransformOperations::CanBlendWith(
181 const TransformOperations
& other
) const {
182 gfx::Transform dummy
;
183 return BlendInternal(other
, 0.5, &dummy
);
186 void TransformOperations::AppendTranslate(SkMScalar x
,
189 TransformOperation to_add
;
190 to_add
.matrix
.Translate3d(x
, y
, z
);
191 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_TRANSLATE
;
192 to_add
.translate
.x
= x
;
193 to_add
.translate
.y
= y
;
194 to_add
.translate
.z
= z
;
195 operations_
.push_back(to_add
);
196 decomposed_transform_dirty_
= true;
199 void TransformOperations::AppendRotate(SkMScalar x
,
203 TransformOperation to_add
;
204 to_add
.matrix
.RotateAbout(gfx::Vector3dF(x
, y
, z
), degrees
);
205 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_ROTATE
;
206 to_add
.rotate
.axis
.x
= x
;
207 to_add
.rotate
.axis
.y
= y
;
208 to_add
.rotate
.axis
.z
= z
;
209 to_add
.rotate
.angle
= degrees
;
210 operations_
.push_back(to_add
);
211 decomposed_transform_dirty_
= true;
214 void TransformOperations::AppendScale(SkMScalar x
, SkMScalar y
, SkMScalar z
) {
215 TransformOperation to_add
;
216 to_add
.matrix
.Scale3d(x
, y
, z
);
217 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_SCALE
;
221 operations_
.push_back(to_add
);
222 decomposed_transform_dirty_
= true;
225 void TransformOperations::AppendSkew(SkMScalar x
, SkMScalar y
) {
226 TransformOperation to_add
;
227 to_add
.matrix
.Skew(x
, y
);
228 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_SKEW
;
231 operations_
.push_back(to_add
);
232 decomposed_transform_dirty_
= true;
235 void TransformOperations::AppendPerspective(SkMScalar depth
) {
236 TransformOperation to_add
;
237 to_add
.matrix
.ApplyPerspectiveDepth(depth
);
238 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
;
239 to_add
.perspective_depth
= depth
;
240 operations_
.push_back(to_add
);
241 decomposed_transform_dirty_
= true;
244 void TransformOperations::AppendMatrix(const gfx::Transform
& matrix
) {
245 TransformOperation to_add
;
246 to_add
.matrix
= matrix
;
247 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_MATRIX
;
248 operations_
.push_back(to_add
);
249 decomposed_transform_dirty_
= true;
252 void TransformOperations::AppendIdentity() {
253 operations_
.push_back(TransformOperation());
256 bool TransformOperations::IsIdentity() const {
257 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
258 if (!operations_
[i
].IsIdentity())
264 bool TransformOperations::BlendInternal(const TransformOperations
& from
,
266 gfx::Transform
* result
) const {
267 bool from_identity
= from
.IsIdentity();
268 bool to_identity
= IsIdentity();
269 if (from_identity
&& to_identity
)
272 if (MatchesTypes(from
)) {
273 size_t num_operations
=
274 std::max(from_identity
? 0 : from
.operations_
.size(),
275 to_identity
? 0 : operations_
.size());
276 for (size_t i
= 0; i
< num_operations
; ++i
) {
277 gfx::Transform blended
;
278 if (!TransformOperation::BlendTransformOperations(
279 from_identity
? 0 : &from
.operations_
[i
],
280 to_identity
? 0 : &operations_
[i
],
284 result
->PreconcatTransform(blended
);
289 if (!ComputeDecomposedTransform() || !from
.ComputeDecomposedTransform())
292 gfx::DecomposedTransform to_return
;
293 if (!gfx::BlendDecomposedTransforms(&to_return
,
294 *decomposed_transform_
.get(),
295 *from
.decomposed_transform_
.get(),
299 *result
= ComposeTransform(to_return
);
303 bool TransformOperations::ComputeDecomposedTransform() const {
304 if (decomposed_transform_dirty_
) {
305 if (!decomposed_transform_
)
306 decomposed_transform_
.reset(new gfx::DecomposedTransform());
307 gfx::Transform transform
= Apply();
308 if (!gfx::DecomposeTransform(decomposed_transform_
.get(), transform
))
310 decomposed_transform_dirty_
= false;