Implement the device_offset functionality at surface, not gstate layer

This is a mega-patch that has the advantage that the entire test suite
passes both immediately before and immediately after this commit.

The disadvantage of the mega-patch is that it does not reflect the
development history of the device-offset branch, (with its various
fumblings and flailings). To capture that history, we will next merge
in that branch.
This commit is contained in:
Carl Worth 2006-05-04 01:45:41 -07:00
parent 40b39dddf9
commit a6b1b014bb
13 changed files with 449 additions and 157 deletions

View file

@ -435,6 +435,15 @@ _cairo_clip_clip (cairo_clip_t *clip,
{
cairo_status_t status;
cairo_traps_t traps;
cairo_path_fixed_t path_transformed;
if (_cairo_surface_has_device_offset_or_scale (target)) {
_cairo_path_fixed_init_copy (&path_transformed, path);
_cairo_path_fixed_offset (&path_transformed,
_cairo_fixed_from_double (target->device_x_offset),
_cairo_fixed_from_double (target->device_y_offset));
path = &path_transformed;
}
status = _cairo_clip_intersect_path (clip,
path, fill_rule, tolerance,
@ -458,6 +467,8 @@ _cairo_clip_clip (cairo_clip_t *clip,
bail:
_cairo_traps_fini (&traps);
if (path == &path_transformed)
_cairo_path_fixed_fini (&path_transformed);
return status;
}

View file

@ -501,37 +501,10 @@ _cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
return gstate->stroke_style.miter_limit;
}
static void
_cairo_gstate_apply_device_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix)
{
if (gstate->target->device_x_scale != 1.0 ||
gstate->target->device_y_scale != 1.0)
{
cairo_matrix_scale (matrix,
gstate->target->device_x_scale,
gstate->target->device_y_scale);
}
}
static void
_cairo_gstate_apply_device_inverse_transform (cairo_gstate_t *gstate,
cairo_matrix_t *matrix)
{
if (gstate->target->device_x_scale != 1.0 ||
gstate->target->device_y_scale != 1.0)
{
cairo_matrix_scale (matrix,
1/gstate->target->device_x_scale,
1/gstate->target->device_y_scale);
}
}
void
_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
{
*matrix = gstate->ctm;
_cairo_gstate_apply_device_inverse_transform (gstate, matrix);
}
cairo_status_t
@ -617,9 +590,6 @@ _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
if (status)
return status;
_cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
_cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
return CAIRO_STATUS_SUCCESS;
}
@ -631,9 +601,6 @@ _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
cairo_matrix_init_identity (&gstate->ctm);
cairo_matrix_init_identity (&gstate->ctm_inverse);
_cairo_gstate_apply_device_transform (gstate, &gstate->ctm);
_cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse);
return CAIRO_STATUS_SUCCESS;
}
@ -675,15 +642,11 @@ void
_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
{
cairo_matrix_transform_point (&gstate->ctm, x, y);
*x += gstate->target->device_x_offset;
*y += gstate->target->device_y_offset;
}
void
_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
{
*x -= gstate->target->device_x_offset;
*y -= gstate->target->device_y_offset;
cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
}
@ -704,16 +667,24 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
cairo_pattern_t *original,
cairo_matrix_t *ctm_inverse)
{
cairo_matrix_t tmp_matrix = *ctm_inverse;
cairo_surface_pattern_t *surface_pattern;
cairo_surface_t *surface;
cairo_matrix_t offset_matrix;
_cairo_pattern_init_copy (pattern, original);
_cairo_pattern_transform (pattern, ctm_inverse);
if (gstate->target)
cairo_matrix_translate (&tmp_matrix,
- gstate->target->device_x_offset,
- gstate->target->device_y_offset);
if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) {
surface_pattern = (cairo_surface_pattern_t *) original;
surface = surface_pattern->surface;
if (_cairo_surface_has_device_offset_or_scale (surface)) {
cairo_matrix_init_translate (&offset_matrix,
surface->device_x_offset,
surface->device_y_offset);
_cairo_pattern_transform (pattern, &offset_matrix);
}
}
_cairo_pattern_transform (pattern, &tmp_matrix);
}
static void

View file

