Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: cc/transform_operations.cc

Issue 11876016: Define cc::TransformOperations and webkit::WebTransformOperationsImpl (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fix nits Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include <algorithm>
6 #include <cmath>
7 #include <limits>
8 #include <vector>
9
10 #include "cc/transform_operations.h"
11
12 using WebKit::WebTransformationMatrix;
13
14 namespace {
15 const double kAngleEpsilon = 1e-4;
16 }
17
18 namespace cc {
19
20 struct TransformOperation {
21 enum Type {
22 TransformOperationTranslate,
23 TransformOperationRotate,
24 TransformOperationScale,
25 TransformOperationSkew,
26 TransformOperationPerspective,
27 TransformOperationMatrix,
28 TransformOperationIdentity
29 };
30
31 TransformOperation()
32 : type(TransformOperationIdentity) {
33 }
34
35 Type type;
36 WebKit::WebTransformationMatrix matrix;
37
38 union {
39 double perspective_depth;
40
41 struct {
42 double x, y;
43 } skew;
44
45 struct {
46 double x, y, z;
47 } scale;
48
49 struct {
50 double x, y, z;
51 } translate;
52
53 struct {
54 struct {
55 double x, y, z;
56 } axis;
57
58 double angle;
59 } rotate;
60 };
61
62 bool IsIdentity() const { return matrix.isIdentity(); }
63 };
64
65 TransformOperations::TransformOperations() {
66 }
67
68 TransformOperations::TransformOperations(const TransformOperations& other) {
69 operations_ = other.operations_;
70 }
71
72 TransformOperations::~TransformOperations() {
73 }
74
75 WebTransformationMatrix TransformOperations::Apply() const {
76 WebTransformationMatrix to_return;
77 for (size_t i = 0; i < operations_.size(); ++i)
78 to_return.multiply(operations_[i].matrix);
79 return to_return;
80 }
81
82 static bool IsIdentity(const TransformOperation* operation) {
83 return !operation || operation->IsIdentity();
84 }
85
86 static bool ShareSameAxis(const TransformOperation* from,
87 const TransformOperation* to,
88 double& axis_x, double& axis_y, double& axis_z,
89 double& angle_from) {
90 if (IsIdentity(from) && IsIdentity(to))
91 return false;
92
93 if (IsIdentity(from) && !IsIdentity(to)) {
94 axis_x = to->rotate.axis.x;
95 axis_y = to->rotate.axis.y;
96 axis_z = to->rotate.axis.z;
97 angle_from = 0;
98 return true;
99 }
100
101 if (!IsIdentity(from) && IsIdentity(to)) {
102 axis_x = from->rotate.axis.x;
103 axis_y = from->rotate.axis.y;
104 axis_z = from->rotate.axis.z;
105 angle_from = from->rotate.angle;
106 return true;
107 }
108
109 double length_2 = from->rotate.axis.x * from->rotate.axis.x +
110 from->rotate.axis.y * from->rotate.axis.y +
111 from->rotate.axis.z * from->rotate.axis.z;
112 double other_length_2 = to->rotate.axis.x * to->rotate.axis.x +
113 to->rotate.axis.y * to->rotate.axis.y +
114 to->rotate.axis.z * to->rotate.axis.z;
115
116 if (length_2 <= kAngleEpsilon || other_length_2 <= kAngleEpsilon)
117 return false;
118
119 double dot = to->rotate.axis.x * from->rotate.axis.x +
120 to->rotate.axis.y * from->rotate.axis.y +
121 to->rotate.axis.z * from->rotate.axis.z;
122 double error = std::fabs(1.0 - (dot * dot) / (length_2 * other_length_2));
123 bool result = error < kAngleEpsilon;
124 if (result) {
125 axis_x = to->rotate.axis.x;
126 axis_y = to->rotate.axis.y;
127 axis_z = to->rotate.axis.z;
128 // If the axes are pointing in opposite directions, we need to reverse
129 // the angle.
130 angle_from = dot > 0 ? from->rotate.angle : -from->rotate.angle;
131 }
132 return result;
133 }
134
135 static double BlendDoubles(double from, double to, double progress) {
136 return from * (1 - progress) + to * progress;
137 }
138
139 static bool BlendTransformOperations(const TransformOperation* from,
140 const TransformOperation* to,
141 double progress,
142 WebTransformationMatrix& result) {
143 if (IsIdentity(from) && IsIdentity(to))
144 return true;
145
146 TransformOperation::Type interpolation_type =
147 TransformOperation::TransformOperationIdentity;
148 if (IsIdentity(to))
149 interpolation_type = from->type;
150 else
151 interpolation_type = to->type;
152
153 switch (interpolation_type) {
154 case TransformOperation::TransformOperationTranslate: {
155 double from_x = IsIdentity(from) ? 0 : from->translate.x;
156 double from_y = IsIdentity(from) ? 0 : from->translate.y;
157 double from_z = IsIdentity(from) ? 0 : from->translate.z;
158 double to_x = IsIdentity(to) ? 0 : to->translate.x;
159 double to_y = IsIdentity(to) ? 0 : to->translate.y;
160 double to_z = IsIdentity(to) ? 0 : to->translate.z;
161 result.translate3d(BlendDoubles(from_x, to_x, progress),
162 BlendDoubles(from_y, to_y, progress),
163 BlendDoubles(from_z, to_z, progress));
164 break;
165 }
166 case TransformOperation::TransformOperationRotate: {
167 double axis_x = 0;
168 double axis_y = 0;
169 double axis_z = 1;
170 double from_angle = 0;
171 double to_angle = IsIdentity(to) ? 0 : to->rotate.angle;
172 if (ShareSameAxis(from, to, axis_x, axis_y, axis_z, from_angle))
173 result.rotate3d(axis_x, axis_y, axis_z,
174 BlendDoubles(from_angle, to_angle, progress));
175 else {
176 WebTransformationMatrix to_matrix;
177 if (!IsIdentity(to))
178 to_matrix = to->matrix;
179 WebTransformationMatrix from_matrix;
180 if (!IsIdentity(from))
181 from_matrix = from->matrix;
182 result = to_matrix;
183 if (!result.blend(from_matrix, progress))
184 return false;
185 }
186 break;
187 }
188 case TransformOperation::TransformOperationScale: {
189 double from_x = IsIdentity(from) ? 1 : from->scale.x;
190 double from_y = IsIdentity(from) ? 1 : from->scale.y;
191 double from_z = IsIdentity(from) ? 1 : from->scale.z;
192 double to_x = IsIdentity(to) ? 1 : to->scale.x;
193 double to_y = IsIdentity(to) ? 1 : to->scale.y;
194 double to_z = IsIdentity(to) ? 1 : to->scale.z;
195 result.scale3d(BlendDoubles(from_x, to_x, progress),
196 BlendDoubles(from_y, to_y, progress),
197 BlendDoubles(from_z, to_z, progress));
198 break;
199 }
200 case TransformOperation::TransformOperationSkew: {
201 double from_x = IsIdentity(from) ? 0 : from->skew.x;
202 double from_y = IsIdentity(from) ? 0 : from->skew.y;
203 double to_x = IsIdentity(to) ? 0 : to->skew.x;
204 double to_y = IsIdentity(to) ? 0 : to->skew.y;
205 result.skewX(BlendDoubles(from_x, to_x, progress));
206 result.skewY(BlendDoubles(from_y, to_y, progress));
207 break;
208 }
209 case TransformOperation::TransformOperationPerspective: {
210 double from_perspective_depth = IsIdentity(from) ?
211 std::numeric_limits<double>::max() : from->perspective_depth;
212 double to_perspective_depth = IsIdentity(to) ?
213 std::numeric_limits<double>::max() : to->perspective_depth;
214 result.applyPerspective(
215 BlendDoubles(from_perspective_depth, to_perspective_depth, progress));
216 break;
217 }
218 case TransformOperation::TransformOperationMatrix: {
219 WebTransformationMatrix to_matrix;
220 if (!IsIdentity(to))
221 to_matrix = to->matrix;
222 WebTransformationMatrix from_matrix;
223 if (!IsIdentity(from))
224 from_matrix = from->matrix;
225 result = to_matrix;
226 if (!result.blend(from_matrix, progress))
227 return false;
228 break;
229 }
230 case TransformOperation::TransformOperationIdentity:
231 // Do nothing.
232 break;
233 }
234
235 return true;
236 }
237
238 WebTransformationMatrix TransformOperations::Blend(
239 const TransformOperations& from, double progress) const {
240 WebTransformationMatrix to_return;
241 BlendInternal(from, progress, to_return);
242 return to_return;
243 }
244
245 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
246 if (IsIdentity() || other.IsIdentity())
247 return true;
248
249 if (operations_.size() != other.operations_.size())
250 return false;
251
252 for (size_t i = 0; i < operations_.size(); ++i) {
253 if (operations_[i].type != other.operations_[i].type
254 && !operations_[i].IsIdentity()
255 && !other.operations_[i].IsIdentity())
256 return false;
257 }
258
259 return true;
260 }
261
262 bool TransformOperations::CanBlendWith(
263 const TransformOperations& other) const {
264 WebTransformationMatrix dummy;
265 return BlendInternal(other, 0.5, dummy);
266 }
267
268 void TransformOperations::AppendTranslate(double x, double y, double z) {
269 TransformOperation to_add;
270 to_add.matrix.translate3d(x, y, z);
271 to_add.type = TransformOperation::TransformOperationTranslate;
272 to_add.translate.x = x;
273 to_add.translate.y = y;
274 to_add.translate.z = z;
275 operations_.push_back(to_add);
276 }
277
278 void TransformOperations::AppendRotate(double x, double y, double z,
279 double degrees) {
280 TransformOperation to_add;
281 to_add.matrix.rotate3d(x, y, z, degrees);
282 to_add.type = TransformOperation::TransformOperationRotate;
283 to_add.rotate.axis.x = x;
284 to_add.rotate.axis.y = y;
285 to_add.rotate.axis.z = z;
286 to_add.rotate.angle = degrees;
287 operations_.push_back(to_add);
288 }
289
290 void TransformOperations::AppendScale(double x, double y, double z) {
291 TransformOperation to_add;
292 to_add.matrix.scale3d(x, y, z);
293 to_add.type = TransformOperation::TransformOperationScale;
294 to_add.scale.x = x;
295 to_add.scale.y = y;
296 to_add.scale.z = z;
297 operations_.push_back(to_add);
298 }
299
300 void TransformOperations::AppendSkew(double x, double y) {
301 TransformOperation to_add;
302 to_add.matrix.skewX(x);
303 to_add.matrix.skewY(y);
304 to_add.type = TransformOperation::TransformOperationSkew;
305 to_add.skew.x = x;
306 to_add.skew.y = y;
307 operations_.push_back(to_add);
308 }
309
310 void TransformOperations::AppendPerspective(double depth) {
311 TransformOperation to_add;
312 to_add.matrix.applyPerspective(depth);
313 to_add.type = TransformOperation::TransformOperationPerspective;
314 to_add.perspective_depth = depth;
315 operations_.push_back(to_add);
316 }
317
318 void TransformOperations::AppendMatrix(const WebTransformationMatrix& matrix) {
319 TransformOperation to_add;
320 to_add.matrix = matrix;
321 to_add.type = TransformOperation::TransformOperationMatrix;
322 operations_.push_back(to_add);
323 }
324
325 void TransformOperations::AppendIdentity() {
326 operations_.push_back(TransformOperation());
327 }
328
329 bool TransformOperations::IsIdentity() const {
330 for (size_t i = 0; i < operations_.size(); ++i) {
331 if (!operations_[i].IsIdentity())
332 return false;
333 }
334 return true;
335 }
336
337 bool TransformOperations::BlendInternal(const TransformOperations& from,
338 double progress,
339 WebTransformationMatrix& result) const {
340 bool from_identity = from.IsIdentity();
341 bool to_identity = IsIdentity();
342 if (from_identity && to_identity)
343 return true;
344
345 if (MatchesTypes(from)) {
346 size_t num_operations =
347 std::max(from_identity ? 0 : from.operations_.size(),
348 to_identity ? 0 : operations_.size());
349 for (size_t i = 0; i < num_operations; ++i) {
350 WebTransformationMatrix blended;
351 if (!BlendTransformOperations(
352 from_identity ? 0 : &from.operations_[i],
353 to_identity ? 0 : &operations_[i],
354 progress,
355 blended))
356 return false;
357 result.multiply(blended);
358 }
359 return true;
360 }
361
362 result = Apply();
363 WebTransformationMatrix from_transform = from.Apply();
364 return result.blend(from_transform, progress);
365 }
366
367 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698