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