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"
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"
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);
39 gfx::Transform TransformOperations::Blend(const TransformOperations& from,
40 SkMScalar progress) const {
41 gfx::Transform to_return;
42 BlendInternal(from, progress, &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 {
53 bool from_identity = from.IsIdentity();
54 bool to_identity = IsIdentity();
55 if (from_identity && to_identity)
58 if (!MatchesTypes(from))
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,
78 &bounds_for_operation))
80 *bounds = bounds_for_operation;
86 bool TransformOperations::AffectsScale() const {
87 for (size_t i = 0; i < operations_.size(); ++i) {
88 if (operations_[i].type == TransformOperation::TransformOperationScale)
90 if (operations_[i].type == TransformOperation::TransformOperationMatrix &&
91 !operations_[i].matrix.IsIdentityOrTranslation())
97 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:
103 case TransformOperation::TransformOperationMatrix:
104 if (!operations_[i].matrix.IsIdentityOrTranslation())
107 case TransformOperation::TransformOperationRotate:
108 case TransformOperation::TransformOperationScale:
109 case TransformOperation::TransformOperationSkew:
110 case TransformOperation::TransformOperationPerspective:
117 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
118 *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
119 bool has_scale_component = false;
120 for (size_t i = 0; i < operations_.size(); ++i) {
121 switch (operations_[i].type) {
122 case TransformOperation::TransformOperationIdentity:
123 case TransformOperation::TransformOperationTranslate:
125 case TransformOperation::TransformOperationMatrix:
126 if (!operations_[i].matrix.IsIdentityOrTranslation())
129 case TransformOperation::TransformOperationRotate:
130 case TransformOperation::TransformOperationSkew:
131 case TransformOperation::TransformOperationPerspective:
133 case TransformOperation::TransformOperationScale:
134 if (has_scale_component)
136 has_scale_component = true;
137 scale->Scale(operations_[i].scale.x,
138 operations_[i].scale.y,
139 operations_[i].scale.z);
145 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
146 if (IsIdentity() || other.IsIdentity())
149 if (operations_.size() != other.operations_.size())
152 for (size_t i = 0; i < operations_.size(); ++i) {
153 if (operations_[i].type != other.operations_[i].type
154 && !operations_[i].IsIdentity()
155 && !other.operations_[i].IsIdentity())
162 bool TransformOperations::CanBlendWith(
163 const TransformOperations& other) const {
164 gfx::Transform dummy;
165 return BlendInternal(other, 0.5, &dummy);
168 void TransformOperations::AppendTranslate(SkMScalar x,
171 TransformOperation to_add;
172 to_add.matrix.Translate3d(x, y, z);
173 to_add.type = TransformOperation::TransformOperationTranslate;
174 to_add.translate.x = x;
175 to_add.translate.y = y;
176 to_add.translate.z = z;
177 operations_.push_back(to_add);
178 decomposed_transform_dirty_ = true;
181 void TransformOperations::AppendRotate(SkMScalar x,
185 TransformOperation to_add;
186 to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
187 to_add.type = TransformOperation::TransformOperationRotate;
188 to_add.rotate.axis.x = x;
189 to_add.rotate.axis.y = y;
190 to_add.rotate.axis.z = z;
191 to_add.rotate.angle = degrees;
192 operations_.push_back(to_add);
193 decomposed_transform_dirty_ = true;
196 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
197 TransformOperation to_add;
198 to_add.matrix.Scale3d(x, y, z);
199 to_add.type = TransformOperation::TransformOperationScale;
203 operations_.push_back(to_add);
204 decomposed_transform_dirty_ = true;
207 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
208 TransformOperation to_add;
209 to_add.matrix.SkewX(x);
210 to_add.matrix.SkewY(y);
211 to_add.type = TransformOperation::TransformOperationSkew;
214 operations_.push_back(to_add);
215 decomposed_transform_dirty_ = true;
218 void TransformOperations::AppendPerspective(SkMScalar depth) {
219 TransformOperation to_add;
220 to_add.matrix.ApplyPerspectiveDepth(depth);
221 to_add.type = TransformOperation::TransformOperationPerspective;
222 to_add.perspective_depth = depth;
223 operations_.push_back(to_add);
224 decomposed_transform_dirty_ = true;
227 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
228 TransformOperation to_add;
229 to_add.matrix = matrix;
230 to_add.type = TransformOperation::TransformOperationMatrix;
231 operations_.push_back(to_add);
232 decomposed_transform_dirty_ = true;
235 void TransformOperations::AppendIdentity() {
236 operations_.push_back(TransformOperation());
239 bool TransformOperations::IsIdentity() const {
240 for (size_t i = 0; i < operations_.size(); ++i) {
241 if (!operations_[i].IsIdentity())
247 bool TransformOperations::BlendInternal(const TransformOperations& from,
249 gfx::Transform* result) const {
250 bool from_identity = from.IsIdentity();
251 bool to_identity = IsIdentity();
252 if (from_identity && to_identity)
255 if (MatchesTypes(from)) {
256 size_t num_operations =
257 std::max(from_identity ? 0 : from.operations_.size(),
258 to_identity ? 0 : operations_.size());
259 for (size_t i = 0; i < num_operations; ++i) {
260 gfx::Transform blended;
261 if (!TransformOperation::BlendTransformOperations(
262 from_identity ? 0 : &from.operations_[i],
263 to_identity ? 0 : &operations_[i],
267 result->PreconcatTransform(blended);
272 if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
275 gfx::DecomposedTransform to_return;
276 if (!gfx::BlendDecomposedTransforms(&to_return,
277 *decomposed_transform_.get(),
278 *from.decomposed_transform_.get(),
282 *result = ComposeTransform(to_return);
286 bool TransformOperations::ComputeDecomposedTransform() const {
287 if (decomposed_transform_dirty_) {
288 if (!decomposed_transform_)
289 decomposed_transform_.reset(new gfx::DecomposedTransform());
290 gfx::Transform transform = Apply();
291 if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
293 decomposed_transform_dirty_ = false;