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