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