blob: 2889f3e14c4babdf126db806a3e4a79c1205922c [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.
[email protected]803f6b52013-09-12 00:51:2649 Transform(SkMScalar col1row1,
50 SkMScalar col2row1,
51 SkMScalar col3row1,
52 SkMScalar col4row1,
53 SkMScalar col1row2,
54 SkMScalar col2row2,
55 SkMScalar col3row2,
56 SkMScalar col4row2,
57 SkMScalar col1row3,
58 SkMScalar col2row3,
59 SkMScalar col3row3,
60 SkMScalar col4row3,
61 SkMScalar col1row4,
62 SkMScalar col2row4,
63 SkMScalar col3row4,
64 SkMScalar 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.
[email protected]803f6b52013-09-12 00:51:2668 Transform(SkMScalar col1row1,
69 SkMScalar col2row1,
70 SkMScalar col1row2,
71 SkMScalar col2row2,
72 SkMScalar x_translation,
73 SkMScalar 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|.
[email protected]803f6b52013-09-12 00:51:2697 void Scale(SkMScalar x, SkMScalar y);
98 void Scale3d(SkMScalar x, SkMScalar y, SkMScalar 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|.
105 void PostScale(SkMScalar x, SkMScalar y);
106
[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);
[email protected]803f6b52013-09-12 00:51:26110 void Translate(SkMScalar x, SkMScalar y);
flackr2215b4e2016-09-21 20:16:01111 void Translate3d(const Vector3dF& offset);
[email protected]803f6b52013-09-12 00:51:26112 void Translate3d(SkMScalar x, SkMScalar y, SkMScalar 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);
117 void PostTranslate(SkMScalar x, SkMScalar y);
118
[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|.
[email protected]803f6b52013-09-12 00:51:26125 void ApplyPerspectiveDepth(SkMScalar 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.
149 bool IsApproximatelyIdentityOrTranslation(SkMScalar tolerance) const;
150
[email protected]aedf4e52013-01-09 23:24:44151 // Returns true if the matrix is either a positive scale and/or a translation.
152 bool IsPositiveScaleOrTranslation() const {
153 if (!IsScaleOrTranslation())
154 return false;
[email protected]803f6b52013-09-12 00:51:26155 return matrix_.get(0, 0) > 0.0 && matrix_.get(1, 1) > 0.0 &&
156 matrix_.get(2, 2) > 0.0;
[email protected]aedf4e52013-01-09 23:24:44157 }
158
danakj602038a2016-12-19 22:06:46159 // Returns true if the matrix is identity or, if the matrix consists only
160 // of a translation whose components can be represented as integers. Returns
161 // false if the translation contains a fractional component or is too large to
162 // fit in an integer.
[email protected]d1a56f02012-12-04 12:18:30163 bool IsIdentityOrIntegerTranslation() const;
164
[email protected]adeda572014-01-31 00:49:47165 // Returns true if the matrix had only scaling components.
tfarina81090b42014-11-06 14:50:43166 bool IsScale2d() const { return matrix_.isScale(); }
[email protected]adeda572014-01-31 00:49:47167
[email protected]2c7cd6d2012-11-28 23:49:26168 // Returns true if the matrix is has only scaling and translation components.
danakj670a4ab2014-09-19 19:38:28169 bool IsScaleOrTranslation() const { return matrix_.isScaleTranslate(); }
[email protected]2c7cd6d2012-11-28 23:49:26170
[email protected]3a9a92d2013-07-11 04:37:00171 // Returns true if axis-aligned 2d rects will remain axis-aligned after being
172 // transformed by this matrix.
173 bool Preserves2dAxisAlignment() const;
174
[email protected]2c7cd6d2012-11-28 23:49:26175 // Returns true if the matrix has any perspective component that would
176 // change the w-component of a homogeneous point.
danakj670a4ab2014-09-19 19:38:28177 bool HasPerspective() const { return matrix_.hasPerspective(); }
[email protected]2c7cd6d2012-11-28 23:49:26178
[email protected]45127922012-11-17 12:24:49179 // Returns true if this transform is non-singular.
[email protected]0db13222012-12-13 21:27:54180 bool IsInvertible() const { return matrix_.invert(NULL); }
[email protected]36df22b2011-02-24 21:47:56181
[email protected]2c7cd6d2012-11-28 23:49:26182 // Returns true if a layer with a forward-facing normal of (0, 0, 1) would
183 // have its back side facing frontwards after applying the transform.
184 bool IsBackFaceVisible() const;
185
danakj54af81a2018-05-24 23:59:02186 // Inverts the transform which is passed in. Returns true if successful, or
187 // sets |transform| to the identify matrix on failure.
[email protected]45127922012-11-17 12:24:49188 bool GetInverse(Transform* transform) const WARN_UNUSED_RESULT;
189
190 // Transposes this transform in place.
191 void Transpose();
[email protected]38919392011-10-24 22:26:23192
[email protected]78634b0c2013-01-15 07:49:40193 // Set 3rd row and 3rd colum to (0, 0, 1, 0). Note that this flattening
194 // operation is not quite the same as an orthographic projection and is
195 // technically not a linear operation.
196 //
197 // One useful interpretation of doing this operation:
198 // - For x and y values, the new transform behaves effectively like an
199 // orthographic projection was added to the matrix sequence.
200 // - For z values, the new transform overrides any effect that the transform
201 // had on z, and instead it preserves the z value for any points that are
202 // transformed.
203 // - Because of linearity of transforms, this flattened transform also
204 // preserves the effect that any subsequent (multiplied from the right)
205 // transforms would have on z values.
206 //
207 void FlattenTo2d();
208
ajumad0d64422015-03-14 04:20:08209 // Returns true if the 3rd row and 3rd column are both (0, 0, 1, 0).
210 bool IsFlat() const;
211
[email protected]d81752b2013-10-25 08:32:23212 // Returns the x and y translation components of the matrix.
[email protected]bea4c872013-08-14 18:10:00213 Vector2dF To2dTranslation() const;
214
[email protected]908af422013-10-10 22:22:42215 // Applies the transformation to the point.
[email protected]26d7ece2013-09-12 20:59:47216 void TransformPoint(Point3F* point) const;
[email protected]36df22b2011-02-24 21:47:56217
[email protected]908af422013-10-10 22:22:42218 // Applies the transformation to the point.
Ella Ge7540c842017-10-19 03:27:27219 void TransformPoint(PointF* point) const;
220
221 // Applies the transformation to the point.
[email protected]26d7ece2013-09-12 20:59:47222 void TransformPoint(Point* point) const;
[email protected]36df22b2011-02-24 21:47:56223
petermayo59d37682016-04-13 14:37:35224 // Applies the transformation to the vector.
225 void TransformVector(Vector3dF* vector) const;
226
[email protected]80248e32011-07-08 15:31:11227 // Applies the reverse transformation on the point. Returns true if the
228 // transformation can be inverted.
[email protected]26d7ece2013-09-12 20:59:47229 bool TransformPointReverse(Point3F* point) const;
[email protected]463eb0e2011-05-10 03:11:04230
[email protected]80248e32011-07-08 15:31:11231 // Applies the reverse transformation on the point. Returns true if the
232 // transformation can be inverted. Rounds the result to the nearest point.
[email protected]26d7ece2013-09-12 20:59:47233 bool TransformPointReverse(Point* point) const;
[email protected]80248e32011-07-08 15:31:11234
[email protected]f4d2b9012013-10-11 19:10:50235 // Applies transformation on the given rect. After the function completes,
236 // |rect| will be the smallest axis aligned bounding rect containing the
237 // transformed rect.
[email protected]79fbdab02012-11-14 07:28:11238 void TransformRect(RectF* rect) const;
[email protected]80248e32011-07-08 15:31:11239
[email protected]f4d2b9012013-10-11 19:10:50240 // Applies the reverse transformation on the given rect. After the function
241 // completes, |rect| will be the smallest axis aligned bounding rect
242 // containing the transformed rect. Returns false if the matrix cannot be
243 // inverted.
[email protected]79fbdab02012-11-14 07:28:11244 bool TransformRectReverse(RectF* rect) const;
[email protected]277c7b72011-06-06 15:23:09245
Malay Keshavf5124312019-10-17 07:20:27246 // Applies transformation on the given |rrect|. Returns false if the transform
247 // matrix cannot be applied to rrect.
248 bool TransformRRectF(RRectF* rrect) const;
249
[email protected]f4d2b9012013-10-11 19:10:50250 // Applies transformation on the given box. After the function completes,
251 // |box| will be the smallest axis aligned bounding box containing the
252 // transformed box.
253 void TransformBox(BoxF* box) const;
254
255 // Applies the reverse transformation on the given box. After the function
256 // completes, |box| will be the smallest axis aligned bounding box
257 // containing the transformed box. Returns false if the matrix cannot be
258 // inverted.
259 bool TransformBoxReverse(BoxF* box) const;
260
[email protected]2fcafa02012-11-15 01:12:55261 // Decomposes |this| and |from|, interpolates the decomposed values, and
262 // sets |this| to the reconstituted result. Returns false if either matrix
263 // can't be decomposed. Uses routines described in this spec:
264 // http://www.w3.org/TR/css3-3d-transforms/.
265 //
266 // Note: this call is expensive since we need to decompose the transform. If
267 // you're going to be calling this rapidly (e.g., in an animation) you should
268 // decompose once using gfx::DecomposeTransforms and reuse your
269 // DecomposedTransform.
[email protected]6138db702013-09-25 03:25:05270 bool Blend(const Transform& from, double progress);
[email protected]2fcafa02012-11-15 01:12:55271
vollickb169ff622015-02-10 01:22:33272 void RoundTranslationComponents();
273
[email protected]f7c321eb2012-11-26 20:13:08274 // Returns |this| * |other|.
[email protected]d9a6f3302012-12-07 19:17:54275 Transform operator*(const Transform& other) const {
276 return Transform(*this, other);
277 }
[email protected]f7c321eb2012-11-26 20:13:08278
279 // Sets |this| = |this| * |other|
[email protected]0db13222012-12-13 21:27:54280 Transform& operator*=(const Transform& other) {
281 PreconcatTransform(other);
282 return *this;
283 }
[email protected]f7c321eb2012-11-26 20:13:08284
[email protected]b9b1e7a42011-05-17 15:29:51285 // Returns the underlying matrix.
[email protected]80248e32011-07-08 15:31:11286 const SkMatrix44& matrix() const { return matrix_; }
287 SkMatrix44& matrix() { return matrix_; }
jaydasikacb93d1c2015-12-09 23:52:46288 bool ApproximatelyEqual(const gfx::Transform& transform) const;
[email protected]b9b1e7a42011-05-17 15:29:51289
[email protected]6ab42d92012-12-20 20:36:53290 std::string ToString() const;
291
[email protected]b9b1e7a42011-05-17 15:29:51292 private:
[email protected]80248e32011-07-08 15:31:11293 void TransformPointInternal(const SkMatrix44& xform,
[email protected]26d7ece2013-09-12 20:59:47294 Point* point) const;
[email protected]80248e32011-07-08 15:31:11295
Ella Ge7540c842017-10-19 03:27:27296 void TransformPointInternal(const SkMatrix44& xform, PointF* point) const;
297
[email protected]80248e32011-07-08 15:31:11298 void TransformPointInternal(const SkMatrix44& xform,
[email protected]26d7ece2013-09-12 20:59:47299 Point3F* point) const;
[email protected]80248e32011-07-08 15:31:11300
petermayo59d37682016-04-13 14:37:35301 void TransformVectorInternal(const SkMatrix44& xform,
302 Vector3dF* vector) const;
303
[email protected]80248e32011-07-08 15:31:11304 SkMatrix44 matrix_;
[email protected]b9b1e7a42011-05-17 15:29:51305
306 // copy/assign are allowed.
[email protected]36df22b2011-02-24 21:47:56307};
308
[email protected]a109fd02014-07-10 07:41:43309// This is declared here for use in gtest-based unit tests but is defined in
mlliua8e9f712016-08-20 02:17:52310// the //ui/gfx:test_support target. Depend on that to use this in your unit
311// test. This should not be used in production code - call ToString() instead.
[email protected]a109fd02014-07-10 07:41:43312void PrintTo(const Transform& transform, ::std::ostream* os);
313
[email protected]0f0453e2012-10-14 18:15:35314} // namespace gfx
[email protected]36df22b2011-02-24 21:47:56315
316#endif // UI_GFX_TRANSFORM_H_