1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Oracle Corporation code.
16 : *
17 : * The Initial Developer of the Original Code is Oracle Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2005
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Stuart Parmenter <pavlov@pavlov.net>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef GFX_MATRIX_H
39 : #define GFX_MATRIX_H
40 :
41 : #include "gfxPoint.h"
42 : #include "gfxTypes.h"
43 : #include "gfxRect.h"
44 : #include "nsMathUtils.h"
45 :
46 : // XX - I don't think this class should use gfxFloat at all,
47 : // but should use 'double' and be called gfxDoubleMatrix;
48 : // we can then typedef that to gfxMatrix where we typedef
49 : // double to be gfxFloat.
50 :
51 : /**
52 : * A matrix that represents an affine transformation. Projective
53 : * transformations are not supported. This matrix looks like:
54 : *
55 : * / a b 0 \
56 : * | c d 0 |
57 : * \ tx ty 1 /
58 : *
59 : * So, transforming a point (x, y) results in:
60 : *
61 : * / a b 0 \ / a * x + c * y + tx \ T
62 : * (x y 1) * | c d 0 | = | b * x + d * y + ty |
63 : * \ tx ty 1 / \ 1 /
64 : *
65 : */
66 : struct THEBES_API gfxMatrix {
67 : double xx; double yx;
68 : double xy; double yy;
69 : double x0; double y0;
70 :
71 : public:
72 : /**
73 : * Initializes this matrix as the identity matrix.
74 : */
75 0 : gfxMatrix() { Reset(); }
76 :
77 : /**
78 : * Initializes the matrix from individual components. See the class
79 : * description for the layout of the matrix.
80 : */
81 0 : gfxMatrix(gfxFloat a, gfxFloat b, gfxFloat c, gfxFloat d, gfxFloat tx, gfxFloat ty) :
82 : xx(a), yx(b),
83 : xy(c), yy(d),
84 0 : x0(tx), y0(ty) { }
85 :
86 : /**
87 : * Post-multiplies m onto the matrix.
88 : */
89 0 : const gfxMatrix& operator *= (const gfxMatrix& m) {
90 0 : return Multiply(m);
91 : }
92 :
93 : /**
94 : * Multiplies *this with m and returns the result.
95 : */
96 0 : gfxMatrix operator * (const gfxMatrix& m) const {
97 0 : return gfxMatrix(*this).Multiply(m);
98 : }
99 :
100 : // matrix operations
101 : /**
102 : * Resets this matrix to the identity matrix.
103 : */
104 : const gfxMatrix& Reset();
105 :
106 0 : bool IsIdentity() const {
107 : return xx == 1.0 && yx == 0.0 &&
108 : xy == 0.0 && yy == 1.0 &&
109 0 : x0 == 0.0 && y0 == 0.0;
110 : }
111 :
112 : /**
113 : * Inverts this matrix, if possible. Otherwise, the matrix is left
114 : * unchanged.
115 : *
116 : * XXX should this do something with the return value of
117 : * cairo_matrix_invert?
118 : */
119 : const gfxMatrix& Invert();
120 :
121 : /**
122 : * Check if matrix is singular (no inverse exists).
123 : */
124 0 : bool IsSingular() const {
125 : // if the determinant (ad - bc) is zero it's singular
126 0 : return (xx * yy) == (yx * xy);
127 : }
128 :
129 : /**
130 : * Scales this matrix. The scale is pre-multiplied onto this matrix,
131 : * i.e. the scaling takes place before the other transformations.
132 : */
133 : const gfxMatrix& Scale(gfxFloat x, gfxFloat y);
134 :
135 : /**
136 : * Translates this matrix. The translation is pre-multiplied onto this matrix,
137 : * i.e. the translation takes place before the other transformations.
138 : */
139 : const gfxMatrix& Translate(const gfxPoint& pt);
140 :
141 : /**
142 : * Rotates this matrix. The rotation is pre-multiplied onto this matrix,
143 : * i.e. the translation takes place after the other transformations.
144 : *
145 : * @param radians Angle in radians.
146 : */
147 : const gfxMatrix& Rotate(gfxFloat radians);
148 :
149 : /**
150 : * Multiplies the current matrix with m.
151 : * This is a post-multiplication, i.e. the transformations of m are
152 : * applied _after_ the existing transformations.
153 : *
154 : * XXX is that difference (compared to Rotate etc) a good thing?
155 : */
156 : const gfxMatrix& Multiply(const gfxMatrix& m);
157 :
158 : /**
159 : * Multiplies the current matrix with m.
160 : * This is a pre-multiplication, i.e. the transformations of m are
161 : * applied _before_ the existing transformations.
162 : */
163 : const gfxMatrix& PreMultiply(const gfxMatrix& m);
164 :
165 : /**
166 : * Transforms a point according to this matrix.
167 : */
168 : gfxPoint Transform(const gfxPoint& point) const;
169 :
170 :
171 : /**
172 : * Transform a distance according to this matrix. This does not apply
173 : * any translation components.
174 : */
175 : gfxSize Transform(const gfxSize& size) const;
176 :
177 : /**
178 : * Transforms both the point and distance according to this matrix.
179 : */
180 : gfxRect Transform(const gfxRect& rect) const;
181 :
182 : gfxRect TransformBounds(const gfxRect& rect) const;
183 :
184 : /**
185 : * Returns the translation component of this matrix.
186 : */
187 0 : gfxPoint GetTranslation() const {
188 0 : return gfxPoint(x0, y0);
189 : }
190 :
191 : /**
192 : * Returns true if the matrix is anything other than a straight
193 : * translation by integers.
194 : */
195 0 : bool HasNonIntegerTranslation() const {
196 0 : return HasNonTranslation() ||
197 0 : !FuzzyEqual(x0, floor(x0 + 0.5)) ||
198 0 : !FuzzyEqual(y0, floor(y0 + 0.5));
199 : }
200 :
201 : /**
202 : * Returns true if the matrix has any transform other
203 : * than a straight translation
204 : */
205 0 : bool HasNonTranslation() const {
206 0 : return !FuzzyEqual(xx, 1.0) || !FuzzyEqual(yy, 1.0) ||
207 0 : !FuzzyEqual(xy, 0.0) || !FuzzyEqual(yx, 0.0);
208 : }
209 :
210 : /**
211 : * Returns true if the matrix only has an integer translation.
212 : */
213 : bool HasOnlyIntegerTranslation() const {
214 : return !HasNonIntegerTranslation();
215 : }
216 :
217 : /**
218 : * Returns true if the matrix has any transform other
219 : * than a translation or a -1 y scale (y axis flip)
220 : */
221 0 : bool HasNonTranslationOrFlip() const {
222 0 : return !FuzzyEqual(xx, 1.0) ||
223 0 : (!FuzzyEqual(yy, 1.0) && !FuzzyEqual(yy, -1.0)) ||
224 0 : !FuzzyEqual(xy, 0.0) || !FuzzyEqual(yx, 0.0);
225 : }
226 :
227 : /**
228 : * Returns true if the matrix has any transform other
229 : * than a translation or scale; this is, if there is
230 : * no rotation.
231 : */
232 0 : bool HasNonAxisAlignedTransform() const {
233 0 : return !FuzzyEqual(xy, 0.0) || !FuzzyEqual(yx, 0.0);
234 : }
235 :
236 : /**
237 : * Computes the determinant of this matrix.
238 : */
239 0 : double Determinant() const {
240 0 : return xx*yy - yx*xy;
241 : }
242 :
243 : /* Computes the scale factors of this matrix; that is,
244 : * the amounts each basis vector is scaled by.
245 : * The xMajor parameter indicates if the larger scale is
246 : * to be assumed to be in the X direction or not.
247 : */
248 0 : gfxSize ScaleFactors(bool xMajor) const {
249 0 : double det = Determinant();
250 :
251 0 : if (det == 0.0)
252 0 : return gfxSize(0.0, 0.0);
253 :
254 0 : gfxSize sz = xMajor ? gfxSize(1.0, 0.0) : gfxSize(0.0, 1.0);
255 0 : sz = Transform(sz);
256 :
257 0 : double major = sqrt(sz.width * sz.width + sz.height * sz.height);
258 0 : double minor = 0.0;
259 :
260 : // ignore mirroring
261 0 : if (det < 0.0)
262 0 : det = - det;
263 :
264 0 : if (major)
265 0 : minor = det / major;
266 :
267 0 : if (xMajor)
268 0 : return gfxSize(major, minor);
269 :
270 0 : return gfxSize(minor, major);
271 : }
272 :
273 : /**
274 : * Snap matrix components that are close to integers
275 : * to integers. In particular, components that are integral when
276 : * converted to single precision are set to those integers.
277 : */
278 : void NudgeToIntegers(void);
279 :
280 : /**
281 : * Returns true if matrix is multiple of 90 degrees rotation with flipping,
282 : * scaling and translation.
283 : */
284 0 : bool PreservesAxisAlignedRectangles() const {
285 0 : return ((FuzzyEqual(xx, 0.0) && FuzzyEqual(yy, 0.0))
286 0 : || (FuzzyEqual(xy, 0.0) && FuzzyEqual(yx, 0.0)));
287 : }
288 :
289 : /**
290 : * Returns true if the matrix has non-integer scale
291 : */
292 0 : bool HasNonIntegerScale() const {
293 0 : return !FuzzyEqual(xx, floor(xx + 0.5)) ||
294 0 : !FuzzyEqual(yy, floor(yy + 0.5));
295 : }
296 :
297 : private:
298 0 : static bool FuzzyEqual(gfxFloat aV1, gfxFloat aV2) {
299 0 : return fabs(aV2 - aV1) < 1e-6;
300 : }
301 : };
302 :
303 : #endif /* GFX_MATRIX_H */
|