summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2006-05-04 01:45:41 -0700
committerCarl Worth <cworth@cworth.org>2006-05-04 01:45:41 -0700
commita6b1b014bbd12be0f20c44d38d8847181be6d3ae (patch)
treece01dacaf9262eb98aa365d960cb19a1a1552e5e
parent40b39dddf9cd919fb2f456a8e296a60cc8296fbf (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.c11
-rw-r--r--src/cairo-gstate.c61
-rw-r--r--src/cairo-path.c46
-rw-r--r--src/cairo-ps-surface.c6
-rw-r--r--src/cairo-scaled-font.c8
-rw-r--r--src/cairo-surface-fallback.c64
-rw-r--r--src/cairo-surface.c292
-rw-r--r--src/cairo-traps.c49
-rw-r--r--src/cairo-xlib-surface.c4
-rw-r--r--src/cairo.h5
-rw-r--r--src/cairoint.h19
-rw-r--r--test/buffer-diff.c8
-rw-r--r--test/cairo-test.c23
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);