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.
5 #ifndef UI_GFX_TRANSFORM_H_
6 #define UI_GFX_TRANSFORM_H_
11 #include "base/compiler_specific.h"
12 #include "third_party/skia/include/utils/SkMatrix44.h"
13 #include "ui/gfx/geometry/vector2d_f.h"
14 #include "ui/gfx/gfx_export.h"
24 // 4x4 transformation matrix. Transform is cheap and explicitly allows
26 class GFX_EXPORT Transform
{
29 enum SkipInitialization
{
33 Transform() : matrix_(SkMatrix44::kIdentity_Constructor
) {}
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
,
61 // Constructs a transform from explicit 2d elements. All other matrix
62 // elements remain the same as the corresponding elements of an identity
64 Transform(SkMScalar col1row1
,
68 SkMScalar x_translation
,
69 SkMScalar y_translation
);
72 bool operator==(const Transform
& rhs
) const { return matrix_
== rhs
.matrix_
; }
73 bool operator!=(const Transform
& rhs
) const { return matrix_
!= rhs
.matrix_
; }
75 // Resets this transform to the identity transform.
76 void MakeIdentity() { matrix_
.setIdentity(); }
78 // Applies the current transformation on a 2d rotation and assigns the result
80 void Rotate(double degrees
) { RotateAboutZAxis(degrees
); }
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
);
89 // Applies the current transformation on a scaling and assigns the result
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));
97 // Applies the current transformation on a translation and assigns the result
99 void Translate(SkMScalar x
, SkMScalar y
);
100 void Translate3d(SkMScalar x
, SkMScalar y
, SkMScalar z
);
102 // Applies the current transformation on a skew and assigns the result
104 void Skew(double angle_x
, double angle_y
);
106 // Applies the current transformation on a perspective transform and assigns
107 // the result to |this|.
108 void ApplyPerspectiveDepth(SkMScalar depth
);
110 // Applies a transformation on the current transformation
111 // (i.e. 'this = this * transform;').
112 void PreconcatTransform(const Transform
& transform
);
114 // Applies a transformation on the current transformation
115 // (i.e. 'this = transform * this;').
116 void ConcatTransform(const Transform
& transform
);
118 // Returns true if this is the identity matrix.
119 bool IsIdentity() const { return matrix_
.isIdentity(); }
121 // Returns true if the matrix is either identity or pure translation.
122 bool IsIdentityOrTranslation() const { return matrix_
.isTranslate(); }
124 // Returns true if the matrix is either the identity or a 2d translation.
125 bool IsIdentityOr2DTranslation() const {
126 return matrix_
.isTranslate() && matrix_
.get(2, 3) == 0;
129 // Returns true if the matrix is either identity or pure translation,
130 // allowing for an amount of inaccuracy as specified by the parameter.
131 bool IsApproximatelyIdentityOrTranslation(SkMScalar tolerance
) const;
133 // Returns true if the matrix is either a positive scale and/or a translation.
134 bool IsPositiveScaleOrTranslation() const {
135 if (!IsScaleOrTranslation())
137 return matrix_
.get(0, 0) > 0.0 && matrix_
.get(1, 1) > 0.0 &&
138 matrix_
.get(2, 2) > 0.0;
141 // Returns true if the matrix is either identity or pure, non-fractional
143 bool IsIdentityOrIntegerTranslation() const;
145 // Returns true if the matrix had only scaling components.
146 bool IsScale2d() const { return matrix_
.isScale(); }
148 // Returns true if the matrix is has only scaling and translation components.
149 bool IsScaleOrTranslation() const { return matrix_
.isScaleTranslate(); }
151 // Returns true if axis-aligned 2d rects will remain axis-aligned after being
152 // transformed by this matrix.
153 bool Preserves2dAxisAlignment() const;
155 // Returns true if the matrix has any perspective component that would
156 // change the w-component of a homogeneous point.
157 bool HasPerspective() const { return matrix_
.hasPerspective(); }
159 // Returns true if this transform is non-singular.
160 bool IsInvertible() const { return matrix_
.invert(NULL
); }
162 // Returns true if a layer with a forward-facing normal of (0, 0, 1) would
163 // have its back side facing frontwards after applying the transform.
164 bool IsBackFaceVisible() const;
166 // Inverts the transform which is passed in. Returns true if successful.
167 bool GetInverse(Transform
* transform
) const WARN_UNUSED_RESULT
;
169 // Transposes this transform in place.
172 // Set 3rd row and 3rd colum to (0, 0, 1, 0). Note that this flattening
173 // operation is not quite the same as an orthographic projection and is
174 // technically not a linear operation.
176 // One useful interpretation of doing this operation:
177 // - For x and y values, the new transform behaves effectively like an
178 // orthographic projection was added to the matrix sequence.
179 // - For z values, the new transform overrides any effect that the transform
180 // had on z, and instead it preserves the z value for any points that are
182 // - Because of linearity of transforms, this flattened transform also
183 // preserves the effect that any subsequent (multiplied from the right)
184 // transforms would have on z values.
188 // Returns true if the 3rd row and 3rd column are both (0, 0, 1, 0).
191 // Returns the x and y translation components of the matrix.
192 Vector2dF
To2dTranslation() const;
194 // Applies the transformation to the point.
195 void TransformPoint(Point3F
* point
) const;
197 // Applies the transformation to the point.
198 void TransformPoint(Point
* point
) const;
200 // Applies the reverse transformation on the point. Returns true if the
201 // transformation can be inverted.
202 bool TransformPointReverse(Point3F
* point
) const;
204 // Applies the reverse transformation on the point. Returns true if the
205 // transformation can be inverted. Rounds the result to the nearest point.
206 bool TransformPointReverse(Point
* point
) const;
208 // Applies transformation on the given rect. After the function completes,
209 // |rect| will be the smallest axis aligned bounding rect containing the
211 void TransformRect(RectF
* rect
) const;
213 // Applies the reverse transformation on the given rect. After the function
214 // completes, |rect| will be the smallest axis aligned bounding rect
215 // containing the transformed rect. Returns false if the matrix cannot be
217 bool TransformRectReverse(RectF
* rect
) const;
219 // Applies transformation on the given box. After the function completes,
220 // |box| will be the smallest axis aligned bounding box containing the
222 void TransformBox(BoxF
* box
) const;
224 // Applies the reverse transformation on the given box. After the function
225 // completes, |box| will be the smallest axis aligned bounding box
226 // containing the transformed box. Returns false if the matrix cannot be
228 bool TransformBoxReverse(BoxF
* box
) const;
230 // Decomposes |this| and |from|, interpolates the decomposed values, and
231 // sets |this| to the reconstituted result. Returns false if either matrix
232 // can't be decomposed. Uses routines described in this spec:
233 // http://www.w3.org/TR/css3-3d-transforms/.
235 // Note: this call is expensive since we need to decompose the transform. If
236 // you're going to be calling this rapidly (e.g., in an animation) you should
237 // decompose once using gfx::DecomposeTransforms and reuse your
238 // DecomposedTransform.
239 bool Blend(const Transform
& from
, double progress
);
241 void RoundTranslationComponents();
243 // Returns |this| * |other|.
244 Transform
operator*(const Transform
& other
) const {
245 return Transform(*this, other
);
248 // Sets |this| = |this| * |other|
249 Transform
& operator*=(const Transform
& other
) {
250 PreconcatTransform(other
);
254 // Returns the underlying matrix.
255 const SkMatrix44
& matrix() const { return matrix_
; }
256 SkMatrix44
& matrix() { return matrix_
; }
258 std::string
ToString() const;
261 void TransformPointInternal(const SkMatrix44
& xform
,
264 void TransformPointInternal(const SkMatrix44
& xform
,
265 Point3F
* point
) const;
269 // copy/assign are allowed.
272 // This is declared here for use in gtest-based unit tests but is defined in
273 // the gfx_test_support target. Depend on that to use this in your unit test.
274 // This should not be used in production code - call ToString() instead.
275 void PrintTo(const Transform
& transform
, ::std::ostream
* os
);
279 #endif // UI_GFX_TRANSFORM_H_