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 gfx::Vector2dF Scale2d() const { 93 return gfx::Vector2dF(matrix_.get(0, 0), matrix_.get(1, 1)); 94 } 95 96 // Applies the current transformation on a translation and assigns the result 97 // to |this|. 98 void Translate(SkMScalar x, SkMScalar y); 99 void Translate3d(SkMScalar x, SkMScalar y, SkMScalar z); 100 101 // Applies the current transformation on a skew and assigns the result 102 // to |this|. 103 void SkewX(double angle_x); 104 void SkewY(double angle_y); 105 106 // Applies the current transformation on a perspective transform and assigns 107 // the result to |this|. 108 void ApplyPerspectiveDepth(SkMScalar depth); 109 110 // Applies a transformation on the current transformation 111 // (i.e. 'this = this * transform;'). 112 void PreconcatTransform(const Transform& transform); 113 114 // Applies a transformation on the current transformation 115 // (i.e. 'this = transform * this;'). 116 void ConcatTransform(const Transform& transform); 117 118 // Returns true if this is the identity matrix. 119 bool IsIdentity() const { return matrix_.isIdentity(); } 120 121 // Returns true if the matrix is either identity or pure translation. 122 bool IsIdentityOrTranslation() const { 123 return !(matrix_.getType() & ~SkMatrix44::kTranslate_Mask); 124 } 125 126 // Returns true if the matrix is either identity or pure translation, 127 // allowing for an amount of inaccuracy as specified by the parameter. 128 bool IsApproximatelyIdentityOrTranslation(SkMScalar tolerance) const; 129 130 // Returns true if the matrix is either a positive scale and/or a translation. 131 bool IsPositiveScaleOrTranslation() const { 132 if (!IsScaleOrTranslation()) 133 return false; 134 return matrix_.get(0, 0) > 0.0 && matrix_.get(1, 1) > 0.0 && 135 matrix_.get(2, 2) > 0.0; 136 } 137 138 // Returns true if the matrix is either identity or pure, non-fractional 139 // translation. 140 bool IsIdentityOrIntegerTranslation() const; 141 142 // Returns true if the matrix had only scaling components. 143 bool IsScale2d() const { 144 return !(matrix_.getType() & ~SkMatrix44::kScale_Mask); 145 } 146 147 // Returns true if the matrix is has only scaling and translation components. 148 bool IsScaleOrTranslation() const { 149 int mask = SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask; 150 return (matrix_.getType() & ~mask) == 0; 151 } 152 153 // Returns true if axis-aligned 2d rects will remain axis-aligned after being 154 // transformed by this matrix. 155 bool Preserves2dAxisAlignment() const; 156 157 // Returns true if the matrix has any perspective component that would 158 // change the w-component of a homogeneous point. 159 bool HasPerspective() const { 160 return (matrix_.getType() & SkMatrix44::kPerspective_Mask) != 0; 161 } 162 163 // Returns true if this transform is non-singular. 164 bool IsInvertible() const { return matrix_.invert(NULL); } 165 166 // Returns true if a layer with a forward-facing normal of (0, 0, 1) would 167 // have its back side facing frontwards after applying the transform. 168 bool IsBackFaceVisible() const; 169 170 // Inverts the transform which is passed in. Returns true if successful. 171 bool GetInverse(Transform* transform) const WARN_UNUSED_RESULT; 172 173 // Transposes this transform in place. 174 void Transpose(); 175 176 // Set 3rd row and 3rd colum to (0, 0, 1, 0). Note that this flattening 177 // operation is not quite the same as an orthographic projection and is 178 // technically not a linear operation. 179 // 180 // One useful interpretation of doing this operation: 181 // - For x and y values, the new transform behaves effectively like an 182 // orthographic projection was added to the matrix sequence. 183 // - For z values, the new transform overrides any effect that the transform 184 // had on z, and instead it preserves the z value for any points that are 185 // transformed. 186 // - Because of linearity of transforms, this flattened transform also 187 // preserves the effect that any subsequent (multiplied from the right) 188 // transforms would have on z values. 189 // 190 void FlattenTo2d(); 191 192 // Returns the x and y translation components of the matrix. 193 Vector2dF To2dTranslation() const; 194 195 // Applies the transformation to the point. 196 void TransformPoint(Point3F* point) const; 197 198 // Applies the transformation to the point. 199 void TransformPoint(Point* point) const; 200 201 // Applies the reverse transformation on the point. Returns true if the 202 // transformation can be inverted. 203 bool TransformPointReverse(Point3F* point) const; 204 205 // Applies the reverse transformation on the point. Returns true if the 206 // transformation can be inverted. Rounds the result to the nearest point. 207 bool TransformPointReverse(Point* point) const; 208 209 // Applies transformation on the given rect. After the function completes, 210 // |rect| will be the smallest axis aligned bounding rect containing the 211 // transformed rect. 212 void TransformRect(RectF* rect) const; 213 214 // Applies the reverse transformation on the given rect. After the function 215 // completes, |rect| will be the smallest axis aligned bounding rect 216 // containing the transformed rect. Returns false if the matrix cannot be 217 // inverted. 218 bool TransformRectReverse(RectF* rect) const; 219 220 // Applies transformation on the given box. After the function completes, 221 // |box| will be the smallest axis aligned bounding box containing the 222 // transformed box. 223 void TransformBox(BoxF* box) const; 224 225 // Applies the reverse transformation on the given box. After the function 226 // completes, |box| will be the smallest axis aligned bounding box 227 // containing the transformed box. Returns false if the matrix cannot be 228 // inverted. 229 bool TransformBoxReverse(BoxF* box) const; 230 231 // Decomposes |this| and |from|, interpolates the decomposed values, and 232 // sets |this| to the reconstituted result. Returns false if either matrix 233 // can't be decomposed. Uses routines described in this spec: 234 // http://www.w3.org/TR/css3-3d-transforms/. 235 // 236 // Note: this call is expensive since we need to decompose the transform. If 237 // you're going to be calling this rapidly (e.g., in an animation) you should 238 // decompose once using gfx::DecomposeTransforms and reuse your 239 // DecomposedTransform. 240 bool Blend(const Transform& from, double progress); 241 242 // Returns |this| * |other|. 243 Transform operator*(const Transform& other) const { 244 return Transform(*this, other); 245 } 246 247 // Sets |this| = |this| * |other| 248 Transform& operator*=(const Transform& other) { 249 PreconcatTransform(other); 250 return *this; 251 } 252 253 // Returns the underlying matrix. 254 const SkMatrix44& matrix() const { return matrix_; } 255 SkMatrix44& matrix() { return matrix_; } 256 257 std::string ToString() const; 258 259 private: 260 void TransformPointInternal(const SkMatrix44& xform, 261 Point* point) const; 262 263 void TransformPointInternal(const SkMatrix44& xform, 264 Point3F* point) const; 265 266 SkMatrix44 matrix_; 267 268 // copy/assign are allowed. 269 }; 270 271 } // namespace gfx 272 273 #endif // UI_GFX_TRANSFORM_H_ 274