@ -568,3 +568,49 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy,
cairo_fixed_t scalex,
cairo_fixed_t scaley)
{
cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
int i;
cairo_int64_t i64temp;
cairo_fixed_t fixedtemp;
while (arg_buf) {
for (i = 0; i < arg_buf->num_points; i++) {
if (scalex == CAIRO_FIXED_ONE) {
arg_buf->points[i].x += offx;
} else {
fixedtemp = arg_buf->points[i].x + offx;
i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex);
arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
}
if (scaley == CAIRO_FIXED_ONE) {
arg_buf->points[i].y += offy;
} else {
fixedtemp = arg_buf->points[i].y + offy;
i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley);
arg_buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
}
}
arg_buf = arg_buf->next;
}
}
void
_cairo_path_fixed_offset (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy)
{
_cairo_path_fixed_offset_and_scale (path, offx, offy,
CAIRO_FIXED_ONE,
CAIRO_FIXED_ONE);
}

View file

@ -1194,10 +1194,8 @@ _cairo_ps_surface_start_page (void *abstract_surface)
(int) ceil (surface->height));
_cairo_output_stream_printf (surface->stream,
"gsave %f %f translate %f %f scale \n",
0.0, surface->height,
1.0/surface->base.device_x_scale,
-1.0/surface->base.device_y_scale);
"gsave %f %f translate 1.0 -1.0 scale \n",
0.0, surface->height);
_cairo_output_stream_printf (surface->stream,
"%%%%EndPageSetup\n");

View file

@ -920,11 +920,11 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
/* round glyph locations to the nearest pixel */
x = (int) floor (glyphs[i].x +
glyph_surface->base.device_x_offset +
0.5);
glyph_surface->base.device_x_offset +
0.5);
y = (int) floor (glyphs[i].y +
glyph_surface->base.device_y_offset +
0.5);
glyph_surface->base.device_y_offset +
0.5);
_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);

View file

@ -895,7 +895,8 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure,
op,
src, dst,
extents->x, extents->y,
extents->x - dst_x, extents->y - dst_y,
extents->x - dst_x,
extents->y - dst_y,
extents->width, extents->height,
glyph_info->glyphs,
glyph_info->num_glyphs);
@ -989,6 +990,9 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
_cairo_surface_release_source_image (surface,
image, &image_extra);
snapshot->device_x_offset = surface->device_x_offset;
snapshot->device_y_offset = surface->device_y_offset;
snapshot->is_snapshot = TRUE;
return snapshot;
@ -1018,12 +1022,17 @@ _cairo_surface_fallback_composite (cairo_operator_t op,
return status;
}
status = state.image->base.backend->composite (op, src, mask,
&state.image->base,
src_x, src_y, mask_x, mask_y,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
width, height);
/* We know this will never fail with the image backend; but
* instead of calling into it directly, we call
* _cairo_surface_composite so that we get the correct device
* offset handling.
*/
status = _cairo_surface_composite (op, src, mask,
&state.image->base,
src_x, src_y, mask_x, mask_y,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
width, height);
_fallback_fini (&state);
return status;
@ -1093,9 +1102,9 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
rects = offset_rects;
}
status = state.image->base.backend->fill_rectangles (&state.image->base,
op, color,
rects, num_rects);
status = _cairo_surface_fill_rectangles (&state.image->base,
op, color,
rects, num_rects);
free (offset_rects);
@ -1122,7 +1131,6 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
fallback_state_t state;
cairo_trapezoid_t *offset_traps = NULL;
cairo_status_t status;
int i;
status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
if (status) {
@ -1134,39 +1142,25 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
/* If the destination image isn't at 0,0, we need to offset the trapezoids */
if (state.image_rect.x != 0 || state.image_rect.y != 0) {
cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x);
cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y);
offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
if (!offset_traps) {
status = CAIRO_STATUS_NO_MEMORY;
goto DONE;
}
for (i = 0; i < num_traps; i++) {
offset_traps[i].top = traps[i].top - yoff;
offset_traps[i].bottom = traps[i].bottom - yoff;
offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff;
offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff;
offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff;
offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff;
offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff;
offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff;
offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff;
offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff;
}
_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
- state.image_rect.x, - state.image_rect.y,
1.0, 1.0);
traps = offset_traps;
}
state.image->base.backend->composite_trapezoids (op, pattern,
&state.image->base,
antialias,
src_x, src_y,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
width, height, traps, num_traps);
_cairo_surface_composite_trapezoids (op, pattern,
&state.image->base,
antialias,
src_x, src_y,
dst_x - state.image_rect.x,
dst_y - state.image_rect.y,
width, height, traps, num_traps);
if (offset_traps)
free (offset_traps);

