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/box_f.h"
10 #include "ui/gfx/transform_util.h"
11 #include "ui/gfx/vector3d_f.h"
15 TransformOperations::TransformOperations()
16 : decomposed_transform_dirty_(true) {
19 TransformOperations::TransformOperations(const TransformOperations
& other
) {
20 operations_
= other
.operations_
;
21 decomposed_transform_dirty_
= other
.decomposed_transform_dirty_
;
22 if (!decomposed_transform_dirty_
) {
23 decomposed_transform_
.reset(
24 new gfx::DecomposedTransform(*other
.decomposed_transform_
.get()));
28 TransformOperations::~TransformOperations() {
31 gfx::Transform
TransformOperations::Apply() const {
32 gfx::Transform to_return
;
33 for (size_t i
= 0; i
< operations_
.size(); ++i
)
34 to_return
.PreconcatTransform(operations_
[i
].matrix
);
38 gfx::Transform
TransformOperations::Blend(const TransformOperations
& from
,
39 SkMScalar progress
) const {
40 gfx::Transform to_return
;
41 BlendInternal(from
, progress
, &to_return
);
45 bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF
& box
,
46 const TransformOperations
& from
,
47 SkMScalar min_progress
,
48 SkMScalar max_progress
,
49 gfx::BoxF
* bounds
) const {
52 bool from_identity
= from
.IsIdentity();
53 bool to_identity
= IsIdentity();
54 if (from_identity
&& to_identity
)
57 if (!MatchesTypes(from
))
60 size_t num_operations
=
61 std::max(from_identity
? 0 : from
.operations_
.size(),
62 to_identity
? 0 : operations_
.size());
63 for (size_t i
= 0; i
< num_operations
; ++i
) {
64 gfx::BoxF bounds_for_operation
;
65 const TransformOperation
* from_op
=
66 from_identity
? NULL
: &from
.operations_
[i
];
67 const TransformOperation
* to_op
= to_identity
? NULL
: &operations_
[i
];
68 if (!TransformOperation::BlendedBoundsForBox(*bounds
,
73 &bounds_for_operation
))
75 *bounds
= bounds_for_operation
;
81 bool TransformOperations::MatchesTypes(const TransformOperations
& other
) const {
82 if (IsIdentity() || other
.IsIdentity())
85 if (operations_
.size() != other
.operations_
.size())
88 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
89 if (operations_
[i
].type
!= other
.operations_
[i
].type
90 && !operations_
[i
].IsIdentity()
91 && !other
.operations_
[i
].IsIdentity())
98 bool TransformOperations::CanBlendWith(
99 const TransformOperations
& other
) const {
100 gfx::Transform dummy
;
101 return BlendInternal(other
, 0.5, &dummy
);
104 void TransformOperations::AppendTranslate(SkMScalar x
,
107 TransformOperation to_add
;
108 to_add
.matrix
.Translate3d(x
, y
, z
);
109 to_add
.type
= TransformOperation::TransformOperationTranslate
;
110 to_add
.translate
.x
= x
;
111 to_add
.translate
.y
= y
;
112 to_add
.translate
.z
= z
;
113 operations_
.push_back(to_add
);
114 decomposed_transform_dirty_
= true;
117 void TransformOperations::AppendRotate(SkMScalar x
,
121 TransformOperation to_add
;
122 to_add
.matrix
.RotateAbout(gfx::Vector3dF(x
, y
, z
), degrees
);
123 to_add
.type
= TransformOperation::TransformOperationRotate
;
124 to_add
.rotate
.axis
.x
= x
;
125 to_add
.rotate
.axis
.y
= y
;
126 to_add
.rotate
.axis
.z
= z
;
127 to_add
.rotate
.angle
= degrees
;
128 operations_
.push_back(to_add
);
129 decomposed_transform_dirty_
= true;
132 void TransformOperations::AppendScale(SkMScalar x
, SkMScalar y
, SkMScalar z
) {
133 TransformOperation to_add
;
134 to_add
.matrix
.Scale3d(x
, y
, z
);
135 to_add
.type
= TransformOperation::TransformOperationScale
;
139 operations_
.push_back(to_add
);
140 decomposed_transform_dirty_
= true;
143 void TransformOperations::AppendSkew(SkMScalar x
, SkMScalar y
) {
144 TransformOperation to_add
;
145 to_add
.matrix
.SkewX(x
);
146 to_add
.matrix
.SkewY(y
);
147 to_add
.type
= TransformOperation::TransformOperationSkew
;
150 operations_
.push_back(to_add
);
151 decomposed_transform_dirty_
= true;
154 void TransformOperations::AppendPerspective(SkMScalar depth
) {
155 TransformOperation to_add
;
156 to_add
.matrix
.ApplyPerspectiveDepth(depth
);
157 to_add
.type
= TransformOperation::TransformOperationPerspective
;
158 to_add
.perspective_depth
= depth
;
159 operations_
.push_back(to_add
);
160 decomposed_transform_dirty_
= true;
163 void TransformOperations::AppendMatrix(const gfx::Transform
& matrix
) {
164 TransformOperation to_add
;
165 to_add
.matrix
= matrix
;
166 to_add
.type
= TransformOperation::TransformOperationMatrix
;
167 operations_
.push_back(to_add
);
168 decomposed_transform_dirty_
= true;
171 void TransformOperations::AppendIdentity() {
172 operations_
.push_back(TransformOperation());
175 bool TransformOperations::IsIdentity() const {
176 for (size_t i
= 0; i
< operations_
.size(); ++i
) {
177 if (!operations_
[i
].IsIdentity())
183 bool TransformOperations::BlendInternal(const TransformOperations
& from
,
185 gfx::Transform
* result
) const {
186 bool from_identity
= from
.IsIdentity();
187 bool to_identity
= IsIdentity();
188 if (from_identity
&& to_identity
)
191 if (MatchesTypes(from
)) {
192 size_t num_operations
=
193 std::max(from_identity
? 0 : from
.operations_
.size(),
194 to_identity
? 0 : operations_
.size());
195 for (size_t i
= 0; i
< num_operations
; ++i
) {
196 gfx::Transform blended
;
197 if (!TransformOperation::BlendTransformOperations(
198 from_identity
? 0 : &from
.operations_
[i
],
199 to_identity
? 0 : &operations_
[i
],
203 result
->PreconcatTransform(blended
);
208 if (!ComputeDecomposedTransform() || !from
.ComputeDecomposedTransform())
211 gfx::DecomposedTransform to_return
;
212 if (!gfx::BlendDecomposedTransforms(&to_return
,
213 *decomposed_transform_
.get(),
214 *from
.decomposed_transform_
.get(),
218 *result
= ComposeTransform(to_return
);
222 bool TransformOperations::ComputeDecomposedTransform() const {
223 if (decomposed_transform_dirty_
) {
224 if (!decomposed_transform_
)
225 decomposed_transform_
.reset(new gfx::DecomposedTransform());
226 gfx::Transform transform
= Apply();
227 if (!gfx::DecomposeTransform(decomposed_transform_
.get(), transform
))
229 decomposed_transform_dirty_
= false;