Home | History | Annotate | Download | only in gfx
      1 // Copyright (c) 2012 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 #ifndef UI_GFX_TRANSFORM_H_
      6 #define UI_GFX_TRANSFORM_H_
      7 
      8 #include <string>
      9 
     10 #include "base/compiler_specific.h"
     11 #include "third_party/skia/include/utils/SkMatrix44.h"
     12 #include "ui/base/ui_export.h"
     13 
     14 namespace gfx {
     15 
     16 class RectF;
     17 class Point;
     18 class Point3F;
     19 class Vector3dF;
     20 
     21 // 4x4 transformation matrix. Transform is cheap and explicitly allows
     22 // copy/assign.
     23 class UI_EXPORT Transform {
     24  public:
     25 
     26   enum SkipInitialization {
     27     kSkipInitialization
     28   };
     29 
     30   Transform() : matrix_(SkMatrix44::kIdentity_Constructor) {}
     31 
     32   // Skips initializing this matrix to avoid overhead, when we know it will be
     33   // initialized before use.
     34   Transform(SkipInitialization)
     35       : matrix_(SkMatrix44::kUninitialized_Constructor) {}
     36   Transform(const Transform& rhs) : matrix_(rhs.matrix_) {}
     37   // Initialize with the concatenation of lhs * rhs.
     38   Transform(const Transform& lhs, const Transform& rhs)
     39       : matrix_(lhs.matrix_, rhs.matrix_) {}
     40   // Constructs a transform from explicit 16 matrix elements. Elements
     41   // should be given in row-major order.
     42   Transform(double col1row1, double col2row1, double col3row1, double col4row1,
     43             double col1row2, double col2row2, double col3row2, double col4row2,
     44             double col1row3, double col2row3, double col3row3, double col4row3,
     45             double col1row4, double col2row4, double col3row4, double col4row4);
     46   // Constructs a transform from explicit 2d elements. All other matrix
     47   // elements remain the same as the corresponding elements of an identity
     48   // matrix.
     49   Transform(double col1row1, double col2row1,
     50             double col1row2, double col2row2,
     51             double x_translation, double y_translation);
     52   ~Transform() {}
     53 
     54   bool operator==(const Transform& rhs) const { return matrix_ == rhs.matrix_; }
     55   bool operator!=(const Transform& rhs) const { return matrix_ != rhs.matrix_; }
     56 
     57   // Resets this transform to the identity transform.
     58   void MakeIdentity() { matrix_.setIdentity(); }
     59 
     60   // Applies the current transformation on a 2d rotation and assigns the result
     61   // to |this|.
     62   void Rotate(double degrees) { RotateAboutZAxis(degrees); }
     63 
     64   // Applies the current transformation on an axis-angle rotation and assigns
     65   // the result to |this|.
     66   void RotateAboutXAxis(double degrees);
     67   void RotateAboutYAxis(double degrees);
     68   void RotateAboutZAxis(double degrees);
     69   void RotateAbout(const Vector3dF& axis, double degrees);
     70 
     71   // Applies the current transformation on a scaling and assigns the result
     72   // to |this|.
     73   void Scale(double x, double y);
     74   void Scale3d(double x, double y, double z);
     75 
     76   // Applies the current transformation on a translation and assigns the result
     77   // to |this|.
     78   void Translate(double x, double y);
     79   void Translate3d(double x, double y, double z);
     80 
     81   // Applies the current transformation on a skew and assigns the result
     82   // to |this|.
     83   void SkewX(double angle_x);
     84   void SkewY(double angle_y);
     85 
     86   // Applies the current transformation on a perspective transform and assigns
     87   // the result to |this|.
     88   void ApplyPerspectiveDepth(double depth);
     89 
     90   // Applies a transformation on the current transformation
     91   // (i.e. 'this = this * transform;').
     92   void PreconcatTransform(const Transform& transform);
     93 
     94   // Applies a transformation on the current transformation
     95   // (i.e. 'this = transform * this;').
     96   void ConcatTransform(const Transform& transform);
     97 
     98   // Returns true if this is the identity matrix.
     99   bool IsIdentity() const { return matrix_.isIdentity(); }
    100 
    101   // Returns true if the matrix is either identity or pure translation.
    102   bool IsIdentityOrTranslation() const {
    103     return !(matrix_.getType() & ~SkMatrix44::kTranslate_Mask);
    104   }
    105 
    106   // Returns true if the matrix is either a positive scale and/or a translation.
    107   bool IsPositiveScaleOrTranslation() const {
    108     if (!IsScaleOrTranslation())
    109       return false;
    110     return matrix_.getDouble(0, 0) > 0.0 &&
    111         matrix_.getDouble(1, 1) > 0.0 &&
    112         matrix_.getDouble(2, 2) > 0.0;
    113   }
    114 
    115   // Returns true if the matrix is either identity or pure, non-fractional
    116   // translation.
    117   bool IsIdentityOrIntegerTranslation() const;
    118 
    119   // Returns true if the matrix is has only scaling and translation components.
    120   bool IsScaleOrTranslation() const {
    121     int mask = SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask;
    122     return (matrix_.getType() & ~mask) == 0;
    123   }
    124 
    125   // Returns true if axis-aligned 2d rects will remain axis-aligned after being
    126   // transformed by this matrix.
    127   bool Preserves2dAxisAlignment() const;
    128 
    129   // Returns true if the matrix has any perspective component that would
    130   // change the w-component of a homogeneous point.
    131   bool HasPerspective() const {
    132     return (matrix_.getType() & SkMatrix44::kPerspective_Mask) != 0;
    133   }
    134 
    135   // Returns true if this transform is non-singular.
    136   bool IsInvertible() const { return matrix_.invert(NULL); }
    137 
    138   // Returns true if a layer with a forward-facing normal of (0, 0, 1) would
    139   // have its back side facing frontwards after applying the transform.
    140   bool IsBackFaceVisible() const;
    141 
    142   // Inverts the transform which is passed in. Returns true if successful.
    143   bool GetInverse(Transform* transform) const WARN_UNUSED_RESULT;
    144 
    145   // Transposes this transform in place.
    146   void Transpose();
    147 
    148   // Set 3rd row and 3rd colum to (0, 0, 1, 0). Note that this flattening
    149   // operation is not quite the same as an orthographic projection and is
    150   // technically not a linear operation.
    151   //
    152   // One useful interpretation of doing this operation:
    153   //  - For x and y values, the new transform behaves effectively like an
    154   //    orthographic projection was added to the matrix sequence.
    155   //  - For z values, the new transform overrides any effect that the transform
    156   //    had on z, and instead it preserves the z value for any points that are
    157   //    transformed.
    158   //  - Because of linearity of transforms, this flattened transform also
    159   //    preserves the effect that any subsequent (multiplied from the right)
    160   //    transforms would have on z values.
    161   //
    162   void FlattenTo2d();
    163 
    164   // Applies the transformation on the point. Returns true if the point is
    165   // transformed successfully.
    166   void TransformPoint(Point3F& point) const;
    167 
    168   // Applies the transformation on the point. Returns true if the point is
    169   // transformed successfully. Rounds the result to the nearest point.
    170   void TransformPoint(Point& point) const;
    171 
    172   // Applies the reverse transformation on the point. Returns true if the
    173   // transformation can be inverted.
    174   bool TransformPointReverse(Point3F& point) const;
    175 
    176   // Applies the reverse transformation on the point. Returns true if the
    177   // transformation can be inverted. Rounds the result to the nearest point.
    178   bool TransformPointReverse(Point& point) const;
    179 
    180   // Applies transformation on the rectangle. Returns true if the transformed
    181   // rectangle was axis aligned. If it returns false, rect will be the
    182   // smallest axis aligned bounding box containing the transformed rect.
    183   void TransformRect(RectF* rect) const;
    184 
    185   // Applies the reverse transformation on the rectangle. Returns true if
    186   // the transformed rectangle was axis aligned. If it returns false,
    187   // rect will be the smallest axis aligned bounding box containing the
    188   // transformed rect.
    189   bool TransformRectReverse(RectF* rect) const;
    190 
    191   // Decomposes |this| and |from|, interpolates the decomposed values, and
    192   // sets |this| to the reconstituted result. Returns false if either matrix
    193   // can't be decomposed. Uses routines described in this spec:
    194   // http://www.w3.org/TR/css3-3d-transforms/.
    195   //
    196   // Note: this call is expensive since we need to decompose the transform. If
    197   // you're going to be calling this rapidly (e.g., in an animation) you should
    198   // decompose once using gfx::DecomposeTransforms and reuse your
    199   // DecomposedTransform.
    200   bool Blend(const Transform& from, double progress);
    201 
    202   // Returns |this| * |other|.
    203   Transform operator*(const Transform& other) const {
    204     return Transform(*this, other);
    205   }
    206 
    207   // Sets |this| = |this| * |other|
    208   Transform& operator*=(const Transform& other) {
    209     PreconcatTransform(other);
    210     return *this;
    211   }
    212 
    213   // Returns the underlying matrix.
    214   const SkMatrix44& matrix() const { return matrix_; }
    215   SkMatrix44& matrix() { return matrix_; }
    216 
    217   std::string ToString() const;
    218 
    219  private:
    220   void TransformPointInternal(const SkMatrix44& xform,
    221                               Point& point) const;
    222 
    223   void TransformPointInternal(const SkMatrix44& xform,
    224                               Point3F& point) const;
    225 
    226   SkMatrix44 matrix_;
    227 
    228   // copy/assign are allowed.
    229 };
    230 
    231 }  // namespace gfx
    232 
    233 #endif  // UI_GFX_TRANSFORM_H_
    234