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