| OLD | NEW |
| (Empty) |
| 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/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" | |
| 13 | |
| 14 namespace cc { | |
| 15 | |
| 16 TransformOperations::TransformOperations() | |
| 17 : decomposed_transform_dirty_(true) { | |
| 18 } | |
| 19 | |
| 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())); | |
| 26 } | |
| 27 } | |
| 28 | |
| 29 TransformOperations::~TransformOperations() { | |
| 30 } | |
| 31 | |
| 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; | |
| 37 } | |
| 38 | |
| 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; | |
| 44 } | |
| 45 | |
| 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; | |
| 52 | |
| 53 bool from_identity = from.IsIdentity(); | |
| 54 bool to_identity = IsIdentity(); | |
| 55 if (from_identity && to_identity) | |
| 56 return true; | |
| 57 | |
| 58 if (!MatchesTypes(from)) | |
| 59 return false; | |
| 60 | |
| 61 size_t num_operations = | |
| 62 std::max(from_identity ? 0 : from.operations_.size(), | |
| 63 to_identity ? 0 : operations_.size()); | |
| 64 | |
| 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, | |
| 74 from_op, | |
| 75 to_op, | |
| 76 min_progress, | |
| 77 max_progress, | |
| 78 &bounds_for_operation)) | |
| 79 return false; | |
| 80 *bounds = bounds_for_operation; | |
| 81 } | |
| 82 | |
| 83 return true; | |
| 84 } | |
| 85 | |
| 86 bool TransformOperations::AffectsScale() const { | |
| 87 for (size_t i = 0; i < operations_.size(); ++i) { | |
| 88 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_SCALE) | |
| 89 return true; | |
| 90 if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_MATRIX && | |
| 91 !operations_[i].matrix.IsIdentityOrTranslation()) | |
| 92 return true; | |
| 93 } | |
| 94 return false; | |
| 95 } | |
| 96 | |
| 97 bool TransformOperations::PreservesAxisAlignment() const { | |
| 98 for (size_t i = 0; i < operations_.size(); ++i) { | |
| 99 switch (operations_[i].type) { | |
| 100 case TransformOperation::TRANSFORM_OPERATION_IDENTITY: | |
| 101 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: | |
| 102 case TransformOperation::TRANSFORM_OPERATION_SCALE: | |
| 103 continue; | |
| 104 case TransformOperation::TRANSFORM_OPERATION_MATRIX: | |
| 105 if (!operations_[i].matrix.IsIdentity() && | |
| 106 !operations_[i].matrix.IsScaleOrTranslation()) | |
| 107 return false; | |
| 108 continue; | |
| 109 case TransformOperation::TRANSFORM_OPERATION_ROTATE: | |
| 110 case TransformOperation::TRANSFORM_OPERATION_SKEW: | |
| 111 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: | |
| 112 return false; | |
| 113 } | |
| 114 } | |
| 115 return true; | |
| 116 } | |
| 117 | |
| 118 bool TransformOperations::IsTranslation() const { | |
| 119 for (size_t i = 0; i < operations_.size(); ++i) { | |
| 120 switch (operations_[i].type) { | |
| 121 case TransformOperation::TRANSFORM_OPERATION_IDENTITY: | |
| 122 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: | |
| 123 continue; | |
| 124 case TransformOperation::TRANSFORM_OPERATION_MATRIX: | |
| 125 if (!operations_[i].matrix.IsIdentityOrTranslation()) | |
| 126 return false; | |
| 127 continue; | |
| 128 case TransformOperation::TRANSFORM_OPERATION_ROTATE: | |
| 129 case TransformOperation::TRANSFORM_OPERATION_SCALE: | |
| 130 case TransformOperation::TRANSFORM_OPERATION_SKEW: | |
| 131 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: | |
| 132 return false; | |
| 133 } | |
| 134 } | |
| 135 return true; | |
| 136 } | |
| 137 | |
| 138 bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const { | |
| 139 *scale = gfx::Vector3dF(1.f, 1.f, 1.f); | |
| 140 bool has_scale_component = false; | |
| 141 for (size_t i = 0; i < operations_.size(); ++i) { | |
| 142 switch (operations_[i].type) { | |
| 143 case TransformOperation::TRANSFORM_OPERATION_IDENTITY: | |
| 144 case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: | |
| 145 continue; | |
| 146 case TransformOperation::TRANSFORM_OPERATION_MATRIX: | |
| 147 if (!operations_[i].matrix.IsIdentityOrTranslation()) | |
| 148 return false; | |
| 149 continue; | |
| 150 case TransformOperation::TRANSFORM_OPERATION_ROTATE: | |
| 151 case TransformOperation::TRANSFORM_OPERATION_SKEW: | |
| 152 case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: | |
| 153 return false; | |
| 154 case TransformOperation::TRANSFORM_OPERATION_SCALE: | |
| 155 if (has_scale_component) | |
| 156 return false; | |
| 157 has_scale_component = true; | |
| 158 scale->Scale(operations_[i].scale.x, | |
| 159 operations_[i].scale.y, | |
| 160 operations_[i].scale.z); | |
| 161 } | |
| 162 } | |
| 163 return true; | |
| 164 } | |
| 165 | |
| 166 bool TransformOperations::MatchesTypes(const TransformOperations& other) const { | |
| 167 if (IsIdentity() || other.IsIdentity()) | |
| 168 return true; | |
| 169 | |
| 170 if (operations_.size() != other.operations_.size()) | |
| 171 return false; | |
| 172 | |
| 173 for (size_t i = 0; i < operations_.size(); ++i) { | |
| 174 if (operations_[i].type != other.operations_[i].type | |
| 175 && !operations_[i].IsIdentity() | |
| 176 && !other.operations_[i].IsIdentity()) | |
| 177 return false; | |
| 178 } | |
| 179 | |
| 180 return true; | |
| 181 } | |
| 182 | |
| 183 bool TransformOperations::CanBlendWith( | |
| 184 const TransformOperations& other) const { | |
| 185 gfx::Transform dummy; | |
| 186 return BlendInternal(other, 0.5, &dummy); | |
| 187 } | |
| 188 | |
| 189 void TransformOperations::AppendTranslate(SkMScalar x, | |
| 190 SkMScalar y, | |
| 191 SkMScalar z) { | |
| 192 TransformOperation to_add; | |
| 193 to_add.matrix.Translate3d(x, y, z); | |
| 194 to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE; | |
| 195 to_add.translate.x = x; | |
| 196 to_add.translate.y = y; | |
| 197 to_add.translate.z = z; | |
| 198 operations_.push_back(to_add); | |
| 199 decomposed_transform_dirty_ = true; | |
| 200 } | |
| 201 | |
| 202 void TransformOperations::AppendRotate(SkMScalar x, | |
| 203 SkMScalar y, | |
| 204 SkMScalar z, | |
| 205 SkMScalar degrees) { | |
| 206 TransformOperation to_add; | |
| 207 to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees); | |
| 208 to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE; | |
| 209 to_add.rotate.axis.x = x; | |
| 210 to_add.rotate.axis.y = y; | |
| 211 to_add.rotate.axis.z = z; | |
| 212 to_add.rotate.angle = degrees; | |
| 213 operations_.push_back(to_add); | |
| 214 decomposed_transform_dirty_ = true; | |
| 215 } | |
| 216 | |
| 217 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) { | |
| 218 TransformOperation to_add; | |
| 219 to_add.matrix.Scale3d(x, y, z); | |
| 220 to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE; | |
| 221 to_add.scale.x = x; | |
| 222 to_add.scale.y = y; | |
| 223 to_add.scale.z = z; | |
| 224 operations_.push_back(to_add); | |
| 225 decomposed_transform_dirty_ = true; | |
| 226 } | |
| 227 | |
| 228 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) { | |
| 229 TransformOperation to_add; | |
| 230 to_add.matrix.SkewX(x); | |
| 231 to_add.matrix.SkewY(y); | |
| 232 to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW; | |
| 233 to_add.skew.x = x; | |
| 234 to_add.skew.y = y; | |
| 235 operations_.push_back(to_add); | |
| 236 decomposed_transform_dirty_ = true; | |
| 237 } | |
| 238 | |
| 239 void TransformOperations::AppendPerspective(SkMScalar depth) { | |
| 240 TransformOperation to_add; | |
| 241 to_add.matrix.ApplyPerspectiveDepth(depth); | |
| 242 to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE; | |
| 243 to_add.perspective_depth = depth; | |
| 244 operations_.push_back(to_add); | |
| 245 decomposed_transform_dirty_ = true; | |
| 246 } | |
| 247 | |
| 248 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) { | |
| 249 TransformOperation to_add; | |
| 250 to_add.matrix = matrix; | |
| 251 to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX; | |
| 252 operations_.push_back(to_add); | |
| 253 decomposed_transform_dirty_ = true; | |
| 254 } | |
| 255 | |
| 256 void TransformOperations::AppendIdentity() { | |
| 257 operations_.push_back(TransformOperation()); | |
| 258 } | |
| 259 | |
| 260 bool TransformOperations::IsIdentity() const { | |
| 261 for (size_t i = 0; i < operations_.size(); ++i) { | |
| 262 if (!operations_[i].IsIdentity()) | |
| 263 return false; | |
| 264 } | |
| 265 return true; | |
| 266 } | |
| 267 | |
| 268 bool TransformOperations::BlendInternal(const TransformOperations& from, | |
| 269 SkMScalar progress, | |
| 270 gfx::Transform* result) const { | |
| 271 bool from_identity = from.IsIdentity(); | |
| 272 bool to_identity = IsIdentity(); | |
| 273 if (from_identity && to_identity) | |
| 274 return true; | |
| 275 | |
| 276 if (MatchesTypes(from)) { | |
| 277 size_t num_operations = | |
| 278 std::max(from_identity ? 0 : from.operations_.size(), | |
| 279 to_identity ? 0 : operations_.size()); | |
| 280 for (size_t i = 0; i < num_operations; ++i) { | |
| 281 gfx::Transform blended; | |
| 282 if (!TransformOperation::BlendTransformOperations( | |
| 283 from_identity ? 0 : &from.operations_[i], | |
| 284 to_identity ? 0 : &operations_[i], | |
| 285 progress, | |
| 286 &blended)) | |
| 287 return false; | |
| 288 result->PreconcatTransform(blended); | |
| 289 } | |
| 290 return true; | |
| 291 } | |
| 292 | |
| 293 if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform()) | |
| 294 return false; | |
| 295 | |
| 296 gfx::DecomposedTransform to_return; | |
| 297 if (!gfx::BlendDecomposedTransforms(&to_return, | |
| 298 *decomposed_transform_.get(), | |
| 299 *from.decomposed_transform_.get(), | |
| 300 progress)) | |
| 301 return false; | |
| 302 | |
| 303 *result = ComposeTransform(to_return); | |
| 304 return true; | |
| 305 } | |
| 306 | |
| 307 bool TransformOperations::ComputeDecomposedTransform() const { | |
| 308 if (decomposed_transform_dirty_) { | |
| 309 if (!decomposed_transform_) | |
| 310 decomposed_transform_.reset(new gfx::DecomposedTransform()); | |
| 311 gfx::Transform transform = Apply(); | |
| 312 if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform)) | |
| 313 return false; | |
| 314 decomposed_transform_dirty_ = false; | |
| 315 } | |
| 316 return true; | |
| 317 } | |
| 318 | |
| 319 } // namespace cc | |
| OLD | NEW |