Add a string for translation.
[chromium-blink-merge.git] / cc / animation / transform_operations.cc
blob2d34290387eba6db6b57c313861308ac82f36619
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.
5 #include "cc/animation/transform_operations.h"
7 #include <algorithm>
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"
14 namespace cc {
16 TransformOperations::TransformOperations()
17 : decomposed_transform_dirty_(true) {
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()));
29 TransformOperations::~TransformOperations() {
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;
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;
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;
53 bool from_identity = from.IsIdentity();
54 bool to_identity = IsIdentity();
55 if (from_identity && to_identity)
56 return true;
58 if (!MatchesTypes(from))
59 return false;
61 size_t num_operations =
62 std::max(from_identity ? 0 : from.operations_.size(),
63 to_identity ? 0 : operations_.size());
64 for (size_t i = 0; i < num_operations; ++i) {
65 gfx::BoxF bounds_for_operation;
66 const TransformOperation* from_op =
67 from_identity ? NULL : &from.operations_[i];
68 const TransformOperation* to_op = to_identity ? NULL : &operations_[i];
69 if (!TransformOperation::BlendedBoundsForBox(*bounds,
70 from_op,
71 to_op,
72 min_progress,
73 max_progress,
74 &bounds_for_operation))
75 return false;
76 *bounds = bounds_for_operation;
79 return true;
82 bool TransformOperations::AffectsScale() const {
83 for (size_t i = 0; i < operations_.size(); ++i) {
84 if (operations_[i].type == TransformOperation::TransformOperationScale)
85 return true;
86 if (operations_[i].type == TransformOperation::TransformOperationMatrix &&
87 !operations_[i].matrix.IsIdentityOrTranslation())
88 return true;
90 return false;
93 bool TransformOperations::IsTranslation() const {
94 for (size_t i = 0; i < operations_.size(); ++i) {
95 switch (operations_[i].type) {
96 case TransformOperation::TransformOperationIdentity:
97 case TransformOperation::TransformOperationTranslate:
98 continue;
99 case TransformOperation::TransformOperationMatrix:
100 if (!operations_[i].matrix.IsIdentityOrTranslation())
101 return false;
102 continue;
103 case TransformOperation::TransformOperationRotate:
104 case TransformOperation::TransformOperationScale:
105 case TransformOperation::TransformOperationSkew:
106 case TransformOperation::TransformOperationPerspective:
107 return false;
110 return true;
113 bool TransformOperations::MaximumScale(const TransformOperations& from,
114 SkMScalar min_progress,
115 SkMScalar max_progress,
116 float* max_scale) const {
117 if (!MatchesTypes(from))
118 return false;
120 gfx::Vector3dF from_scale;
121 gfx::Vector3dF to_scale;
123 if (!from.ScaleComponent(&from_scale) || !ScaleComponent(&to_scale))
124 return false;
126 gfx::Vector3dF scale_at_min_progress(
127 std::abs(gfx::Tween::FloatValueBetween(
128 min_progress, from_scale.x(), to_scale.x())),
129 std::abs(gfx::Tween::FloatValueBetween(
130 min_progress, from_scale.y(), to_scale.y())),
131 std::abs(gfx::Tween::FloatValueBetween(
132 min_progress, from_scale.z(), to_scale.z())));
133 gfx::Vector3dF scale_at_max_progress(
134 std::abs(gfx::Tween::FloatValueBetween(
135 max_progress, from_scale.x(), to_scale.x())),
136 std::abs(gfx::Tween::FloatValueBetween(
137 max_progress, from_scale.y(), to_scale.y())),
138 std::abs(gfx::Tween::FloatValueBetween(
139 max_progress, from_scale.z(), to_scale.z())));
141 gfx::Vector3dF max_scale_3d = scale_at_min_progress;
142 max_scale_3d.SetToMax(scale_at_max_progress);
143 *max_scale =
144 std::max(max_scale_3d.x(), std::max(max_scale_3d.y(), max_scale_3d.z()));
145 return true;
148 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
149 *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
150 bool has_scale_component = false;
151 for (size_t i = 0; i < operations_.size(); ++i) {
152 switch (operations_[i].type) {
153 case TransformOperation::TransformOperationIdentity:
154 case TransformOperation::TransformOperationTranslate:
155 continue;
156 case TransformOperation::TransformOperationMatrix:
157 if (!operations_[i].matrix.IsIdentityOrTranslation())
158 return false;
159 continue;
160 case TransformOperation::TransformOperationRotate:
161 case TransformOperation::TransformOperationSkew:
162 case TransformOperation::TransformOperationPerspective:
163 return false;
164 case TransformOperation::TransformOperationScale:
165 if (has_scale_component)
166 return false;
167 has_scale_component = true;
168 scale->Scale(operations_[i].scale.x,
169 operations_[i].scale.y,
170 operations_[i].scale.z);
173 return true;
176 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
177 if (IsIdentity() || other.IsIdentity())
178 return true;
180 if (operations_.size() != other.operations_.size())
181 return false;
183 for (size_t i = 0; i < operations_.size(); ++i) {
184 if (operations_[i].type != other.operations_[i].type
185 && !operations_[i].IsIdentity()
186 && !other.operations_[i].IsIdentity())
187 return false;
190 return true;
193 bool TransformOperations::CanBlendWith(
194 const TransformOperations& other) const {
195 gfx::Transform dummy;
196 return BlendInternal(other, 0.5, &dummy);
199 void TransformOperations::AppendTranslate(SkMScalar x,
200 SkMScalar y,
201 SkMScalar z) {
202 TransformOperation to_add;
203 to_add.matrix.Translate3d(x, y, z);
204 to_add.type = TransformOperation::TransformOperationTranslate;
205 to_add.translate.x = x;
206 to_add.translate.y = y;
207 to_add.translate.z = z;
208 operations_.push_back(to_add);
209 decomposed_transform_dirty_ = true;
212 void TransformOperations::AppendRotate(SkMScalar x,
213 SkMScalar y,
214 SkMScalar z,
215 SkMScalar degrees) {
216 TransformOperation to_add;
217 to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
218 to_add.type = TransformOperation::TransformOperationRotate;
219 to_add.rotate.axis.x = x;
220 to_add.rotate.axis.y = y;
221 to_add.rotate.axis.z = z;
222 to_add.rotate.angle = degrees;
223 operations_.push_back(to_add);
224 decomposed_transform_dirty_ = true;
227 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
228 TransformOperation to_add;
229 to_add.matrix.Scale3d(x, y, z);
230 to_add.type = TransformOperation::TransformOperationScale;
231 to_add.scale.x = x;
232 to_add.scale.y = y;
233 to_add.scale.z = z;
234 operations_.push_back(to_add);
235 decomposed_transform_dirty_ = true;
238 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
239 TransformOperation to_add;
240 to_add.matrix.SkewX(x);
241 to_add.matrix.SkewY(y);
242 to_add.type = TransformOperation::TransformOperationSkew;
243 to_add.skew.x = x;
244 to_add.skew.y = y;
245 operations_.push_back(to_add);
246 decomposed_transform_dirty_ = true;
249 void TransformOperations::AppendPerspective(SkMScalar depth) {
250 TransformOperation to_add;
251 to_add.matrix.ApplyPerspectiveDepth(depth);
252 to_add.type = TransformOperation::TransformOperationPerspective;
253 to_add.perspective_depth = depth;
254 operations_.push_back(to_add);
255 decomposed_transform_dirty_ = true;
258 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
259 TransformOperation to_add;
260 to_add.matrix = matrix;
261 to_add.type = TransformOperation::TransformOperationMatrix;
262 operations_.push_back(to_add);
263 decomposed_transform_dirty_ = true;
266 void TransformOperations::AppendIdentity() {
267 operations_.push_back(TransformOperation());
270 bool TransformOperations::IsIdentity() const {
271 for (size_t i = 0; i < operations_.size(); ++i) {
272 if (!operations_[i].IsIdentity())
273 return false;
275 return true;
278 bool TransformOperations::BlendInternal(const TransformOperations& from,
279 SkMScalar progress,
280 gfx::Transform* result) const {
281 bool from_identity = from.IsIdentity();
282 bool to_identity = IsIdentity();
283 if (from_identity && to_identity)
284 return true;
286 if (MatchesTypes(from)) {
287 size_t num_operations =
288 std::max(from_identity ? 0 : from.operations_.size(),
289 to_identity ? 0 : operations_.size());
290 for (size_t i = 0; i < num_operations; ++i) {
291 gfx::Transform blended;
292 if (!TransformOperation::BlendTransformOperations(
293 from_identity ? 0 : &from.operations_[i],
294 to_identity ? 0 : &operations_[i],
295 progress,
296 &blended))
297 return false;
298 result->PreconcatTransform(blended);
300 return true;
303 if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
304 return false;
306 gfx::DecomposedTransform to_return;
307 if (!gfx::BlendDecomposedTransforms(&to_return,
308 *decomposed_transform_.get(),
309 *from.decomposed_transform_.get(),
310 progress))
311 return false;
313 *result = ComposeTransform(to_return);
314 return true;
317 bool TransformOperations::ComputeDecomposedTransform() const {
318 if (decomposed_transform_dirty_) {
319 if (!decomposed_transform_)
320 decomposed_transform_.reset(new gfx::DecomposedTransform());
321 gfx::Transform transform = Apply();
322 if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
323 return false;
324 decomposed_transform_dirty_ = false;
326 return true;
329 } // namespace cc