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