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