blob: c056ab0f854f0500b7e9aa915981f957699576d2 [file] [log] [blame]
[email protected]3c2196b22012-03-17 03:42:251// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]36df22b2011-02-24 21:47:562// 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_
[email protected]36df22b2011-02-24 21:47:567
[email protected]a109fd02014-07-10 07:41:438#include <iosfwd>
[email protected]6ab42d92012-12-20 20:36:539#include <string>
10
[email protected]45127922012-11-17 12:24:4911#include "base/compiler_specific.h"
reede3d451232016-05-05 23:29:3812#include "third_party/skia/include/core/SkMatrix44.h"
tfarina93bfa912014-12-05 14:23:1513#include "ui/gfx/geometry/vector2d_f.h"
danakjf3e1d7f2018-10-04 18:00:2514#include "ui/gfx/geometry_skia_export.h"
[email protected]b9b1e7a42011-05-17 15:29:5115
[email protected]36df22b2011-02-24 21:47:5616namespace gfx {
[email protected]0f0453e2012-10-14 18:15:3517
[email protected]f4d2b9012013-10-11 19:10:5018class BoxF;
[email protected]79fbdab02012-11-14 07:28:1119class RectF;
Malay Keshavf5124312019-10-17 07:20:2720class RRectF;
[email protected]80248e32011-07-08 15:31:1121class Point;
Ella Ge7540c842017-10-19 03:27:2722class PointF;
[email protected]2771b1c2012-10-31 05:15:4323class Point3F;
Ian Vollick4d40fcb2017-06-08 01:13:1524class Quaternion;
[email protected]f7c321eb2012-11-26 20:13:0825class Vector3dF;
[email protected]36df22b2011-02-24 21:47:5626
[email protected]80248e32011-07-08 15:31:1127// 4x4 transformation matrix. Transform is cheap and explicitly allows
[email protected]b9b1e7a42011-05-17 15:29:5128// copy/assign.
danakjf3e1d7f2018-10-04 18:00:2529class GEOMETRY_SKIA_EXPORT Transform {
[email protected]36df22b2011-02-24 21:47:5630 public:
[email protected]bda41962013-01-07 18:46:1731
32 enum SkipInitialization {
33 kSkipInitialization
34 };
35
Aldo Culquicondord01cf10d2018-07-28 02:59:3036 constexpr Transform() : matrix_(SkMatrix44::kIdentity_Constructor) {}
[email protected]bda41962013-01-07 18:46:1737
38 // Skips initializing this matrix to avoid overhead, when we know it will be
39 // initialized before use.
40 Transform(SkipInitialization)
41 : matrix_(SkMatrix44::kUninitialized_Constructor) {}
[email protected]0db13222012-12-13 21:27:5442 Transform(const Transform& rhs) : matrix_(rhs.matrix_) {}
[email protected]d9a6f3302012-12-07 19:17:5443 // Initialize with the concatenation of lhs * rhs.
[email protected]0db13222012-12-13 21:27:5444 Transform(const Transform& lhs, const Transform& rhs)
45 : matrix_(lhs.matrix_, rhs.matrix_) {}
vollick9c7f6d02016-01-08 04:36:3846 explicit Transform(const SkMatrix44& matrix) : matrix_(matrix) {}
[email protected]78634b0c2013-01-15 07:49:4047 // Constructs a transform from explicit 16 matrix elements. Elements
48 // should be given in row-major order.
Mike Reed2f2c2002020-01-23 22:09:4049 Transform(SkScalar col1row1,
50 SkScalar col2row1,
51 SkScalar col3row1,
52 SkScalar col4row1,
53 SkScalar col1row2,
54 SkScalar col2row2,
55 SkScalar col3row2,
56 SkScalar col4row2,
57 SkScalar col1row3,
58 SkScalar col2row3,
59 SkScalar col3row3,
60 SkScalar col4row3,
61 SkScalar col1row4,
62 SkScalar col2row4,
63 SkScalar col3row4,
64 SkScalar col4row4);
[email protected]78634b0c2013-01-15 07:49:4065 // Constructs a transform from explicit 2d elements. All other matrix
66 // elements remain the same as the corresponding elements of an identity
67 // matrix.
Mike Reed2f2c2002020-01-23 22:09:4068 Transform(SkScalar col1row1,
69 SkScalar col2row1,
70 SkScalar col1row2,
71 SkScalar col2row2,
72 SkScalar x_translation,
73 SkScalar y_translation);
[email protected]36df22b2011-02-24 21:47:5674
Ian Vollick4d40fcb2017-06-08 01:13:1575 // Constructs a transform corresponding to the given quaternion.
76 explicit Transform(const Quaternion& q);
77
[email protected]0db13222012-12-13 21:27:5478 bool operator==(const Transform& rhs) const { return matrix_ == rhs.matrix_; }
79 bool operator!=(const Transform& rhs) const { return matrix_ != rhs.matrix_; }
[email protected]80248e32011-07-08 15:31:1180
[email protected]f7c321eb2012-11-26 20:13:0881 // Resets this transform to the identity transform.
[email protected]0db13222012-12-13 21:27:5482 void MakeIdentity() { matrix_.setIdentity(); }
[email protected]2fcafa02012-11-15 01:12:5583
[email protected]2c7cd6d2012-11-28 23:49:2684 // Applies the current transformation on a 2d rotation and assigns the result
[email protected]2fcafa02012-11-15 01:12:5585 // to |this|.
[email protected]2c7cd6d2012-11-28 23:49:2686 void Rotate(double degrees) { RotateAboutZAxis(degrees); }
[email protected]2fcafa02012-11-15 01:12:5587
88 // Applies the current transformation on an axis-angle rotation and assigns
89 // the result to |this|.
[email protected]2c7cd6d2012-11-28 23:49:2690 void RotateAboutXAxis(double degrees);
91 void RotateAboutYAxis(double degrees);
92 void RotateAboutZAxis(double degrees);
93 void RotateAbout(const Vector3dF& axis, double degrees);
[email protected]2fcafa02012-11-15 01:12:5594
95 // Applies the current transformation on a scaling and assigns the result
96 // to |this|.
Mike Reed2f2c2002020-01-23 22:09:4097 void Scale(SkScalar x, SkScalar y);
98 void Scale3d(SkScalar x, SkScalar y, SkScalar z);
[email protected]adeda572014-01-31 00:49:4799 gfx::Vector2dF Scale2d() const {
100 return gfx::Vector2dF(matrix_.get(0, 0), matrix_.get(1, 1));
101 }
[email protected]2fcafa02012-11-15 01:12:55102
Mason Freed86923682019-05-02 03:36:04103 // Applies a scale to the current transformation and assigns the result to
104 // |this|.
Mike Reed2f2c2002020-01-23 22:09:40105 void PostScale(SkScalar x, SkScalar y);
Mason Freed86923682019-05-02 03:36:04106
[email protected]2fcafa02012-11-15 01:12:55107 // Applies the current transformation on a translation and assigns the result
108 // to |this|.
flackr2215b4e2016-09-21 20:16:01109 void Translate(const Vector2dF& offset);
Mike Reed2f2c2002020-01-23 22:09:40110 void Translate(SkScalar x, SkScalar y);
flackr2215b4e2016-09-21 20:16:01111 void Translate3d(const Vector3dF& offset);
Mike Reed2f2c2002020-01-23 22:09:40112 void Translate3d(SkScalar x, SkScalar y, SkScalar z);
[email protected]2fcafa02012-11-15 01:12:55113
Mason Freed86923682019-05-02 03:36:04114 // Applies a translation to the current transformation and assigns the result
115 // to |this|.
116 void PostTranslate(const Vector2dF& offset);
Mike Reed2f2c2002020-01-23 22:09:40117 void PostTranslate(SkScalar x, SkScalar y);
Mason Freed86923682019-05-02 03:36:04118
[email protected]2fcafa02012-11-15 01:12:55119 // Applies the current transformation on a skew and assigns the result
120 // to |this|.
nainar8ca8ee62015-09-03 01:04:10121 void Skew(double angle_x, double angle_y);
[email protected]2fcafa02012-11-15 01:12:55122
123 // Applies the current transformation on a perspective transform and assigns
124 // the result to |this|.
Mike Reed2f2c2002020-01-23 22:09:40125 void ApplyPerspectiveDepth(SkScalar depth);
[email protected]2fcafa02012-11-15 01:12:55126
[email protected]b9b1e7a42011-05-17 15:29:51127 // Applies a transformation on the current transformation
[email protected]80248e32011-07-08 15:31:11128 // (i.e. 'this = this * transform;').
129 void PreconcatTransform(const Transform& transform);
[email protected]36df22b2011-02-24 21:47:56130
[email protected]598080082011-04-14 19:36:33131 // Applies a transformation on the current transformation
[email protected]80248e32011-07-08 15:31:11132 // (i.e. 'this = transform * this;').
133 void ConcatTransform(const Transform& transform);
[email protected]36df22b2011-02-24 21:47:56134
[email protected]45127922012-11-17 12:24:49135 // Returns true if this is the identity matrix.
Ria Jiang5be06c082017-09-13 15:22:25136 // This function modifies a mutable variable in |matrix_|.
[email protected]d9a6f3302012-12-07 19:17:54137 bool IsIdentity() const { return matrix_.isIdentity(); }
[email protected]45127922012-11-17 12:24:49138
[email protected]2c7cd6d2012-11-28 23:49:26139 // Returns true if the matrix is either identity or pure translation.
danakj670a4ab2014-09-19 19:38:28140 bool IsIdentityOrTranslation() const { return matrix_.isTranslate(); }
[email protected]2c7cd6d2012-11-28 23:49:26141
vollick51ed1a22014-12-17 02:03:00142 // Returns true if the matrix is either the identity or a 2d translation.
143 bool IsIdentityOr2DTranslation() const {
144 return matrix_.isTranslate() && matrix_.get(2, 3) == 0;
145 }
146
[email protected]19f90542013-10-19 18:26:07147 // Returns true if the matrix is either identity or pure translation,
148 // allowing for an amount of inaccuracy as specified by the parameter.
Mike Reed2f2c2002020-01-23 22:09:40149 bool IsApproximatelyIdentityOrTranslation(SkScalar tolerance) const;
Xianzhu Wanga036fbde2020-06-02 18:17:26150 bool IsApproximatelyIdentityOrIntegerTranslation(SkScalar tolerance) const;
[email protected]19f90542013-10-19 18:26:07151
[email protected]aedf4e52013-01-09 23:24:44152 // Returns true if the matrix is either a positive scale and/or a translation.
153 bool IsPositiveScaleOrTranslation() const {
154 if (!IsScaleOrTranslation())
155 return false;
[email protected]803f6b52013-09-12 00:51:26156 return matrix_.get(0, 0) > 0.0 && matrix_.get(1, 1) > 0.0 &&
157 matrix_.get(2, 2) > 0.0;
[email protected]aedf4e52013-01-09 23:24:44158 }
159
danakj602038a2016-12-19 22:06:46160 // Returns true if the matrix is identity or, if the matrix consists only
161 // of a translation whose components can be represented as integers. Returns
162 // false if the translation contains a fractional component or is too large to
163 // fit in an integer.
[email protected]d1a56f02012-12-04 12:18:30164 bool IsIdentityOrIntegerTranslation() const;
165
[email protected]adeda572014-01-31 00:49:47166 // Returns true if the matrix had only scaling components.
tfarina81090b42014-11-06 14:50:43167 bool IsScale2d() const { return matrix_.isScale(); }
[email protected]adeda572014-01-31 00:49:47168
[email protected]2c7cd6d2012-11-28 23:49:26169 // Returns true if the matrix is has only scaling and translation components.
danakj670a4ab2014-09-19 19:38:28170 bool IsScaleOrTranslation() const { return matrix_.isScaleTranslate(); }
[email protected]2c7cd6d2012-11-28 23:49:26171
[email protected]3a9a92d2013-07-11 04:37:00172 // Returns true if axis-aligned 2d rects will remain axis-aligned after being
173 // transformed by this matrix.
174 bool Preserves2dAxisAlignment() const;
175
[email protected]2c7cd6d2012-11-28 23:49:26176 // Returns true if the matrix has any perspective component that would
177 // change the w-component of a homogeneous point.
danakj670a4ab2014-09-19 19:38:28178 bool HasPerspective() const { return matrix_.hasPerspective(); }
[email protected]2c7cd6d2012-11-28 23:49:26179
[email protected]45127922012-11-17 12:24:49180 // Returns true if this transform is non-singular.
[email protected]0db13222012-12-13 21:27:54181 bool IsInvertible() const { return matrix_.invert(NULL); }
[email protected]36df22b2011-02-24 21:47:56182
[email protected]2c7cd6d2012-11-28 23:49:26183 // Returns true if a layer with a forward-facing normal of (0, 0, 1) would
184 // have its back side facing frontwards after applying the transform.
185 bool IsBackFaceVisible() const;
186
danakj54af81a2018-05-24 23:59:02187 // Inverts the transform which is passed in. Returns true if successful, or
188 // sets |transform| to the identify matrix on failure.
[email protected]45127922012-11-17 12:24:49189 bool GetInverse(Transform* transform) const WARN_UNUSED_RESULT;
190
191 // Transposes this transform in place.
192 void Transpose();
[email protected]38919392011-10-24 22:26:23193
[email protected]78634b0c2013-01-15 07:49:40194 // Set 3rd row and 3rd colum to (0, 0, 1, 0). Note that this flattening
195 // operation is not quite the same as an orthographic projection and is
196 // technically not a linear operation.
197 //
198 // One useful interpretation of doing this operation:
199 // - For x and y values, the new transform behaves effectively like an
200 // orthographic projection was added to the matrix sequence.
201 // - For z values, the new transform overrides any effect that the transform
202 // had on z, and instead it preserves the z value for any points that are
203 // transformed.
204 // - Because of linearity of transforms, this flattened transform also
205 // preserves the effect that any subsequent (multiplied from the right)
206 // transforms would have on z values.
207 //
208 void FlattenTo2d();
209
ajumad0d64422015-03-14 04:20:08210 // Returns true if the 3rd row and 3rd column are both (0, 0, 1, 0).
211 bool IsFlat() const;
212
[email protected]d81752b2013-10-25 08:32:23213 // Returns the x and y translation components of the matrix.
[email protected]bea4c872013-08-14 18:10:00214 Vector2dF To2dTranslation() const;
215
[email protected]908af422013-10-10 22:22:42216 // Applies the transformation to the point.
[email protected]26d7ece2013-09-12 20:59:47217 void TransformPoint(Point3F* point) const;
[email protected]36df22b2011-02-24 21:47:56218
[email protected]908af422013-10-10 22:22:42219 // Applies the transformation to the point.
Ella Ge7540c842017-10-19 03:27:27220 void TransformPoint(PointF* point) const;
221
222 // Applies the transformation to the point.
[email protected]26d7ece2013-09-12 20:59:47223 void TransformPoint(Point* point) const;
[email protected]36df22b2011-02-24 21:47:56224
petermayo59d37682016-04-13 14:37:35225 // Applies the transformation to the vector.
226 void TransformVector(Vector3dF* vector) const;
227
[email protected]80248e32011-07-08 15:31:11228 // Applies the reverse transformation on the point. Returns true if the
229 // transformation can be inverted.
[email protected]26d7ece2013-09-12 20:59:47230 bool TransformPointReverse(Point3F* point) const;
[email protected]463eb0e2011-05-10 03:11:04231
[email protected]80248e32011-07-08 15:31:11232 // Applies the reverse transformation on the point. Returns true if the
233 // transformation can be inverted. Rounds the result to the nearest point.
[email protected]26d7ece2013-09-12 20:59:47234 bool TransformPointReverse(Point* point) const;
[email protected]80248e32011-07-08 15:31:11235
[email protected]f4d2b9012013-10-11 19:10:50236 // Applies transformation on the given rect. After the function completes,
237 // |rect| will be the smallest axis aligned bounding rect containing the
238 // transformed rect.
[email protected]79fbdab02012-11-14 07:28:11239 void TransformRect(RectF* rect) const;
[email protected]80248e32011-07-08 15:31:11240
[email protected]f4d2b9012013-10-11 19:10:50241 // Applies the reverse transformation on the given rect. After the function
242 // completes, |rect| will be the smallest axis aligned bounding rect
243 // containing the transformed rect. Returns false if the matrix cannot be
244 // inverted.
[email protected]79fbdab02012-11-14 07:28:11245 bool TransformRectReverse(RectF* rect) const;
[email protected]277c7b72011-06-06 15:23:09246
Malay Keshavf5124312019-10-17 07:20:27247 // Applies transformation on the given |rrect|. Returns false if the transform
248 // matrix cannot be applied to rrect.
249 bool TransformRRectF(RRectF* rrect) const;
250
[email protected]f4d2b9012013-10-11 19:10:50251 // Applies transformation on the given box. After the function completes,
252 // |box| will be the smallest axis aligned bounding box containing the
253 // transformed box.
254 void TransformBox(BoxF* box) const;
255
256 // Applies the reverse transformation on the given box. After the function
257 // completes, |box| will be the smallest axis aligned bounding box
258 // containing the transformed box. Returns false if the matrix cannot be
259 // inverted.
260 bool TransformBoxReverse(BoxF* box) const;
261
[email protected]2fcafa02012-11-15 01:12:55262 // Decomposes |this| and |from|, interpolates the decomposed values, and
263 // sets |this| to the reconstituted result. Returns false if either matrix
264 // can't be decomposed. Uses routines described in this spec:
265 // http://www.w3.org/TR/css3-3d-transforms/.
266 //
267 // Note: this call is expensive since we need to decompose the transform. If
268 // you're going to be calling this rapidly (e.g., in an animation) you should
269 // decompose once using gfx::DecomposeTransforms and reuse your
270 // DecomposedTransform.
[email protected]6138db702013-09-25 03:25:05271 bool Blend(const Transform& from, double progress);
[email protected]2fcafa02012-11-15 01:12:55272
vollickb169ff622015-02-10 01:22:33273 void RoundTranslationComponents();
274
[email protected]f7c321eb2012-11-26 20:13:08275 // Returns |this| * |other|.
[email protected]d9a6f3302012-12-07 19:17:54276 Transform operator*(const Transform& other) const {
277 return Transform(*this, other);
278 }
[email protected]f7c321eb2012-11-26 20:13:08279
280 // Sets |this| = |this| * |other|
[email protected]0db13222012-12-13 21:27:54281 Transform& operator*=(const Transform& other) {
282 PreconcatTransform(other);
283 return *this;
284 }
[email protected]f7c321eb2012-11-26 20:13:08285
[email protected]b9b1e7a42011-05-17 15:29:51286 // Returns the underlying matrix.
[email protected]80248e32011-07-08 15:31:11287 const SkMatrix44& matrix() const { return matrix_; }
288 SkMatrix44& matrix() { return matrix_; }
jaydasikacb93d1c2015-12-09 23:52:46289 bool ApproximatelyEqual(const gfx::Transform& transform) const;
[email protected]b9b1e7a42011-05-17 15:29:51290
[email protected]6ab42d92012-12-20 20:36:53291 std::string ToString() const;
292
[email protected]b9b1e7a42011-05-17 15:29:51293 private:
[email protected]80248e32011-07-08 15:31:11294 void TransformPointInternal(const SkMatrix44& xform,
[email protected]26d7ece2013-09-12 20:59:47295 Point* point) const;
[email protected]80248e32011-07-08 15:31:11296
Ella Ge7540c842017-10-19 03:27:27297 void TransformPointInternal(const SkMatrix44& xform, PointF* point) const;
298
[email protected]80248e32011-07-08 15:31:11299 void TransformPointInternal(const SkMatrix44& xform,
[email protected]26d7ece2013-09-12 20:59:47300 Point3F* point) const;
[email protected]80248e32011-07-08 15:31:11301
petermayo59d37682016-04-13 14:37:35302 void TransformVectorInternal(const SkMatrix44& xform,
303 Vector3dF* vector) const;
304
[email protected]80248e32011-07-08 15:31:11305 SkMatrix44 matrix_;
[email protected]b9b1e7a42011-05-17 15:29:51306
307 // copy/assign are allowed.
[email protected]36df22b2011-02-24 21:47:56308};
309
[email protected]a109fd02014-07-10 07:41:43310// This is declared here for use in gtest-based unit tests but is defined in
mlliua8e9f712016-08-20 02:17:52311// the //ui/gfx:test_support target. Depend on that to use this in your unit
312// test. This should not be used in production code - call ToString() instead.
[email protected]a109fd02014-07-10 07:41:43313void PrintTo(const Transform& transform, ::std::ostream* os);
314
[email protected]0f0453e2012-10-14 18:15:35315} // namespace gfx
[email protected]36df22b2011-02-24 21:47:56316
317#endif // UI_GFX_TRANSFORM_H_