blob: c7a4684f56fdd1deda4ca54057196a13c8c405a5 [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"
[email protected]d34e4072013-09-05 20:28:3014#include "ui/gfx/gfx_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;
[email protected]80248e32011-07-08 15:31:1120class Point;
[email protected]2771b1c2012-10-31 05:15:4321class Point3F;
[email protected]f7c321eb2012-11-26 20:13:0822class Vector3dF;
[email protected]36df22b2011-02-24 21:47:5623
[email protected]80248e32011-07-08 15:31:1124// 4x4 transformation matrix. Transform is cheap and explicitly allows
[email protected]b9b1e7a42011-05-17 15:29:5125// copy/assign.
[email protected]4ffa7892013-09-27 16:56:0626class GFX_EXPORT Transform {
[email protected]36df22b2011-02-24 21:47:5627 public:
[email protected]bda41962013-01-07 18:46:1728
29 enum SkipInitialization {
30 kSkipInitialization
31 };
32
[email protected]0db13222012-12-13 21:27:5433 Transform() : matrix_(SkMatrix44::kIdentity_Constructor) {}
[email protected]bda41962013-01-07 18:46:1734
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) {}
[email protected]0db13222012-12-13 21:27:5439 Transform(const Transform& rhs) : matrix_(rhs.matrix_) {}
[email protected]d9a6f3302012-12-07 19:17:5440 // Initialize with the concatenation of lhs * rhs.
[email protected]0db13222012-12-13 21:27:5441 Transform(const Transform& lhs, const Transform& rhs)
42 : matrix_(lhs.matrix_, rhs.matrix_) {}
vollick9c7f6d02016-01-08 04:36:3843 explicit Transform(const SkMatrix44& matrix) : matrix_(matrix) {}
[email protected]78634b0c2013-01-15 07:49:4044 // Constructs a transform from explicit 16 matrix elements. Elements
45 // should be given in row-major order.
[email protected]803f6b52013-09-12 00:51:2646 Transform(SkMScalar col1row1,
47 SkMScalar col2row1,
48 SkMScalar col3row1,
49 SkMScalar col4row1,
50 SkMScalar col1row2,
51 SkMScalar col2row2,
52 SkMScalar col3row2,
53 SkMScalar col4row2,
54 SkMScalar col1row3,
55 SkMScalar col2row3,
56 SkMScalar col3row3,
57 SkMScalar col4row3,
58 SkMScalar col1row4,
59 SkMScalar col2row4,
60 SkMScalar col3row4,
61 SkMScalar col4row4);
[email protected]78634b0c2013-01-15 07:49:4062 // Constructs a transform from explicit 2d elements. All other matrix
63 // elements remain the same as the corresponding elements of an identity
64 // matrix.
[email protected]803f6b52013-09-12 00:51:2665 Transform(SkMScalar col1row1,
66 SkMScalar col2row1,
67 SkMScalar col1row2,
68 SkMScalar col2row2,
69 SkMScalar x_translation,
70 SkMScalar y_translation);
[email protected]0db13222012-12-13 21:27:5471 ~Transform() {}
[email protected]36df22b2011-02-24 21:47:5672
[email protected]0db13222012-12-13 21:27:5473 bool operator==(const Transform& rhs) const { return matrix_ == rhs.matrix_; }
74 bool operator!=(const Transform& rhs) const { return matrix_ != rhs.matrix_; }
[email protected]80248e32011-07-08 15:31:1175
[email protected]f7c321eb2012-11-26 20:13:0876 // Resets this transform to the identity transform.
[email protected]0db13222012-12-13 21:27:5477 void MakeIdentity() { matrix_.setIdentity(); }
[email protected]2fcafa02012-11-15 01:12:5578
[email protected]2c7cd6d2012-11-28 23:49:2679 // Applies the current transformation on a 2d rotation and assigns the result
[email protected]2fcafa02012-11-15 01:12:5580 // to |this|.
[email protected]2c7cd6d2012-11-28 23:49:2681 void Rotate(double degrees) { RotateAboutZAxis(degrees); }
[email protected]2fcafa02012-11-15 01:12:5582
83 // Applies the current transformation on an axis-angle rotation and assigns
84 // the result to |this|.
[email protected]2c7cd6d2012-11-28 23:49:2685 void RotateAboutXAxis(double degrees);
86 void RotateAboutYAxis(double degrees);
87 void RotateAboutZAxis(double degrees);
88 void RotateAbout(const Vector3dF& axis, double degrees);
[email protected]2fcafa02012-11-15 01:12:5589
90 // Applies the current transformation on a scaling and assigns the result
91 // to |this|.
[email protected]803f6b52013-09-12 00:51:2692 void Scale(SkMScalar x, SkMScalar y);
93 void Scale3d(SkMScalar x, SkMScalar y, SkMScalar z);
[email protected]adeda572014-01-31 00:49:4794 gfx::Vector2dF Scale2d() const {
95 return gfx::Vector2dF(matrix_.get(0, 0), matrix_.get(1, 1));
96 }
[email protected]2fcafa02012-11-15 01:12:5597
98 // Applies the current transformation on a translation and assigns the result
99 // to |this|.
[email protected]803f6b52013-09-12 00:51:26100 void Translate(SkMScalar x, SkMScalar y);
101 void Translate3d(SkMScalar x, SkMScalar y, SkMScalar z);
[email protected]2fcafa02012-11-15 01:12:55102
103 // Applies the current transformation on a skew and assigns the result
104 // to |this|.
nainar8ca8ee62015-09-03 01:04:10105 void Skew(double angle_x, double angle_y);
[email protected]2fcafa02012-11-15 01:12:55106
107 // Applies the current transformation on a perspective transform and assigns
108 // the result to |this|.
[email protected]803f6b52013-09-12 00:51:26109 void ApplyPerspectiveDepth(SkMScalar depth);
[email protected]2fcafa02012-11-15 01:12:55110
[email protected]b9b1e7a42011-05-17 15:29:51111 // Applies a transformation on the current transformation
[email protected]80248e32011-07-08 15:31:11112 // (i.e. 'this = this * transform;').
113 void PreconcatTransform(const Transform& transform);
[email protected]36df22b2011-02-24 21:47:56114
[email protected]598080082011-04-14 19:36:33115 // Applies a transformation on the current transformation
[email protected]80248e32011-07-08 15:31:11116 // (i.e. 'this = transform * this;').
117 void ConcatTransform(const Transform& transform);
[email protected]36df22b2011-02-24 21:47:56118
[email protected]45127922012-11-17 12:24:49119 // Returns true if this is the identity matrix.
[email protected]d9a6f3302012-12-07 19:17:54120 bool IsIdentity() const { return matrix_.isIdentity(); }
[email protected]45127922012-11-17 12:24:49121
[email protected]2c7cd6d2012-11-28 23:49:26122 // Returns true if the matrix is either identity or pure translation.
danakj670a4ab2014-09-19 19:38:28123 bool IsIdentityOrTranslation() const { return matrix_.isTranslate(); }
[email protected]2c7cd6d2012-11-28 23:49:26124
vollick51ed1a22014-12-17 02:03:00125 // Returns true if the matrix is either the identity or a 2d translation.
126 bool IsIdentityOr2DTranslation() const {
127 return matrix_.isTranslate() && matrix_.get(2, 3) == 0;
128 }
129
[email protected]19f90542013-10-19 18:26:07130 // Returns true if the matrix is either identity or pure translation,
131 // allowing for an amount of inaccuracy as specified by the parameter.
132 bool IsApproximatelyIdentityOrTranslation(SkMScalar tolerance) const;
133
[email protected]aedf4e52013-01-09 23:24:44134 // Returns true if the matrix is either a positive scale and/or a translation.
135 bool IsPositiveScaleOrTranslation() const {
136 if (!IsScaleOrTranslation())
137 return false;
[email protected]803f6b52013-09-12 00:51:26138 return matrix_.get(0, 0) > 0.0 && matrix_.get(1, 1) > 0.0 &&
139 matrix_.get(2, 2) > 0.0;
[email protected]aedf4e52013-01-09 23:24:44140 }
141
[email protected]d1a56f02012-12-04 12:18:30142 // Returns true if the matrix is either identity or pure, non-fractional
143 // translation.
144 bool IsIdentityOrIntegerTranslation() const;
145
[email protected]adeda572014-01-31 00:49:47146 // Returns true if the matrix had only scaling components.
tfarina81090b42014-11-06 14:50:43147 bool IsScale2d() const { return matrix_.isScale(); }
[email protected]adeda572014-01-31 00:49:47148
[email protected]2c7cd6d2012-11-28 23:49:26149 // Returns true if the matrix is has only scaling and translation components.
danakj670a4ab2014-09-19 19:38:28150 bool IsScaleOrTranslation() const { return matrix_.isScaleTranslate(); }
[email protected]2c7cd6d2012-11-28 23:49:26151
[email protected]3a9a92d2013-07-11 04:37:00152 // Returns true if axis-aligned 2d rects will remain axis-aligned after being
153 // transformed by this matrix.
154 bool Preserves2dAxisAlignment() const;
155
[email protected]2c7cd6d2012-11-28 23:49:26156 // Returns true if the matrix has any perspective component that would
157 // change the w-component of a homogeneous point.
danakj670a4ab2014-09-19 19:38:28158 bool HasPerspective() const { return matrix_.hasPerspective(); }
[email protected]2c7cd6d2012-11-28 23:49:26159
[email protected]45127922012-11-17 12:24:49160 // Returns true if this transform is non-singular.
[email protected]0db13222012-12-13 21:27:54161 bool IsInvertible() const { return matrix_.invert(NULL); }
[email protected]36df22b2011-02-24 21:47:56162
[email protected]2c7cd6d2012-11-28 23:49:26163 // Returns true if a layer with a forward-facing normal of (0, 0, 1) would
164 // have its back side facing frontwards after applying the transform.
165 bool IsBackFaceVisible() const;
166
[email protected]38919392011-10-24 22:26:23167 // Inverts the transform which is passed in. Returns true if successful.
[email protected]45127922012-11-17 12:24:49168 bool GetInverse(Transform* transform) const WARN_UNUSED_RESULT;
169
170 // Transposes this transform in place.
171 void Transpose();
[email protected]38919392011-10-24 22:26:23172
[email protected]78634b0c2013-01-15 07:49:40173 // Set 3rd row and 3rd colum to (0, 0, 1, 0). Note that this flattening
174 // operation is not quite the same as an orthographic projection and is
175 // technically not a linear operation.
176 //
177 // One useful interpretation of doing this operation:
178 // - For x and y values, the new transform behaves effectively like an
179 // orthographic projection was added to the matrix sequence.
180 // - For z values, the new transform overrides any effect that the transform
181 // had on z, and instead it preserves the z value for any points that are
182 // transformed.
183 // - Because of linearity of transforms, this flattened transform also
184 // preserves the effect that any subsequent (multiplied from the right)
185 // transforms would have on z values.
186 //
187 void FlattenTo2d();
188
ajumad0d64422015-03-14 04:20:08189 // Returns true if the 3rd row and 3rd column are both (0, 0, 1, 0).
190 bool IsFlat() const;
191
[email protected]d81752b2013-10-25 08:32:23192 // Returns the x and y translation components of the matrix.
[email protected]bea4c872013-08-14 18:10:00193 Vector2dF To2dTranslation() const;
194
[email protected]908af422013-10-10 22:22:42195 // Applies the transformation to the point.
[email protected]26d7ece2013-09-12 20:59:47196 void TransformPoint(Point3F* point) const;
[email protected]36df22b2011-02-24 21:47:56197
[email protected]908af422013-10-10 22:22:42198 // Applies the transformation to the point.
[email protected]26d7ece2013-09-12 20:59:47199 void TransformPoint(Point* point) const;
[email protected]36df22b2011-02-24 21:47:56200
petermayo59d37682016-04-13 14:37:35201 // Applies the transformation to the vector.
202 void TransformVector(Vector3dF* vector) const;
203
[email protected]80248e32011-07-08 15:31:11204 // Applies the reverse transformation on the point. Returns true if the
205 // transformation can be inverted.
[email protected]26d7ece2013-09-12 20:59:47206 bool TransformPointReverse(Point3F* point) const;
[email protected]463eb0e2011-05-10 03:11:04207
[email protected]80248e32011-07-08 15:31:11208 // Applies the reverse transformation on the point. Returns true if the
209 // transformation can be inverted. Rounds the result to the nearest point.
[email protected]26d7ece2013-09-12 20:59:47210 bool TransformPointReverse(Point* point) const;
[email protected]80248e32011-07-08 15:31:11211
[email protected]f4d2b9012013-10-11 19:10:50212 // Applies transformation on the given rect. After the function completes,
213 // |rect| will be the smallest axis aligned bounding rect containing the
214 // transformed rect.
[email protected]79fbdab02012-11-14 07:28:11215 void TransformRect(RectF* rect) const;
[email protected]80248e32011-07-08 15:31:11216
[email protected]f4d2b9012013-10-11 19:10:50217 // Applies the reverse transformation on the given rect. After the function
218 // completes, |rect| will be the smallest axis aligned bounding rect
219 // containing the transformed rect. Returns false if the matrix cannot be
220 // inverted.
[email protected]79fbdab02012-11-14 07:28:11221 bool TransformRectReverse(RectF* rect) const;
[email protected]277c7b72011-06-06 15:23:09222
[email protected]f4d2b9012013-10-11 19:10:50223 // Applies transformation on the given box. After the function completes,
224 // |box| will be the smallest axis aligned bounding box containing the
225 // transformed box.
226 void TransformBox(BoxF* box) const;
227
228 // Applies the reverse transformation on the given box. After the function
229 // completes, |box| will be the smallest axis aligned bounding box
230 // containing the transformed box. Returns false if the matrix cannot be
231 // inverted.
232 bool TransformBoxReverse(BoxF* box) const;
233
[email protected]2fcafa02012-11-15 01:12:55234 // Decomposes |this| and |from|, interpolates the decomposed values, and
235 // sets |this| to the reconstituted result. Returns false if either matrix
236 // can't be decomposed. Uses routines described in this spec:
237 // http://www.w3.org/TR/css3-3d-transforms/.
238 //
239 // Note: this call is expensive since we need to decompose the transform. If
240 // you're going to be calling this rapidly (e.g., in an animation) you should
241 // decompose once using gfx::DecomposeTransforms and reuse your
242 // DecomposedTransform.
[email protected]6138db702013-09-25 03:25:05243 bool Blend(const Transform& from, double progress);
[email protected]2fcafa02012-11-15 01:12:55244
vollickb169ff622015-02-10 01:22:33245 void RoundTranslationComponents();
246
[email protected]f7c321eb2012-11-26 20:13:08247 // Returns |this| * |other|.
[email protected]d9a6f3302012-12-07 19:17:54248 Transform operator*(const Transform& other) const {
249 return Transform(*this, other);
250 }
[email protected]f7c321eb2012-11-26 20:13:08251
252 // Sets |this| = |this| * |other|
[email protected]0db13222012-12-13 21:27:54253 Transform& operator*=(const Transform& other) {
254 PreconcatTransform(other);
255 return *this;
256 }
[email protected]f7c321eb2012-11-26 20:13:08257
[email protected]b9b1e7a42011-05-17 15:29:51258 // Returns the underlying matrix.
[email protected]80248e32011-07-08 15:31:11259 const SkMatrix44& matrix() const { return matrix_; }
260 SkMatrix44& matrix() { return matrix_; }
jaydasikacb93d1c2015-12-09 23:52:46261 bool ApproximatelyEqual(const gfx::Transform& transform) const;
[email protected]b9b1e7a42011-05-17 15:29:51262
[email protected]6ab42d92012-12-20 20:36:53263 std::string ToString() const;
264
[email protected]b9b1e7a42011-05-17 15:29:51265 private:
[email protected]80248e32011-07-08 15:31:11266 void TransformPointInternal(const SkMatrix44& xform,
[email protected]26d7ece2013-09-12 20:59:47267 Point* point) const;
[email protected]80248e32011-07-08 15:31:11268
269 void TransformPointInternal(const SkMatrix44& xform,
[email protected]26d7ece2013-09-12 20:59:47270 Point3F* point) const;
[email protected]80248e32011-07-08 15:31:11271
petermayo59d37682016-04-13 14:37:35272 void TransformVectorInternal(const SkMatrix44& xform,
273 Vector3dF* vector) const;
274
[email protected]80248e32011-07-08 15:31:11275 SkMatrix44 matrix_;
[email protected]b9b1e7a42011-05-17 15:29:51276
277 // copy/assign are allowed.
[email protected]36df22b2011-02-24 21:47:56278};
279
[email protected]a109fd02014-07-10 07:41:43280// This is declared here for use in gtest-based unit tests but is defined in
281// the gfx_test_support target. Depend on that to use this in your unit test.
282// This should not be used in production code - call ToString() instead.
283void PrintTo(const Transform& transform, ::std::ostream* os);
284
[email protected]0f0453e2012-10-14 18:15:35285} // namespace gfx
[email protected]36df22b2011-02-24 21:47:56286
287#endif // UI_GFX_TRANSFORM_H_