• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/box_f.h"
11 #include "ui/gfx/transform_util.h"
12 #include "ui/gfx/vector3d_f.h"
13 
14 namespace cc {
15 
TransformOperations()16 TransformOperations::TransformOperations()
17     : decomposed_transform_dirty_(true) {
18 }
19 
TransformOperations(const TransformOperations & other)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 
~TransformOperations()29 TransformOperations::~TransformOperations() {
30 }
31 
Apply() const32 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 
Blend(const TransformOperations & from,SkMScalar progress) const39 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 
BlendedBoundsForBox(const gfx::BoxF & box,const TransformOperations & from,SkMScalar min_progress,SkMScalar max_progress,gfx::BoxF * bounds) const46 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 ? NULL : &from.operations_[i];
72     const TransformOperation* to_op = to_identity ? NULL : &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 
AffectsScale() const86 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 
IsTranslation() const97 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 
MaximumScale(const TransformOperations & from,SkMScalar min_progress,SkMScalar max_progress,float * max_scale) const117 bool TransformOperations::MaximumScale(const TransformOperations& from,
118                                        SkMScalar min_progress,
119                                        SkMScalar max_progress,
120                                        float* max_scale) const {
121   if (!MatchesTypes(from))
122     return false;
123 
124   gfx::Vector3dF from_scale;
125   gfx::Vector3dF to_scale;
126 
127   if (!from.ScaleComponent(&from_scale) || !ScaleComponent(&to_scale))
128     return false;
129 
130   gfx::Vector3dF scale_at_min_progress(
131       std::abs(gfx::Tween::FloatValueBetween(
132           min_progress, from_scale.x(), to_scale.x())),
133       std::abs(gfx::Tween::FloatValueBetween(
134           min_progress, from_scale.y(), to_scale.y())),
135       std::abs(gfx::Tween::FloatValueBetween(
136           min_progress, from_scale.z(), to_scale.z())));
137   gfx::Vector3dF scale_at_max_progress(
138       std::abs(gfx::Tween::FloatValueBetween(
139           max_progress, from_scale.x(), to_scale.x())),
140       std::abs(gfx::Tween::FloatValueBetween(
141           max_progress, from_scale.y(), to_scale.y())),
142       std::abs(gfx::Tween::FloatValueBetween(
143           max_progress, from_scale.z(), to_scale.z())));
144 
145   gfx::Vector3dF max_scale_3d = scale_at_min_progress;
146   max_scale_3d.SetToMax(scale_at_max_progress);
147   *max_scale =
148       std::max(max_scale_3d.x(), std::max(max_scale_3d.y(), max_scale_3d.z()));
149   return true;
150 }
151 
ScaleComponent(gfx::Vector3dF * scale) const152 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
153   *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
154   bool has_scale_component = false;
155   for (size_t i = 0; i < operations_.size(); ++i) {
156     switch (operations_[i].type) {
157       case TransformOperation::TransformOperationIdentity:
158       case TransformOperation::TransformOperationTranslate:
159         continue;
160       case TransformOperation::TransformOperationMatrix:
161         if (!operations_[i].matrix.IsIdentityOrTranslation())
162           return false;
163         continue;
164       case TransformOperation::TransformOperationRotate:
165       case TransformOperation::TransformOperationSkew:
166       case TransformOperation::TransformOperationPerspective:
167         return false;
168       case TransformOperation::TransformOperationScale:
169         if (has_scale_component)
170           return false;
171         has_scale_component = true;
172         scale->Scale(operations_[i].scale.x,
173                      operations_[i].scale.y,
174                      operations_[i].scale.z);
175     }
176   }
177   return true;
178 }
179 
MatchesTypes(const TransformOperations & other) const180 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
181   if (IsIdentity() || other.IsIdentity())
182     return true;
183 
184   if (operations_.size() != other.operations_.size())
185     return false;
186 
187   for (size_t i = 0; i < operations_.size(); ++i) {
188     if (operations_[i].type != other.operations_[i].type
189       && !operations_[i].IsIdentity()
190       && !other.operations_[i].IsIdentity())
191       return false;
192   }
193 
194   return true;
195 }
196 
CanBlendWith(const TransformOperations & other) const197 bool TransformOperations::CanBlendWith(
198     const TransformOperations& other) const {
199   gfx::Transform dummy;
200   return BlendInternal(other, 0.5, &dummy);
201 }
202 
AppendTranslate(SkMScalar x,SkMScalar y,SkMScalar z)203 void TransformOperations::AppendTranslate(SkMScalar x,
204                                           SkMScalar y,
205                                           SkMScalar z) {
206   TransformOperation to_add;
207   to_add.matrix.Translate3d(x, y, z);
208   to_add.type = TransformOperation::TransformOperationTranslate;
209   to_add.translate.x = x;
210   to_add.translate.y = y;
211   to_add.translate.z = z;
212   operations_.push_back(to_add);
213   decomposed_transform_dirty_ = true;
214 }
215 
AppendRotate(SkMScalar x,SkMScalar y,SkMScalar z,SkMScalar degrees)216 void TransformOperations::AppendRotate(SkMScalar x,
217                                        SkMScalar y,
218                                        SkMScalar z,
219                                        SkMScalar degrees) {
220   TransformOperation to_add;
221   to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
222   to_add.type = TransformOperation::TransformOperationRotate;
223   to_add.rotate.axis.x = x;
224   to_add.rotate.axis.y = y;
225   to_add.rotate.axis.z = z;
226   to_add.rotate.angle = degrees;
227   operations_.push_back(to_add);
228   decomposed_transform_dirty_ = true;
229 }
230 
AppendScale(SkMScalar x,SkMScalar y,SkMScalar z)231 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
232   TransformOperation to_add;
233   to_add.matrix.Scale3d(x, y, z);
234   to_add.type = TransformOperation::TransformOperationScale;
235   to_add.scale.x = x;
236   to_add.scale.y = y;
237   to_add.scale.z = z;
238   operations_.push_back(to_add);
239   decomposed_transform_dirty_ = true;
240 }
241 
AppendSkew(SkMScalar x,SkMScalar y)242 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
243   TransformOperation to_add;
244   to_add.matrix.SkewX(x);
245   to_add.matrix.SkewY(y);
246   to_add.type = TransformOperation::TransformOperationSkew;
247   to_add.skew.x = x;
248   to_add.skew.y = y;
249   operations_.push_back(to_add);
250   decomposed_transform_dirty_ = true;
251 }
252 
AppendPerspective(SkMScalar depth)253 void TransformOperations::AppendPerspective(SkMScalar depth) {
254   TransformOperation to_add;
255   to_add.matrix.ApplyPerspectiveDepth(depth);
256   to_add.type = TransformOperation::TransformOperationPerspective;
257   to_add.perspective_depth = depth;
258   operations_.push_back(to_add);
259   decomposed_transform_dirty_ = true;
260 }
261 
AppendMatrix(const gfx::Transform & matrix)262 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
263   TransformOperation to_add;
264   to_add.matrix = matrix;
265   to_add.type = TransformOperation::TransformOperationMatrix;
266   operations_.push_back(to_add);
267   decomposed_transform_dirty_ = true;
268 }
269 
AppendIdentity()270 void TransformOperations::AppendIdentity() {
271   operations_.push_back(TransformOperation());
272 }
273 
IsIdentity() const274 bool TransformOperations::IsIdentity() const {
275   for (size_t i = 0; i < operations_.size(); ++i) {
276     if (!operations_[i].IsIdentity())
277       return false;
278   }
279   return true;
280 }
281 
BlendInternal(const TransformOperations & from,SkMScalar progress,gfx::Transform * result) const282 bool TransformOperations::BlendInternal(const TransformOperations& from,
283                                         SkMScalar progress,
284                                         gfx::Transform* result) const {
285   bool from_identity = from.IsIdentity();
286   bool to_identity = IsIdentity();
287   if (from_identity && to_identity)
288     return true;
289 
290   if (MatchesTypes(from)) {
291     size_t num_operations =
292         std::max(from_identity ? 0 : from.operations_.size(),
293                  to_identity ? 0 : operations_.size());
294     for (size_t i = 0; i < num_operations; ++i) {
295       gfx::Transform blended;
296       if (!TransformOperation::BlendTransformOperations(
297           from_identity ? 0 : &from.operations_[i],
298           to_identity ? 0 : &operations_[i],
299           progress,
300           &blended))
301           return false;
302       result->PreconcatTransform(blended);
303     }
304     return true;
305   }
306 
307   if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
308     return false;
309 
310   gfx::DecomposedTransform to_return;
311   if (!gfx::BlendDecomposedTransforms(&to_return,
312                                       *decomposed_transform_.get(),
313                                       *from.decomposed_transform_.get(),
314                                       progress))
315     return false;
316 
317   *result = ComposeTransform(to_return);
318   return true;
319 }
320 
ComputeDecomposedTransform() const321 bool TransformOperations::ComputeDecomposedTransform() const {
322   if (decomposed_transform_dirty_) {
323     if (!decomposed_transform_)
324       decomposed_transform_.reset(new gfx::DecomposedTransform());
325     gfx::Transform transform = Apply();
326     if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
327       return false;
328     decomposed_transform_dirty_ = false;
329   }
330   return true;
331 }
332 
333 }  // namespace cc
334