Home | History | Annotate | Download | only in animation
      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 
     13 namespace cc {
     14 
     15 TransformOperations::TransformOperations()
     16     : decomposed_transform_dirty_(true) {
     17 }
     18 
     19 TransformOperations::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 
     28 TransformOperations::~TransformOperations() {
     29 }
     30 
     31 gfx::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 
     38 gfx::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 
     45 bool 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 
     81 bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
     82   if (IsIdentity() || other.IsIdentity())
     83     return true;
     84 
     85   if (operations_.size() != other.operations_.size())
     86     return false;
     87 
     88   for (size_t i = 0; i < operations_.size(); ++i) {
     89     if (operations_[i].type != other.operations_[i].type
     90       && !operations_[i].IsIdentity()
     91       && !other.operations_[i].IsIdentity())
     92       return false;
     93   }
     94 
     95   return true;
     96 }
     97 
     98 bool TransformOperations::CanBlendWith(
     99     const TransformOperations& other) const {
    100   gfx::Transform dummy;
    101   return BlendInternal(other, 0.5, &dummy);
    102 }
    103 
    104 void TransformOperations::AppendTranslate(SkMScalar x,
    105                                           SkMScalar y,
    106                                           SkMScalar z) {
    107   TransformOperation to_add;
    108   to_add.matrix.Translate3d(x, y, z);
    109   to_add.type = TransformOperation::TransformOperationTranslate;
    110   to_add.translate.x = x;
    111   to_add.translate.y = y;
    112   to_add.translate.z = z;
    113   operations_.push_back(to_add);
    114   decomposed_transform_dirty_ = true;
    115 }
    116 
    117 void TransformOperations::AppendRotate(SkMScalar x,
    118                                        SkMScalar y,
    119                                        SkMScalar z,
    120                                        SkMScalar degrees) {
    121   TransformOperation to_add;
    122   to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
    123   to_add.type = TransformOperation::TransformOperationRotate;
    124   to_add.rotate.axis.x = x;
    125   to_add.rotate.axis.y = y;
    126   to_add.rotate.axis.z = z;
    127   to_add.rotate.angle = degrees;
    128   operations_.push_back(to_add);
    129   decomposed_transform_dirty_ = true;
    130 }
    131 
    132 void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
    133   TransformOperation to_add;
    134   to_add.matrix.Scale3d(x, y, z);
    135   to_add.type = TransformOperation::TransformOperationScale;
    136   to_add.scale.x = x;
    137   to_add.scale.y = y;
    138   to_add.scale.z = z;
    139   operations_.push_back(to_add);
    140   decomposed_transform_dirty_ = true;
    141 }
    142 
    143 void TransformOperations::AppendSkew(SkMScalar x, SkMScalar y) {
    144   TransformOperation to_add;
    145   to_add.matrix.SkewX(x);
    146   to_add.matrix.SkewY(y);
    147   to_add.type = TransformOperation::TransformOperationSkew;
    148   to_add.skew.x = x;
    149   to_add.skew.y = y;
    150   operations_.push_back(to_add);
    151   decomposed_transform_dirty_ = true;
    152 }
    153 
    154 void TransformOperations::AppendPerspective(SkMScalar depth) {
    155   TransformOperation to_add;
    156   to_add.matrix.ApplyPerspectiveDepth(depth);
    157   to_add.type = TransformOperation::TransformOperationPerspective;
    158   to_add.perspective_depth = depth;
    159   operations_.push_back(to_add);
    160   decomposed_transform_dirty_ = true;
    161 }
    162 
    163 void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
    164   TransformOperation to_add;
    165   to_add.matrix = matrix;
    166   to_add.type = TransformOperation::TransformOperationMatrix;
    167   operations_.push_back(to_add);
    168   decomposed_transform_dirty_ = true;
    169 }
    170 
    171 void TransformOperations::AppendIdentity() {
    172   operations_.push_back(TransformOperation());
    173 }
    174 
    175 bool TransformOperations::IsIdentity() const {
    176   for (size_t i = 0; i < operations_.size(); ++i) {
    177     if (!operations_[i].IsIdentity())
    178       return false;
    179   }
    180   return true;
    181 }
    182 
    183 bool TransformOperations::BlendInternal(const TransformOperations& from,
    184                                         SkMScalar progress,
    185                                         gfx::Transform* result) const {
    186   bool from_identity = from.IsIdentity();
    187   bool to_identity = IsIdentity();
    188   if (from_identity && to_identity)
    189     return true;
    190 
    191   if (MatchesTypes(from)) {
    192     size_t num_operations =
    193         std::max(from_identity ? 0 : from.operations_.size(),
    194                  to_identity ? 0 : operations_.size());
    195     for (size_t i = 0; i < num_operations; ++i) {
    196       gfx::Transform blended;
    197       if (!TransformOperation::BlendTransformOperations(
    198           from_identity ? 0 : &from.operations_[i],
    199           to_identity ? 0 : &operations_[i],
    200           progress,
    201           &blended))
    202           return false;
    203       result->PreconcatTransform(blended);
    204     }
    205     return true;
    206   }
    207 
    208   if (!ComputeDecomposedTransform() || !from.ComputeDecomposedTransform())
    209     return false;
    210 
    211   gfx::DecomposedTransform to_return;
    212   if (!gfx::BlendDecomposedTransforms(&to_return,
    213                                       *decomposed_transform_.get(),
    214                                       *from.decomposed_transform_.get(),
    215                                       progress))
    216     return false;
    217 
    218   *result = ComposeTransform(to_return);
    219   return true;
    220 }
    221 
    222 bool TransformOperations::ComputeDecomposedTransform() const {
    223   if (decomposed_transform_dirty_) {
    224     if (!decomposed_transform_)
    225       decomposed_transform_.reset(new gfx::DecomposedTransform());
    226     gfx::Transform transform = Apply();
    227     if (!gfx::DecomposeTransform(decomposed_transform_.get(), transform))
    228       return false;
    229     decomposed_transform_dirty_ = false;
    230   }
    231   return true;
    232 }
    233 
    234 }  // namespace cc
    235