• 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/box_f.h"
10 #include "ui/gfx/transform_util.h"
11 #include "ui/gfx/vector3d_f.h"
12 
13 namespace cc {
14 
TransformOperations()15 TransformOperations::TransformOperations()
16     : decomposed_transform_dirty_(true) {
17 }
18 
TransformOperations(const TransformOperations & other)19 TransformOperations::TransformOperations(const TransformOperations& other) {
20   operations_ = other.operations_;
21   decomposed_transform_dirty_ = other.decomposed_transform_dirty_;
22   if (!decomposed_transform_dirty_) {
23     decomposed_transform_.reset(
24         new gfx::DecomposedTransform(*other.decomposed_transform_.get()));
25   }
26 }
27 
~TransformOperations()28 TransformOperations::~TransformOperations() {
29 }
30 
Apply() const31 gfx::Transform TransformOperations::Apply() const {
32   gfx::Transform to_return;
33   for (size_t i = 0; i < operations_.size(); ++i)
34     to_return.PreconcatTransform(operations_[i].matrix);
35   return to_return;
36 }
37 
Blend(const TransformOperations & from,SkMScalar progress) const38 gfx::Transform TransformOperations::Blend(const TransformOperations& from,
39                                           SkMScalar progress) const {
40   gfx::Transform to_return;
41   BlendInternal(from, progress, &to_return);
42   return to_return;
43 }
44 
BlendedBoundsForBox(const gfx::BoxF & box,const TransformOperations & from,SkMScalar min_progress,SkMScalar max_progress,gfx::BoxF * bounds) const45 bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box,
46                                               const TransformOperations& from,
47                                               SkMScalar min_progress,
48                                               SkMScalar max_progress,
49                                               gfx::BoxF* bounds) const {
50   *bounds = box;
51 
52   bool from_identity = from.IsIdentity();
53   bool to_identity = IsIdentity();
54   if (from_identity && to_identity)
55     return true;
56 
57   if (!MatchesTypes(from))
58     return false;
59 
60   size_t num_operations =
61       std::max(from_identity ? 0 : from.operations_.size(),
62                to_identity ? 0 : operations_.size());
63   for (size_t i = 0; i < num_operations; ++i) {
64     gfx::BoxF bounds_for_operation;
65     const TransformOperation* from_op =
66         from_identity ? NULL : &from.operations_[i];
67     const TransformOperation* to_op = to_identity ? NULL : &operations_[i];
68     if (!TransformOperation::BlendedBoundsForBox(*bounds,
69                                                  from_op,
70                                                  to_op,
71                                                  min_progress,
72                                                  max_progress,
73                                                  &bounds_for_operation))
74       return false;
75     *bounds = bounds_for_operation;
76   }
77 
78   return true;
79 }
80 
MatchesTypes(const TransformOperations & other) const81 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
82   if (IsIdentity() || other.IsIdentity())
83     return true;
84 
85   if (operations_.size() != other.operations_.size())
86     return false;
87 
88   for (size_t i = 0; i < operations_.size(); ++i) {
89     if (operations_[i].type != other.operations_[i].type
90       && !operations_[i].IsIdentity()
91       && !other.operations_[i].IsIdentity())
92       return false;
93   }
94 
95   return true;
96 }
97 
CanBlendWith(const TransformOperations & other) const98 bool TransformOperations::CanBlendWith(
99     const TransformOperations& other) const {
100   gfx::Transform dummy;
101   return BlendInternal(other, 0.5, &dummy);
102 }
103 
AppendTranslate(SkMScalar x,SkMScalar y,SkMScalar z)104 void TransformOperations::AppendTranslate(SkMScalar x,
105                                           SkMScalar y,
106                                           SkMScalar z) {
107   TransformOperation to_add;
108   to_add.matrix.Translate3d(x, y, z);
109   to_add.type = TransformOperation::TransformOperationTranslate;
110   to_add.translate.x = x;
111   to_add.translate.y = y;
112   to_add.translate.z = z;
113   operations_.push_back(to_add);
114   decomposed_transform_dirty_ = true;
115 }
116 
AppendRotate(SkMScalar x,SkMScalar y,SkMScalar z,SkMScalar degrees)117 void TransformOperations::AppendRotate(SkMScalar x,
118                                        SkMScalar y,
119                                        SkMScalar z,
120                                        SkMScalar degrees) {
121   TransformOperation to_add;
122   to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
123   to_add.type = TransformOperation::TransformOperationRotate;
124   to_add.rotate.axis.x = x;
125   to_add.rotate.axis.y = y;
126   to_add.rotate.axis.z = z;
127   to_add.rotate.angle = degrees;
128   operations_.push_back(to_add);
129   decomposed_transform_dirty_ = true;
130 }
131 
AppendScale(SkMScalar x,SkMScalar y,SkMScalar z)132 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
133   TransformOperation to_add;
134   to_add.matrix.Scale3d(x, y, z);
135   to_add.type = TransformOperation::TransformOperationScale;
136   to_add.scale.x = x;
137   to_add.scale.y = y;
138   to_add.scale.z = z;
139   operations_.push_back(to_add);
140   decomposed_transform_dirty_ = true;
141 }
142 
AppendSkew(SkMScalar x,SkMScalar y)143 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
144   TransformOperation to_add;
145   to_add.matrix.SkewX(x);
146   to_add.matrix.SkewY(y);
147   to_add.type = TransformOperation::TransformOperationSkew;
148   to_add.skew.x = x;
149   to_add.skew.y = y;
150   operations_.push_back(to_add);
151   decomposed_transform_dirty_ = true;
152 }
153 
AppendPerspective(SkMScalar depth)154 void TransformOperations::AppendPerspective(SkMScalar depth) {
155   TransformOperation to_add;
156   to_add.matrix.ApplyPerspectiveDepth(depth);
157   to_add.type = TransformOperation::TransformOperationPerspective;
158   to_add.perspective_depth = depth;
159   operations_.push_back(to_add);
160   decomposed_transform_dirty_ = true;
161 }
162 
AppendMatrix(const gfx::Transform & matrix)163 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
164   TransformOperation to_add;
165   to_add.matrix = matrix;
166   to_add.type = TransformOperation::TransformOperationMatrix;
167   operations_.push_back(to_add);
168   decomposed_transform_dirty_ = true;
169 }
170 
AppendIdentity()171 void TransformOperations::AppendIdentity() {
172   operations_.push_back(TransformOperation());
173 }
174 
IsIdentity() const175 bool TransformOperations::IsIdentity() const {
176   for (size_t i = 0; i < operations_.size(); ++i) {
177     if (!operations_[i].IsIdentity())
178       return false;
179   }
180   return true;
181 }
182 
BlendInternal(const TransformOperations & from,SkMScalar progress,gfx::Transform * result) const183 bool TransformOperations::BlendInternal(const TransformOperations& from,
184                                         SkMScalar progress,
185                                         gfx::Transform* result) const {
186   bool from_identity = from.IsIdentity();
187   bool to_identity = IsIdentity();
188   if (from_identity && to_identity)
189     return true;
190 
191   if (MatchesTypes(from)) {
192     size_t num_operations =
193         std::max(from_identity ? 0 : from.operations_.size(),
194                  to_identity ? 0 : operations_.size());
195     for (size_t i = 0; i < num_operations; ++i) {
196       gfx::Transform blended;
197       if (!TransformOperation::BlendTransformOperations(
198           from_identity ? 0 : &from.operations_[i],
199           to_identity ? 0 : &operations_[i],
200           progress,
201           &blended))
202           return false;
203       result->PreconcatTransform(blended);
204     }
205     return true;
206   }
207 
208   if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
209     return false;
210 
211   gfx::DecomposedTransform to_return;
212   if (!gfx::BlendDecomposedTransforms(&to_return,
213                                       *decomposed_transform_.get(),
214                                       *from.decomposed_transform_.get(),
215                                       progress))
216     return false;
217 
218   *result = ComposeTransform(to_return);
219   return true;
220 }
221 
ComputeDecomposedTransform() const222 bool TransformOperations::ComputeDecomposedTransform() const {
223   if (decomposed_transform_dirty_) {
224     if (!decomposed_transform_)
225       decomposed_transform_.reset(new gfx::DecomposedTransform());
226     gfx::Transform transform = Apply();
227     if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
228       return false;
229     decomposed_transform_dirty_ = false;
230   }
231   return true;
232 }
233 
234 }  // namespace cc
235