View file

@ -92,6 +92,14 @@ const cairo_surface_t _cairo_surface_nil_read_error = {
0 /* current_clip_serial */
};
/* Helper macros for transforming surface coords to backend coords */
#define SURFACE_TO_BACKEND_X(_surf, _sx) ((_sx)+((_surf)->device_x_offset))
#define SURFACE_TO_BACKEND_Y(_surf, _sy) ((_sy)+((_surf)->device_y_offset))
static void _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
cairo_surface_t *destination,
cairo_pattern_t *pattern_out);
/**
* _cairo_surface_set_error:
* @surface: a surface
@ -171,8 +179,6 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->device_x_offset = 0.0;
surface->device_y_offset = 0.0;
surface->device_x_scale = 1.0;
surface->device_y_scale = 1.0;
surface->clip = NULL;
surface->next_clip_serial = 0;
@ -556,7 +562,10 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
if (surface->backend->mark_dirty_rectangle) {
cairo_status_t status;
status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height);
status = surface->backend->mark_dirty_rectangle (surface,
SURFACE_TO_BACKEND_X(surface, x),
SURFACE_TO_BACKEND_Y(surface, y),
width, height);
if (status)
_cairo_surface_set_error (surface, status);
@ -596,8 +605,34 @@ cairo_surface_set_device_offset (cairo_surface_t *surface,
return;
}
surface->device_x_offset = x_offset * surface->device_x_scale;
surface->device_y_offset = y_offset * surface->device_y_scale;
surface->device_x_offset = x_offset;
surface->device_y_offset = y_offset;
}
/**
* cairo_surface_get_device_offset:
* @surface: a #cairo_surface_t
* @x_offset: the offset in the X direction, in device units
* @y_offset: the offset in the Y direction, in device units
*
* Returns a previous device offset set by
* cairo_surface_set_device_offset().
*
**/
void
cairo_surface_get_device_offset (cairo_surface_t *surface,
double *x_offset,
double *y_offset)
{
*x_offset = surface->device_x_offset;
*y_offset = surface->device_y_offset;
}
cairo_bool_t
_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface)
{
return (surface->device_x_offset != 0.0 ||
surface->device_y_offset != 0.0);
}
/**
@ -651,6 +686,7 @@ _cairo_surface_release_source_image (cairo_surface_t *surface,
* @surface: a #cairo_surface_t
* @interest_rect: area of @surface for which fallback drawing is being done.
* A value of %NULL indicates that the entire surface is desired.
* XXXX I'd like to get rid of being able to pass NULL here (nothing seems to)
* @image_out: location to store a pointer to an image surface that includes at least
* the intersection of @interest_rect with the visible area of @surface.
* This surface could be @surface itself, a surface held internal to @surface,
@ -685,7 +721,8 @@ _cairo_surface_acquire_dest_image (cairo_surface_t *surface,
{
assert (!surface->finished);
return surface->backend->acquire_dest_image (surface, interest_rect,
return surface->backend->acquire_dest_image (surface,
interest_rect,
image_out, image_rect, image_extra);
}
@ -747,6 +784,11 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
status = surface->backend->clone_similar (surface, src, clone_out);
if (status == CAIRO_STATUS_SUCCESS) {
(*clone_out)->device_x_offset = src->device_x_offset;
(*clone_out)->device_y_offset = src->device_y_offset;
}
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
@ -755,6 +797,10 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
return status;
status = surface->backend->clone_similar (surface, &image->base, clone_out);
if (status == CAIRO_STATUS_SUCCESS) {
(*clone_out)->device_x_offset = src->device_x_offset;
(*clone_out)->device_y_offset = src->device_y_offset;
}
/* If the above failed point, we could implement a full fallback
* using acquire_dest_image, but that's going to be very
@ -829,9 +875,9 @@ _cairo_surface_composite (cairo_operator_t op,
if (dst->backend->composite) {
status = dst->backend->composite (op,
src, mask, dst,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
src_x, src_y,
mask_x, mask_y,
dst_x, dst_y,
width, height);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
@ -989,16 +1035,24 @@ _cairo_surface_paint (cairo_surface_t *surface,
cairo_pattern_t *source)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
assert (! surface->is_snapshot);
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (surface->backend->paint) {
status = surface->backend->paint (surface, op, source);
status = surface->backend->paint (surface, op, &dev_source.base);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
goto FINISH;
}
return _cairo_surface_fallback_paint (surface, op, source);
status = _cairo_surface_fallback_paint (surface, op, &dev_source.base);
FINISH:
_cairo_pattern_fini (&dev_source.base);
return status;
}
cairo_status_t
@ -1008,16 +1062,27 @@ _cairo_surface_mask (cairo_surface_t *surface,
cairo_pattern_t *mask)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
cairo_pattern_union_t dev_mask;
assert (! surface->is_snapshot);
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
_cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base);
if (surface->backend->mask) {
status = surface->backend->mask (surface, op, source, mask);
status = surface->backend->mask (surface, op, &dev_source.base, &dev_mask.base);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
goto FINISH;
}
return _cairo_surface_fallback_mask (surface, op, source, mask);
status = _cairo_surface_fallback_mask (surface, op, &dev_source.base, &dev_mask.base);
FINISH:
_cairo_pattern_fini (&dev_source.base);
_cairo_pattern_fini (&dev_mask.base);
return status;
}
cairo_status_t
@ -1031,22 +1096,45 @@ _cairo_surface_stroke (cairo_surface_t *surface,
double tolerance,
cairo_antialias_t antialias)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
cairo_path_fixed_t *dev_path = path;
cairo_path_fixed_t real_dev_path;
assert (! surface->is_snapshot);
if (surface->backend->stroke) {
cairo_status_t status;
status = surface->backend->stroke (surface, op, source,
path, stroke_style,
ctm, ctm_inverse,
tolerance, antialias);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (_cairo_surface_has_device_offset_or_scale (surface))
{
_cairo_path_fixed_init_copy (&real_dev_path, path);
_cairo_path_fixed_offset (&real_dev_path,
_cairo_fixed_from_double (surface->device_x_offset),
_cairo_fixed_from_double (surface->device_y_offset));
dev_path = &real_dev_path;
}
return _cairo_surface_fallback_stroke (surface, op, source,
path, stroke_style,
if (surface->backend->stroke) {
status = surface->backend->stroke (surface, op, &dev_source.base,
dev_path, stroke_style,
ctm, ctm_inverse,
tolerance, antialias);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
status = _cairo_surface_fallback_stroke (surface, op, &dev_source.base,
dev_path, stroke_style,
ctm, ctm_inverse,
tolerance, antialias);
FINISH:
if (dev_path == &real_dev_path)
_cairo_path_fixed_fini (&real_dev_path);
_cairo_pattern_fini (&dev_source.base);
return status;
}
cairo_status_t
@ -1059,20 +1147,42 @@ _cairo_surface_fill (cairo_surface_t *surface,
cairo_antialias_t antialias)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
cairo_path_fixed_t *dev_path = path;
cairo_path_fixed_t real_dev_path;
assert (! surface->is_snapshot);
if (surface->backend->fill) {
status = surface->backend->fill (surface, op, source,
path, fill_rule,
tolerance, antialias);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (_cairo_surface_has_device_offset_or_scale (surface))
{
_cairo_path_fixed_init_copy (&real_dev_path, path);
_cairo_path_fixed_offset (&real_dev_path,
_cairo_fixed_from_double (surface->device_x_offset),
_cairo_fixed_from_double (surface->device_y_offset));
dev_path = &real_dev_path;
}
return _cairo_surface_fallback_fill (surface, op, source,
path, fill_rule,
if (surface->backend->fill) {
status = surface->backend->fill (surface, op, &dev_source.base,
dev_path, fill_rule,
tolerance, antialias);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
status = _cairo_surface_fallback_fill (surface, op, &dev_source.base,
dev_path, fill_rule,
tolerance, antialias);
FINISH:
if (dev_path == &real_dev_path)
_cairo_path_fixed_fini (&real_dev_path);
_cairo_pattern_fini (&dev_source.base);
return status;
}
cairo_status_t
@ -1109,7 +1219,7 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
pattern, dst,
antialias,
src_x, src_y,
dst_x, dst_y,
dst_x, dst_y,
width, height,
traps, num_traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@ -1258,6 +1368,8 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface,
pixman_region16_t *region,
unsigned int serial)
{
cairo_status_t status;
if (surface->status)
return surface->status;
@ -1265,10 +1377,12 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface,
return CAIRO_STATUS_SURFACE_FINISHED;
assert (surface->backend->set_clip_region != NULL);
surface->current_clip_serial = serial;
return surface->backend->set_clip_region (surface, region);
status = surface->backend->set_clip_region (surface, region);
return status;
}
cairo_int_status_t
@ -1278,6 +1392,9 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface,
double tolerance,
cairo_antialias_t antialias)
{
cairo_path_fixed_t *dev_path = path;
cairo_status_t status;
if (surface->status)
return surface->status;
@ -1286,11 +1403,13 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface,
assert (surface->backend->intersect_clip_path != NULL);
return surface->backend->intersect_clip_path (surface,
path,
fill_rule,
tolerance,
antialias);
status = surface->backend->intersect_clip_path (surface,
dev_path,
fill_rule,
tolerance,
antialias);
return status;
}
static cairo_status_t
@ -1306,11 +1425,11 @@ _cairo_surface_set_clip_path_recursive (cairo_surface_t *surface,
if (status)
return status;
return surface->backend->intersect_clip_path (surface,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
return _cairo_surface_intersect_clip_path (surface,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
}
/**
@ -1413,13 +1532,22 @@ cairo_status_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_t *rectangle)
{
cairo_status_t status;
if (surface->status)
return surface->status;
if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED;
return surface->backend->get_extents (surface, rectangle);
status = surface->backend->get_extents (surface, rectangle);
rectangle->x = SURFACE_TO_BACKEND_X(surface, rectangle->x);
rectangle->y = SURFACE_TO_BACKEND_Y(surface, rectangle->y);
rectangle->width = rectangle->width - surface->device_x_offset;
rectangle->height = rectangle->height - surface->device_y_offset;
return status;
}
cairo_status_t
@ -1431,20 +1559,48 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
cairo_glyph_t *dev_glyphs = (cairo_glyph_t*) glyphs;
cairo_pattern_union_t dev_source;
assert (! surface->is_snapshot);
if (surface->backend->show_glyphs) {
status = surface->backend->show_glyphs (surface, op, source,
glyphs, num_glyphs,
scaled_font);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_surface_copy_pattern_for_destination (source,
surface,
&dev_source.base);
if (_cairo_surface_has_device_offset_or_scale (surface))
{
int i;
dev_glyphs = malloc (sizeof(cairo_glyph_t) * num_glyphs);
if (!dev_glyphs)
return CAIRO_STATUS_NO_MEMORY;
for (i = 0; i < num_glyphs; i++) {
dev_glyphs[i].index = glyphs[i].index;
/* XXX: err, we really should scale the size of the glyphs, no? */
dev_glyphs[i].x = SURFACE_TO_BACKEND_X(surface, glyphs[i].x);
dev_glyphs[i].y = SURFACE_TO_BACKEND_Y(surface, glyphs[i].y);
}
}
return _cairo_surface_fallback_show_glyphs (surface, op, source,
glyphs, num_glyphs,
scaled_font);
if (surface->backend->show_glyphs) {
status = surface->backend->show_glyphs (surface, op, &dev_source.base,
dev_glyphs, num_glyphs,
scaled_font);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
status = _cairo_surface_fallback_show_glyphs (surface, op, &dev_source.base,
dev_glyphs, num_glyphs,
scaled_font);
FINISH:
if (dev_glyphs != glyphs)
free (dev_glyphs);
return status;
}
/* XXX: Previously, we had a function named _cairo_surface_show_glyphs
@ -1476,14 +1632,14 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
if (dst->finished)
return CAIRO_STATUS_SURFACE_FINISHED;
if (dst->backend->old_show_glyphs)
if (dst->backend->old_show_glyphs) {
status = dst->backend->old_show_glyphs (scaled_font,
op, pattern, dst,
source_x, source_y,
dest_x, dest_y,
dest_x, dest_y,
width, height,
glyphs, num_glyphs);
else
} else
status = CAIRO_INT_STATUS_UNSUPPORTED;
return status;
@ -1593,7 +1749,7 @@ _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst,
cairo_rectangle_t *mask_rectangle = NULL;
assert (! dst->is_snapshot);
/* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
* non-repeating sources and masks. Other sources and masks can be ignored.
*/
@ -1668,7 +1824,7 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
cairo_rectangle_t *mask_rectangle = NULL;
assert (! dst->is_snapshot);
/* The RENDER/libpixman operators are clipped to the bounds of the untransformed,
* non-repeating sources and masks. Other sources and masks can be ignored.
*/
@ -1729,3 +1885,29 @@ _cairo_surface_is_opaque (const cairo_surface_t *surface)
return FALSE;
}
/**
* _cairo_surface_copy_pattern_for_destination
* @pattern: the pattern to copy
* @destination: the destination surface for which the pattern is being copied
* @pattern_out: the location to hold the copy
*
* Copies the given pattern, taking into account device scale and offsets
* of the destination surface.
*/
void
_cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
cairo_surface_t *destination,
cairo_pattern_t *pattern_out)
{
_cairo_pattern_init_copy (pattern_out, pattern);
if (_cairo_surface_has_device_offset_or_scale (destination)) {
cairo_matrix_t device_to_surface;
cairo_matrix_init_translate (&device_to_surface,
- destination->device_x_offset,
- destination->device_y_offset);
_cairo_pattern_transform (pattern_out, &device_to_surface);
}
}

View file

@ -258,6 +258,54 @@ _cairo_traps_translate (cairo_traps_t *traps, int x, int y)
}
}
void
_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
cairo_trapezoid_t *src_traps,
int num_traps,
double tx, double ty,
double sx, double sy)
{
int i;
cairo_fixed_t xoff = _cairo_fixed_from_double (tx);
cairo_fixed_t yoff = _cairo_fixed_from_double (ty);
if (sx == 1.0 && sy == 1.0) {
for (i = 0; i < num_traps; i++) {
offset_traps[i].top = src_traps[i].top + yoff;
offset_traps[i].bottom = src_traps[i].bottom + yoff;
offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff;
offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff;
offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff;
offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff;
offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff;
offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff;
offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff;
offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff;
}
} else {
cairo_fixed_t xsc = _cairo_fixed_from_double (sx);
cairo_fixed_t ysc = _cairo_fixed_from_double (sy);
for (i = 0; i < num_traps; i++) {
#define FIXED_MUL(_a, _b) \
(_cairo_int64_to_int32(_cairo_int64_rsl(_cairo_int32x32_64_mul((_a), (_b)), 16)))
offset_traps[i].top = FIXED_MUL(src_traps[i].top + yoff, ysc);
offset_traps[i].bottom = FIXED_MUL(src_traps[i].bottom + yoff, ysc);
offset_traps[i].left.p1.x = FIXED_MUL(src_traps[i].left.p1.x + xoff, xsc);
offset_traps[i].left.p1.y = FIXED_MUL(src_traps[i].left.p1.y + yoff, ysc);
offset_traps[i].left.p2.x = FIXED_MUL(src_traps[i].left.p2.x + xoff, xsc);
offset_traps[i].left.p2.y = FIXED_MUL(src_traps[i].left.p2.y + yoff, ysc);
offset_traps[i].right.p1.x = FIXED_MUL(src_traps[i].right.p1.x + xoff, xsc);
offset_traps[i].right.p1.y = FIXED_MUL(src_traps[i].right.p1.y + yoff, ysc);
offset_traps[i].right.p2.x = FIXED_MUL(src_traps[i].right.p2.x + xoff, xsc);
offset_traps[i].right.p2.y = FIXED_MUL(src_traps[i].right.p2.y + yoff, ysc);
#undef FIXED_MUL
}
}
}
cairo_status_t
_cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3])
{
@ -859,4 +907,3 @@ _cairo_traps_extract_region (cairo_traps_t *traps,
return CAIRO_STATUS_SUCCESS;
}

View file

@ -2151,8 +2151,8 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
* sitting around for x and y.
*/
glyph_info.x = -(int) glyph_surface->base.device_x_offset;
glyph_info.y = -(int) glyph_surface->base.device_y_offset;
glyph_info.x = - (int) floor(glyph_surface->base.device_x_offset + 0.5);
glyph_info.y = - (int) floor(glyph_surface->base.device_y_offset + 0.5);
glyph_info.width = glyph_surface->width;
glyph_info.height = glyph_surface->height;
glyph_info.xOff = 0;

View file

@ -1304,6 +1304,11 @@ cairo_surface_set_device_offset (cairo_surface_t *surface,
double x_offset,
double y_offset);
cairo_public void
cairo_surface_get_device_offset (cairo_surface_t *surface,
double *x_offset,
double *y_offset);
/* Image-surface functions */
/**

View file

@ -861,8 +861,6 @@ struct _cairo_surface {
double device_x_offset;
double device_y_offset;
double device_x_scale;
double device_y_scale;
cairo_clip_t *clip;
@ -1058,6 +1056,8 @@ _cairo_restrict_value (double *value, double min, double max);
cairo_private cairo_fixed_t
_cairo_fixed_from_int (int i);
#define CAIRO_FIXED_ONE _cairo_fixed_from_int (1)
cairo_private cairo_fixed_t
_cairo_fixed_from_double (double d);
@ -1488,6 +1488,11 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2);
cairo_private void
_cairo_path_fixed_offset (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy);
/* cairo_path_fill.c */
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
@ -1836,6 +1841,9 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
cairo_private cairo_bool_t
_cairo_surface_is_opaque (const cairo_surface_t *surface);
cairo_private cairo_bool_t
_cairo_surface_has_device_offset_or_scale (cairo_surface_t *surface);
/* cairo_image_surface.c */
#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \
@ -2038,6 +2046,13 @@ cairo_private cairo_status_t
_cairo_traps_extract_region (cairo_traps_t *tr,
pixman_region16_t **region);
cairo_private void
_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps,
cairo_trapezoid_t *src_traps,
int num_traps,
double tx, double ty,
double sx, double sy);
/* cairo_slope.c */
cairo_private void
_cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b);

