GoogleURLTrackerInfoBarDelegate: Initialize uninitialized member in constructor.
[chromium-blink-merge.git] / cc / animation / transform_operations.cc
blob34c526b9a40535d3decc0e33ec849105219b7e74
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());
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 ? NULL : &from.operations_[i];
72 const TransformOperation* to_op = to_identity ? NULL : &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::TransformOperationScale)
89 return true;
90 if (operations_[i].type == TransformOperation::TransformOperationMatrix &&
91 !operations_[i].matrix.IsIdentityOrTranslation())
92 return true;
94 return false;
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:
102 continue;
103 case TransformOperation::TransformOperationMatrix:
104 if (!operations_[i].matrix.IsIdentityOrTranslation())
105 return false;
106 continue;
107 case TransformOperation::TransformOperationRotate:
108 case TransformOperation::TransformOperationScale:
109 case TransformOperation::TransformOperationSkew:
110 case TransformOperation::TransformOperationPerspective:
111 return false;
114 return true;
117 bool TransformOperations::MaximumScale(const TransformOperations& from,
118 SkMScalar min_progress,
119 SkMScalar max_progress,
120 float* max_scale) const {
121 if (!MatchesTypes(from))
122 return false;
124 gfx::Vector3dF from_scale;
125 gfx::Vector3dF to_scale;
127 if (!from.ScaleComponent(&from_scale) || !ScaleComponent(&to_scale))
128 return false;
130 gfx::Vector3dF scale_at_min_progress(
131 std::abs(gfx::Tween::FloatValueBetween(
132 min_progress, from_scale.x(), to_scale.x())),
133 std::abs(gfx::Tween::FloatValueBetween(
134 min_progress, from_scale.y(), to_scale.y())),
135 std::abs(gfx::Tween::FloatValueBetween(
136 min_progress, from_scale.z(), to_scale.z())));
137 gfx::Vector3dF scale_at_max_progress(
138 std::abs(gfx::Tween::FloatValueBetween(
139 max_progress, from_scale.x(), to_scale.x())),
140 std::abs(gfx::Tween::FloatValueBetween(
141 max_progress, from_scale.y(), to_scale.y())),
142 std::abs(gfx::Tween::FloatValueBetween(
143 max_progress, from_scale.z(), to_scale.z())));
145 gfx::Vector3dF max_scale_3d = scale_at_min_progress;
146 max_scale_3d.SetToMax(scale_at_max_progress);
147 *max_scale =
148 std::max(max_scale_3d.x(), std::max(max_scale_3d.y(), max_scale_3d.z()));
149 return true;
152 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
153 *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
154 bool has_scale_component = false;
155 for (size_t i = 0; i < operations_.size(); ++i) {
156 switch (operations_[i].type) {
157 case TransformOperation::TransformOperationIdentity:
158 case TransformOperation::TransformOperationTranslate:
159 continue;
160 case TransformOperation::TransformOperationMatrix:
161 if (!operations_[i].matrix.IsIdentityOrTranslation())
162 return false;
163 continue;
164 case TransformOperation::TransformOperationRotate:
165 case TransformOperation::TransformOperationSkew:
166 case TransformOperation::TransformOperationPerspective:
167 return false;
168 case TransformOperation::TransformOperationScale:
169 if (has_scale_component)
170 return false;
171 has_scale_component = true;
172 scale->Scale(operations_[i].scale.x,
173 operations_[i].scale.y,
174 operations_[i].scale.z);
177 return true;
180 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
181 if (IsIdentity() || other.IsIdentity())
182 return true;
184 if (operations_.size() != other.operations_.size())
185 return false;
187 for (size_t i = 0; i < operations_.size(); ++i) {
188 if (operations_[i].type != other.operations_[i].type
189 && !operations_[i].IsIdentity()
190 && !other.operations_[i].IsIdentity())
191 return false;
194 return true;
197 bool TransformOperations::CanBlendWith(
198 const TransformOperations& other) const {
199 gfx::Transform dummy;
200 return BlendInternal(other, 0.5, &dummy);
203 void TransformOperations::AppendTranslate(SkMScalar x,
204 SkMScalar y,
205 SkMScalar z) {
206 TransformOperation to_add;
207 to_add.matrix.Translate3d(x, y, z);
208 to_add.type = TransformOperation::TransformOperationTranslate;
209 to_add.translate.x = x;
210 to_add.translate.y = y;
211 to_add.translate.z = z;
212 operations_.push_back(to_add);
213 decomposed_transform_dirty_ = true;
216 void TransformOperations::AppendRotate(SkMScalar x,
217 SkMScalar y,
218 SkMScalar z,
219 SkMScalar degrees) {
220 TransformOperation to_add;
221 to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
222 to_add.type = TransformOperation::TransformOperationRotate;
223 to_add.rotate.axis.x = x;
224 to_add.rotate.axis.y = y;
225 to_add.rotate.axis.z = z;
226 to_add.rotate.angle = degrees;
227 operations_.push_back(to_add);
228 decomposed_transform_dirty_ = true;
231 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
232 TransformOperation to_add;
233 to_add.matrix.Scale3d(x, y, z);
234 to_add.type = TransformOperation::TransformOperationScale;
235 to_add.scale.x = x;
236 to_add.scale.y = y;
237 to_add.scale.z = z;
238 operations_.push_back(to_add);
239 decomposed_transform_dirty_ = true;
242 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
243 TransformOperation to_add;
244 to_add.matrix.SkewX(x);
245 to_add.matrix.SkewY(y);
246 to_add.type = TransformOperation::TransformOperationSkew;
247 to_add.skew.x = x;
248 to_add.skew.y = y;
249 operations_.push_back(to_add);
250 decomposed_transform_dirty_ = true;
253 void TransformOperations::AppendPerspective(SkMScalar depth) {
254 TransformOperation to_add;
255 to_add.matrix.ApplyPerspectiveDepth(depth);
256 to_add.type = TransformOperation::TransformOperationPerspective;
257 to_add.perspective_depth = depth;
258 operations_.push_back(to_add);
259 decomposed_transform_dirty_ = true;
262 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
263 TransformOperation to_add;
264 to_add.matrix = matrix;
265 to_add.type = TransformOperation::TransformOperationMatrix;
266 operations_.push_back(to_add);
267 decomposed_transform_dirty_ = true;
270 void TransformOperations::AppendIdentity() {
271 operations_.push_back(TransformOperation());
274 bool TransformOperations::IsIdentity() const {
275 for (size_t i = 0; i < operations_.size(); ++i) {
276 if (!operations_[i].IsIdentity())
277 return false;
279 return true;
282 bool TransformOperations::BlendInternal(const TransformOperations& from,
283 SkMScalar progress,
284 gfx::Transform* result) const {
285 bool from_identity = from.IsIdentity();
286 bool to_identity = IsIdentity();
287 if (from_identity && to_identity)
288 return true;
290 if (MatchesTypes(from)) {
291 size_t num_operations =
292 std::max(from_identity ? 0 : from.operations_.size(),
293 to_identity ? 0 : operations_.size());
294 for (size_t i = 0; i < num_operations; ++i) {
295 gfx::Transform blended;
296 if (!TransformOperation::BlendTransformOperations(
297 from_identity ? 0 : &from.operations_[i],
298 to_identity ? 0 : &operations_[i],
299 progress,
300 &blended))
301 return false;
302 result->PreconcatTransform(blended);
304 return true;
307 if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
308 return false;
310 gfx::DecomposedTransform to_return;
311 if (!gfx::BlendDecomposedTransforms(&to_return,
312 *decomposed_transform_.get(),
313 *from.decomposed_transform_.get(),
314 progress))
315 return false;
317 *result = ComposeTransform(to_return);
318 return true;
321 bool TransformOperations::ComputeDecomposedTransform() const {
322 if (decomposed_transform_dirty_) {
323 if (!decomposed_transform_)
324 decomposed_transform_.reset(new gfx::DecomposedTransform());
325 gfx::Transform transform = Apply();
326 if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
327 return false;
328 decomposed_transform_dirty_ = false;
330 return true;
333 } // namespace cc