Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1892 | Rev 3959 | ||
---|---|---|---|
Line 34... | Line 34... | ||
34 | * Carl D. Worth |
34 | * Carl D. Worth |
35 | */ |
35 | */ |
Line 36... | Line 36... | ||
36 | 36 | ||
37 | #include "cairoint.h" |
37 | #include "cairoint.h" |
- | 38 | #include "cairo-error-private.h" |
|
- | 39 | #include |
|
- | 40 | ||
Line 38... | Line 41... | ||
38 | #include "cairo-error-private.h" |
41 | #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ |
39 | 42 | ||
40 | #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) |
43 | #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) |
41 | #define ISFINITE(x) isfinite (x) |
44 | #define ISFINITE(x) isfinite (x) |
Line 62... | Line 65... | ||
62 | * |
65 | * |
63 | * The current transformation matrix of a #cairo_t, represented as a |
66 | * The current transformation matrix of a #cairo_t, represented as a |
64 | * #cairo_matrix_t, defines the transformation from user-space |
67 | * #cairo_matrix_t, defines the transformation from user-space |
65 | * coordinates to device-space coordinates. See cairo_get_matrix() and |
68 | * coordinates to device-space coordinates. See cairo_get_matrix() and |
66 | * cairo_set_matrix(). |
69 | * cairo_set_matrix(). |
67 | */ |
70 | **/ |
Line 68... | Line 71... | ||
68 | 71 | ||
69 | static void |
72 | static void |
Line 70... | Line 73... | ||
70 | _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar); |
73 | _cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar); |
Line 75... | Line 78... | ||
75 | /** |
78 | /** |
76 | * cairo_matrix_init_identity: |
79 | * cairo_matrix_init_identity: |
77 | * @matrix: a #cairo_matrix_t |
80 | * @matrix: a #cairo_matrix_t |
78 | * |
81 | * |
79 | * Modifies @matrix to be an identity transformation. |
82 | * Modifies @matrix to be an identity transformation. |
- | 83 | * |
|
- | 84 | * Since: 1.0 |
|
80 | **/ |
85 | **/ |
81 | void |
86 | void |
82 | cairo_matrix_init_identity (cairo_matrix_t *matrix) |
87 | cairo_matrix_init_identity (cairo_matrix_t *matrix) |
83 | { |
88 | { |
84 | cairo_matrix_init (matrix, |
89 | cairo_matrix_init (matrix, |
Line 103... | Line 108... | ||
103 | * by: |
108 | * by: |
104 | * |
109 | * |
105 | * x_new = xx * x + xy * y + x0; |
110 | * x_new = xx * x + xy * y + x0; |
106 | * y_new = yx * x + yy * y + y0; |
111 | * y_new = yx * x + yy * y + y0; |
107 | * |
112 | * |
- | 113 | * |
|
- | 114 | * Since: 1.0 |
|
108 | **/ |
115 | **/ |
109 | void |
116 | void |
110 | cairo_matrix_init (cairo_matrix_t *matrix, |
117 | cairo_matrix_init (cairo_matrix_t *matrix, |
111 | double xx, double yx, |
118 | double xx, double yx, |
Line 163... | Line 170... | ||
163 | * @tx: amount to translate in the X direction |
170 | * @tx: amount to translate in the X direction |
164 | * @ty: amount to translate in the Y direction |
171 | * @ty: amount to translate in the Y direction |
165 | * |
172 | * |
166 | * Initializes @matrix to a transformation that translates by @tx and |
173 | * Initializes @matrix to a transformation that translates by @tx and |
167 | * @ty in the X and Y dimensions, respectively. |
174 | * @ty in the X and Y dimensions, respectively. |
- | 175 | * |
|
- | 176 | * Since: 1.0 |
|
168 | **/ |
177 | **/ |
169 | void |
178 | void |
170 | cairo_matrix_init_translate (cairo_matrix_t *matrix, |
179 | cairo_matrix_init_translate (cairo_matrix_t *matrix, |
171 | double tx, double ty) |
180 | double tx, double ty) |
172 | { |
181 | { |
Line 185... | Line 194... | ||
185 | * |
194 | * |
186 | * Applies a translation by @tx, @ty to the transformation in |
195 | * Applies a translation by @tx, @ty to the transformation in |
187 | * @matrix. The effect of the new transformation is to first translate |
196 | * @matrix. The effect of the new transformation is to first translate |
188 | * the coordinates by @tx and @ty, then apply the original transformation |
197 | * the coordinates by @tx and @ty, then apply the original transformation |
189 | * to the coordinates. |
198 | * to the coordinates. |
- | 199 | * |
|
- | 200 | * Since: 1.0 |
|
190 | **/ |
201 | **/ |
191 | void |
202 | void |
192 | cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty) |
203 | cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty) |
193 | { |
204 | { |
194 | cairo_matrix_t tmp; |
205 | cairo_matrix_t tmp; |
Line 205... | Line 216... | ||
205 | * @sx: scale factor in the X direction |
216 | * @sx: scale factor in the X direction |
206 | * @sy: scale factor in the Y direction |
217 | * @sy: scale factor in the Y direction |
207 | * |
218 | * |
208 | * Initializes @matrix to a transformation that scales by @sx and @sy |
219 | * Initializes @matrix to a transformation that scales by @sx and @sy |
209 | * in the X and Y dimensions, respectively. |
220 | * in the X and Y dimensions, respectively. |
- | 221 | * |
|
- | 222 | * Since: 1.0 |
|
210 | **/ |
223 | **/ |
211 | void |
224 | void |
212 | cairo_matrix_init_scale (cairo_matrix_t *matrix, |
225 | cairo_matrix_init_scale (cairo_matrix_t *matrix, |
213 | double sx, double sy) |
226 | double sx, double sy) |
214 | { |
227 | { |
Line 226... | Line 239... | ||
226 | * @sy: scale factor in the Y direction |
239 | * @sy: scale factor in the Y direction |
227 | * |
240 | * |
228 | * Applies scaling by @sx, @sy to the transformation in @matrix. The |
241 | * Applies scaling by @sx, @sy to the transformation in @matrix. The |
229 | * effect of the new transformation is to first scale the coordinates |
242 | * effect of the new transformation is to first scale the coordinates |
230 | * by @sx and @sy, then apply the original transformation to the coordinates. |
243 | * by @sx and @sy, then apply the original transformation to the coordinates. |
- | 244 | * |
|
- | 245 | * Since: 1.0 |
|
231 | **/ |
246 | **/ |
232 | void |
247 | void |
233 | cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy) |
248 | cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy) |
234 | { |
249 | { |
235 | cairo_matrix_t tmp; |
250 | cairo_matrix_t tmp; |
Line 248... | Line 263... | ||
248 | * the positive X axis toward the positive Y axis. With the default |
263 | * the positive X axis toward the positive Y axis. With the default |
249 | * axis orientation of cairo, positive angles rotate in a clockwise |
264 | * axis orientation of cairo, positive angles rotate in a clockwise |
250 | * direction. |
265 | * direction. |
251 | * |
266 | * |
252 | * Initialized @matrix to a transformation that rotates by @radians. |
267 | * Initialized @matrix to a transformation that rotates by @radians. |
- | 268 | * |
|
- | 269 | * Since: 1.0 |
|
253 | **/ |
270 | **/ |
254 | void |
271 | void |
255 | cairo_matrix_init_rotate (cairo_matrix_t *matrix, |
272 | cairo_matrix_init_rotate (cairo_matrix_t *matrix, |
256 | double radians) |
273 | double radians) |
257 | { |
274 | { |
Line 279... | Line 296... | ||
279 | * |
296 | * |
280 | * Applies rotation by @radians to the transformation in |
297 | * Applies rotation by @radians to the transformation in |
281 | * @matrix. The effect of the new transformation is to first rotate the |
298 | * @matrix. The effect of the new transformation is to first rotate the |
282 | * coordinates by @radians, then apply the original transformation |
299 | * coordinates by @radians, then apply the original transformation |
283 | * to the coordinates. |
300 | * to the coordinates. |
- | 301 | * |
|
- | 302 | * Since: 1.0 |
|
284 | **/ |
303 | **/ |
285 | void |
304 | void |
286 | cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) |
305 | cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) |
287 | { |
306 | { |
288 | cairo_matrix_t tmp; |
307 | cairo_matrix_t tmp; |
Line 303... | Line 322... | ||
303 | * transformation is to first apply the transformation in @a to the |
322 | * transformation is to first apply the transformation in @a to the |
304 | * coordinates and then apply the transformation in @b to the |
323 | * coordinates and then apply the transformation in @b to the |
305 | * coordinates. |
324 | * coordinates. |
306 | * |
325 | * |
307 | * It is allowable for @result to be identical to either @a or @b. |
326 | * It is allowable for @result to be identical to either @a or @b. |
- | 327 | * |
|
- | 328 | * Since: 1.0 |
|
308 | **/ |
329 | **/ |
309 | /* |
330 | /* |
310 | * XXX: The ordering of the arguments to this function corresponds |
331 | * XXX: The ordering of the arguments to this function corresponds |
311 | * to [row_vector]*A*B. If we want to use column vectors instead, |
332 | * to [row_vector]*A*B. If we want to use column vectors instead, |
312 | * then we need to switch the two arguments and fix up all |
333 | * then we need to switch the two arguments and fix up all |
Line 328... | Line 349... | ||
328 | 349 | ||
329 | *result = r; |
350 | *result = r; |
330 | } |
351 | } |
Line -... | Line 352... | ||
- | 352 | slim_hidden_def(cairo_matrix_multiply); |
|
- | 353 | ||
- | 354 | void |
|
- | 355 | _cairo_matrix_multiply (cairo_matrix_t *r, |
|
- | 356 | const cairo_matrix_t *a, |
|
- | 357 | const cairo_matrix_t *b) |
|
- | 358 | { |
|
- | 359 | r->xx = a->xx * b->xx + a->yx * b->xy; |
|
- | 360 | r->yx = a->xx * b->yx + a->yx * b->yy; |
|
- | 361 | ||
- | 362 | r->xy = a->xy * b->xx + a->yy * b->xy; |
|
- | 363 | r->yy = a->xy * b->yx + a->yy * b->yy; |
|
- | 364 | ||
- | 365 | r->x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; |
|
- | 366 | r->y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; |
|
331 | slim_hidden_def(cairo_matrix_multiply); |
367 | } |
332 | 368 | ||
333 | /** |
369 | /** |
334 | * cairo_matrix_transform_distance: |
370 | * cairo_matrix_transform_distance: |
335 | * @matrix: a #cairo_matrix_t |
371 | * @matrix: a #cairo_matrix_t |
Line 348... | Line 384... | ||
348 | * |
384 | * |
349 | * Affine transformations are position invariant, so the same vector |
385 | * Affine transformations are position invariant, so the same vector |
350 | * always transforms to the same vector. If (@x1,@y1) transforms |
386 | * always transforms to the same vector. If (@x1,@y1) transforms |
351 | * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to |
387 | * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to |
352 | * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2. |
388 | * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2. |
- | 389 | * |
|
- | 390 | * Since: 1.0 |
|
353 | **/ |
391 | **/ |
354 | void |
392 | void |
355 | cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy) |
393 | cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy) |
356 | { |
394 | { |
357 | double new_x, new_y; |
395 | double new_x, new_y; |
Line 369... | Line 407... | ||
369 | * @matrix: a #cairo_matrix_t |
407 | * @matrix: a #cairo_matrix_t |
370 | * @x: X position. An in/out parameter |
408 | * @x: X position. An in/out parameter |
371 | * @y: Y position. An in/out parameter |
409 | * @y: Y position. An in/out parameter |
372 | * |
410 | * |
373 | * Transforms the point (@x, @y) by @matrix. |
411 | * Transforms the point (@x, @y) by @matrix. |
- | 412 | * |
|
- | 413 | * Since: 1.0 |
|
374 | **/ |
414 | **/ |
375 | void |
415 | void |
376 | cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y) |
416 | cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y) |
377 | { |
417 | { |
378 | cairo_matrix_transform_distance (matrix, x, y); |
418 | cairo_matrix_transform_distance (matrix, x, y); |
Line 543... | Line 583... | ||
543 | * then it has no inverse and this function will fail. |
583 | * then it has no inverse and this function will fail. |
544 | * |
584 | * |
545 | * Returns: If @matrix has an inverse, modifies @matrix to |
585 | * Returns: If @matrix has an inverse, modifies @matrix to |
546 | * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise, |
586 | * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise, |
547 | * returns %CAIRO_STATUS_INVALID_MATRIX. |
587 | * returns %CAIRO_STATUS_INVALID_MATRIX. |
- | 588 | * |
|
- | 589 | * Since: 1.0 |
|
548 | **/ |
590 | **/ |
549 | cairo_status_t |
591 | cairo_status_t |
550 | cairo_matrix_invert (cairo_matrix_t *matrix) |
592 | cairo_matrix_invert (cairo_matrix_t *matrix) |
551 | { |
593 | { |
552 | double det; |
594 | double det; |
Line 681... | Line 723... | ||
681 | 723 | ||
682 | return CAIRO_STATUS_SUCCESS; |
724 | return CAIRO_STATUS_SUCCESS; |
Line 683... | Line 725... | ||
683 | } |
725 | } |
684 | - | ||
685 | cairo_bool_t |
- | |
686 | _cairo_matrix_is_identity (const cairo_matrix_t *matrix) |
- | |
687 | { |
- | |
688 | return (matrix->xx == 1.0 && matrix->yx == 0.0 && |
- | |
689 | matrix->xy == 0.0 && matrix->yy == 1.0 && |
- | |
690 | matrix->x0 == 0.0 && matrix->y0 == 0.0); |
- | |
691 | } |
- | |
692 | - | ||
693 | cairo_bool_t |
- | |
694 | _cairo_matrix_is_translation (const cairo_matrix_t *matrix) |
- | |
695 | { |
- | |
696 | return (matrix->xx == 1.0 && matrix->yx == 0.0 && |
- | |
697 | matrix->xy == 0.0 && matrix->yy == 1.0); |
- | |
698 | } |
- | |
699 | 726 | ||
700 | cairo_bool_t |
727 | cairo_bool_t |
701 | _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix, |
728 | _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix, |
702 | int *itx, int *ity) |
729 | int *itx, int *ity) |
703 | { |
730 | { |
Line 884... | Line 911... | ||
884 | _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, |
911 | _cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, |
885 | double radius) |
912 | double radius) |
886 | { |
913 | { |
887 | double a, b, c, d, f, g, h, i, j; |
914 | double a, b, c, d, f, g, h, i, j; |
Line -... | Line 915... | ||
- | 915 | ||
- | 916 | if (_cairo_matrix_has_unity_scale (matrix)) |
|
- | 917 | return radius; |
|
888 | 918 | ||
889 | _cairo_matrix_get_affine (matrix, |
919 | _cairo_matrix_get_affine (matrix, |
890 | &a, &b, |
920 | &a, &b, |
891 | &c, &d, |
921 | &c, &d, |
Line 904... | Line 934... | ||
904 | * we don't need the minor axis length, which is |
934 | * we don't need the minor axis length, which is |
905 | * double min = radius * sqrt (f - sqrt (g*g+h*h)); |
935 | * double min = radius * sqrt (f - sqrt (g*g+h*h)); |
906 | */ |
936 | */ |
907 | } |
937 | } |
Line 908... | Line -... | ||
908 | - | ||
909 | void |
- | |
910 | _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, |
- | |
911 | pixman_transform_t *pixman_transform, |
- | |
912 | double xc, |
- | |
913 | double yc) |
- | |
914 | { |
938 | |
915 | static const pixman_transform_t pixman_identity_transform = {{ |
939 | static const pixman_transform_t pixman_identity_transform = {{ |
916 | {1 << 16, 0, 0}, |
940 | {1 << 16, 0, 0}, |
917 | { 0, 1 << 16, 0}, |
941 | { 0, 1 << 16, 0}, |
918 | { 0, 0, 1 << 16} |
942 | { 0, 0, 1 << 16} |
Line -... | Line 943... | ||
- | 943 | }}; |
|
919 | }}; |
944 | |
920 | 945 | static cairo_status_t |
|
- | 946 | _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, |
|
921 | if (_cairo_matrix_is_identity (matrix)) { |
947 | pixman_transform_t *pixman_transform, |
- | 948 | double xc, |
|
922 | *pixman_transform = pixman_identity_transform; |
949 | double yc) |
923 | } else { |
950 | { |
Line 924... | Line 951... | ||
924 | cairo_matrix_t inv; |
951 | cairo_matrix_t inv; |
925 | unsigned max_iterations; |
952 | unsigned max_iterations; |
Line 946... | Line 973... | ||
946 | * space and adjust pixman's transform to agree with cairo's at |
973 | * space and adjust pixman's transform to agree with cairo's at |
947 | * that point. |
974 | * that point. |
948 | */ |
975 | */ |
Line 949... | Line 976... | ||
949 | 976 | ||
- | 977 | if (_cairo_matrix_has_unity_scale (matrix)) |
|
- | 978 | return CAIRO_STATUS_SUCCESS; |
|
- | 979 | ||
- | 980 | if (unlikely (fabs (matrix->xx) > PIXMAN_MAX_INT || |
|
- | 981 | fabs (matrix->xy) > PIXMAN_MAX_INT || |
|
- | 982 | fabs (matrix->x0) > PIXMAN_MAX_INT || |
|
- | 983 | fabs (matrix->yx) > PIXMAN_MAX_INT || |
|
- | 984 | fabs (matrix->yy) > PIXMAN_MAX_INT || |
|
950 | if (_cairo_matrix_has_unity_scale (matrix)) |
985 | fabs (matrix->y0) > PIXMAN_MAX_INT)) |
- | 986 | { |
|
- | 987 | return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); |
|
Line 951... | Line 988... | ||
951 | return; |
988 | } |
952 | 989 | ||
953 | /* Note: If we can't invert the transformation, skip the adjustment. */ |
990 | /* Note: If we can't invert the transformation, skip the adjustment. */ |
954 | inv = *matrix; |
991 | inv = *matrix; |
Line 955... | Line 992... | ||
955 | if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS) |
992 | if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS) |
956 | return; |
- | |
957 | 993 | return CAIRO_STATUS_SUCCESS; |
|
958 | /* find the pattern space coordinate that maps to (xc, yc) */ |
994 | |
959 | xc += .5; yc += .5; /* offset for the pixel centre */ |
995 | /* find the pattern space coordinate that maps to (xc, yc) */ |
960 | max_iterations = 5; |
996 | max_iterations = 5; |
961 | do { |
997 | do { |
Line 962... | Line 998... | ||
962 | double x,y; |
998 | double x,y; |
963 | pixman_vector_t vector; |
999 | pixman_vector_t vector; |
964 | cairo_fixed_16_16_t dx, dy; |
1000 | cairo_fixed_16_16_t dx, dy; |
Line -... | Line 1001... | ||
- | 1001 | ||
965 | 1002 | vector.vector[0] = _cairo_fixed_16_16_from_double (xc); |
|
966 | vector.vector[0] = _cairo_fixed_16_16_from_double (xc); |
1003 | vector.vector[1] = _cairo_fixed_16_16_from_double (yc); |
Line 967... | Line 1004... | ||
967 | vector.vector[1] = _cairo_fixed_16_16_from_double (yc); |
1004 | vector.vector[2] = 1 << 16; |
968 | vector.vector[2] = 1 << 16; |
1005 | |
969 | 1006 | /* If we can't transform the reference point, skip the adjustment. */ |
|
Line 984... | Line 1021... | ||
984 | dy = _cairo_fixed_16_16_from_double (y); |
1021 | dy = _cairo_fixed_16_16_from_double (y); |
985 | pixman_transform->matrix[0][2] -= dx; |
1022 | pixman_transform->matrix[0][2] -= dx; |
986 | pixman_transform->matrix[1][2] -= dy; |
1023 | pixman_transform->matrix[1][2] -= dy; |
Line 987... | Line 1024... | ||
987 | 1024 | ||
988 | if (dx == 0 && dy == 0) |
1025 | if (dx == 0 && dy == 0) |
989 | break; |
1026 | return CAIRO_STATUS_SUCCESS; |
- | 1027 | } while (--max_iterations); |
|
- | 1028 | ||
- | 1029 | /* We didn't find an exact match between cairo and pixman, but |
|
- | 1030 | * the matrix should be mostly correct */ |
|
- | 1031 | return CAIRO_STATUS_SUCCESS; |
|
- | 1032 | } |
|
- | 1033 | ||
- | 1034 | static inline double |
|
- | 1035 | _pixman_nearest_sample (double d) |
|
- | 1036 | { |
|
- | 1037 | return ceil (d - .5); |
|
- | 1038 | } |
|
- | 1039 | ||
- | 1040 | /** |
|
- | 1041 | * _cairo_matrix_is_pixman_translation: |
|
- | 1042 | * @matrix: a matrix |
|
- | 1043 | * @filter: the filter to be used on the pattern transformed by @matrix |
|
- | 1044 | * @x_offset: the translation in the X direction |
|
- | 1045 | * @y_offset: the translation in the Y direction |
|
- | 1046 | * |
|
- | 1047 | * Checks if @matrix translated by (x_offset, y_offset) can be |
|
- | 1048 | * represented using just an offset (within the range pixman can |
|
- | 1049 | * accept) and an identity matrix. |
|
- | 1050 | * |
|
- | 1051 | * Passing a non-zero value in x_offset/y_offset has the same effect |
|
- | 1052 | * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and |
|
- | 1053 | * setting x_offset and y_offset to 0. |
|
- | 1054 | * |
|
- | 1055 | * Upon return x_offset and y_offset contain the translation vector if |
|
- | 1056 | * the return value is %TRUE. If the return value is %FALSE, they will |
|
- | 1057 | * not be modified. |
|
- | 1058 | * |
|
- | 1059 | * Return value: %TRUE if @matrix can be represented as a pixman |
|
- | 1060 | * translation, %FALSE otherwise. |
|
- | 1061 | **/ |
|
- | 1062 | cairo_bool_t |
|
- | 1063 | _cairo_matrix_is_pixman_translation (const cairo_matrix_t *matrix, |
|
- | 1064 | cairo_filter_t filter, |
|
- | 1065 | int *x_offset, |
|
- | 1066 | int *y_offset) |
|
- | 1067 | { |
|
- | 1068 | double tx, ty; |
|
- | 1069 | ||
- | 1070 | if (!_cairo_matrix_is_translation (matrix)) |
|
- | 1071 | return FALSE; |
|
- | 1072 | ||
- | 1073 | if (matrix->x0 == 0. && matrix->y0 == 0.) |
|
- | 1074 | return TRUE; |
|
- | 1075 | ||
- | 1076 | tx = matrix->x0 + *x_offset; |
|
- | 1077 | ty = matrix->y0 + *y_offset; |
|
- | 1078 | ||
- | 1079 | if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) { |
|
- | 1080 | tx = _pixman_nearest_sample (tx); |
|
- | 1081 | ty = _pixman_nearest_sample (ty); |
|
- | 1082 | } else if (tx != floor (tx) || ty != floor (ty)) { |
|
- | 1083 | return FALSE; |
|
- | 1084 | } |
|
- | 1085 | ||
- | 1086 | if (fabs (tx) > PIXMAN_MAX_INT || fabs (ty) > PIXMAN_MAX_INT) |
|
- | 1087 | return FALSE; |
|
- | 1088 | ||
- | 1089 | *x_offset = _cairo_lround (tx); |
|
- | 1090 | *y_offset = _cairo_lround (ty); |
|
- | 1091 | return TRUE; |
|
- | 1092 | } |
|
- | 1093 | ||
- | 1094 | /** |
|
- | 1095 | * _cairo_matrix_to_pixman_matrix_offset: |
|
- | 1096 | * @matrix: a matrix |
|
- | 1097 | * @filter: the filter to be used on the pattern transformed by @matrix |
|
- | 1098 | * @xc: the X coordinate of the point to fix in pattern space |
|
- | 1099 | * @yc: the Y coordinate of the point to fix in pattern space |
|
- | 1100 | * @out_transform: the transformation which best approximates @matrix |
|
- | 1101 | * @x_offset: the translation in the X direction |
|
- | 1102 | * @y_offset: the translation in the Y direction |
|
- | 1103 | * |
|
- | 1104 | * This function tries to represent @matrix translated by (x_offset, |
|
- | 1105 | * y_offset) as a %pixman_transform_t and an translation. |
|
- | 1106 | * |
|
- | 1107 | * Passing a non-zero value in x_offset/y_offset has the same effect |
|
- | 1108 | * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and |
|
- | 1109 | * setting x_offset and y_offset to 0. |
|
- | 1110 | * |
|
- | 1111 | * If it is possible to represent the matrix with an identity |
|
- | 1112 | * %pixman_transform_t and a translation within the valid range for |
|
- | 1113 | * pixman, this function will set @out_transform to be the identity, |
|
- | 1114 | * @x_offset and @y_offset to be the translation vector and will |
|
- | 1115 | * return %CAIRO_INT_STATUS_NOTHING_TO_DO. Otherwise it will try to |
|
- | 1116 | * evenly divide the translational component of @matrix between |
|
- | 1117 | * @out_transform and (@x_offset, @y_offset). |
|
- | 1118 | * |
|
- | 1119 | * Upon return x_offset and y_offset contain the translation vector. |
|
- | 1120 | * |
|
- | 1121 | * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the out_transform |
|
- | 1122 | * is the identity, %CAIRO_STATUS_INVALID_MATRIX if it was not |
|
- | 1123 | * possible to represent @matrix as a pixman_transform_t without |
|
- | 1124 | * overflows, %CAIRO_STATUS_SUCCESS otherwise. |
|
- | 1125 | **/ |
|
- | 1126 | cairo_status_t |
|
- | 1127 | _cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t *matrix, |
|
- | 1128 | cairo_filter_t filter, |
|
- | 1129 | double xc, |
|
- | 1130 | double yc, |
|
- | 1131 | pixman_transform_t *out_transform, |
|
- | 1132 | int *x_offset, |
|
- | 1133 | int *y_offset) |
|
- | 1134 | { |
|
- | 1135 | cairo_bool_t is_pixman_translation; |
|
- | 1136 | ||
- | 1137 | is_pixman_translation = _cairo_matrix_is_pixman_translation (matrix, |
|
- | 1138 | filter, |
|
- | 1139 | x_offset, |
|
- | 1140 | y_offset); |
|
- | 1141 | ||
- | 1142 | if (is_pixman_translation) { |
|
- | 1143 | *out_transform = pixman_identity_transform; |
|
- | 1144 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
|
- | 1145 | } else { |
|
- | 1146 | cairo_matrix_t m; |
|
- | 1147 | ||
- | 1148 | m = *matrix; |
|
- | 1149 | cairo_matrix_translate (&m, *x_offset, *y_offset); |
|
- | 1150 | if (m.x0 != 0.0 || m.y0 != 0.0) { |
|
- | 1151 | double tx, ty, norm; |
|
- | 1152 | int i, j; |
|
- | 1153 | ||
- | 1154 | /* pixman also limits the [xy]_offset to 16 bits so evenly |
|
- | 1155 | * spread the bits between the two. |
|
- | 1156 | * |
|
- | 1157 | * To do this, find the solutions of: |
|
- | 1158 | * |x| = |x*m.xx + y*m.xy + m.x0| |
|
- | 1159 | * |y| = |x*m.yx + y*m.yy + m.y0| |
|
- | 1160 | * |
|
- | 1161 | * and select the one whose maximum norm is smallest. |
|
- | 1162 | */ |
|
- | 1163 | tx = m.x0; |
|
- | 1164 | ty = m.y0; |
|
- | 1165 | norm = MAX (fabs (tx), fabs (ty)); |
|
- | 1166 | ||
- | 1167 | for (i = -1; i < 2; i+=2) { |
|
- | 1168 | for (j = -1; j < 2; j+=2) { |
|
- | 1169 | double x, y, den, new_norm; |
|
- | 1170 | ||
- | 1171 | den = (m.xx + i) * (m.yy + j) - m.xy * m.yx; |
|
- | 1172 | if (fabs (den) < DBL_EPSILON) |
|
- | 1173 | continue; |
|
- | 1174 | ||
- | 1175 | x = m.y0 * m.xy - m.x0 * (m.yy + j); |
|
- | 1176 | y = m.x0 * m.yx - m.y0 * (m.xx + i); |
|
- | 1177 | ||
- | 1178 | den = 1 / den; |
|
- | 1179 | x *= den; |
|
- | 1180 | y *= den; |
|
- | 1181 | ||
- | 1182 | new_norm = MAX (fabs (x), fabs (y)); |
|
- | 1183 | if (norm > new_norm) { |
|
- | 1184 | norm = new_norm; |
|
- | 1185 | tx = x; |
|
- | 1186 | ty = y; |
|
- | 1187 | } |
|
- | 1188 | } |
|
- | 1189 | } |
|
- | 1190 | ||
- | 1191 | tx = floor (tx); |
|
- | 1192 | ty = floor (ty); |
|
- | 1193 | *x_offset = -tx; |
|
- | 1194 | *y_offset = -ty; |
|
- | 1195 | cairo_matrix_translate (&m, tx, ty); |
|
- | 1196 | } else { |
|
- | 1197 | *x_offset = 0; |
|
- | 1198 | *y_offset = 0; |
|
- | 1199 | } |
|
- | 1200 | ||
990 | } while (--max_iterations); |
1201 | return _cairo_matrix_to_pixman_matrix (&m, out_transform, xc, yc); |
991 | } |
1202 | } |