diff options
author | Carl Worth <cworth@cworth.org> | 2006-05-04 01:45:41 -0700 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-05-04 01:45:41 -0700 |
commit | a6b1b014bbd12be0f20c44d38d8847181be6d3ae (patch) | |
tree | ce01dacaf9262eb98aa365d960cb19a1a1552e5e | |
parent | 40b39dddf9cd919fb2f456a8e296a60cc8296fbf (diff) |
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.
-rw-r--r-- | src/cairo-clip.c | 11 | ||||
-rw-r--r-- | src/cairo-gstate.c | 61 | ||||
-rw-r--r-- | src/cairo-path.c | 46 | ||||
-rw-r--r-- | src/cairo-ps-surface.c | 6 | ||||
-rw-r--r-- | src/cairo-scaled-font.c | 8 | ||||
-rw-r--r-- | src/cairo-surface-fallback.c | 64 | ||||
-rw-r--r-- | src/cairo-surface.c | 292 | ||||
-rw-r--r-- | src/cairo-traps.c | 49 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 4 | ||||
-rw-r--r-- | src/cairo.h | 5 | ||||
-rw-r--r-- | src/cairoint.h | 19 | ||||
-rw-r--r-- | test/buffer-diff.c | 8 | ||||
-rw-r--r-- | test/cairo-test.c | 23 |
13 files changed, 444 insertions, 152 deletions
diff --git a/src/cairo-clip.c b/src/cairo-clip.c index 0c862a38..7edb9150 100644 --- a/src/cairo-clip.c +++ b/src/cairo-clip.c @@ -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; } diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 10212cc7..1a4ca6a0 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -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_pattern_init_copy (pattern, original); + cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *surface; + cairo_matrix_t offset_matrix; - if (gstate->target) - cairo_matrix_translate (&tmp_matrix, - - gstate->target->device_x_offset, - - gstate->target->device_y_offset); + _cairo_pattern_init_copy (pattern, original); + _cairo_pattern_transform (pattern, ctm_inverse); + + 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 diff --git a/src/cairo-path.c b/src/cairo-path.c index 7358bee5..5c94ad90 100644 --- a/src/cairo-path.c +++ b/src/cairo-path.c @@ -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); +} + diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index f24e6336..8bf46f5d 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -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"); diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c index 91e62578..3e40c7e4 100644 --- a/src/cairo-scaled-font.c +++ b/src/cairo-scaled-font.c @@ -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); diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c index a5c723f1..5b01039c 100644 --- a/src/cairo-surface-fallback.c +++ b/src/cairo-surface-fallback.c @@ -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); diff --git a/src/cairo-surface.c b/src/cairo-surface.c index f905dfd0..025f3003 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -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); + _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; + } + if (surface->backend->stroke) { - cairo_status_t status; - status = surface->backend->stroke (surface, op, source, - path, stroke_style, + status = surface->backend->stroke (surface, op, &dev_source.base, + dev_path, stroke_style, ctm, ctm_inverse, tolerance, antialias); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto FINISH; } - return _cairo_surface_fallback_stroke (surface, op, source, - path, stroke_style, - ctm, ctm_inverse, - tolerance, antialias); + 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); + _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; + } + if (surface->backend->fill) { - status = surface->backend->fill (surface, op, source, - path, fill_rule, + status = surface->backend->fill (surface, op, &dev_source.base, + dev_path, fill_rule, tolerance, antialias); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto FINISH; } - return _cairo_surface_fallback_fill (surface, op, source, - path, fill_rule, - tolerance, antialias); + 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); + _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); + } + } + if (surface->backend->show_glyphs) { - status = surface->backend->show_glyphs (surface, op, source, - glyphs, num_glyphs, - scaled_font); + status = surface->backend->show_glyphs (surface, op, &dev_source.base, + dev_glyphs, num_glyphs, + scaled_font); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto FINISH; } - return _cairo_surface_fallback_show_glyphs (surface, op, source, - glyphs, num_glyphs, - scaled_font); + 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); + } +} diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 6afb499b..6733ca58 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -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; } - diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 3245af6c..567ef011 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -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; diff --git a/src/cairo.h b/src/cairo.h index ea4e20b2..c1f191c5 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -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 */ /** diff --git a/src/cairoint.h b/src/cairoint.h index cfa8b7d2..09d2e657 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -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); diff --git a/test/buffer-diff.c b/test/buffer-diff.c index c62c44ef..89af811c 100644 --- a/test/buffer-diff.c +++ b/test/buffer-diff.c @@ -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"); diff --git a/test/cairo-test.c b/test/cairo-test.c index 6a3d52a5..d0052de9 100644 --- a/test/cairo-test.c +++ b/test/cairo-test.c @@ -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); |