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/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
,
27 double& axis_x
, double& axis_y
, double& axis_z
,
29 if (IsOperationIdentity(from
) && IsOperationIdentity(to
))
32 if (IsOperationIdentity(from
) && !IsOperationIdentity(to
)) {
33 axis_x
= to
->rotate
.axis
.x
;
34 axis_y
= to
->rotate
.axis
.y
;
35 axis_z
= to
->rotate
.axis
.z
;
40 if (!IsOperationIdentity(from
) && IsOperationIdentity(to
)) {
41 axis_x
= from
->rotate
.axis
.x
;
42 axis_y
= from
->rotate
.axis
.y
;
43 axis_z
= from
->rotate
.axis
.z
;
44 angle_from
= from
->rotate
.angle
;
48 double length_2
= from
->rotate
.axis
.x
* from
->rotate
.axis
.x
+
49 from
->rotate
.axis
.y
* from
->rotate
.axis
.y
+
50 from
->rotate
.axis
.z
* from
->rotate
.axis
.z
;
51 double other_length_2
= to
->rotate
.axis
.x
* to
->rotate
.axis
.x
+
52 to
->rotate
.axis
.y
* to
->rotate
.axis
.y
+
53 to
->rotate
.axis
.z
* to
->rotate
.axis
.z
;
55 if (length_2
<= kAngleEpsilon
|| other_length_2
<= kAngleEpsilon
)
58 double dot
= to
->rotate
.axis
.x
* from
->rotate
.axis
.x
+
59 to
->rotate
.axis
.y
* from
->rotate
.axis
.y
+
60 to
->rotate
.axis
.z
* from
->rotate
.axis
.z
;
61 double error
= std::fabs(1.0 - (dot
* dot
) / (length_2
* other_length_2
));
62 bool result
= error
< kAngleEpsilon
;
64 axis_x
= to
->rotate
.axis
.x
;
65 axis_y
= to
->rotate
.axis
.y
;
66 axis_z
= to
->rotate
.axis
.z
;
67 // If the axes are pointing in opposite directions, we need to reverse
69 angle_from
= dot
> 0 ? from
->rotate
.angle
: -from
->rotate
.angle
;
74 static double BlendDoubles(double from
, double to
, double progress
) {
81 return from
* (1 - progress
) + to
* progress
;
84 bool TransformOperation::BlendTransformOperations(
85 const TransformOperation
* from
,
86 const TransformOperation
* to
,
88 gfx::Transform
& result
) {
89 if (IsOperationIdentity(from
) && IsOperationIdentity(to
))
92 TransformOperation::Type interpolation_type
=
93 TransformOperation::TransformOperationIdentity
;
94 if (IsOperationIdentity(to
))
95 interpolation_type
= from
->type
;
97 interpolation_type
= to
->type
;
99 switch (interpolation_type
) {
100 case TransformOperation::TransformOperationTranslate
: {
101 double from_x
= IsOperationIdentity(from
) ? 0 : from
->translate
.x
;
102 double from_y
= IsOperationIdentity(from
) ? 0 : from
->translate
.y
;
103 double from_z
= IsOperationIdentity(from
) ? 0 : from
->translate
.z
;
104 double to_x
= IsOperationIdentity(to
) ? 0 : to
->translate
.x
;
105 double to_y
= IsOperationIdentity(to
) ? 0 : to
->translate
.y
;
106 double to_z
= IsOperationIdentity(to
) ? 0 : to
->translate
.z
;
107 result
.Translate3d(BlendDoubles(from_x
, to_x
, progress
),
108 BlendDoubles(from_y
, to_y
, progress
),
109 BlendDoubles(from_z
, to_z
, progress
));
112 case TransformOperation::TransformOperationRotate
: {
116 double from_angle
= 0;
117 double to_angle
= IsOperationIdentity(to
) ? 0 : to
->rotate
.angle
;
118 if (ShareSameAxis(from
, to
, axis_x
, axis_y
, axis_z
, from_angle
))
119 result
.RotateAbout(gfx::Vector3dF(axis_x
, axis_y
, axis_z
),
120 BlendDoubles(from_angle
, to_angle
, progress
));
122 gfx::Transform to_matrix
;
123 if (!IsOperationIdentity(to
))
124 to_matrix
= to
->matrix
;
125 gfx::Transform from_matrix
;
126 if (!IsOperationIdentity(from
))
127 from_matrix
= from
->matrix
;
129 if (!result
.Blend(from_matrix
, progress
))
134 case TransformOperation::TransformOperationScale
: {
135 double from_x
= IsOperationIdentity(from
) ? 1 : from
->scale
.x
;
136 double from_y
= IsOperationIdentity(from
) ? 1 : from
->scale
.y
;
137 double from_z
= IsOperationIdentity(from
) ? 1 : from
->scale
.z
;
138 double to_x
= IsOperationIdentity(to
) ? 1 : to
->scale
.x
;
139 double to_y
= IsOperationIdentity(to
) ? 1 : to
->scale
.y
;
140 double to_z
= IsOperationIdentity(to
) ? 1 : to
->scale
.z
;
141 result
.Scale3d(BlendDoubles(from_x
, to_x
, progress
),
142 BlendDoubles(from_y
, to_y
, progress
),
143 BlendDoubles(from_z
, to_z
, progress
));
146 case TransformOperation::TransformOperationSkew
: {
147 double from_x
= IsOperationIdentity(from
) ? 0 : from
->skew
.x
;
148 double from_y
= IsOperationIdentity(from
) ? 0 : from
->skew
.y
;
149 double to_x
= IsOperationIdentity(to
) ? 0 : to
->skew
.x
;
150 double to_y
= IsOperationIdentity(to
) ? 0 : to
->skew
.y
;
151 result
.SkewX(BlendDoubles(from_x
, to_x
, progress
));
152 result
.SkewY(BlendDoubles(from_y
, to_y
, progress
));
155 case TransformOperation::TransformOperationPerspective
: {
156 double from_perspective_depth
= IsOperationIdentity(from
) ?
157 std::numeric_limits
<double>::max() : from
->perspective_depth
;
158 double to_perspective_depth
= IsOperationIdentity(to
) ?
159 std::numeric_limits
<double>::max() : to
->perspective_depth
;
160 result
.ApplyPerspectiveDepth(
161 BlendDoubles(from_perspective_depth
, to_perspective_depth
, progress
));
164 case TransformOperation::TransformOperationMatrix
: {
165 gfx::Transform to_matrix
;
166 if (!IsOperationIdentity(to
))
167 to_matrix
= to
->matrix
;
168 gfx::Transform from_matrix
;
169 if (!IsOperationIdentity(from
))
170 from_matrix
= from
->matrix
;
172 if (!result
.Blend(from_matrix
, progress
))
176 case TransformOperation::TransformOperationIdentity
: