gstate: Handle device scale on surface as source

When creating a transformed pattern we must apply the device
transform *before* the transform set on the pattern itself, otherwise
e.g. its translation will not be affected by the device scale.

We also fix up the device_transform related handling in
_cairo_default_context_pop_group().  With a device scale we can
no longer just use the device_transform_inverse to unset the
device offset for the extents, so we make that a simple translate
instead.

We also remove some weird code that tries to handle the device
transform but seems unnecessary (maybe a workaround for applying
the device transform in the wrong order?). With that code removed
things work fine, but with it things get translated wrongly when
there is a scale.
This commit is contained in:
Alexander Larsson 2013-05-31 16:44:29 +02:00 committed by Chris Wilson
parent 900fc4a890
commit f0e2cd4494
4 changed files with 23 additions and 16 deletions

View file

@ -218,7 +218,8 @@ _cairo_default_context_pop_group (void *abstract_cr)
cairo_default_context_t *cr = abstract_cr;
cairo_surface_t *group_surface;
cairo_pattern_t *group_pattern;
cairo_matrix_t group_matrix, device_transform_matrix;
cairo_surface_t *parent_surface;
cairo_matrix_t group_matrix;
cairo_status_t status;
/* Verify that we are at the right nesting level */
@ -232,29 +233,21 @@ _cairo_default_context_pop_group (void *abstract_cr)
status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
assert (status == CAIRO_STATUS_SUCCESS);
parent_surface = _cairo_gstate_get_target (cr->gstate);
group_pattern = cairo_pattern_create_for_surface (group_surface);
status = group_pattern->status;
if (unlikely (status))
goto done;
_cairo_gstate_get_matrix (cr->gstate, &group_matrix);
/* Transform by group_matrix centered around device_transform so that when
* we call _cairo_gstate_copy_transformed_pattern the result is a pattern
* with a matrix equivalent to the device_transform of group_surface. */
if (_cairo_surface_has_device_transform (group_surface)) {
cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform);
_cairo_pattern_transform (group_pattern, &group_matrix);
_cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse);
} else {
cairo_pattern_set_matrix (group_pattern, &group_matrix);
}
cairo_pattern_set_matrix (group_pattern, &group_matrix);
/* If we have a current path, we need to adjust it to compensate for
* the device offset just removed. */
cairo_matrix_multiply (&device_transform_matrix,
&_cairo_gstate_get_target (cr->gstate)->device_transform,
&group_surface->device_transform_inverse);
_cairo_path_fixed_transform (cr->path, &device_transform_matrix);
_cairo_path_fixed_translate (cr->path,
_cairo_fixed_from_int (parent_surface->device_transform.x0 - group_surface->device_transform.x0),
_cairo_fixed_from_int (parent_surface->device_transform.y0 - group_surface->device_transform.y0));
done:
cairo_surface_destroy (group_surface);

View file

@ -954,7 +954,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
surface = surface_pattern->surface;
if (_cairo_surface_has_device_transform (surface))
_cairo_pattern_transform (pattern, &surface->device_transform);
_cairo_pattern_pretransform (pattern, &surface->device_transform);
}
if (! _cairo_matrix_is_identity (ctm_inverse))

View file

@ -237,6 +237,10 @@ cairo_private void
_cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse);
cairo_private void
_cairo_pattern_pretransform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm);
cairo_private cairo_bool_t
_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);

View file

@ -2127,6 +2127,16 @@ cairo_pattern_get_extend (cairo_pattern_t *pattern)
}
slim_hidden_def (cairo_pattern_get_extend);
void
_cairo_pattern_pretransform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm)
{
if (pattern->status)
return;
cairo_matrix_multiply (&pattern->matrix, &pattern->matrix, ctm);
}
void
_cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse)