/work/workdir/UnpackedTarball/cairo/src/cairo-matrix.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* cairo - a vector graphics library with display and print output |
2 | | * |
3 | | * Copyright © 2002 University of Southern California |
4 | | * |
5 | | * This library is free software; you can redistribute it and/or |
6 | | * modify it either under the terms of the GNU Lesser General Public |
7 | | * License version 2.1 as published by the Free Software Foundation |
8 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
9 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
10 | | * notice, a recipient may use your version of this file under either |
11 | | * the MPL or the LGPL. |
12 | | * |
13 | | * You should have received a copy of the LGPL along with this library |
14 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
15 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
16 | | * You should have received a copy of the MPL along with this library |
17 | | * in the file COPYING-MPL-1.1 |
18 | | * |
19 | | * The contents of this file are subject to the Mozilla Public License |
20 | | * Version 1.1 (the "License"); you may not use this file except in |
21 | | * compliance with the License. You may obtain a copy of the License at |
22 | | * http://www.mozilla.org/MPL/ |
23 | | * |
24 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
25 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
26 | | * the specific language governing rights and limitations. |
27 | | * |
28 | | * The Original Code is the cairo graphics library. |
29 | | * |
30 | | * The Initial Developer of the Original Code is University of Southern |
31 | | * California. |
32 | | * |
33 | | * Contributor(s): |
34 | | * Carl D. Worth <cworth@cworth.org> |
35 | | */ |
36 | | |
37 | | #include "cairoint.h" |
38 | | #include "cairo-error-private.h" |
39 | | #include <float.h> |
40 | | |
41 | 1.52M | #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ |
42 | | |
43 | | /** |
44 | | * SECTION:cairo-matrix |
45 | | * @Title: cairo_matrix_t |
46 | | * @Short_Description: Generic matrix operations |
47 | | * @See_Also: #cairo_t |
48 | | * |
49 | | * #cairo_matrix_t is used throughout cairo to convert between different |
50 | | * coordinate spaces. A #cairo_matrix_t holds an affine transformation, |
51 | | * such as a scale, rotation, shear, or a combination of these. |
52 | | * The transformation of a point (<literal>x</literal>,<literal>y</literal>) |
53 | | * is given by: |
54 | | * |
55 | | * <programlisting> |
56 | | * x_new = xx * x + xy * y + x0; |
57 | | * y_new = yx * x + yy * y + y0; |
58 | | * </programlisting> |
59 | | * |
60 | | * The current transformation matrix of a #cairo_t, represented as a |
61 | | * #cairo_matrix_t, defines the transformation from user-space |
62 | | * coordinates to device-space coordinates. See cairo_get_matrix() and |
63 | | * cairo_set_matrix(). |
64 | | **/ |
65 | | |
66 | | static void |
67 | | _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar); |
68 | | |
69 | | static void |
70 | | _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix); |
71 | | |
72 | | /** |
73 | | * cairo_matrix_init_identity: |
74 | | * @matrix: a #cairo_matrix_t |
75 | | * |
76 | | * Modifies @matrix to be an identity transformation. |
77 | | * |
78 | | * Since: 1.0 |
79 | | **/ |
80 | | void |
81 | | cairo_matrix_init_identity (cairo_matrix_t *matrix) |
82 | 18.9M | { |
83 | 18.9M | cairo_matrix_init (matrix, |
84 | 18.9M | 1, 0, |
85 | 18.9M | 0, 1, |
86 | 18.9M | 0, 0); |
87 | 18.9M | } |
88 | | slim_hidden_def(cairo_matrix_init_identity); |
89 | | |
90 | | /** |
91 | | * cairo_matrix_init: |
92 | | * @matrix: a #cairo_matrix_t |
93 | | * @xx: xx component of the affine transformation |
94 | | * @yx: yx component of the affine transformation |
95 | | * @xy: xy component of the affine transformation |
96 | | * @yy: yy component of the affine transformation |
97 | | * @x0: X translation component of the affine transformation |
98 | | * @y0: Y translation component of the affine transformation |
99 | | * |
100 | | * Sets @matrix to be the affine transformation given by |
101 | | * @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given |
102 | | * by: |
103 | | * <programlisting> |
104 | | * x_new = xx * x + xy * y + x0; |
105 | | * y_new = yx * x + yy * y + y0; |
106 | | * </programlisting> |
107 | | * |
108 | | * Since: 1.0 |
109 | | **/ |
110 | | void |
111 | | cairo_matrix_init (cairo_matrix_t *matrix, |
112 | | double xx, double yx, |
113 | | |
114 | | double xy, double yy, |
115 | | double x0, double y0) |
116 | 37.9M | { |
117 | 37.9M | matrix->xx = xx; matrix->yx = yx; |
118 | 37.9M | matrix->xy = xy; matrix->yy = yy; |
119 | 37.9M | matrix->x0 = x0; matrix->y0 = y0; |
120 | 37.9M | } |
121 | | slim_hidden_def(cairo_matrix_init); |
122 | | |
123 | | /** |
124 | | * _cairo_matrix_get_affine: |
125 | | * @matrix: a #cairo_matrix_t |
126 | | * @xx: location to store xx component of matrix |
127 | | * @yx: location to store yx component of matrix |
128 | | * @xy: location to store xy component of matrix |
129 | | * @yy: location to store yy component of matrix |
130 | | * @x0: location to store x0 (X-translation component) of matrix, or %NULL |
131 | | * @y0: location to store y0 (Y-translation component) of matrix, or %NULL |
132 | | * |
133 | | * Gets the matrix values for the affine transformation that @matrix represents. |
134 | | * See cairo_matrix_init(). |
135 | | * |
136 | | * |
137 | | * This function is a leftover from the old public API, but is still |
138 | | * mildly useful as an internal means for getting at the matrix |
139 | | * members in a positional way. For example, when reassigning to some |
140 | | * external matrix type, or when renaming members to more meaningful |
141 | | * names (such as a,b,c,d,e,f) for particular manipulations. |
142 | | **/ |
143 | | void |
144 | | _cairo_matrix_get_affine (const cairo_matrix_t *matrix, |
145 | | double *xx, double *yx, |
146 | | double *xy, double *yy, |
147 | | double *x0, double *y0) |
148 | 5.01k | { |
149 | 5.01k | *xx = matrix->xx; |
150 | 5.01k | *yx = matrix->yx; |
151 | | |
152 | 5.01k | *xy = matrix->xy; |
153 | 5.01k | *yy = matrix->yy; |
154 | | |
155 | 5.01k | if (x0) |
156 | 139 | *x0 = matrix->x0; |
157 | 5.01k | if (y0) |
158 | 139 | *y0 = matrix->y0; |
159 | 5.01k | } |
160 | | |
161 | | /** |
162 | | * cairo_matrix_init_translate: |
163 | | * @matrix: a #cairo_matrix_t |
164 | | * @tx: amount to translate in the X direction |
165 | | * @ty: amount to translate in the Y direction |
166 | | * |
167 | | * Initializes @matrix to a transformation that translates by @tx and |
168 | | * @ty in the X and Y dimensions, respectively. |
169 | | * |
170 | | * Since: 1.0 |
171 | | **/ |
172 | | void |
173 | | cairo_matrix_init_translate (cairo_matrix_t *matrix, |
174 | | double tx, double ty) |
175 | 1.41M | { |
176 | 1.41M | cairo_matrix_init (matrix, |
177 | 1.41M | 1, 0, |
178 | 1.41M | 0, 1, |
179 | 1.41M | tx, ty); |
180 | 1.41M | } |
181 | | slim_hidden_def(cairo_matrix_init_translate); |
182 | | |
183 | | /** |
184 | | * cairo_matrix_translate: |
185 | | * @matrix: a #cairo_matrix_t |
186 | | * @tx: amount to translate in the X direction |
187 | | * @ty: amount to translate in the Y direction |
188 | | * |
189 | | * Applies a translation by @tx, @ty to the transformation in |
190 | | * @matrix. The effect of the new transformation is to first translate |
191 | | * the coordinates by @tx and @ty, then apply the original transformation |
192 | | * to the coordinates. |
193 | | * |
194 | | * Since: 1.0 |
195 | | **/ |
196 | | void |
197 | | cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty) |
198 | 3.07k | { |
199 | 3.07k | cairo_matrix_t tmp; |
200 | | |
201 | 3.07k | cairo_matrix_init_translate (&tmp, tx, ty); |
202 | | |
203 | 3.07k | cairo_matrix_multiply (matrix, &tmp, matrix); |
204 | 3.07k | } |
205 | | slim_hidden_def (cairo_matrix_translate); |
206 | | |
207 | | /** |
208 | | * cairo_matrix_init_scale: |
209 | | * @matrix: a #cairo_matrix_t |
210 | | * @sx: scale factor in the X direction |
211 | | * @sy: scale factor in the Y direction |
212 | | * |
213 | | * Initializes @matrix to a transformation that scales by @sx and @sy |
214 | | * in the X and Y dimensions, respectively. |
215 | | * |
216 | | * Since: 1.0 |
217 | | **/ |
218 | | void |
219 | | cairo_matrix_init_scale (cairo_matrix_t *matrix, |
220 | | double sx, double sy) |
221 | 13.2M | { |
222 | 13.2M | cairo_matrix_init (matrix, |
223 | 13.2M | sx, 0, |
224 | 13.2M | 0, sy, |
225 | 13.2M | 0, 0); |
226 | 13.2M | } |
227 | | slim_hidden_def(cairo_matrix_init_scale); |
228 | | |
229 | | /** |
230 | | * cairo_matrix_scale: |
231 | | * @matrix: a #cairo_matrix_t |
232 | | * @sx: scale factor in the X direction |
233 | | * @sy: scale factor in the Y direction |
234 | | * |
235 | | * Applies scaling by @sx, @sy to the transformation in @matrix. The |
236 | | * effect of the new transformation is to first scale the coordinates |
237 | | * by @sx and @sy, then apply the original transformation to the coordinates. |
238 | | * |
239 | | * Since: 1.0 |
240 | | **/ |
241 | | void |
242 | | cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy) |
243 | 2.56M | { |
244 | 2.56M | cairo_matrix_t tmp; |
245 | | |
246 | 2.56M | cairo_matrix_init_scale (&tmp, sx, sy); |
247 | | |
248 | 2.56M | cairo_matrix_multiply (matrix, &tmp, matrix); |
249 | 2.56M | } |
250 | | slim_hidden_def(cairo_matrix_scale); |
251 | | |
252 | | /** |
253 | | * cairo_matrix_init_rotate: |
254 | | * @matrix: a #cairo_matrix_t |
255 | | * @radians: angle of rotation, in radians. The direction of rotation |
256 | | * is defined such that positive angles rotate in the direction from |
257 | | * the positive X axis toward the positive Y axis. With the default |
258 | | * axis orientation of cairo, positive angles rotate in a clockwise |
259 | | * direction. |
260 | | * |
261 | | * Initialized @matrix to a transformation that rotates by @radians. |
262 | | * |
263 | | * Since: 1.0 |
264 | | **/ |
265 | | void |
266 | | cairo_matrix_init_rotate (cairo_matrix_t *matrix, |
267 | | double radians) |
268 | 4.22M | { |
269 | 4.22M | double s; |
270 | 4.22M | double c; |
271 | | |
272 | 4.22M | s = sin (radians); |
273 | 4.22M | c = cos (radians); |
274 | | |
275 | 4.22M | cairo_matrix_init (matrix, |
276 | 4.22M | c, s, |
277 | 4.22M | -s, c, |
278 | 4.22M | 0, 0); |
279 | 4.22M | } |
280 | | slim_hidden_def(cairo_matrix_init_rotate); |
281 | | |
282 | | /** |
283 | | * cairo_matrix_rotate: |
284 | | * @matrix: a #cairo_matrix_t |
285 | | * @radians: angle of rotation, in radians. The direction of rotation |
286 | | * is defined such that positive angles rotate in the direction from |
287 | | * the positive X axis toward the positive Y axis. With the default |
288 | | * axis orientation of cairo, positive angles rotate in a clockwise |
289 | | * direction. |
290 | | * |
291 | | * Applies rotation by @radians to the transformation in |
292 | | * @matrix. The effect of the new transformation is to first rotate the |
293 | | * coordinates by @radians, then apply the original transformation |
294 | | * to the coordinates. |
295 | | * |
296 | | * Since: 1.0 |
297 | | **/ |
298 | | void |
299 | | cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) |
300 | 4.22M | { |
301 | 4.22M | cairo_matrix_t tmp; |
302 | | |
303 | 4.22M | cairo_matrix_init_rotate (&tmp, radians); |
304 | | |
305 | 4.22M | cairo_matrix_multiply (matrix, &tmp, matrix); |
306 | 4.22M | } |
307 | | |
308 | | /** |
309 | | * cairo_matrix_multiply: |
310 | | * @result: a #cairo_matrix_t in which to store the result |
311 | | * @a: a #cairo_matrix_t |
312 | | * @b: a #cairo_matrix_t |
313 | | * |
314 | | * Multiplies the affine transformations in @a and @b together |
315 | | * and stores the result in @result. The effect of the resulting |
316 | | * transformation is to first apply the transformation in @a to the |
317 | | * coordinates and then apply the transformation in @b to the |
318 | | * coordinates. |
319 | | * |
320 | | * It is allowable for @result to be identical to either @a or @b. |
321 | | * |
322 | | * Since: 1.0 |
323 | | **/ |
324 | | /* |
325 | | * XXX: The ordering of the arguments to this function corresponds |
326 | | * to [row_vector]*A*B. If we want to use column vectors instead, |
327 | | * then we need to switch the two arguments and fix up all |
328 | | * uses. |
329 | | */ |
330 | | void |
331 | | cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b) |
332 | 12.8M | { |
333 | 12.8M | cairo_matrix_t r; |
334 | | |
335 | 12.8M | r.xx = a->xx * b->xx + a->yx * b->xy; |
336 | 12.8M | r.yx = a->xx * b->yx + a->yx * b->yy; |
337 | | |
338 | 12.8M | r.xy = a->xy * b->xx + a->yy * b->xy; |
339 | 12.8M | r.yy = a->xy * b->yx + a->yy * b->yy; |
340 | | |
341 | 12.8M | r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; |
342 | 12.8M | r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; |
343 | | |
344 | 12.8M | *result = r; |
345 | 12.8M | } |
346 | | slim_hidden_def(cairo_matrix_multiply); |
347 | | |
348 | | void |
349 | | _cairo_matrix_multiply (cairo_matrix_t *r, |
350 | | const cairo_matrix_t *a, |
351 | | const cairo_matrix_t *b) |
352 | 0 | { |
353 | 0 | r->xx = a->xx * b->xx + a->yx * b->xy; |
354 | 0 | r->yx = a->xx * b->yx + a->yx * b->yy; |
355 | |
|
356 | 0 | r->xy = a->xy * b->xx + a->yy * b->xy; |
357 | 0 | r->yy = a->xy * b->yx + a->yy * b->yy; |
358 | |
|
359 | 0 | r->x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; |
360 | 0 | r->y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; |
361 | 0 | } |
362 | | |
363 | | /** |
364 | | * cairo_matrix_transform_distance: |
365 | | * @matrix: a #cairo_matrix_t |
366 | | * @dx: X component of a distance vector. An in/out parameter |
367 | | * @dy: Y component of a distance vector. An in/out parameter |
368 | | * |
369 | | * Transforms the distance vector (@dx,@dy) by @matrix. This is |
370 | | * similar to cairo_matrix_transform_point() except that the translation |
371 | | * components of the transformation are ignored. The calculation of |
372 | | * the returned vector is as follows: |
373 | | * |
374 | | * <programlisting> |
375 | | * dx2 = dx1 * a + dy1 * c; |
376 | | * dy2 = dx1 * b + dy1 * d; |
377 | | * </programlisting> |
378 | | * |
379 | | * Affine transformations are position invariant, so the same vector |
380 | | * always transforms to the same vector. If (@x1,@y1) transforms |
381 | | * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to |
382 | | * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2. |
383 | | * |
384 | | * Since: 1.0 |
385 | | **/ |
386 | | void |
387 | | cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy) |
388 | 47.6M | { |
389 | 47.6M | double new_x, new_y; |
390 | | |
391 | 47.6M | new_x = (matrix->xx * *dx + matrix->xy * *dy); |
392 | 47.6M | new_y = (matrix->yx * *dx + matrix->yy * *dy); |
393 | | |
394 | 47.6M | *dx = new_x; |
395 | 47.6M | *dy = new_y; |
396 | 47.6M | } |
397 | | slim_hidden_def(cairo_matrix_transform_distance); |
398 | | |
399 | | /** |
400 | | * cairo_matrix_transform_point: |
401 | | * @matrix: a #cairo_matrix_t |
402 | | * @x: X position. An in/out parameter |
403 | | * @y: Y position. An in/out parameter |
404 | | * |
405 | | * Transforms the point (@x, @y) by @matrix. |
406 | | * |
407 | | * Since: 1.0 |
408 | | **/ |
409 | | void |
410 | | cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y) |
411 | 12.4M | { |
412 | 12.4M | cairo_matrix_transform_distance (matrix, x, y); |
413 | | |
414 | 12.4M | *x += matrix->x0; |
415 | 12.4M | *y += matrix->y0; |
416 | 12.4M | } |
417 | | slim_hidden_def(cairo_matrix_transform_point); |
418 | | |
419 | | void |
420 | | _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, |
421 | | double *x1, double *y1, |
422 | | double *x2, double *y2, |
423 | | cairo_bool_t *is_tight) |
424 | 2.19M | { |
425 | 2.19M | int i; |
426 | 2.19M | double quad_x[4], quad_y[4]; |
427 | 2.19M | double min_x, max_x; |
428 | 2.19M | double min_y, max_y; |
429 | | |
430 | 2.19M | if (matrix->xy == 0. && matrix->yx == 0.) { |
431 | | /* non-rotation/skew matrix, just map the two extreme points */ |
432 | | |
433 | 2.19M | if (matrix->xx != 1.) { |
434 | 24.6k | quad_x[0] = *x1 * matrix->xx; |
435 | 24.6k | quad_x[1] = *x2 * matrix->xx; |
436 | 24.6k | if (quad_x[0] < quad_x[1]) { |
437 | 19.0k | *x1 = quad_x[0]; |
438 | 19.0k | *x2 = quad_x[1]; |
439 | 19.0k | } else { |
440 | 5.61k | *x1 = quad_x[1]; |
441 | 5.61k | *x2 = quad_x[0]; |
442 | 5.61k | } |
443 | 24.6k | } |
444 | 2.19M | if (matrix->x0 != 0.) { |
445 | 2.13M | *x1 += matrix->x0; |
446 | 2.13M | *x2 += matrix->x0; |
447 | 2.13M | } |
448 | | |
449 | 2.19M | if (matrix->yy != 1.) { |
450 | 23.9k | quad_y[0] = *y1 * matrix->yy; |
451 | 23.9k | quad_y[1] = *y2 * matrix->yy; |
452 | 23.9k | if (quad_y[0] < quad_y[1]) { |
453 | 20.4k | *y1 = quad_y[0]; |
454 | 20.4k | *y2 = quad_y[1]; |
455 | 20.4k | } else { |
456 | 3.46k | *y1 = quad_y[1]; |
457 | 3.46k | *y2 = quad_y[0]; |
458 | 3.46k | } |
459 | 23.9k | } |
460 | 2.19M | if (matrix->y0 != 0.) { |
461 | 2.13M | *y1 += matrix->y0; |
462 | 2.13M | *y2 += matrix->y0; |
463 | 2.13M | } |
464 | | |
465 | 2.19M | if (is_tight) |
466 | 0 | *is_tight = TRUE; |
467 | | |
468 | 2.19M | return; |
469 | 2.19M | } |
470 | | |
471 | | /* general matrix */ |
472 | 0 | quad_x[0] = *x1; |
473 | 0 | quad_y[0] = *y1; |
474 | 0 | cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]); |
475 | |
|
476 | 0 | quad_x[1] = *x2; |
477 | 0 | quad_y[1] = *y1; |
478 | 0 | cairo_matrix_transform_point (matrix, &quad_x[1], &quad_y[1]); |
479 | |
|
480 | 0 | quad_x[2] = *x1; |
481 | 0 | quad_y[2] = *y2; |
482 | 0 | cairo_matrix_transform_point (matrix, &quad_x[2], &quad_y[2]); |
483 | |
|
484 | 0 | quad_x[3] = *x2; |
485 | 0 | quad_y[3] = *y2; |
486 | 0 | cairo_matrix_transform_point (matrix, &quad_x[3], &quad_y[3]); |
487 | |
|
488 | 0 | min_x = max_x = quad_x[0]; |
489 | 0 | min_y = max_y = quad_y[0]; |
490 | |
|
491 | 0 | for (i=1; i < 4; i++) { |
492 | 0 | if (quad_x[i] < min_x) |
493 | 0 | min_x = quad_x[i]; |
494 | 0 | if (quad_x[i] > max_x) |
495 | 0 | max_x = quad_x[i]; |
496 | |
|
497 | 0 | if (quad_y[i] < min_y) |
498 | 0 | min_y = quad_y[i]; |
499 | 0 | if (quad_y[i] > max_y) |
500 | 0 | max_y = quad_y[i]; |
501 | 0 | } |
502 | |
|
503 | 0 | *x1 = min_x; |
504 | 0 | *y1 = min_y; |
505 | 0 | *x2 = max_x; |
506 | 0 | *y2 = max_y; |
507 | |
|
508 | 0 | if (is_tight) { |
509 | | /* it's tight if and only if the four corner points form an axis-aligned |
510 | | rectangle. |
511 | | And that's true if and only if we can derive corners 0 and 3 from |
512 | | corners 1 and 2 in one of two straightforward ways... |
513 | | We could use a tolerance here but for now we'll fall back to FALSE in the case |
514 | | of floating point error. |
515 | | */ |
516 | 0 | *is_tight = |
517 | 0 | (quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] && |
518 | 0 | quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) || |
519 | 0 | (quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] && |
520 | 0 | quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]); |
521 | 0 | } |
522 | 0 | } |
523 | | |
524 | | cairo_private void |
525 | | _cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix, |
526 | | cairo_box_t *bbox, |
527 | | cairo_bool_t *is_tight) |
528 | 0 | { |
529 | 0 | double x1, y1, x2, y2; |
530 | |
|
531 | 0 | _cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2); |
532 | 0 | _cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight); |
533 | 0 | _cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2); |
534 | 0 | } |
535 | | |
536 | | static void |
537 | | _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar) |
538 | 139 | { |
539 | 139 | matrix->xx *= scalar; |
540 | 139 | matrix->yx *= scalar; |
541 | | |
542 | 139 | matrix->xy *= scalar; |
543 | 139 | matrix->yy *= scalar; |
544 | | |
545 | 139 | matrix->x0 *= scalar; |
546 | 139 | matrix->y0 *= scalar; |
547 | 139 | } |
548 | | |
549 | | /* This function isn't a correct adjoint in that the implicit 1 in the |
550 | | homogeneous result should actually be ad-bc instead. But, since this |
551 | | adjoint is only used in the computation of the inverse, which |
552 | | divides by det (A)=ad-bc anyway, everything works out in the end. */ |
553 | | static void |
554 | | _cairo_matrix_compute_adjoint (cairo_matrix_t *matrix) |
555 | 139 | { |
556 | | /* adj (A) = transpose (C:cofactor (A,i,j)) */ |
557 | 139 | double a, b, c, d, tx, ty; |
558 | | |
559 | 139 | _cairo_matrix_get_affine (matrix, |
560 | 139 | &a, &b, |
561 | 139 | &c, &d, |
562 | 139 | &tx, &ty); |
563 | | |
564 | 139 | cairo_matrix_init (matrix, |
565 | 139 | d, -b, |
566 | 139 | -c, a, |
567 | 139 | c*ty - d*tx, b*tx - a*ty); |
568 | 139 | } |
569 | | |
570 | | /** |
571 | | * cairo_matrix_invert: |
572 | | * @matrix: a #cairo_matrix_t |
573 | | * |
574 | | * Changes @matrix to be the inverse of its original value. Not |
575 | | * all transformation matrices have inverses; if the matrix |
576 | | * collapses points together (it is <firstterm>degenerate</firstterm>), |
577 | | * then it has no inverse and this function will fail. |
578 | | * |
579 | | * Returns: If @matrix has an inverse, modifies @matrix to |
580 | | * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise, |
581 | | * returns %CAIRO_STATUS_INVALID_MATRIX. |
582 | | * |
583 | | * Since: 1.0 |
584 | | **/ |
585 | | cairo_status_t |
586 | | cairo_matrix_invert (cairo_matrix_t *matrix) |
587 | 3.23M | { |
588 | 3.23M | double det; |
589 | | |
590 | | /* Simple scaling|translation matrices are quite common... */ |
591 | 3.23M | if (matrix->xy == 0. && matrix->yx == 0.) { |
592 | 3.23M | matrix->x0 = -matrix->x0; |
593 | 3.23M | matrix->y0 = -matrix->y0; |
594 | | |
595 | 3.23M | if (matrix->xx != 1.) { |
596 | 15.4k | if (matrix->xx == 0.) |
597 | 0 | return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); |
598 | | |
599 | 15.4k | matrix->xx = 1. / matrix->xx; |
600 | 15.4k | matrix->x0 *= matrix->xx; |
601 | 15.4k | } |
602 | | |
603 | 3.23M | if (matrix->yy != 1.) { |
604 | 15.0k | if (matrix->yy == 0.) |
605 | 0 | return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); |
606 | | |
607 | 15.0k | matrix->yy = 1. / matrix->yy; |
608 | 15.0k | matrix->y0 *= matrix->yy; |
609 | 15.0k | } |
610 | | |
611 | 3.23M | return CAIRO_STATUS_SUCCESS; |
612 | 3.23M | } |
613 | | |
614 | | /* inv (A) = 1/det (A) * adj (A) */ |
615 | 139 | det = _cairo_matrix_compute_determinant (matrix); |
616 | | |
617 | 139 | if (! ISFINITE (det)) |
618 | 0 | return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); |
619 | | |
620 | 139 | if (det == 0) |
621 | 0 | return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); |
622 | | |
623 | 139 | _cairo_matrix_compute_adjoint (matrix); |
624 | 139 | _cairo_matrix_scalar_multiply (matrix, 1 / det); |
625 | | |
626 | 139 | return CAIRO_STATUS_SUCCESS; |
627 | 139 | } |
628 | | slim_hidden_def(cairo_matrix_invert); |
629 | | |
630 | | cairo_bool_t |
631 | | _cairo_matrix_is_invertible (const cairo_matrix_t *matrix) |
632 | 889k | { |
633 | 889k | double det; |
634 | | |
635 | 889k | det = _cairo_matrix_compute_determinant (matrix); |
636 | | |
637 | 889k | return ISFINITE (det) && det != 0.; |
638 | 889k | } |
639 | | |
640 | | cairo_bool_t |
641 | | _cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix) |
642 | 0 | { |
643 | 0 | return matrix->xx == 0. && |
644 | 0 | matrix->xy == 0. && |
645 | 0 | matrix->yx == 0. && |
646 | 0 | matrix->yy == 0.; |
647 | 0 | } |
648 | | |
649 | | double |
650 | | _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix) |
651 | 8.22M | { |
652 | 8.22M | double a, b, c, d; |
653 | | |
654 | 8.22M | a = matrix->xx; b = matrix->yx; |
655 | 8.22M | c = matrix->xy; d = matrix->yy; |
656 | | |
657 | 8.22M | return a*d - b*c; |
658 | 8.22M | } |
659 | | |
660 | | /** |
661 | | * _cairo_matrix_compute_basis_scale_factors: |
662 | | * @matrix: a matrix |
663 | | * @basis_scale: the scale factor in the direction of basis |
664 | | * @normal_scale: the scale factor in the direction normal to the basis |
665 | | * @x_basis: basis to use. X basis if true, Y basis otherwise. |
666 | | * |
667 | | * Computes |Mv| and det(M)/|Mv| for v=[1,0] if x_basis is true, and v=[0,1] |
668 | | * otherwise, and M is @matrix. |
669 | | * |
670 | | * Return value: the scale factor of @matrix on the height of the font, |
671 | | * or 1.0 if @matrix is %NULL. |
672 | | **/ |
673 | | cairo_status_t |
674 | | _cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix, |
675 | | double *basis_scale, double *normal_scale, |
676 | | cairo_bool_t x_basis) |
677 | 1.09k | { |
678 | 1.09k | double det; |
679 | | |
680 | 1.09k | det = _cairo_matrix_compute_determinant (matrix); |
681 | | |
682 | 1.09k | if (! ISFINITE (det)) |
683 | 0 | return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); |
684 | | |
685 | 1.09k | if (det == 0) |
686 | 0 | { |
687 | 0 | *basis_scale = *normal_scale = 0; |
688 | 0 | } |
689 | 1.09k | else |
690 | 1.09k | { |
691 | 1.09k | double x = x_basis != 0; |
692 | 1.09k | double y = x == 0; |
693 | 1.09k | double major, minor; |
694 | | |
695 | 1.09k | cairo_matrix_transform_distance (matrix, &x, &y); |
696 | 1.09k | major = hypot (x, y); |
697 | | /* |
698 | | * ignore mirroring |
699 | | */ |
700 | 1.09k | if (det < 0) |
701 | 0 | det = -det; |
702 | 1.09k | if (major) |
703 | 1.09k | minor = det / major; |
704 | 0 | else |
705 | 0 | minor = 0.0; |
706 | 1.09k | if (x_basis) |
707 | 1.09k | { |
708 | 1.09k | *basis_scale = major; |
709 | 1.09k | *normal_scale = minor; |
710 | 1.09k | } |
711 | 0 | else |
712 | 0 | { |
713 | 0 | *basis_scale = minor; |
714 | 0 | *normal_scale = major; |
715 | 0 | } |
716 | 1.09k | } |
717 | | |
718 | 1.09k | return CAIRO_STATUS_SUCCESS; |
719 | 1.09k | } |
720 | | |
721 | | cairo_bool_t |
722 | | _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix, |
723 | | int *itx, int *ity) |
724 | 539k | { |
725 | 539k | if (_cairo_matrix_is_translation (matrix)) |
726 | 539k | { |
727 | 539k | cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0); |
728 | 539k | cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0); |
729 | | |
730 | 539k | if (_cairo_fixed_is_integer (x0_fixed) && |
731 | 539k | _cairo_fixed_is_integer (y0_fixed)) |
732 | 539k | { |
733 | 539k | if (itx) |
734 | 539k | *itx = _cairo_fixed_integer_part (x0_fixed); |
735 | 539k | if (ity) |
736 | 539k | *ity = _cairo_fixed_integer_part (y0_fixed); |
737 | | |
738 | 539k | return TRUE; |
739 | 539k | } |
740 | 539k | } |
741 | | |
742 | 93 | return FALSE; |
743 | 539k | } |
744 | | |
745 | 8.84M | #define SCALING_EPSILON _cairo_fixed_to_double(1) |
746 | | |
747 | | /* This only returns true if the matrix is 90 degree rotations or |
748 | | * flips. It appears calling code is relying on this. It will return |
749 | | * false for other rotations even if the scale is one. Approximations |
750 | | * are allowed to handle matricies filled in using trig functions |
751 | | * such as sin(M_PI_2). |
752 | | */ |
753 | | cairo_bool_t |
754 | | _cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix) |
755 | 2.22M | { |
756 | | /* check that the determinant is near +/-1 */ |
757 | 2.22M | double det = _cairo_matrix_compute_determinant (matrix); |
758 | 2.22M | if (fabs (det * det - 1.0) < SCALING_EPSILON) { |
759 | | /* check that one axis is close to zero */ |
760 | 2.20M | if (fabs (matrix->xy) < SCALING_EPSILON && |
761 | 2.20M | fabs (matrix->yx) < SCALING_EPSILON) |
762 | 2.20M | return TRUE; |
763 | 0 | if (fabs (matrix->xx) < SCALING_EPSILON && |
764 | 0 | fabs (matrix->yy) < SCALING_EPSILON) |
765 | 0 | return TRUE; |
766 | | /* If rotations are allowed then it must instead test for |
767 | | * orthogonality. This is xx*xy+yx*yy ~= 0. |
768 | | */ |
769 | 0 | } |
770 | 10.5k | return FALSE; |
771 | 2.22M | } |
772 | | |
773 | | /* By pixel exact here, we mean a matrix that is composed only of |
774 | | * 90 degree rotations, flips, and integer translations and produces a 1:1 |
775 | | * mapping between source and destination pixels. If we transform an image |
776 | | * with a pixel-exact matrix, filtering is not useful. |
777 | | */ |
778 | | cairo_bool_t |
779 | | _cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) |
780 | 543k | { |
781 | 543k | cairo_fixed_t x0_fixed, y0_fixed; |
782 | | |
783 | 543k | if (! _cairo_matrix_has_unity_scale (matrix)) |
784 | 253 | return FALSE; |
785 | | |
786 | 543k | x0_fixed = _cairo_fixed_from_double (matrix->x0); |
787 | 543k | y0_fixed = _cairo_fixed_from_double (matrix->y0); |
788 | | |
789 | 543k | return _cairo_fixed_is_integer (x0_fixed) && _cairo_fixed_is_integer (y0_fixed); |
790 | 543k | } |
791 | | |
792 | | /* |
793 | | A circle in user space is transformed into an ellipse in device space. |
794 | | |
795 | | The following is a derivation of a formula to calculate the length of the |
796 | | major axis for this ellipse; this is useful for error bounds calculations. |
797 | | |
798 | | Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this derivation: |
799 | | |
800 | | 1. First some notation: |
801 | | |
802 | | All capital letters represent vectors in two dimensions. A prime ' |
803 | | represents a transformed coordinate. Matrices are written in underlined |
804 | | form, ie _R_. Lowercase letters represent scalar real values. |
805 | | |
806 | | 2. The question has been posed: What is the maximum expansion factor |
807 | | achieved by the linear transformation |
808 | | |
809 | | X' = X _R_ |
810 | | |
811 | | where _R_ is a real-valued 2x2 matrix with entries: |
812 | | |
813 | | _R_ = [a b] |
814 | | [c d] . |
815 | | |
816 | | In other words, what is the maximum radius, MAX[ |X'| ], reached for any |
817 | | X on the unit circle ( |X| = 1 ) ? |
818 | | |
819 | | 3. Some useful formulae |
820 | | |
821 | | (A) through (C) below are standard double-angle formulae. (D) is a lesser |
822 | | known result and is derived below: |
823 | | |
824 | | (A) sin²(θ) = (1 - cos(2*θ))/2 |
825 | | (B) cos²(θ) = (1 + cos(2*θ))/2 |
826 | | (C) sin(θ)*cos(θ) = sin(2*θ)/2 |
827 | | (D) MAX[a*cos(θ) + b*sin(θ)] = sqrt(a² + b²) |
828 | | |
829 | | Proof of (D): |
830 | | |
831 | | find the maximum of the function by setting the derivative to zero: |
832 | | |
833 | | -a*sin(θ)+b*cos(θ) = 0 |
834 | | |
835 | | From this it follows that |
836 | | |
837 | | tan(θ) = b/a |
838 | | |
839 | | and hence |
840 | | |
841 | | sin(θ) = b/sqrt(a² + b²) |
842 | | |
843 | | and |
844 | | |
845 | | cos(θ) = a/sqrt(a² + b²) |
846 | | |
847 | | Thus the maximum value is |
848 | | |
849 | | MAX[a*cos(θ) + b*sin(θ)] = (a² + b²)/sqrt(a² + b²) |
850 | | = sqrt(a² + b²) |
851 | | |
852 | | 4. Derivation of maximum expansion |
853 | | |
854 | | To find MAX[ |X'| ] we search brute force method using calculus. The unit |
855 | | circle on which X is constrained is to be parameterized by t: |
856 | | |
857 | | X(θ) = (cos(θ), sin(θ)) |
858 | | |
859 | | Thus |
860 | | |
861 | | X'(θ) = X(θ) * _R_ = (cos(θ), sin(θ)) * [a b] |
862 | | [c d] |
863 | | = (a*cos(θ) + c*sin(θ), b*cos(θ) + d*sin(θ)). |
864 | | |
865 | | Define |
866 | | |
867 | | r(θ) = |X'(θ)| |
868 | | |
869 | | Thus |
870 | | |
871 | | r²(θ) = (a*cos(θ) + c*sin(θ))² + (b*cos(θ) + d*sin(θ))² |
872 | | = (a² + b²)*cos²(θ) + (c² + d²)*sin²(θ) |
873 | | + 2*(a*c + b*d)*cos(θ)*sin(θ) |
874 | | |
875 | | Now apply the double angle formulae (A) to (C) from above: |
876 | | |
877 | | r²(θ) = (a² + b² + c² + d²)/2 |
878 | | + (a² + b² - c² - d²)*cos(2*θ)/2 |
879 | | + (a*c + b*d)*sin(2*θ) |
880 | | = f + g*cos(φ) + h*sin(φ) |
881 | | |
882 | | Where |
883 | | |
884 | | f = (a² + b² + c² + d²)/2 |
885 | | g = (a² + b² - c² - d²)/2 |
886 | | h = (a*c + d*d) |
887 | | φ = 2*θ |
888 | | |
889 | | It is clear that MAX[ |X'| ] = sqrt(MAX[ r² ]). Here we determine MAX[ r² ] |
890 | | using (D) from above: |
891 | | |
892 | | MAX[ r² ] = f + sqrt(g² + h²) |
893 | | |
894 | | And finally |
895 | | |
896 | | MAX[ |X'| ] = sqrt( f + sqrt(g² + h²) ) |
897 | | |
898 | | Which is the solution to this problem. |
899 | | |
900 | | Walter Brisken |
901 | | 2004/10/08 |
902 | | |
903 | | (Note that the minor axis length is at the minimum of the above solution, |
904 | | which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)). |
905 | | |
906 | | |
907 | | For another derivation of the same result, using Singular Value Decomposition, |
908 | | see doc/tutorial/src/singular.c. |
909 | | */ |
910 | | |
911 | | /* determine the length of the major axis of a circle of the given radius |
912 | | after applying the transformation matrix. */ |
913 | | double |
914 | | _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, |
915 | | double radius) |
916 | 834k | { |
917 | 834k | double a, b, c, d, f, g, h, i, j; |
918 | | |
919 | 834k | if (_cairo_matrix_has_unity_scale (matrix)) |
920 | 830k | return radius; |
921 | | |
922 | 3.98k | _cairo_matrix_get_affine (matrix, |
923 | 3.98k | &a, &b, |
924 | 3.98k | &c, &d, |
925 | 3.98k | NULL, NULL); |
926 | | |
927 | 3.98k | i = a*a + b*b; |
928 | 3.98k | j = c*c + d*d; |
929 | | |
930 | 3.98k | f = 0.5 * (i + j); |
931 | 3.98k | g = 0.5 * (i - j); |
932 | 3.98k | h = a*c + b*d; |
933 | | |
934 | 3.98k | return radius * sqrt (f + hypot (g, h)); |
935 | | |
936 | | /* |
937 | | * we don't need the minor axis length, which is |
938 | | * double min = radius * sqrt (f - sqrt (g*g+h*h)); |
939 | | */ |
940 | 834k | } |
941 | | |
942 | | static const pixman_transform_t pixman_identity_transform = {{ |
943 | | {1 << 16, 0, 0}, |
944 | | { 0, 1 << 16, 0}, |
945 | | { 0, 0, 1 << 16} |
946 | | }}; |
947 | | |
948 | | static cairo_status_t |
949 | | _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, |
950 | | pixman_transform_t *pixman_transform, |
951 | | double xc, |
952 | | double yc) |
953 | 2.72k | { |
954 | 2.72k | cairo_matrix_t inv; |
955 | 2.72k | unsigned max_iterations; |
956 | | |
957 | 2.72k | pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx); |
958 | 2.72k | pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy); |
959 | 2.72k | pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0); |
960 | | |
961 | 2.72k | pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx); |
962 | 2.72k | pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy); |
963 | 2.72k | pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0); |
964 | | |
965 | 2.72k | pixman_transform->matrix[2][0] = 0; |
966 | 2.72k | pixman_transform->matrix[2][1] = 0; |
967 | 2.72k | pixman_transform->matrix[2][2] = 1 << 16; |
968 | | |
969 | | /* The conversion above breaks cairo's translation invariance: |
970 | | * a translation of (a, b) in device space translates to |
971 | | * a translation of (xx * a + xy * b, yx * a + yy * b) |
972 | | * for cairo, while pixman uses rounded versions of xx ... yy. |
973 | | * This error increases as a and b get larger. |
974 | | * |
975 | | * To compensate for this, we fix the point (xc, yc) in pattern |
976 | | * space and adjust pixman's transform to agree with cairo's at |
977 | | * that point. |
978 | | */ |
979 | | |
980 | 2.72k | if (_cairo_matrix_has_unity_scale (matrix)) |
981 | 223 | return CAIRO_STATUS_SUCCESS; |
982 | | |
983 | 2.50k | if (unlikely (fabs (matrix->xx) > PIXMAN_MAX_INT || |
984 | 2.50k | fabs (matrix->xy) > PIXMAN_MAX_INT || |
985 | 2.50k | fabs (matrix->x0) > PIXMAN_MAX_INT || |
986 | 2.50k | fabs (matrix->yx) > PIXMAN_MAX_INT || |
987 | 2.50k | fabs (matrix->yy) > PIXMAN_MAX_INT || |
988 | 2.50k | fabs (matrix->y0) > PIXMAN_MAX_INT)) |
989 | 29 | { |
990 | 29 | return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); |
991 | 29 | } |
992 | | |
993 | | /* Note: If we can't invert the transformation, skip the adjustment. */ |
994 | 2.47k | inv = *matrix; |
995 | 2.47k | if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS) |
996 | 0 | return CAIRO_STATUS_SUCCESS; |
997 | | |
998 | | /* find the pattern space coordinate that maps to (xc, yc) */ |
999 | 2.47k | max_iterations = 5; |
1000 | 3.35k | do { |
1001 | 3.35k | double x,y; |
1002 | 3.35k | pixman_vector_t vector; |
1003 | 3.35k | cairo_fixed_16_16_t dx, dy; |
1004 | | |
1005 | 3.35k | vector.vector[0] = _cairo_fixed_16_16_from_double (xc); |
1006 | 3.35k | vector.vector[1] = _cairo_fixed_16_16_from_double (yc); |
1007 | 3.35k | vector.vector[2] = 1 << 16; |
1008 | | |
1009 | | /* If we can't transform the reference point, skip the adjustment. */ |
1010 | 3.35k | if (! pixman_transform_point_3d (pixman_transform, &vector)) |
1011 | 0 | return CAIRO_STATUS_SUCCESS; |
1012 | | |
1013 | 3.35k | x = pixman_fixed_to_double (vector.vector[0]); |
1014 | 3.35k | y = pixman_fixed_to_double (vector.vector[1]); |
1015 | 3.35k | cairo_matrix_transform_point (&inv, &x, &y); |
1016 | | |
1017 | | /* Ideally, the vector should now be (xc, yc). |
1018 | | * We can now compensate for the resulting error. |
1019 | | */ |
1020 | 3.35k | x -= xc; |
1021 | 3.35k | y -= yc; |
1022 | 3.35k | cairo_matrix_transform_distance (matrix, &x, &y); |
1023 | 3.35k | dx = _cairo_fixed_16_16_from_double (x); |
1024 | 3.35k | dy = _cairo_fixed_16_16_from_double (y); |
1025 | 3.35k | pixman_transform->matrix[0][2] -= dx; |
1026 | 3.35k | pixman_transform->matrix[1][2] -= dy; |
1027 | | |
1028 | 3.35k | if (dx == 0 && dy == 0) |
1029 | 2.47k | return CAIRO_STATUS_SUCCESS; |
1030 | 3.35k | } while (--max_iterations); |
1031 | | |
1032 | | /* We didn't find an exact match between cairo and pixman, but |
1033 | | * the matrix should be mostly correct */ |
1034 | 0 | return CAIRO_STATUS_SUCCESS; |
1035 | 2.47k | } |
1036 | | |
1037 | | static inline double |
1038 | | _pixman_nearest_sample (double d) |
1039 | 1.01M | { |
1040 | 1.01M | return ceil (d - .5); |
1041 | 1.01M | } |
1042 | | |
1043 | | /** |
1044 | | * _cairo_matrix_is_pixman_translation: |
1045 | | * @matrix: a matrix |
1046 | | * @filter: the filter to be used on the pattern transformed by @matrix |
1047 | | * @x_offset: the translation in the X direction |
1048 | | * @y_offset: the translation in the Y direction |
1049 | | * |
1050 | | * Checks if @matrix translated by (x_offset, y_offset) can be |
1051 | | * represented using just an offset (within the range pixman can |
1052 | | * accept) and an identity matrix. |
1053 | | * |
1054 | | * Passing a non-zero value in x_offset/y_offset has the same effect |
1055 | | * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and |
1056 | | * setting x_offset and y_offset to 0. |
1057 | | * |
1058 | | * Upon return x_offset and y_offset contain the translation vector if |
1059 | | * the return value is %TRUE. If the return value is %FALSE, they will |
1060 | | * not be modified. |
1061 | | * |
1062 | | * Return value: %TRUE if @matrix can be represented as a pixman |
1063 | | * translation, %FALSE otherwise. |
1064 | | **/ |
1065 | | cairo_bool_t |
1066 | | _cairo_matrix_is_pixman_translation (const cairo_matrix_t *matrix, |
1067 | | cairo_filter_t filter, |
1068 | | int *x_offset, |
1069 | | int *y_offset) |
1070 | 547k | { |
1071 | 547k | double tx, ty; |
1072 | | |
1073 | 547k | if (!_cairo_matrix_is_translation (matrix)) |
1074 | 2.75k | return FALSE; |
1075 | | |
1076 | 544k | if (matrix->x0 == 0. && matrix->y0 == 0.) |
1077 | 36.8k | return TRUE; |
1078 | | |
1079 | 507k | tx = matrix->x0 + *x_offset; |
1080 | 507k | ty = matrix->y0 + *y_offset; |
1081 | | |
1082 | 507k | if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) { |
1083 | 507k | tx = _pixman_nearest_sample (tx); |
1084 | 507k | ty = _pixman_nearest_sample (ty); |
1085 | 507k | } else if (tx != floor (tx) || ty != floor (ty)) { |
1086 | 0 | return FALSE; |
1087 | 0 | } |
1088 | | |
1089 | 507k | if (fabs (tx) > PIXMAN_MAX_INT || fabs (ty) > PIXMAN_MAX_INT) |
1090 | 1.03k | return FALSE; |
1091 | | |
1092 | 506k | *x_offset = _cairo_lround (tx); |
1093 | 506k | *y_offset = _cairo_lround (ty); |
1094 | 506k | return TRUE; |
1095 | 507k | } |
1096 | | |
1097 | | /** |
1098 | | * _cairo_matrix_to_pixman_matrix_offset: |
1099 | | * @matrix: a matrix |
1100 | | * @filter: the filter to be used on the pattern transformed by @matrix |
1101 | | * @xc: the X coordinate of the point to fix in pattern space |
1102 | | * @yc: the Y coordinate of the point to fix in pattern space |
1103 | | * @out_transform: the transformation which best approximates @matrix |
1104 | | * @x_offset: the translation in the X direction |
1105 | | * @y_offset: the translation in the Y direction |
1106 | | * |
1107 | | * This function tries to represent @matrix translated by (x_offset, |
1108 | | * y_offset) as a %pixman_transform_t and an translation. |
1109 | | * |
1110 | | * Passing a non-zero value in x_offset/y_offset has the same effect |
1111 | | * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and |
1112 | | * setting x_offset and y_offset to 0. |
1113 | | * |
1114 | | * If it is possible to represent the matrix with an identity |
1115 | | * %pixman_transform_t and a translation within the valid range for |
1116 | | * pixman, this function will set @out_transform to be the identity, |
1117 | | * @x_offset and @y_offset to be the translation vector and will |
1118 | | * return %CAIRO_INT_STATUS_NOTHING_TO_DO. Otherwise it will try to |
1119 | | * evenly divide the translational component of @matrix between |
1120 | | * @out_transform and (@x_offset, @y_offset). |
1121 | | * |
1122 | | * Upon return x_offset and y_offset contain the translation vector. |
1123 | | * |
1124 | | * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the out_transform |
1125 | | * is the identity, %CAIRO_STATUS_INVALID_MATRIX if it was not |
1126 | | * possible to represent @matrix as a pixman_transform_t without |
1127 | | * overflows, %CAIRO_STATUS_SUCCESS otherwise. |
1128 | | **/ |
1129 | | cairo_status_t |
1130 | | _cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t *matrix, |
1131 | | cairo_filter_t filter, |
1132 | | double xc, |
1133 | | double yc, |
1134 | | pixman_transform_t *out_transform, |
1135 | | int *x_offset, |
1136 | | int *y_offset) |
1137 | 3.53k | { |
1138 | 3.53k | cairo_bool_t is_pixman_translation; |
1139 | | |
1140 | 3.53k | is_pixman_translation = _cairo_matrix_is_pixman_translation (matrix, |
1141 | 3.53k | filter, |
1142 | 3.53k | x_offset, |
1143 | 3.53k | y_offset); |
1144 | | |
1145 | 3.53k | if (is_pixman_translation) { |
1146 | 808 | *out_transform = pixman_identity_transform; |
1147 | 808 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
1148 | 2.72k | } else { |
1149 | 2.72k | cairo_matrix_t m; |
1150 | | |
1151 | 2.72k | m = *matrix; |
1152 | 2.72k | cairo_matrix_translate (&m, *x_offset, *y_offset); |
1153 | 2.72k | if (m.x0 != 0.0 || m.y0 != 0.0) { |
1154 | 350 | double tx, ty, norm; |
1155 | 350 | int i, j; |
1156 | | |
1157 | | /* pixman also limits the [xy]_offset to 16 bits so evenly |
1158 | | * spread the bits between the two. |
1159 | | * |
1160 | | * To do this, find the solutions of: |
1161 | | * |x| = |x*m.xx + y*m.xy + m.x0| |
1162 | | * |y| = |x*m.yx + y*m.yy + m.y0| |
1163 | | * |
1164 | | * and select the one whose maximum norm is smallest. |
1165 | | */ |
1166 | 350 | tx = m.x0; |
1167 | 350 | ty = m.y0; |
1168 | 350 | norm = MAX (fabs (tx), fabs (ty)); |
1169 | | |
1170 | 1.05k | for (i = -1; i < 2; i+=2) { |
1171 | 2.10k | for (j = -1; j < 2; j+=2) { |
1172 | 1.40k | double x, y, den, new_norm; |
1173 | | |
1174 | 1.40k | den = (m.xx + i) * (m.yy + j) - m.xy * m.yx; |
1175 | 1.40k | if (fabs (den) < DBL_EPSILON) |
1176 | 689 | continue; |
1177 | | |
1178 | 711 | x = m.y0 * m.xy - m.x0 * (m.yy + j); |
1179 | 711 | y = m.x0 * m.yx - m.y0 * (m.xx + i); |
1180 | | |
1181 | 711 | den = 1 / den; |
1182 | 711 | x *= den; |
1183 | 711 | y *= den; |
1184 | | |
1185 | 711 | new_norm = MAX (fabs (x), fabs (y)); |
1186 | 711 | if (norm > new_norm) { |
1187 | 350 | norm = new_norm; |
1188 | 350 | tx = x; |
1189 | 350 | ty = y; |
1190 | 350 | } |
1191 | 711 | } |
1192 | 700 | } |
1193 | | |
1194 | 350 | tx = floor (tx); |
1195 | 350 | ty = floor (ty); |
1196 | 350 | *x_offset = -tx; |
1197 | 350 | *y_offset = -ty; |
1198 | 350 | cairo_matrix_translate (&m, tx, ty); |
1199 | 2.37k | } else { |
1200 | 2.37k | *x_offset = 0; |
1201 | 2.37k | *y_offset = 0; |
1202 | 2.37k | } |
1203 | | |
1204 | 2.72k | return _cairo_matrix_to_pixman_matrix (&m, out_transform, xc, yc); |
1205 | 2.72k | } |
1206 | 3.53k | } |