Merge m-c to inbound.
[gecko.git] / gfx / thebes / gfxMatrix.h
blobb0107c11f9e1602c08e7966a0e416a7a3b51920b
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/. */
6 #ifndef GFX_MATRIX_H
7 #define GFX_MATRIX_H
9 #include "gfxPoint.h"
10 #include "gfxTypes.h"
11 #include "gfxRect.h"
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.
18 /**
19 * A matrix that represents an affine transformation. Projective
20 * transformations are not supported. This matrix looks like:
22 * / a b 0 \
23 * | c d 0 |
24 * \ tx ty 1 /
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 |
30 * \ tx ty 1 / \ 1 /
33 struct gfxMatrix {
34 double xx; double yx;
35 double xy; double yy;
36 double x0; double y0;
38 public:
39 /**
40 * Initializes this matrix as the identity matrix.
42 gfxMatrix() { Reset(); }
44 /**
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) :
49 xx(a), yx(b),
50 xy(c), yy(d),
51 x0(tx), y0(ty) { }
53 /**
54 * Post-multiplies m onto the matrix.
56 const gfxMatrix& operator *= (const gfxMatrix& m) {
57 return Multiply(m);
60 /**
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);
82 // matrix operations
83 /**
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;
94 /**
95 * Inverts this matrix, if possible. Otherwise, the matrix is left
96 * unchanged.
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
212 * no rotation.
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();
233 if (det == 0.0)
234 return gfxSize(0.0, 0.0);
236 gfxSize sz = xMajor ? gfxSize(1.0, 0.0) : gfxSize(0.0, 1.0);
237 sz = Transform(sz);
239 double major = sqrt(sz.width * sz.width + sz.height * sz.height);
240 double minor = 0.0;
242 // ignore mirroring
243 if (det < 0.0)
244 det = - det;
246 if (major)
247 minor = det / major;
249 if (xMajor)
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));
279 private:
280 static bool FuzzyEqual(gfxFloat aV1, gfxFloat aV2) {
281 return fabs(aV2 - aV1) < 1e-6;
285 #endif /* GFX_MATRIX_H */