1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13 // XX - I don't think this class should use gfxFloat at all,
14 // but should use 'double' and be called gfxDoubleMatrix;
15 // we can then typedef that to gfxMatrix where we typedef
16 // double to be gfxFloat.
19 * A matrix that represents an affine transformation. Projective
20 * transformations are not supported. This matrix looks like:
26 * So, transforming a point (x, y) results in:
28 * / a b 0 \ / a * x + c * y + tx \ T
29 * (x y 1) * | c d 0 | = | b * x + d * y + ty |
40 * Initializes this matrix as the identity matrix.
42 gfxMatrix() { Reset(); }
45 * Initializes the matrix from individual components. See the class
46 * description for the layout of the matrix.
48 gfxMatrix(gfxFloat a
, gfxFloat b
, gfxFloat c
, gfxFloat d
, gfxFloat tx
, gfxFloat ty
) :
54 * Post-multiplies m onto the matrix.
56 const gfxMatrix
& operator *= (const gfxMatrix
& m
) {
61 * Multiplies *this with m and returns the result.
63 gfxMatrix
operator * (const gfxMatrix
& m
) const {
64 return gfxMatrix(*this).Multiply(m
);
67 /* Returns true if the other matrix is fuzzy-equal to this matrix.
68 * Note that this isn't a cheap comparison!
70 bool operator==(const gfxMatrix
& other
) const
72 return FuzzyEqual(xx
, other
.xx
) && FuzzyEqual(yx
, other
.yx
) &&
73 FuzzyEqual(xy
, other
.xy
) && FuzzyEqual(yy
, other
.yy
) &&
74 FuzzyEqual(x0
, other
.x0
) && FuzzyEqual(y0
, other
.y0
);
77 bool operator!=(const gfxMatrix
& other
) const
79 return !(*this == other
);
84 * Resets this matrix to the identity matrix.
86 const gfxMatrix
& Reset();
88 bool IsIdentity() const {
89 return xx
== 1.0 && yx
== 0.0 &&
90 xy
== 0.0 && yy
== 1.0 &&
91 x0
== 0.0 && y0
== 0.0;
95 * Inverts this matrix, if possible. Otherwise, the matrix is left
98 * XXX should this do something with the return value of
99 * cairo_matrix_invert?
101 const gfxMatrix
& Invert();
104 * Check if matrix is singular (no inverse exists).
106 bool IsSingular() const {
107 // if the determinant (ad - bc) is zero it's singular
108 return (xx
* yy
) == (yx
* xy
);
112 * Scales this matrix. The scale is pre-multiplied onto this matrix,
113 * i.e. the scaling takes place before the other transformations.
115 const gfxMatrix
& Scale(gfxFloat x
, gfxFloat y
);
118 * Translates this matrix. The translation is pre-multiplied onto this matrix,
119 * i.e. the translation takes place before the other transformations.
121 const gfxMatrix
& Translate(const gfxPoint
& pt
);
124 * Rotates this matrix. The rotation is pre-multiplied onto this matrix,
125 * i.e. the translation takes place after the other transformations.
127 * @param radians Angle in radians.
129 const gfxMatrix
& Rotate(gfxFloat radians
);
132 * Multiplies the current matrix with m.
133 * This is a post-multiplication, i.e. the transformations of m are
134 * applied _after_ the existing transformations.
136 * XXX is that difference (compared to Rotate etc) a good thing?
138 const gfxMatrix
& Multiply(const gfxMatrix
& m
);
141 * Multiplies the current matrix with m.
142 * This is a pre-multiplication, i.e. the transformations of m are
143 * applied _before_ the existing transformations.
145 const gfxMatrix
& PreMultiply(const gfxMatrix
& m
);
148 * Transforms a point according to this matrix.
150 gfxPoint
Transform(const gfxPoint
& point
) const;
154 * Transform a distance according to this matrix. This does not apply
155 * any translation components.
157 gfxSize
Transform(const gfxSize
& size
) const;
160 * Transforms both the point and distance according to this matrix.
162 gfxRect
Transform(const gfxRect
& rect
) const;
164 gfxRect
TransformBounds(const gfxRect
& rect
) const;
167 * Returns the translation component of this matrix.
169 gfxPoint
GetTranslation() const {
170 return gfxPoint(x0
, y0
);
174 * Returns true if the matrix is anything other than a straight
175 * translation by integers.
177 bool HasNonIntegerTranslation() const {
178 return HasNonTranslation() ||
179 !FuzzyEqual(x0
, floor(x0
+ 0.5)) ||
180 !FuzzyEqual(y0
, floor(y0
+ 0.5));
184 * Returns true if the matrix has any transform other
185 * than a straight translation
187 bool HasNonTranslation() const {
188 return !FuzzyEqual(xx
, 1.0) || !FuzzyEqual(yy
, 1.0) ||
189 !FuzzyEqual(xy
, 0.0) || !FuzzyEqual(yx
, 0.0);
193 * Returns true if the matrix only has an integer translation.
195 bool HasOnlyIntegerTranslation() const {
196 return !HasNonIntegerTranslation();
200 * Returns true if the matrix has any transform other
201 * than a translation or a -1 y scale (y axis flip)
203 bool HasNonTranslationOrFlip() const {
204 return !FuzzyEqual(xx
, 1.0) ||
205 (!FuzzyEqual(yy
, 1.0) && !FuzzyEqual(yy
, -1.0)) ||
206 !FuzzyEqual(xy
, 0.0) || !FuzzyEqual(yx
, 0.0);
210 * Returns true if the matrix has any transform other
211 * than a translation or scale; this is, if there is
214 bool HasNonAxisAlignedTransform() const {
215 return !FuzzyEqual(xy
, 0.0) || !FuzzyEqual(yx
, 0.0);
219 * Computes the determinant of this matrix.
221 double Determinant() const {
222 return xx
*yy
- yx
*xy
;
225 /* Computes the scale factors of this matrix; that is,
226 * the amounts each basis vector is scaled by.
227 * The xMajor parameter indicates if the larger scale is
228 * to be assumed to be in the X direction or not.
230 gfxSize
ScaleFactors(bool xMajor
) const {
231 double det
= Determinant();
234 return gfxSize(0.0, 0.0);
236 gfxSize sz
= xMajor
? gfxSize(1.0, 0.0) : gfxSize(0.0, 1.0);
239 double major
= sqrt(sz
.width
* sz
.width
+ sz
.height
* sz
.height
);
250 return gfxSize(major
, minor
);
252 return gfxSize(minor
, major
);
256 * Snap matrix components that are close to integers
257 * to integers. In particular, components that are integral when
258 * converted to single precision are set to those integers.
260 void NudgeToIntegers(void);
263 * Returns true if matrix is multiple of 90 degrees rotation with flipping,
264 * scaling and translation.
266 bool PreservesAxisAlignedRectangles() const {
267 return ((FuzzyEqual(xx
, 0.0) && FuzzyEqual(yy
, 0.0))
268 || (FuzzyEqual(xy
, 0.0) && FuzzyEqual(yx
, 0.0)));
272 * Returns true if the matrix has non-integer scale
274 bool HasNonIntegerScale() const {
275 return !FuzzyEqual(xx
, floor(xx
+ 0.5)) ||
276 !FuzzyEqual(yy
, floor(yy
+ 0.5));
280 static bool FuzzyEqual(gfxFloat aV1
, gfxFloat aV2
) {
281 return fabs(aV2
- aV1
) < 1e-6;
285 #endif /* GFX_MATRIX_H */