[Sync] Add the correct UserAgent to SyncStoppedReporter.
[chromium-blink-merge.git] / cc / animation / transform_operations.cc
blob970eb0dd455a7595d7e2304fec4f766f5f996293
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 = std::max(from_identity ? 0 : from.operations_.size(),
62 to_identity ? 0 : operations_.size());
64 // Because we are squashing all of the matrices together when applying
65 // them to the animation, we must apply them in reverse order when
66 // not squashing them.
67 for (size_t i = 0; i < num_operations; ++i) {
68 size_t operation_index = num_operations - 1 - i;
69 gfx::BoxF bounds_for_operation;
70 const TransformOperation* from_op =
71 from_identity ? nullptr : &from.operations_[operation_index];
72 const TransformOperation* to_op =
73 to_identity ? nullptr : &operations_[operation_index];
74 if (!TransformOperation::BlendedBoundsForBox(*bounds, from_op, to_op,
75 min_progress, max_progress,
76 &bounds_for_operation)) {
77 return false;
79 *bounds = bounds_for_operation;
82 return true;
85 bool TransformOperations::AffectsScale() const {
86 for (size_t i = 0; i < operations_.size(); ++i) {
87 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_SCALE)
88 return true;
89 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_MATRIX &&
90 !operations_[i].matrix.IsIdentityOrTranslation())
91 return true;
93 return false;
96 bool TransformOperations::PreservesAxisAlignment() const {
97 for (size_t i = 0; i < operations_.size(); ++i) {
98 switch (operations_[i].type) {
99 case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
100 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
101 case TransformOperation::TRANSFORM_OPERATION_SCALE:
102 continue;
103 case TransformOperation::TRANSFORM_OPERATION_MATRIX:
104 if (!operations_[i].matrix.IsIdentity() &&
105 !operations_[i].matrix.IsScaleOrTranslation())
106 return false;
107 continue;
108 case TransformOperation::TRANSFORM_OPERATION_ROTATE:
109 case TransformOperation::TRANSFORM_OPERATION_SKEW:
110 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
111 return false;
114 return true;
117 bool TransformOperations::IsTranslation() const {
118 for (size_t i = 0; i < operations_.size(); ++i) {
119 switch (operations_[i].type) {
120 case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
121 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
122 continue;
123 case TransformOperation::TRANSFORM_OPERATION_MATRIX:
124 if (!operations_[i].matrix.IsIdentityOrTranslation())
125 return false;
126 continue;
127 case TransformOperation::TRANSFORM_OPERATION_ROTATE:
128 case TransformOperation::TRANSFORM_OPERATION_SCALE:
129 case TransformOperation::TRANSFORM_OPERATION_SKEW:
130 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
131 return false;
134 return true;
137 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
138 *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
139 bool has_scale_component = false;
140 for (size_t i = 0; i < operations_.size(); ++i) {
141 switch (operations_[i].type) {
142 case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
143 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
144 continue;
145 case TransformOperation::TRANSFORM_OPERATION_MATRIX:
146 if (!operations_[i].matrix.IsIdentityOrTranslation())
147 return false;
148 continue;
149 case TransformOperation::TRANSFORM_OPERATION_ROTATE:
150 case TransformOperation::TRANSFORM_OPERATION_SKEW:
151 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
152 return false;
153 case TransformOperation::TRANSFORM_OPERATION_SCALE:
154 if (has_scale_component)
155 return false;
156 has_scale_component = true;
157 scale->Scale(operations_[i].scale.x,
158 operations_[i].scale.y,
159 operations_[i].scale.z);
162 return true;
165 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
166 if (IsIdentity() || other.IsIdentity())
167 return true;
169 if (operations_.size() != other.operations_.size())
170 return false;
172 for (size_t i = 0; i < operations_.size(); ++i) {
173 if (operations_[i].type != other.operations_[i].type
174 && !operations_[i].IsIdentity()
175 && !other.operations_[i].IsIdentity())
176 return false;
179 return true;
182 bool TransformOperations::CanBlendWith(
183 const TransformOperations& other) const {
184 gfx::Transform dummy;
185 return BlendInternal(other, 0.5, &dummy);
188 void TransformOperations::AppendTranslate(SkMScalar x,
189 SkMScalar y,
190 SkMScalar z) {
191 TransformOperation to_add;
192 to_add.matrix.Translate3d(x, y, z);
193 to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE;
194 to_add.translate.x = x;
195 to_add.translate.y = y;
196 to_add.translate.z = z;
197 operations_.push_back(to_add);
198 decomposed_transform_dirty_ = true;
201 void TransformOperations::AppendRotate(SkMScalar x,
202 SkMScalar y,
203 SkMScalar z,
204 SkMScalar degrees) {
205 TransformOperation to_add;
206 to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
207 to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE;
208 to_add.rotate.axis.x = x;
209 to_add.rotate.axis.y = y;
210 to_add.rotate.axis.z = z;
211 to_add.rotate.angle = degrees;
212 operations_.push_back(to_add);
213 decomposed_transform_dirty_ = true;
216 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
217 TransformOperation to_add;
218 to_add.matrix.Scale3d(x, y, z);
219 to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE;
220 to_add.scale.x = x;
221 to_add.scale.y = y;
222 to_add.scale.z = z;
223 operations_.push_back(to_add);
224 decomposed_transform_dirty_ = true;
227 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
228 TransformOperation to_add;
229 to_add.matrix.SkewX(x);
230 to_add.matrix.SkewY(y);
231 to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW;
232 to_add.skew.x = x;
233 to_add.skew.y = y;
234 operations_.push_back(to_add);
235 decomposed_transform_dirty_ = true;
238 void TransformOperations::AppendPerspective(SkMScalar depth) {
239 TransformOperation to_add;
240 to_add.matrix.ApplyPerspectiveDepth(depth);
241 to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE;
242 to_add.perspective_depth = depth;
243 operations_.push_back(to_add);
244 decomposed_transform_dirty_ = true;
247 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
248 TransformOperation to_add;
249 to_add.matrix = matrix;
250 to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX;
251 operations_.push_back(to_add);
252 decomposed_transform_dirty_ = true;
255 void TransformOperations::AppendIdentity() {
256 operations_.push_back(TransformOperation());
259 bool TransformOperations::IsIdentity() const {
260 for (size_t i = 0; i < operations_.size(); ++i) {
261 if (!operations_[i].IsIdentity())
262 return false;
264 return true;
267 bool TransformOperations::BlendInternal(const TransformOperations& from,
268 SkMScalar progress,
269 gfx::Transform* result) const {
270 bool from_identity = from.IsIdentity();
271 bool to_identity = IsIdentity();
272 if (from_identity && to_identity)
273 return true;
275 if (MatchesTypes(from)) {
276 size_t num_operations =
277 std::max(from_identity ? 0 : from.operations_.size(),
278 to_identity ? 0 : operations_.size());
279 for (size_t i = 0; i < num_operations; ++i) {
280 gfx::Transform blended;
281 if (!TransformOperation::BlendTransformOperations(
282 from_identity ? 0 : &from.operations_[i],
283 to_identity ? 0 : &operations_[i],
284 progress,
285 &blended))
286 return false;
287 result->PreconcatTransform(blended);
289 return true;
292 if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
293 return false;
295 gfx::DecomposedTransform to_return;
296 if (!gfx::BlendDecomposedTransforms(&to_return,
297 *decomposed_transform_.get(),
298 *from.decomposed_transform_.get(),
299 progress))
300 return false;
302 *result = ComposeTransform(to_return);
303 return true;
306 bool TransformOperations::ComputeDecomposedTransform() const {
307 if (decomposed_transform_dirty_) {
308 if (!decomposed_transform_)
309 decomposed_transform_.reset(new gfx::DecomposedTransform());
310 gfx::Transform transform = Apply();
311 if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
312 return false;
313 decomposed_transform_dirty_ = false;
315 return true;
318 } // namespace cc