summaryrefslogtreecommitdiff
path: root/src/cairo-matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-matrix.c')
-rw-r--r--src/cairo-matrix.c65
1 files changed, 41 insertions, 24 deletions
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index b644dec8..6dfe537f 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -865,7 +865,9 @@ _cairo_matrix_transformed_circle_major_axis (cairo_matrix_t *matrix, double radi
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
- pixman_transform_t *pixman_transform)
+ pixman_transform_t *pixman_transform,
+ double xc,
+ double yc)
{
static const pixman_transform_t pixman_identity_transform = {{
{1 << 16, 0, 0},
@@ -875,11 +877,9 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
if (_cairo_matrix_is_identity (matrix)) {
*pixman_transform = pixman_identity_transform;
- }
- else {
+ } else {
cairo_matrix_t inv;
- double x,y;
- pixman_vector_t vector;
+ unsigned max_iterations;
pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
@@ -899,9 +899,10 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
* for cairo, while pixman uses rounded versions of xx ... yy.
* This error increases as a and b get larger.
*
- * To compensate for this, we fix the point (0, 0) in pattern
+ * To compensate for this, we fix the point (xc, yc) in pattern
* space and adjust pixman's transform to agree with cairo's at
- * that point. */
+ * that point.
+ */
if (_cairo_matrix_is_translation (matrix))
return;
@@ -911,22 +912,38 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
return;
- /* find the device space coordinate that maps to (0, 0) */
- x = 0, y = 0;
- cairo_matrix_transform_point (&inv, &x, &y);
-
- /* transform the resulting device space coordinate back
- * to the pattern space, using pixman's transform */
- vector.vector[0] = _cairo_fixed_16_16_from_double (x);
- vector.vector[1] = _cairo_fixed_16_16_from_double (y);
- vector.vector[2] = 1 << 16;
-
- if (! pixman_transform_point_3d (pixman_transform, &vector))
- return;
-
- /* Ideally, the vector should now be (0, 0). We can now compensate
- * for the resulting error */
- pixman_transform->matrix[0][2] -= vector.vector[0];
- pixman_transform->matrix[1][2] -= vector.vector[1];
+ /* find the pattern space coordinate that maps to (xc, yc) */
+ xc += .5; yc += .5; /* offset for the pixel centre */
+ max_iterations = 5;
+ do {
+ double x,y;
+ pixman_vector_t vector;
+ cairo_fixed_16_16_t dx, dy;
+
+ vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
+ vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
+ vector.vector[2] = 1 << 16;
+
+ if (! pixman_transform_point_3d (pixman_transform, &vector))
+ return;
+
+ x = pixman_fixed_to_double (vector.vector[0]);
+ y = pixman_fixed_to_double (vector.vector[1]);
+ cairo_matrix_transform_point (&inv, &x, &y);
+
+ /* Ideally, the vector should now be (xc, yc).
+ * We can now compensate for the resulting error.
+ */
+ x -= xc;
+ y -= yc;
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ dx = _cairo_fixed_16_16_from_double (x);
+ dy = _cairo_fixed_16_16_from_double (y);
+ pixman_transform->matrix[0][2] -= dx;
+ pixman_transform->matrix[1][2] -= dy;
+
+ if (dx == 0 && dy == 0)
+ break;
+ } while (--max_iterations);
}
}