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