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 12namespace cc { 13 14TransformOperations::TransformOperations() 15 : decomposed_transform_dirty_(true) { 16} 17 18TransformOperations::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 27TransformOperations::~TransformOperations() { 28} 29 30gfx::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 37gfx::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 44bool 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 61bool TransformOperations::CanBlendWith( 62 const TransformOperations& other) const { 63 gfx::Transform dummy; 64 return BlendInternal(other, 0.5, &dummy); 65} 66 67void 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 78void 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 91void 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 102void 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 113void 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 122void 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 130void TransformOperations::AppendIdentity() { 131 operations_.push_back(TransformOperation()); 132} 133 134bool 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 142bool 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 181bool 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