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/box_f.h"
11 #include "ui/gfx/transform_util.h"
12 #include "ui/gfx/vector3d_f.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
? NULL
: &from
.operations_
[i
];
72 const TransformOperation
* to_op
= to_identity
? NULL
: &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::TransformOperationScale
)
90 if (operations_
[i
].type
== TransformOperation::TransformOperationMatrix
&&
91 !operations_
[i
].matrix
.IsIdentityOrTranslation())
97 bool TransformOperations::IsTranslation() const {
98 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
99 switch (operations_
[i
].type
) {
100 case TransformOperation::TransformOperationIdentity
:
101 case TransformOperation::TransformOperationTranslate
:
103 case TransformOperation::TransformOperationMatrix
:
104 if (!operations_
[i
].matrix
.IsIdentityOrTranslation())
107 case TransformOperation::TransformOperationRotate
:
108 case TransformOperation::TransformOperationScale
:
109 case TransformOperation::TransformOperationSkew
:
110 case TransformOperation::TransformOperationPerspective
:
117 bool TransformOperations::MaximumScale(const TransformOperations
& from
,
118 SkMScalar min_progress
,
119 SkMScalar max_progress
,
120 float* max_scale
) const {
121 if (!MatchesTypes(from
))
124 gfx::Vector3dF from_scale
;
125 gfx::Vector3dF to_scale
;
127 if (!from
.ScaleComponent(&from_scale
) || !ScaleComponent(&to_scale
))
130 gfx::Vector3dF
scale_at_min_progress(
131 std::abs(gfx::Tween::FloatValueBetween(
132 min_progress
, from_scale
.x(), to_scale
.x())),
133 std::abs(gfx::Tween::FloatValueBetween(
134 min_progress
, from_scale
.y(), to_scale
.y())),
135 std::abs(gfx::Tween::FloatValueBetween(
136 min_progress
, from_scale
.z(), to_scale
.z())));
137 gfx::Vector3dF
scale_at_max_progress(
138 std::abs(gfx::Tween::FloatValueBetween(
139 max_progress
, from_scale
.x(), to_scale
.x())),
140 std::abs(gfx::Tween::FloatValueBetween(
141 max_progress
, from_scale
.y(), to_scale
.y())),
142 std::abs(gfx::Tween::FloatValueBetween(
143 max_progress
, from_scale
.z(), to_scale
.z())));
145 gfx::Vector3dF max_scale_3d
= scale_at_min_progress
;
146 max_scale_3d
.SetToMax(scale_at_max_progress
);
148 std::max(max_scale_3d
.x(), std::max(max_scale_3d
.y(), max_scale_3d
.z()));
152 bool TransformOperations::ScaleComponent(gfx::Vector3dF
* scale
) const {
153 *scale
= gfx::Vector3dF(1.f
, 1.f
, 1.f
);
154 bool has_scale_component
= false;
155 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
156 switch (operations_
[i
].type
) {
157 case TransformOperation::TransformOperationIdentity
:
158 case TransformOperation::TransformOperationTranslate
:
160 case TransformOperation::TransformOperationMatrix
:
161 if (!operations_
[i
].matrix
.IsIdentityOrTranslation())
164 case TransformOperation::TransformOperationRotate
:
165 case TransformOperation::TransformOperationSkew
:
166 case TransformOperation::TransformOperationPerspective
:
168 case TransformOperation::TransformOperationScale
:
169 if (has_scale_component
)
171 has_scale_component
= true;
172 scale
->Scale(operations_
[i
].scale
.x
,
173 operations_
[i
].scale
.y
,
174 operations_
[i
].scale
.z
);
180 bool TransformOperations::MatchesTypes(const TransformOperations
& other
) const {
181 if (IsIdentity() || other
.IsIdentity())
184 if (operations_
.size() != other
.operations_
.size())
187 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
188 if (operations_
[i
].type
!= other
.operations_
[i
].type
189 && !operations_
[i
].IsIdentity()
190 && !other
.operations_
[i
].IsIdentity())
197 bool TransformOperations::CanBlendWith(
198 const TransformOperations
& other
) const {
199 gfx::Transform dummy
;
200 return BlendInternal(other
, 0.5, &dummy
);
203 void TransformOperations::AppendTranslate(SkMScalar x
,
206 TransformOperation to_add
;
207 to_add
.matrix
.Translate3d(x
, y
, z
);
208 to_add
.type
= TransformOperation::TransformOperationTranslate
;
209 to_add
.translate
.x
= x
;
210 to_add
.translate
.y
= y
;
211 to_add
.translate
.z
= z
;
212 operations_
.push_back(to_add
);
213 decomposed_transform_dirty_
= true;
216 void TransformOperations::AppendRotate(SkMScalar x
,
220 TransformOperation to_add
;
221 to_add
.matrix
.RotateAbout(gfx::Vector3dF(x
, y
, z
), degrees
);
222 to_add
.type
= TransformOperation::TransformOperationRotate
;
223 to_add
.rotate
.axis
.x
= x
;
224 to_add
.rotate
.axis
.y
= y
;
225 to_add
.rotate
.axis
.z
= z
;
226 to_add
.rotate
.angle
= degrees
;
227 operations_
.push_back(to_add
);
228 decomposed_transform_dirty_
= true;
231 void TransformOperations::AppendScale(SkMScalar x
, SkMScalar y
, SkMScalar z
) {
232 TransformOperation to_add
;
233 to_add
.matrix
.Scale3d(x
, y
, z
);
234 to_add
.type
= TransformOperation::TransformOperationScale
;
238 operations_
.push_back(to_add
);
239 decomposed_transform_dirty_
= true;
242 void TransformOperations::AppendSkew(SkMScalar x
, SkMScalar y
) {
243 TransformOperation to_add
;
244 to_add
.matrix
.SkewX(x
);
245 to_add
.matrix
.SkewY(y
);
246 to_add
.type
= TransformOperation::TransformOperationSkew
;
249 operations_
.push_back(to_add
);
250 decomposed_transform_dirty_
= true;
253 void TransformOperations::AppendPerspective(SkMScalar depth
) {
254 TransformOperation to_add
;
255 to_add
.matrix
.ApplyPerspectiveDepth(depth
);
256 to_add
.type
= TransformOperation::TransformOperationPerspective
;
257 to_add
.perspective_depth
= depth
;
258 operations_
.push_back(to_add
);
259 decomposed_transform_dirty_
= true;
262 void TransformOperations::AppendMatrix(const gfx::Transform
& matrix
) {
263 TransformOperation to_add
;
264 to_add
.matrix
= matrix
;
265 to_add
.type
= TransformOperation::TransformOperationMatrix
;
266 operations_
.push_back(to_add
);
267 decomposed_transform_dirty_
= true;
270 void TransformOperations::AppendIdentity() {
271 operations_
.push_back(TransformOperation());
274 bool TransformOperations::IsIdentity() const {
275 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
276 if (!operations_
[i
].IsIdentity())
282 bool TransformOperations::BlendInternal(const TransformOperations
& from
,
284 gfx::Transform
* result
) const {
285 bool from_identity
= from
.IsIdentity();
286 bool to_identity
= IsIdentity();
287 if (from_identity
&& to_identity
)
290 if (MatchesTypes(from
)) {
291 size_t num_operations
=
292 std::max(from_identity
? 0 : from
.operations_
.size(),
293 to_identity
? 0 : operations_
.size());
294 for (size_t i
= 0; i
< num_operations
; ++i
) {
295 gfx::Transform blended
;
296 if (!TransformOperation::BlendTransformOperations(
297 from_identity
? 0 : &from
.operations_
[i
],
298 to_identity
? 0 : &operations_
[i
],
302 result
->PreconcatTransform(blended
);
307 if (!ComputeDecomposedTransform() || !from
.ComputeDecomposedTransform())
310 gfx::DecomposedTransform to_return
;
311 if (!gfx::BlendDecomposedTransforms(&to_return
,
312 *decomposed_transform_
.get(),
313 *from
.decomposed_transform_
.get(),
317 *result
= ComposeTransform(to_return
);
321 bool TransformOperations::ComputeDecomposedTransform() const {
322 if (decomposed_transform_dirty_
) {
323 if (!decomposed_transform_
)
324 decomposed_transform_
.reset(new gfx::DecomposedTransform());
325 gfx::Transform transform
= Apply();
326 if (!gfx::DecomposeTransform(decomposed_transform_
.get(), transform
))
328 decomposed_transform_dirty_
= false;