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/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