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 (IsIdentity() || other
.IsIdentity())
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
174 && !operations_
[i
].IsIdentity()
175 && !other
.operations_
[i
].IsIdentity())
182 bool TransformOperations::CanBlendWith(
183 const TransformOperations
& other
) const {
184 gfx::Transform dummy
;
185 return BlendInternal(other
, 0.5, &dummy
);
188 void TransformOperations::AppendTranslate(SkMScalar x
,
191 TransformOperation to_add
;
192 to_add
.matrix
.Translate3d(x
, y
, z
);
193 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_TRANSLATE
;
194 to_add
.translate
.x
= x
;
195 to_add
.translate
.y
= y
;
196 to_add
.translate
.z
= z
;
197 operations_
.push_back(to_add
);
198 decomposed_transform_dirty_
= true;
201 void TransformOperations::AppendRotate(SkMScalar x
,
205 TransformOperation to_add
;
206 to_add
.matrix
.RotateAbout(gfx::Vector3dF(x
, y
, z
), degrees
);
207 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_ROTATE
;
208 to_add
.rotate
.axis
.x
= x
;
209 to_add
.rotate
.axis
.y
= y
;
210 to_add
.rotate
.axis
.z
= z
;
211 to_add
.rotate
.angle
= degrees
;
212 operations_
.push_back(to_add
);
213 decomposed_transform_dirty_
= true;
216 void TransformOperations::AppendScale(SkMScalar x
, SkMScalar y
, SkMScalar z
) {
217 TransformOperation to_add
;
218 to_add
.matrix
.Scale3d(x
, y
, z
);
219 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_SCALE
;
223 operations_
.push_back(to_add
);
224 decomposed_transform_dirty_
= true;
227 void TransformOperations::AppendSkew(SkMScalar x
, SkMScalar y
) {
228 TransformOperation to_add
;
229 to_add
.matrix
.SkewX(x
);
230 to_add
.matrix
.SkewY(y
);
231 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_SKEW
;
234 operations_
.push_back(to_add
);
235 decomposed_transform_dirty_
= true;
238 void TransformOperations::AppendPerspective(SkMScalar depth
) {
239 TransformOperation to_add
;
240 to_add
.matrix
.ApplyPerspectiveDepth(depth
);
241 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
;
242 to_add
.perspective_depth
= depth
;
243 operations_
.push_back(to_add
);
244 decomposed_transform_dirty_
= true;
247 void TransformOperations::AppendMatrix(const gfx::Transform
& matrix
) {
248 TransformOperation to_add
;
249 to_add
.matrix
= matrix
;
250 to_add
.type
= TransformOperation::TRANSFORM_OPERATION_MATRIX
;
251 operations_
.push_back(to_add
);
252 decomposed_transform_dirty_
= true;
255 void TransformOperations::AppendIdentity() {
256 operations_
.push_back(TransformOperation());
259 bool TransformOperations::IsIdentity() const {
260 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
261 if (!operations_
[i
].IsIdentity())
267 bool TransformOperations::BlendInternal(const TransformOperations
& from
,
269 gfx::Transform
* result
) const {
270 bool from_identity
= from
.IsIdentity();
271 bool to_identity
= IsIdentity();
272 if (from_identity
&& to_identity
)
275 if (MatchesTypes(from
)) {
276 size_t num_operations
=
277 std::max(from_identity
? 0 : from
.operations_
.size(),
278 to_identity
? 0 : operations_
.size());
279 for (size_t i
= 0; i
< num_operations
; ++i
) {
280 gfx::Transform blended
;
281 if (!TransformOperation::BlendTransformOperations(
282 from_identity
? 0 : &from
.operations_
[i
],
283 to_identity
? 0 : &operations_
[i
],
287 result
->PreconcatTransform(blended
);
292 if (!ComputeDecomposedTransform() || !from
.ComputeDecomposedTransform())
295 gfx::DecomposedTransform to_return
;
296 if (!gfx::BlendDecomposedTransforms(&to_return
,
297 *decomposed_transform_
.get(),
298 *from
.decomposed_transform_
.get(),
302 *result
= ComposeTransform(to_return
);
306 bool TransformOperations::ComputeDecomposedTransform() const {
307 if (decomposed_transform_dirty_
) {
308 if (!decomposed_transform_
)
309 decomposed_transform_
.reset(new gfx::DecomposedTransform());
310 gfx::Transform transform
= Apply();
311 if (!gfx::DecomposeTransform(decomposed_transform_
.get(), transform
))
313 decomposed_transform_dirty_
= false;