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.
8 #include "cc/animation/transform_operation.h"
9 #include "ui/gfx/vector3d_f.h"
12 const double kAngleEpsilon
= 1e-4;
17 bool TransformOperation::IsIdentity() const {
18 return matrix
.IsIdentity();
21 static bool IsOperationIdentity(const TransformOperation
* operation
) {
22 return !operation
|| operation
->IsIdentity();
25 static bool ShareSameAxis(const TransformOperation
* from
,
26 const TransformOperation
* to
,
31 if (IsOperationIdentity(from
) && IsOperationIdentity(to
))
34 if (IsOperationIdentity(from
) && !IsOperationIdentity(to
)) {
35 *axis_x
= to
->rotate
.axis
.x
;
36 *axis_y
= to
->rotate
.axis
.y
;
37 *axis_z
= to
->rotate
.axis
.z
;
42 if (!IsOperationIdentity(from
) && IsOperationIdentity(to
)) {
43 *axis_x
= from
->rotate
.axis
.x
;
44 *axis_y
= from
->rotate
.axis
.y
;
45 *axis_z
= from
->rotate
.axis
.z
;
46 *angle_from
= from
->rotate
.angle
;
50 double length_2
= from
->rotate
.axis
.x
* from
->rotate
.axis
.x
+
51 from
->rotate
.axis
.y
* from
->rotate
.axis
.y
+
52 from
->rotate
.axis
.z
* from
->rotate
.axis
.z
;
53 double other_length_2
= to
->rotate
.axis
.x
* to
->rotate
.axis
.x
+
54 to
->rotate
.axis
.y
* to
->rotate
.axis
.y
+
55 to
->rotate
.axis
.z
* to
->rotate
.axis
.z
;
57 if (length_2
<= kAngleEpsilon
|| other_length_2
<= kAngleEpsilon
)
60 double dot
= to
->rotate
.axis
.x
* from
->rotate
.axis
.x
+
61 to
->rotate
.axis
.y
* from
->rotate
.axis
.y
+
62 to
->rotate
.axis
.z
* from
->rotate
.axis
.z
;
63 double error
= std::fabs(1.0 - (dot
* dot
) / (length_2
* other_length_2
));
64 bool result
= error
< kAngleEpsilon
;
66 *axis_x
= to
->rotate
.axis
.x
;
67 *axis_y
= to
->rotate
.axis
.y
;
68 *axis_z
= to
->rotate
.axis
.z
;
69 // If the axes are pointing in opposite directions, we need to reverse
71 *angle_from
= dot
> 0 ? from
->rotate
.angle
: -from
->rotate
.angle
;
76 static double BlendDoubles(double from
, double to
, double progress
) {
77 return from
* (1 - progress
) + to
* progress
;
80 bool TransformOperation::BlendTransformOperations(
81 const TransformOperation
* from
,
82 const TransformOperation
* to
,
84 gfx::Transform
* result
) {
85 if (IsOperationIdentity(from
) && IsOperationIdentity(to
))
88 TransformOperation::Type interpolation_type
=
89 TransformOperation::TransformOperationIdentity
;
90 if (IsOperationIdentity(to
))
91 interpolation_type
= from
->type
;
93 interpolation_type
= to
->type
;
95 switch (interpolation_type
) {
96 case TransformOperation::TransformOperationTranslate
: {
97 double from_x
= IsOperationIdentity(from
) ? 0 : from
->translate
.x
;
98 double from_y
= IsOperationIdentity(from
) ? 0 : from
->translate
.y
;
99 double from_z
= IsOperationIdentity(from
) ? 0 : from
->translate
.z
;
100 double to_x
= IsOperationIdentity(to
) ? 0 : to
->translate
.x
;
101 double to_y
= IsOperationIdentity(to
) ? 0 : to
->translate
.y
;
102 double to_z
= IsOperationIdentity(to
) ? 0 : to
->translate
.z
;
103 result
->Translate3d(BlendDoubles(from_x
, to_x
, progress
),
104 BlendDoubles(from_y
, to_y
, progress
),
105 BlendDoubles(from_z
, to_z
, progress
));
108 case TransformOperation::TransformOperationRotate
: {
112 double from_angle
= 0;
113 double to_angle
= IsOperationIdentity(to
) ? 0 : to
->rotate
.angle
;
114 if (ShareSameAxis(from
, to
, &axis_x
, &axis_y
, &axis_z
, &from_angle
)) {
115 result
->RotateAbout(gfx::Vector3dF(axis_x
, axis_y
, axis_z
),
116 BlendDoubles(from_angle
, to_angle
, progress
));
118 gfx::Transform to_matrix
;
119 if (!IsOperationIdentity(to
))
120 to_matrix
= to
->matrix
;
121 gfx::Transform from_matrix
;
122 if (!IsOperationIdentity(from
))
123 from_matrix
= from
->matrix
;
125 if (!result
->Blend(from_matrix
, progress
))
130 case TransformOperation::TransformOperationScale
: {
131 double from_x
= IsOperationIdentity(from
) ? 1 : from
->scale
.x
;
132 double from_y
= IsOperationIdentity(from
) ? 1 : from
->scale
.y
;
133 double from_z
= IsOperationIdentity(from
) ? 1 : from
->scale
.z
;
134 double to_x
= IsOperationIdentity(to
) ? 1 : to
->scale
.x
;
135 double to_y
= IsOperationIdentity(to
) ? 1 : to
->scale
.y
;
136 double to_z
= IsOperationIdentity(to
) ? 1 : to
->scale
.z
;
137 result
->Scale3d(BlendDoubles(from_x
, to_x
, progress
),
138 BlendDoubles(from_y
, to_y
, progress
),
139 BlendDoubles(from_z
, to_z
, progress
));
142 case TransformOperation::TransformOperationSkew
: {
143 double from_x
= IsOperationIdentity(from
) ? 0 : from
->skew
.x
;
144 double from_y
= IsOperationIdentity(from
) ? 0 : from
->skew
.y
;
145 double to_x
= IsOperationIdentity(to
) ? 0 : to
->skew
.x
;
146 double to_y
= IsOperationIdentity(to
) ? 0 : to
->skew
.y
;
147 result
->SkewX(BlendDoubles(from_x
, to_x
, progress
));
148 result
->SkewY(BlendDoubles(from_y
, to_y
, progress
));
151 case TransformOperation::TransformOperationPerspective
: {
152 double from_perspective_depth
= IsOperationIdentity(from
) ?
153 std::numeric_limits
<double>::max() : from
->perspective_depth
;
154 double to_perspective_depth
= IsOperationIdentity(to
) ?
155 std::numeric_limits
<double>::max() : to
->perspective_depth
;
156 result
->ApplyPerspectiveDepth(
157 BlendDoubles(from_perspective_depth
, to_perspective_depth
, progress
));
160 case TransformOperation::TransformOperationMatrix
: {
161 gfx::Transform to_matrix
;
162 if (!IsOperationIdentity(to
))
163 to_matrix
= to
->matrix
;
164 gfx::Transform from_matrix
;
165 if (!IsOperationIdentity(from
))
166 from_matrix
= from
->matrix
;
168 if (!result
->Blend(from_matrix
, progress
))
172 case TransformOperation::TransformOperationIdentity
: