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
=
62 std::max(from_identity
? 0 : from
.operations_
.size(),
63 to_identity
? 0 : operations_
.size());
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
,
78 &bounds_for_operation
))
80 *bounds
= bounds_for_operation
;
86 bool TransformOperations::AffectsScale() const {
87 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
88 if (operations_
[i
].type
== TransformOperation::TRANSFORM_OPERATION_SCALE
)
90 if (operations_
[i
].type
== TransformOperation::TRANSFORM_OPERATION_MATRIX
&&
91 !operations_
[i
].matrix
.IsIdentityOrTranslation())
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
:
104 case TransformOperation::TRANSFORM_OPERATION_MATRIX
:
105 if (!operations_
[i
].matrix
.IsIdentity() &&
106 !operations_
[i
].matrix
.IsScaleOrTranslation())
109 case TransformOperation::TRANSFORM_OPERATION_ROTATE
:
110 case TransformOperation::TRANSFORM_OPERATION_SKEW
:
111 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
:
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
:
124 case TransformOperation::TRANSFORM_OPERATION_MATRIX
:
125 if (!operations_
[i
].matrix
.IsIdentityOrTranslation())
128 case TransformOperation::TRANSFORM_OPERATION_ROTATE
:
129 case TransformOperation::TRANSFORM_OPERATION_SCALE
:
130 case TransformOperation::TRANSFORM_OPERATION_SKEW
:
131 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
:
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
:
146 case TransformOperation::TRANSFORM_OPERATION_MATRIX
:
147 if (!operations_
[i
].matrix
.IsIdentityOrTranslation())
150 case TransformOperation::TRANSFORM_OPERATION_ROTATE
:
151 case TransformOperation::TRANSFORM_OPERATION_SKEW
:
152 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE
:
154 case TransformOperation::TRANSFORM_OPERATION_SCALE
:
155 if (has_scale_component
)
157 has_scale_component
= true;
158 scale
->Scale(operations_
[i
].scale
.x
,
159 operations_
[i
].scale
.y
,
160 operations_
[i
].scale
.z
);
166 bool TransformOperations::MatchesTypes(const TransformOperations
& other
) const {
167 if (IsIdentity() || other
.IsIdentity())
170 if (operations_
.size() != other
.operations_
.size())
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())
183 bool TransformOperations::CanBlendWith(
184 const TransformOperations
& other
) const {
185 gfx::Transform dummy
;
186 return BlendInternal(other
, 0.5, &dummy
);
189 void TransformOperations::AppendTranslate(SkMScalar x
,
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;
202 void TransformOperations::AppendRotate(SkMScalar x
,
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;
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
;
224 operations_
.push_back(to_add
);
225 decomposed_transform_dirty_
= true;
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
;
235 operations_
.push_back(to_add
);
236 decomposed_transform_dirty_
= true;
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;
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;
256 void TransformOperations::AppendIdentity() {
257 operations_
.push_back(TransformOperation());
260 bool TransformOperations::IsIdentity() const {
261 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
262 if (!operations_
[i
].IsIdentity())
268 bool TransformOperations::BlendInternal(const TransformOperations
& from
,
270 gfx::Transform
* result
) const {
271 bool from_identity
= from
.IsIdentity();
272 bool to_identity
= IsIdentity();
273 if (from_identity
&& to_identity
)
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
],
288 result
->PreconcatTransform(blended
);
293 if (!ComputeDecomposedTransform() || !from
.ComputeDecomposedTransform())
296 gfx::DecomposedTransform to_return
;
297 if (!gfx::BlendDecomposedTransforms(&to_return
,
298 *decomposed_transform_
.get(),
299 *from
.decomposed_transform_
.get(),
303 *result
= ComposeTransform(to_return
);
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
))
314 decomposed_transform_dirty_
= false;