View file

@ -287,9 +287,9 @@ image_diff_flattened (const char *filename_a,
b_flat_surface = cairo_image_surface_create_for_data (b_flat,
CAIRO_FORMAT_ARGB32,
width_a, height_a,
stride_a);
/*cairo_surface_set_device_offset (b_flat_surface, -bx, -by);*/
width_b, height_b,
stride_b);
cairo_surface_set_device_offset (b_flat_surface, -bx, -by);
cr = cairo_create (b_flat_surface);
@ -306,7 +306,7 @@ image_diff_flattened (const char *filename_a,
b_flat,
buf_diff,
width_a, height_a,
stride_a, stride_a, stride_a);
stride_a, stride_b, stride_a);
if (pixels_changed) {
FILE *png_file = fopen (filename_diff, "wb");

View file

@ -1181,6 +1181,15 @@ ps_surface_write_to_png (cairo_surface_t *surface, const char *filename)
ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, &ps_closure_key);
char command[4096];
/* Both surface and ptc->target were originally created at the
* same dimensions. We want a 1:1 copy here, so we first clear any
* device offset on surface.
*
* In a more realistic use case of device offsets, the target of
* this copying would be of a different size than the source, and
* the offset would be desirable during the copy operation. */
cairo_surface_set_device_offset (surface, 0, 0);
if (ptc->target) {
cairo_t *cr;
cr = cairo_create (ptc->target);
@ -1273,6 +1282,15 @@ pdf_surface_write_to_png (cairo_surface_t *surface, const char *filename)
pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key);
char command[4096];
/* Both surface and ptc->target were originally created at the
* same dimensions. We want a 1:1 copy here, so we first clear any
* device offset on surface.
*
* In a more realistic use case of device offsets, the target of
* this copying would be of a different size than the source, and
* the offset would be desirable during the copy operation. */
cairo_surface_set_device_offset (surface, 0, 0);
if (ptc->target) {
cairo_t *cr;
cr = cairo_create (ptc->target);
@ -1427,6 +1445,11 @@ cairo_test_for_target (cairo_test_t *test,
else
offset_str = strdup("");
if (dev_offset)
xasprintf (&offset_str, "-%d", dev_offset);
else
offset_str = strdup("");
xasprintf (&png_name, "%s-%s-%s%s%s", test->name,
target->name, format, offset_str, CAIRO_TEST_PNG_SUFFIX);