Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / cc / animation / transform_operations.cc
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 "cc/animation/transform_operations.h"
6
7 #include <algorithm>
8
9 #include "ui/gfx/animation/tween.h"
10 #include "ui/gfx/geometry/box_f.h"
11 #include "ui/gfx/geometry/vector3d_f.h"
12 #include "ui/gfx/transform_util.h"
13
14 namespace cc {
15
16 TransformOperations::TransformOperations()
17     : decomposed_transform_dirty_(true) {
18 }
19
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()));
26   }
27 }
28
29 TransformOperations::~TransformOperations() {
30 }
31
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);
36   return to_return;
37 }
38
39 gfx::Transform TransformOperations::Blend(const TransformOperations& from,
40                                           SkMScalar progress) const {
41   gfx::Transform to_return;
42   BlendInternal(from, progress, &to_return);
43   return to_return;
44 }
45
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 {
51   *bounds = box;
52
53   bool from_identity = from.IsIdentity();
54   bool to_identity = IsIdentity();
55   if (from_identity && to_identity)
56     return true;
57
58   if (!MatchesTypes(from))
59     return false;
60
61   size_t num_operations =
62       std::max(from_identity ? 0 : from.operations_.size(),
63                to_identity ? 0 : operations_.size());
64
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 ? nullptr : &from.operations_[i];
72     const TransformOperation* to_op = to_identity ? nullptr : &operations_[i];
73     if (!TransformOperation::BlendedBoundsForBox(*bounds,
74                                                  from_op,
75                                                  to_op,
76                                                  min_progress,
77                                                  max_progress,
78                                                  &bounds_for_operation))
79       return false;
80     *bounds = bounds_for_operation;
81   }
82
83   return true;
84 }
85
86 bool TransformOperations::AffectsScale() const {
87   for (size_t i = 0; i < operations_.size(); ++i) {
88     if (operations_[i].type == TransformOperation::TransformOperationScale)
89       return true;
90     if (operations_[i].type == TransformOperation::TransformOperationMatrix &&
91         !operations_[i].matrix.IsIdentityOrTranslation())
92       return true;
93   }
94   return false;
95 }
96
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:
102         continue;
103       case TransformOperation::TransformOperationMatrix:
104         if (!operations_[i].matrix.IsIdentityOrTranslation())
105           return false;
106         continue;
107       case TransformOperation::TransformOperationRotate:
108       case TransformOperation::TransformOperationScale:
109       case TransformOperation::TransformOperationSkew:
110       case TransformOperation::TransformOperationPerspective:
111         return false;
112     }
113   }
114   return true;
115 }
116
117 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
118   *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
119   bool has_scale_component = false;
120   for (size_t i = 0; i < operations_.size(); ++i) {
121     switch (operations_[i].type) {
122       case TransformOperation::TransformOperationIdentity:
123       case TransformOperation::TransformOperationTranslate:
124         continue;
125       case TransformOperation::TransformOperationMatrix:
126         if (!operations_[i].matrix.IsIdentityOrTranslation())
127           return false;
128         continue;
129       case TransformOperation::TransformOperationRotate:
130       case TransformOperation::TransformOperationSkew:
131       case TransformOperation::TransformOperationPerspective:
132         return false;
133       case TransformOperation::TransformOperationScale:
134         if (has_scale_component)
135           return false;
136         has_scale_component = true;
137         scale->Scale(operations_[i].scale.x,
138                      operations_[i].scale.y,
139                      operations_[i].scale.z);
140     }
141   }
142   return true;
143 }
144
145 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
146   if (IsIdentity() || other.IsIdentity())
147     return true;
148
149   if (operations_.size() != other.operations_.size())
150     return false;
151
152   for (size_t i = 0; i < operations_.size(); ++i) {
153     if (operations_[i].type != other.operations_[i].type
154       && !operations_[i].IsIdentity()
155       && !other.operations_[i].IsIdentity())
156       return false;
157   }
158
159   return true;
160 }
161
162 bool TransformOperations::CanBlendWith(
163     const TransformOperations& other) const {
164   gfx::Transform dummy;
165   return BlendInternal(other, 0.5, &dummy);
166 }
167
168 void TransformOperations::AppendTranslate(SkMScalar x,
169                                           SkMScalar y,
170                                           SkMScalar z) {
171   TransformOperation to_add;
172   to_add.matrix.Translate3d(x, y, z);
173   to_add.type = TransformOperation::TransformOperationTranslate;
174   to_add.translate.x = x;
175   to_add.translate.y = y;
176   to_add.translate.z = z;
177   operations_.push_back(to_add);
178   decomposed_transform_dirty_ = true;
179 }
180
181 void TransformOperations::AppendRotate(SkMScalar x,
182                                        SkMScalar y,
183                                        SkMScalar z,
184                                        SkMScalar degrees) {
185   TransformOperation to_add;
186   to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
187   to_add.type = TransformOperation::TransformOperationRotate;
188   to_add.rotate.axis.x = x;
189   to_add.rotate.axis.y = y;
190   to_add.rotate.axis.z = z;
191   to_add.rotate.angle = degrees;
192   operations_.push_back(to_add);
193   decomposed_transform_dirty_ = true;
194 }
195
196 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
197   TransformOperation to_add;
198   to_add.matrix.Scale3d(x, y, z);
199   to_add.type = TransformOperation::TransformOperationScale;
200   to_add.scale.x = x;
201   to_add.scale.y = y;
202   to_add.scale.z = z;
203   operations_.push_back(to_add);
204   decomposed_transform_dirty_ = true;
205 }
206
207 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
208   TransformOperation to_add;
209   to_add.matrix.SkewX(x);
210   to_add.matrix.SkewY(y);
211   to_add.type = TransformOperation::TransformOperationSkew;
212   to_add.skew.x = x;
213   to_add.skew.y = y;
214   operations_.push_back(to_add);
215   decomposed_transform_dirty_ = true;
216 }
217
218 void TransformOperations::AppendPerspective(SkMScalar depth) {
219   TransformOperation to_add;
220   to_add.matrix.ApplyPerspectiveDepth(depth);
221   to_add.type = TransformOperation::TransformOperationPerspective;
222   to_add.perspective_depth = depth;
223   operations_.push_back(to_add);
224   decomposed_transform_dirty_ = true;
225 }
226
227 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
228   TransformOperation to_add;
229   to_add.matrix = matrix;
230   to_add.type = TransformOperation::TransformOperationMatrix;
231   operations_.push_back(to_add);
232   decomposed_transform_dirty_ = true;
233 }
234
235 void TransformOperations::AppendIdentity() {
236   operations_.push_back(TransformOperation());
237 }
238
239 bool TransformOperations::IsIdentity() const {
240   for (size_t i = 0; i < operations_.size(); ++i) {
241     if (!operations_[i].IsIdentity())
242       return false;
243   }
244   return true;
245 }
246
247 bool TransformOperations::BlendInternal(const TransformOperations& from,
248                                         SkMScalar progress,
249                                         gfx::Transform* result) const {
250   bool from_identity = from.IsIdentity();
251   bool to_identity = IsIdentity();
252   if (from_identity && to_identity)
253     return true;
254
255   if (MatchesTypes(from)) {
256     size_t num_operations =
257         std::max(from_identity ? 0 : from.operations_.size(),
258                  to_identity ? 0 : operations_.size());
259     for (size_t i = 0; i < num_operations; ++i) {
260       gfx::Transform blended;
261       if (!TransformOperation::BlendTransformOperations(
262           from_identity ? 0 : &from.operations_[i],
263           to_identity ? 0 : &operations_[i],
264           progress,
265           &blended))
266           return false;
267       result->PreconcatTransform(blended);
268     }
269     return true;
270   }
271
272   if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
273     return false;
274
275   gfx::DecomposedTransform to_return;
276   if (!gfx::BlendDecomposedTransforms(&to_return,
277                                       *decomposed_transform_.get(),
278                                       *from.decomposed_transform_.get(),
279                                       progress))
280     return false;
281
282   *result = ComposeTransform(to_return);
283   return true;
284 }
285
286 bool TransformOperations::ComputeDecomposedTransform() const {
287   if (decomposed_transform_dirty_) {
288     if (!decomposed_transform_)
289       decomposed_transform_.reset(new gfx::DecomposedTransform());
290     gfx::Transform transform = Apply();
291     if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
292       return false;
293     decomposed_transform_dirty_ = false;
294   }
295   return true;
296 }
297
298 }  // namespace cc