Move implementation of load methods to chromium layer
[chromium-blink-merge.git] / cc / animation / transform_operations.cc
blob20e8c6a6587abd0f1ca11881062fbf4c75f47199
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/geometry/box_f.h"
11 #include "ui/gfx/geometry/vector3d_f.h"
12 #include "ui/gfx/transform_util.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());
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;
83 return true;
86 bool TransformOperations::AffectsScale() const {
87 for (size_t i = 0; i < operations_.size(); ++i) {
88 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_SCALE)
89 return true;
90 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_MATRIX &&
91 !operations_[i].matrix.IsIdentityOrTranslation())
92 return true;
94 return false;
97 bool TransformOperations::PreservesAxisAlignment() const {
98 for (size_t i = 0; i < operations_.size(); ++i) {
99 switch (operations_[i].type) {
100 case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
101 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
102 case TransformOperation::TRANSFORM_OPERATION_SCALE:
103 continue;
104 case TransformOperation::TRANSFORM_OPERATION_MATRIX:
105 if (!operations_[i].matrix.IsIdentity() &&
106 !operations_[i].matrix.IsScaleOrTranslation())
107 return false;
108 continue;
109 case TransformOperation::TRANSFORM_OPERATION_ROTATE:
110 case TransformOperation::TRANSFORM_OPERATION_SKEW:
111 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
112 return false;
115 return true;
118 bool TransformOperations::IsTranslation() const {
119 for (size_t i = 0; i < operations_.size(); ++i) {
120 switch (operations_[i].type) {
121 case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
122 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
123 continue;
124 case TransformOperation::TRANSFORM_OPERATION_MATRIX:
125 if (!operations_[i].matrix.IsIdentityOrTranslation())
126 return false;
127 continue;
128 case TransformOperation::TRANSFORM_OPERATION_ROTATE:
129 case TransformOperation::TRANSFORM_OPERATION_SCALE:
130 case TransformOperation::TRANSFORM_OPERATION_SKEW:
131 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
132 return false;
135 return true;
138 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
139 *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
140 bool has_scale_component = false;
141 for (size_t i = 0; i < operations_.size(); ++i) {
142 switch (operations_[i].type) {
143 case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
144 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
145 continue;
146 case TransformOperation::TRANSFORM_OPERATION_MATRIX:
147 if (!operations_[i].matrix.IsIdentityOrTranslation())
148 return false;
149 continue;
150 case TransformOperation::TRANSFORM_OPERATION_ROTATE:
151 case TransformOperation::TRANSFORM_OPERATION_SKEW:
152 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
153 return false;
154 case TransformOperation::TRANSFORM_OPERATION_SCALE:
155 if (has_scale_component)
156 return false;
157 has_scale_component = true;
158 scale->Scale(operations_[i].scale.x,
159 operations_[i].scale.y,
160 operations_[i].scale.z);
163 return true;
166 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
167 if (IsIdentity() || other.IsIdentity())
168 return true;
170 if (operations_.size() != other.operations_.size())
171 return false;
173 for (size_t i = 0; i < operations_.size(); ++i) {
174 if (operations_[i].type != other.operations_[i].type
175 && !operations_[i].IsIdentity()
176 && !other.operations_[i].IsIdentity())
177 return false;
180 return true;
183 bool TransformOperations::CanBlendWith(
184 const TransformOperations& other) const {
185 gfx::Transform dummy;
186 return BlendInternal(other, 0.5, &dummy);
189 void TransformOperations::AppendTranslate(SkMScalar x,
190 SkMScalar y,
191 SkMScalar z) {
192 TransformOperation to_add;
193 to_add.matrix.Translate3d(x, y, z);
194 to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE;
195 to_add.translate.x = x;
196 to_add.translate.y = y;
197 to_add.translate.z = z;
198 operations_.push_back(to_add);
199 decomposed_transform_dirty_ = true;
202 void TransformOperations::AppendRotate(SkMScalar x,
203 SkMScalar y,
204 SkMScalar z,
205 SkMScalar degrees) {
206 TransformOperation to_add;
207 to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
208 to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE;
209 to_add.rotate.axis.x = x;
210 to_add.rotate.axis.y = y;
211 to_add.rotate.axis.z = z;
212 to_add.rotate.angle = degrees;
213 operations_.push_back(to_add);
214 decomposed_transform_dirty_ = true;
217 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
218 TransformOperation to_add;
219 to_add.matrix.Scale3d(x, y, z);
220 to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE;
221 to_add.scale.x = x;
222 to_add.scale.y = y;
223 to_add.scale.z = z;
224 operations_.push_back(to_add);
225 decomposed_transform_dirty_ = true;
228 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
229 TransformOperation to_add;
230 to_add.matrix.SkewX(x);
231 to_add.matrix.SkewY(y);
232 to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW;
233 to_add.skew.x = x;
234 to_add.skew.y = y;
235 operations_.push_back(to_add);
236 decomposed_transform_dirty_ = true;
239 void TransformOperations::AppendPerspective(SkMScalar depth) {
240 TransformOperation to_add;
241 to_add.matrix.ApplyPerspectiveDepth(depth);
242 to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE;
243 to_add.perspective_depth = depth;
244 operations_.push_back(to_add);
245 decomposed_transform_dirty_ = true;
248 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
249 TransformOperation to_add;
250 to_add.matrix = matrix;
251 to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX;
252 operations_.push_back(to_add);
253 decomposed_transform_dirty_ = true;
256 void TransformOperations::AppendIdentity() {
257 operations_.push_back(TransformOperation());
260 bool TransformOperations::IsIdentity() const {
261 for (size_t i = 0; i < operations_.size(); ++i) {
262 if (!operations_[i].IsIdentity())
263 return false;
265 return true;
268 bool TransformOperations::BlendInternal(const TransformOperations& from,
269 SkMScalar progress,
270 gfx::Transform* result) const {
271 bool from_identity = from.IsIdentity();
272 bool to_identity = IsIdentity();
273 if (from_identity && to_identity)
274 return true;
276 if (MatchesTypes(from)) {
277 size_t num_operations =
278 std::max(from_identity ? 0 : from.operations_.size(),
279 to_identity ? 0 : operations_.size());
280 for (size_t i = 0; i < num_operations; ++i) {
281 gfx::Transform blended;
282 if (!TransformOperation::BlendTransformOperations(
283 from_identity ? 0 : &from.operations_[i],
284 to_identity ? 0 : &operations_[i],
285 progress,
286 &blended))
287 return false;
288 result->PreconcatTransform(blended);
290 return true;
293 if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
294 return false;
296 gfx::DecomposedTransform to_return;
297 if (!gfx::BlendDecomposedTransforms(&to_return,
298 *decomposed_transform_.get(),
299 *from.decomposed_transform_.get(),
300 progress))
301 return false;
303 *result = ComposeTransform(to_return);
304 return true;
307 bool TransformOperations::ComputeDecomposedTransform() const {
308 if (decomposed_transform_dirty_) {
309 if (!decomposed_transform_)
310 decomposed_transform_.reset(new gfx::DecomposedTransform());
311 gfx::Transform transform = Apply();
312 if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
313 return false;
314 decomposed_transform_dirty_ = false;
316 return true;
319 } // namespace cc