diff --git a/ChangeLog b/ChangeLog index 3e3ae430c..30da73976 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-03-17 Owen Taylor + + * src/cairo.h src/cairo_surface.c src/cairo-xlib.h + src/cairo_xlib_surface.c: Move cairo_xlib_surface_set_device_offset() + to a generic cairo_surface_set_device_offset(). + + * src/cairo_gstate.c: Take the surface's device offset into + account. + + * doc/public/cairo-sections.txt: Update. + 2005-03-17 Owen Taylor * src/cairo_matrix.c: Fix the docs to to correctly describe diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt index aadd4a518..748802e57 100644 --- a/doc/public/cairo-sections.txt +++ b/doc/public/cairo-sections.txt @@ -25,7 +25,9 @@ cairo_glitz_surface_create cairo-pdf PDF Backend cairo_set_target_pdf +cairo_set_target_pdf_as_file cairo_pdf_surface_create +cairo_pdf_surface_create_for_file
@@ -75,7 +77,6 @@ cairo_xlib_surface_create_for_pixmap cairo_xlib_surface_create_for_pixmap_with_visual cairo_xlib_surface_create_for_window_with_visual cairo_xlib_surface_set_size -cairo_xlib_surface_set_device_offset
@@ -86,6 +87,7 @@ cairo_surface_create_for_image cairo_surface_create_similar cairo_surface_reference cairo_surface_destroy +cairo_surface_finish cairo_surface_set_repeat cairo_surface_set_matrix cairo_surface_get_matrix @@ -93,6 +95,7 @@ cairo_surface_set_filter cairo_surface_get_filter cairo_surface_set_user_data cairo_surface_get_user_data +cairo_surface_set_device_offset
@@ -243,6 +246,7 @@ cairo_image_surface_create cairo_image_surface_create_for_data cairo_destroy_func_t cairo_user_data_key_t +cairo_write_func_t CAIRO_API_SHAKEUP_FLAG_DAY CAIRO_BEGIN_DECLS diff --git a/doc/public/tmpl/cairo-pdf.sgml b/doc/public/tmpl/cairo-pdf.sgml index 24fcd9fce..790dd9b93 100644 --- a/doc/public/tmpl/cairo-pdf.sgml +++ b/doc/public/tmpl/cairo-pdf.sgml @@ -23,7 +23,24 @@ PDF Backend @cr: +@write_func: +@destroy_closure_func: +@closure: +@width_inches: +@height_inches: +@x_pixels_per_inch: +@y_pixels_per_inch: + @file: + + + + + + + +@cr: +@fp: @width_inches: @height_inches: @x_pixels_per_inch: @@ -35,7 +52,24 @@ PDF Backend +@write_func: +@destroy_closure_func: +@closure: +@width_inches: +@height_inches: +@x_pixels_per_inch: +@y_pixels_per_inch: +@Returns: + @file: + + + + + + + +@fp: @width_inches: @height_inches: @x_pixels_per_inch: diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml index 65df69fd8..6362d2ba1 100644 --- a/doc/public/tmpl/cairo-surface.sgml +++ b/doc/public/tmpl/cairo-surface.sgml @@ -64,6 +64,15 @@ cairo_surface_t @surface: + + + + + +@surface: +@Returns: + + @@ -137,3 +146,13 @@ cairo_surface_t @Returns: + + + + + +@surface: +@x_offset: +@y_offset: + + diff --git a/doc/public/tmpl/cairo-xlib.sgml b/doc/public/tmpl/cairo-xlib.sgml index b16f5daca..64a7ca509 100644 --- a/doc/public/tmpl/cairo-xlib.sgml +++ b/doc/public/tmpl/cairo-xlib.sgml @@ -85,13 +85,3 @@ XLib Backend @height: - - - - - -@surface: -@x_offset: -@y_offset: - - diff --git a/doc/public/tmpl/cairo.sgml b/doc/public/tmpl/cairo.sgml index 597f236e5..652f5ebdc 100644 --- a/doc/public/tmpl/cairo.sgml +++ b/doc/public/tmpl/cairo.sgml @@ -995,6 +995,8 @@ Drawing contexts. @CAIRO_STATUS_NULL_POINTER: @CAIRO_STATUS_INVALID_STRING: @CAIRO_STATUS_INVALID_PATH_DATA: +@CAIRO_STATUS_WRITE_ERROR: +@CAIRO_STATUS_SURFACE_FINISHED: @@ -1074,3 +1076,14 @@ End: @unused: + + + + + +@closure: +@data: +@length: +@Returns: + + diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index 9a47c20ca..6cb6757fc 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -723,6 +723,26 @@ _cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double return CAIRO_STATUS_SUCCESS; } +static void +_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm, x, y); + if (gstate->surface) { + *x += gstate->surface->device_x_offset; + *y += gstate->surface->device_y_offset; + } +} + +static void +_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) +{ + if (gstate->surface) { + *x -= gstate->surface->device_x_offset; + *y -= gstate->surface->device_y_offset; + } + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); +} + cairo_status_t _cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy) { @@ -744,7 +764,7 @@ _cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y) { cairo_point_t point; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); point.x = _cairo_fixed_from_double (x); point.y = _cairo_fixed_from_double (y); @@ -757,7 +777,7 @@ _cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y) { cairo_point_t point; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); point.x = _cairo_fixed_from_double (x); point.y = _cairo_fixed_from_double (y); @@ -773,9 +793,9 @@ _cairo_gstate_curve_to (cairo_gstate_t *gstate, { cairo_point_t p0, p1, p2; - cairo_matrix_transform_point (&gstate->ctm, &x0, &y0); - cairo_matrix_transform_point (&gstate->ctm, &x1, &y1); - cairo_matrix_transform_point (&gstate->ctm, &x2, &y2); + _cairo_gstate_user_to_backend (gstate, &x0, &y0); + _cairo_gstate_user_to_backend (gstate, &x1, &y1); + _cairo_gstate_user_to_backend (gstate, &x2, &y2); p0.x = _cairo_fixed_from_double (x0); p0.y = _cairo_fixed_from_double (y0); @@ -1146,7 +1166,7 @@ _cairo_gstate_get_current_point (cairo_gstate_t *gstate, double *x_ret, double * } else { x = _cairo_fixed_to_double (point.x); y = _cairo_fixed_to_double (point.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y); + _cairo_gstate_backend_to_user (gstate, &x, &y); } if (x_ret) @@ -1289,6 +1309,11 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, _cairo_path_init_copy (&path, &gstate->path); cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse); + if (gstate->surface) + cairo_matrix_translate (&gpi.ctm_inverse, + - gstate->surface->device_x_offset, + - gstate->surface->device_y_offset); + gpi.tolerance = gstate->tolerance; gpi.move_to = move_to; @@ -1309,6 +1334,20 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, &gpi); } +static void +_cairo_gstate_pattern_transform (cairo_gstate_t *gstate, + cairo_pattern_t *pattern) +{ + cairo_matrix_t tmp_matrix = gstate->ctm_inverse; + + if (gstate->surface) + cairo_matrix_translate (&tmp_matrix, + - gstate->surface->device_x_offset, + - gstate->surface->device_y_offset); + + _cairo_pattern_transform (pattern, &tmp_matrix); +} + /* XXX: gstate->alpha will be going away before too long, and when it * does, it may make sense for this function to just disappear. */ @@ -1318,7 +1357,7 @@ _cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate, cairo_pattern_t *src) { _cairo_pattern_init_copy (&pattern->base, src); - _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse); + _cairo_gstate_pattern_transform (gstate, &pattern->base); _cairo_pattern_set_alpha (&pattern->base, gstate->alpha); } @@ -1363,7 +1402,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); @@ -1658,7 +1697,7 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); _cairo_traps_init (&traps); @@ -1714,8 +1753,8 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate, *x2 = _cairo_fixed_to_double (extents.p2.x); *y2 = _cairo_fixed_to_double (extents.p2.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); - cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + _cairo_gstate_backend_to_user (gstate, x1, y1); + _cairo_gstate_backend_to_user (gstate, x2, y2); BAIL: _cairo_traps_fini (&traps); @@ -1745,8 +1784,8 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate, *x2 = _cairo_fixed_to_double (extents.p2.x); *y2 = _cairo_fixed_to_double (extents.p2.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); - cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + _cairo_gstate_backend_to_user (gstate, x1, y1); + _cairo_gstate_backend_to_user (gstate, x2, y2); BAIL: _cairo_traps_fini (&traps); @@ -2004,9 +2043,9 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, */ cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_matrix_t image_to_user, image_to_device; - double device_x, device_y; - double device_width, device_height; + cairo_matrix_t image_to_user, image_to_device, image_to_backend; + double backend_x, backend_y; + double backend_width, backend_height; cairo_surface_pattern_t pattern; cairo_box_t pattern_extents; cairo_rectangle_t extents; @@ -2014,13 +2053,23 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, cairo_surface_get_matrix (surface, &image_to_user); cairo_matrix_invert (&image_to_user); cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm); + if (gstate->surface) { + cairo_matrix_t device_to_backend; + + _cairo_matrix_set_translate (&device_to_backend, + gstate->surface->device_x_offset, + gstate->surface->device_y_offset); + cairo_matrix_multiply (&image_to_backend, &image_to_device, &device_to_backend); + } else { + image_to_backend = image_to_device; + } - _cairo_gstate_get_current_point (gstate, &device_x, &device_y); - device_width = width; - device_height = height; - _cairo_matrix_transform_bounding_box (&image_to_device, - &device_x, &device_y, - &device_width, &device_height); + _cairo_gstate_get_current_point (gstate, &backend_x, &backend_y); + backend_width = width; + backend_height = height; + _cairo_matrix_transform_bounding_box (&image_to_backend, + &backend_x, &backend_y, + &backend_width, &backend_height); _cairo_pattern_init_for_surface (&pattern, surface); @@ -2033,13 +2082,13 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, else pattern.base.extend = CAIRO_EXTEND_NONE; - _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse); + _cairo_gstate_pattern_transform (gstate, &pattern.base); _cairo_pattern_set_alpha (&pattern.base, gstate->alpha); - pattern_extents.p1.x = _cairo_fixed_from_double (device_x); - pattern_extents.p1.y = _cairo_fixed_from_double (device_y); - pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width); - pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height); + pattern_extents.p1.x = _cairo_fixed_from_double (backend_x); + pattern_extents.p1.y = _cairo_fixed_from_double (backend_y); + pattern_extents.p2.x = _cairo_fixed_from_double (backend_x + backend_width); + pattern_extents.p2.y = _cairo_fixed_from_double (backend_y + backend_height); _cairo_box_round_to_rectangle (&pattern_extents, &extents); if (gstate->clip.surface) @@ -2334,8 +2383,8 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, } else { origin_x = _cairo_fixed_to_double (point.x); origin_y = _cairo_fixed_to_double (point.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, - &origin_x, &origin_y); + _cairo_gstate_backend_to_user (gstate, + &origin_x, &origin_y); } status = _cairo_font_text_to_glyphs (gstate->font, @@ -2417,9 +2466,9 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, for (i = 0; i < num_glyphs; ++i) { transformed_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (&gstate->ctm, - &transformed_glyphs[i].x, - &transformed_glyphs[i].y); + _cairo_gstate_user_to_backend (gstate, + &transformed_glyphs[i].x, + &transformed_glyphs[i].y); } status = _cairo_font_glyph_bbox (gstate->font, @@ -2552,9 +2601,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, for (i = 0; i < num_glyphs; ++i) { transformed_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (&gstate->ctm, - &(transformed_glyphs[i].x), - &(transformed_glyphs[i].y)); + _cairo_gstate_user_to_backend (gstate, + &(transformed_glyphs[i].x), + &(transformed_glyphs[i].y)); } status = _cairo_font_glyph_path (gstate->font, diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 47ed47b7a..f9c84784d 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -59,6 +59,9 @@ _cairo_surface_init (cairo_surface_t *surface, _cairo_matrix_init (&surface->matrix); surface->filter = CAIRO_FILTER_NEAREST; surface->repeat = 0; + + surface->device_x_offset = 0; + surface->device_y_offset = 0; } cairo_surface_t * @@ -290,6 +293,33 @@ cairo_surface_set_user_data (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +/** + * cairo_surface_set_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 + * + * Sets an offset that is added to the device coordinates determined + * by the CTM when drawing to @surface. One use case for this function + * is when we want to create a #cairo_surface_t that redirects drawing + * for a portion of an onscreen surface to an offscreen surface in a + * way that is completely invisible to the user of the cairo + * API. Setting a transformation via cairo_translate() isn't + * sufficient to do this, since functions like + * cairo_inverse_transform_point() will expose the hidden offset. + * + * Note that the offset only affects drawing to the surface, not using + * the surface in a surface pattern. + **/ +void +cairo_surface_set_device_offset (cairo_surface_t *surface, + double x_offset, + double y_offset) +{ + surface->device_x_offset = x_offset; + surface->device_y_offset = y_offset; +} + double _cairo_surface_pixels_per_inch (cairo_surface_t *surface) { diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 3aaa94d6d..fc2f65277 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -105,9 +105,6 @@ struct _cairo_xlib_surface { int height; int depth; - int x_offset; - int y_offset; - Picture picture; }; @@ -252,8 +249,8 @@ _get_image_surface (cairo_xlib_surface_t *surface, if (interest_rect) { cairo_rectangle_t rect; - rect.x = interest_rect->x + surface->x_offset; - rect.y = interest_rect->y + surface->x_offset; + rect.x = interest_rect->x; + rect.y = interest_rect->y; rect.width = interest_rect->width; rect.height = interest_rect->width; @@ -273,8 +270,8 @@ _get_image_surface (cairo_xlib_surface_t *surface, } if (image_rect) { - image_rect->x = x1 - surface->x_offset; - image_rect->y = y1 - surface->y_offset; + image_rect->x = x1; + image_rect->y = y1; image_rect->width = x2 - x1; image_rect->height = y2 - y1; } @@ -396,7 +393,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, _cairo_xlib_surface_ensure_gc (surface); XPutImage(surface->dpy, surface->drawable, surface->gc, - ximage, 0, 0, dst_x + surface->x_offset, dst_y + surface->y_offset, + ximage, 0, 0, dst_x, dst_y, image->width, image->height); /* Foolish XDestroyImage thinks it can free my data, but I won't @@ -735,7 +732,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, src_x + src_attr.x_offset, src_y + src_attr.y_offset, 0, 0, - dst_x + dst->x_offset, dst_y + dst->y_offset, + dst_x, dst_y, width, height); } } @@ -748,20 +745,6 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, return status; } -static void -_translate_rects (cairo_rectangle_t *rects, - int num_rects, - int x_offset, - int y_offset) -{ - int i; - - for (i = 0; i < num_rects; i++) { - rects[i].x += x_offset; - rects[i].y += y_offset; - } -} - static cairo_int_status_t _cairo_xlib_surface_fill_rectangles (void *abstract_surface, cairo_operator_t operator, @@ -780,10 +763,6 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, render_color.blue = color->blue_short; render_color.alpha = color->alpha_short; - if (surface->x_offset != 0 || surface->y_offset != 0) - _translate_rects (rects, num_rects, - surface->x_offset, surface->y_offset); - /* XXX: This XRectangle cast is evil... it needs to go away somehow. */ XRenderFillRectangles (surface->dpy, _render_operator (operator), @@ -793,31 +772,6 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static void -_translate_traps (cairo_trapezoid_t *traps, - int num_traps, - int x_offset, - int y_offset) -{ - cairo_fixed_t xoff, yoff; - int i; - - xoff = _cairo_fixed_from_int (x_offset); - yoff = _cairo_fixed_from_int (y_offset); - - for (i = 0; i < num_traps; i++) { - traps[i].top += yoff; - traps[i].bottom += yoff; - traps[i].left.p1.x += xoff; - traps[i].left.p1.y += yoff; - traps[i].left.p2.x += xoff; - traps[i].left.p2.y += yoff; - traps[i].right.p1.x += xoff; - traps[i].right.p1.y += yoff; - traps[i].right.p2.x += xoff; - traps[i].right.p2.y += yoff; - } -} static cairo_int_status_t _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, @@ -848,9 +802,6 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, if (status) return status; - if (dst->x_offset != 0 || dst->y_offset != 0) - _translate_traps (traps, num_traps, dst->x_offset, dst->y_offset); - if (traps[0].left.p1.y < traps[0].left.p2.y) { render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); @@ -859,8 +810,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); } - render_src_x = src_x + render_reference_x - (dst_x + dst->x_offset); - render_src_y = src_y + render_reference_y - (dst_y + dst->y_offset); + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ status = _cairo_xlib_surface_set_attributes (src, &attributes); @@ -923,8 +874,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, boxes = pixman_region_rects (region); for (i = 0; i < n_boxes; i++) { - rects[i].x = boxes[i].x1 + surface->x_offset; - rects[i].y = boxes[i].y1 + surface->y_offset; + rects[i].x = boxes[i].x1; + rects[i].y = boxes[i].y1; rects[i].width = boxes[i].x2 - boxes[i].x1; rects[i].height = boxes[i].y2 - boxes[i].y1; } @@ -999,8 +950,6 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->owns_pixmap = FALSE; surface->width = -1; surface->height = -1; - surface->x_offset = 0; - surface->y_offset = 0; if (visual) { int i, j, k; @@ -1204,34 +1153,6 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, xlib_surface->height = height; } -/** - * cairo_xlib_surface_set_device_offset: - * @surface: a #cairo_surface_t for the XLib backend - * @x_offset: offset in the X direction, in pixels - * @y_offset: offset in the Y direction, in pixels - * - * Sets an offset that is added to the device coordinates determined - * by the CTM when drawing to @surface. This is useful when we want - * to redirect drawing to a window to a backing pixmap for a portion - * of the window in a way that is completely invisible to the user - * of the Cairo API. Setting a transformation via cairo_translate() isn't - * sufficient to do this, since functions like - * cairo_inverse_transform_point() will expose the hidden offset. - * - * Note that the offset only affects drawing to the surface, not using - * the surface in a surface pattern. - **/ -void -cairo_xlib_surface_set_device_offset (cairo_surface_t *surface, - int x_offset, - int y_offset) -{ - cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *)surface; - - xlib_surface->x_offset = x_offset; - xlib_surface->y_offset = y_offset; -} - /* RENDER glyphset cache code */ typedef struct glyphset_cache { @@ -1488,8 +1409,8 @@ _cairo_xlib_surface_show_glyphs32 (cairo_font_t *font, elts[i].chars = &(chars[i]); elts[i].nchars = 1; elts[i].glyphset = g->glyphset; - thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset; - thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset; + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; elts[i].yOff = thisY - lastY; lastX = thisX; @@ -1565,8 +1486,8 @@ _cairo_xlib_surface_show_glyphs16 (cairo_font_t *font, elts[i].chars = &(chars[i]); elts[i].nchars = 1; elts[i].glyphset = g->glyphset; - thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset; - thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset; + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; elts[i].yOff = thisY - lastY; lastX = thisX; @@ -1641,8 +1562,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo_font_t *font, elts[i].chars = &(chars[i]); elts[i].nchars = 1; elts[i].glyphset = g->glyphset; - thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset; - thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset; + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; elts[i].yOff = thisY - lastY; lastX = thisX; diff --git a/src/cairo-xlib.h b/src/cairo-xlib.h index dc6e81ec6..616ba38bd 100644 --- a/src/cairo-xlib.h +++ b/src/cairo-xlib.h @@ -80,11 +80,6 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); -void -cairo_xlib_surface_set_device_offset (cairo_surface_t *surface, - int x_offset, - int y_offset); - CAIRO_END_DECLS #endif /* CAIRO_HAS_XLIB_SURFACE */ diff --git a/src/cairo.h b/src/cairo.h index e6c27ca8b..e67cf88d6 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -883,6 +883,11 @@ cairo_surface_set_user_data (cairo_surface_t *surface, void *user_data, cairo_destroy_func_t destroy); +void +cairo_surface_set_device_offset (cairo_surface_t *surface, + double x_offset, + double y_offset); + /* Image-surface functions */ cairo_surface_t * diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index 9a47c20ca..6cb6757fc 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -723,6 +723,26 @@ _cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double return CAIRO_STATUS_SUCCESS; } +static void +_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm, x, y); + if (gstate->surface) { + *x += gstate->surface->device_x_offset; + *y += gstate->surface->device_y_offset; + } +} + +static void +_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) +{ + if (gstate->surface) { + *x -= gstate->surface->device_x_offset; + *y -= gstate->surface->device_y_offset; + } + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); +} + cairo_status_t _cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy) { @@ -744,7 +764,7 @@ _cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y) { cairo_point_t point; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); point.x = _cairo_fixed_from_double (x); point.y = _cairo_fixed_from_double (y); @@ -757,7 +777,7 @@ _cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y) { cairo_point_t point; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); point.x = _cairo_fixed_from_double (x); point.y = _cairo_fixed_from_double (y); @@ -773,9 +793,9 @@ _cairo_gstate_curve_to (cairo_gstate_t *gstate, { cairo_point_t p0, p1, p2; - cairo_matrix_transform_point (&gstate->ctm, &x0, &y0); - cairo_matrix_transform_point (&gstate->ctm, &x1, &y1); - cairo_matrix_transform_point (&gstate->ctm, &x2, &y2); + _cairo_gstate_user_to_backend (gstate, &x0, &y0); + _cairo_gstate_user_to_backend (gstate, &x1, &y1); + _cairo_gstate_user_to_backend (gstate, &x2, &y2); p0.x = _cairo_fixed_from_double (x0); p0.y = _cairo_fixed_from_double (y0); @@ -1146,7 +1166,7 @@ _cairo_gstate_get_current_point (cairo_gstate_t *gstate, double *x_ret, double * } else { x = _cairo_fixed_to_double (point.x); y = _cairo_fixed_to_double (point.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y); + _cairo_gstate_backend_to_user (gstate, &x, &y); } if (x_ret) @@ -1289,6 +1309,11 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, _cairo_path_init_copy (&path, &gstate->path); cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse); + if (gstate->surface) + cairo_matrix_translate (&gpi.ctm_inverse, + - gstate->surface->device_x_offset, + - gstate->surface->device_y_offset); + gpi.tolerance = gstate->tolerance; gpi.move_to = move_to; @@ -1309,6 +1334,20 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, &gpi); } +static void +_cairo_gstate_pattern_transform (cairo_gstate_t *gstate, + cairo_pattern_t *pattern) +{ + cairo_matrix_t tmp_matrix = gstate->ctm_inverse; + + if (gstate->surface) + cairo_matrix_translate (&tmp_matrix, + - gstate->surface->device_x_offset, + - gstate->surface->device_y_offset); + + _cairo_pattern_transform (pattern, &tmp_matrix); +} + /* XXX: gstate->alpha will be going away before too long, and when it * does, it may make sense for this function to just disappear. */ @@ -1318,7 +1357,7 @@ _cairo_gstate_pattern_init_copy (cairo_gstate_t *gstate, cairo_pattern_t *src) { _cairo_pattern_init_copy (&pattern->base, src); - _cairo_pattern_transform (&pattern->base, &gstate->ctm_inverse); + _cairo_gstate_pattern_transform (gstate, &pattern->base); _cairo_pattern_set_alpha (&pattern->base, gstate->alpha); } @@ -1363,7 +1402,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); @@ -1658,7 +1697,7 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_traps_t traps; - cairo_matrix_transform_point (&gstate->ctm, &x, &y); + _cairo_gstate_user_to_backend (gstate, &x, &y); _cairo_traps_init (&traps); @@ -1714,8 +1753,8 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate, *x2 = _cairo_fixed_to_double (extents.p2.x); *y2 = _cairo_fixed_to_double (extents.p2.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); - cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + _cairo_gstate_backend_to_user (gstate, x1, y1); + _cairo_gstate_backend_to_user (gstate, x2, y2); BAIL: _cairo_traps_fini (&traps); @@ -1745,8 +1784,8 @@ _cairo_gstate_fill_extents (cairo_gstate_t *gstate, *x2 = _cairo_fixed_to_double (extents.p2.x); *y2 = _cairo_fixed_to_double (extents.p2.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); - cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + _cairo_gstate_backend_to_user (gstate, x1, y1); + _cairo_gstate_backend_to_user (gstate, x2, y2); BAIL: _cairo_traps_fini (&traps); @@ -2004,9 +2043,9 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, */ cairo_status_t status = CAIRO_STATUS_SUCCESS; - cairo_matrix_t image_to_user, image_to_device; - double device_x, device_y; - double device_width, device_height; + cairo_matrix_t image_to_user, image_to_device, image_to_backend; + double backend_x, backend_y; + double backend_width, backend_height; cairo_surface_pattern_t pattern; cairo_box_t pattern_extents; cairo_rectangle_t extents; @@ -2014,13 +2053,23 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, cairo_surface_get_matrix (surface, &image_to_user); cairo_matrix_invert (&image_to_user); cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm); + if (gstate->surface) { + cairo_matrix_t device_to_backend; + + _cairo_matrix_set_translate (&device_to_backend, + gstate->surface->device_x_offset, + gstate->surface->device_y_offset); + cairo_matrix_multiply (&image_to_backend, &image_to_device, &device_to_backend); + } else { + image_to_backend = image_to_device; + } - _cairo_gstate_get_current_point (gstate, &device_x, &device_y); - device_width = width; - device_height = height; - _cairo_matrix_transform_bounding_box (&image_to_device, - &device_x, &device_y, - &device_width, &device_height); + _cairo_gstate_get_current_point (gstate, &backend_x, &backend_y); + backend_width = width; + backend_height = height; + _cairo_matrix_transform_bounding_box (&image_to_backend, + &backend_x, &backend_y, + &backend_width, &backend_height); _cairo_pattern_init_for_surface (&pattern, surface); @@ -2033,13 +2082,13 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, else pattern.base.extend = CAIRO_EXTEND_NONE; - _cairo_pattern_transform (&pattern.base, &gstate->ctm_inverse); + _cairo_gstate_pattern_transform (gstate, &pattern.base); _cairo_pattern_set_alpha (&pattern.base, gstate->alpha); - pattern_extents.p1.x = _cairo_fixed_from_double (device_x); - pattern_extents.p1.y = _cairo_fixed_from_double (device_y); - pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width); - pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height); + pattern_extents.p1.x = _cairo_fixed_from_double (backend_x); + pattern_extents.p1.y = _cairo_fixed_from_double (backend_y); + pattern_extents.p2.x = _cairo_fixed_from_double (backend_x + backend_width); + pattern_extents.p2.y = _cairo_fixed_from_double (backend_y + backend_height); _cairo_box_round_to_rectangle (&pattern_extents, &extents); if (gstate->clip.surface) @@ -2334,8 +2383,8 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate, } else { origin_x = _cairo_fixed_to_double (point.x); origin_y = _cairo_fixed_to_double (point.y); - cairo_matrix_transform_point (&gstate->ctm_inverse, - &origin_x, &origin_y); + _cairo_gstate_backend_to_user (gstate, + &origin_x, &origin_y); } status = _cairo_font_text_to_glyphs (gstate->font, @@ -2417,9 +2466,9 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, for (i = 0; i < num_glyphs; ++i) { transformed_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (&gstate->ctm, - &transformed_glyphs[i].x, - &transformed_glyphs[i].y); + _cairo_gstate_user_to_backend (gstate, + &transformed_glyphs[i].x, + &transformed_glyphs[i].y); } status = _cairo_font_glyph_bbox (gstate->font, @@ -2552,9 +2601,9 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, for (i = 0; i < num_glyphs; ++i) { transformed_glyphs[i] = glyphs[i]; - cairo_matrix_transform_point (&gstate->ctm, - &(transformed_glyphs[i].x), - &(transformed_glyphs[i].y)); + _cairo_gstate_user_to_backend (gstate, + &(transformed_glyphs[i].x), + &(transformed_glyphs[i].y)); } status = _cairo_font_glyph_path (gstate->font, diff --git a/src/cairo_surface.c b/src/cairo_surface.c index 47ed47b7a..f9c84784d 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -59,6 +59,9 @@ _cairo_surface_init (cairo_surface_t *surface, _cairo_matrix_init (&surface->matrix); surface->filter = CAIRO_FILTER_NEAREST; surface->repeat = 0; + + surface->device_x_offset = 0; + surface->device_y_offset = 0; } cairo_surface_t * @@ -290,6 +293,33 @@ cairo_surface_set_user_data (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +/** + * cairo_surface_set_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 + * + * Sets an offset that is added to the device coordinates determined + * by the CTM when drawing to @surface. One use case for this function + * is when we want to create a #cairo_surface_t that redirects drawing + * for a portion of an onscreen surface to an offscreen surface in a + * way that is completely invisible to the user of the cairo + * API. Setting a transformation via cairo_translate() isn't + * sufficient to do this, since functions like + * cairo_inverse_transform_point() will expose the hidden offset. + * + * Note that the offset only affects drawing to the surface, not using + * the surface in a surface pattern. + **/ +void +cairo_surface_set_device_offset (cairo_surface_t *surface, + double x_offset, + double y_offset) +{ + surface->device_x_offset = x_offset; + surface->device_y_offset = y_offset; +} + double _cairo_surface_pixels_per_inch (cairo_surface_t *surface) { diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index 3aaa94d6d..fc2f65277 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -105,9 +105,6 @@ struct _cairo_xlib_surface { int height; int depth; - int x_offset; - int y_offset; - Picture picture; }; @@ -252,8 +249,8 @@ _get_image_surface (cairo_xlib_surface_t *surface, if (interest_rect) { cairo_rectangle_t rect; - rect.x = interest_rect->x + surface->x_offset; - rect.y = interest_rect->y + surface->x_offset; + rect.x = interest_rect->x; + rect.y = interest_rect->y; rect.width = interest_rect->width; rect.height = interest_rect->width; @@ -273,8 +270,8 @@ _get_image_surface (cairo_xlib_surface_t *surface, } if (image_rect) { - image_rect->x = x1 - surface->x_offset; - image_rect->y = y1 - surface->y_offset; + image_rect->x = x1; + image_rect->y = y1; image_rect->width = x2 - x1; image_rect->height = y2 - y1; } @@ -396,7 +393,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, _cairo_xlib_surface_ensure_gc (surface); XPutImage(surface->dpy, surface->drawable, surface->gc, - ximage, 0, 0, dst_x + surface->x_offset, dst_y + surface->y_offset, + ximage, 0, 0, dst_x, dst_y, image->width, image->height); /* Foolish XDestroyImage thinks it can free my data, but I won't @@ -735,7 +732,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, src_x + src_attr.x_offset, src_y + src_attr.y_offset, 0, 0, - dst_x + dst->x_offset, dst_y + dst->y_offset, + dst_x, dst_y, width, height); } } @@ -748,20 +745,6 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, return status; } -static void -_translate_rects (cairo_rectangle_t *rects, - int num_rects, - int x_offset, - int y_offset) -{ - int i; - - for (i = 0; i < num_rects; i++) { - rects[i].x += x_offset; - rects[i].y += y_offset; - } -} - static cairo_int_status_t _cairo_xlib_surface_fill_rectangles (void *abstract_surface, cairo_operator_t operator, @@ -780,10 +763,6 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, render_color.blue = color->blue_short; render_color.alpha = color->alpha_short; - if (surface->x_offset != 0 || surface->y_offset != 0) - _translate_rects (rects, num_rects, - surface->x_offset, surface->y_offset); - /* XXX: This XRectangle cast is evil... it needs to go away somehow. */ XRenderFillRectangles (surface->dpy, _render_operator (operator), @@ -793,31 +772,6 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } -static void -_translate_traps (cairo_trapezoid_t *traps, - int num_traps, - int x_offset, - int y_offset) -{ - cairo_fixed_t xoff, yoff; - int i; - - xoff = _cairo_fixed_from_int (x_offset); - yoff = _cairo_fixed_from_int (y_offset); - - for (i = 0; i < num_traps; i++) { - traps[i].top += yoff; - traps[i].bottom += yoff; - traps[i].left.p1.x += xoff; - traps[i].left.p1.y += yoff; - traps[i].left.p2.x += xoff; - traps[i].left.p2.y += yoff; - traps[i].right.p1.x += xoff; - traps[i].right.p1.y += yoff; - traps[i].right.p2.x += xoff; - traps[i].right.p2.y += yoff; - } -} static cairo_int_status_t _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, @@ -848,9 +802,6 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, if (status) return status; - if (dst->x_offset != 0 || dst->y_offset != 0) - _translate_traps (traps, num_traps, dst->x_offset, dst->y_offset); - if (traps[0].left.p1.y < traps[0].left.p2.y) { render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x); render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y); @@ -859,8 +810,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y); } - render_src_x = src_x + render_reference_x - (dst_x + dst->x_offset); - render_src_y = src_y + render_reference_y - (dst_y + dst->y_offset); + render_src_x = src_x + render_reference_x - dst_x; + render_src_y = src_y + render_reference_y - dst_y; /* XXX: The XTrapezoid cast is evil and needs to go away somehow. */ status = _cairo_xlib_surface_set_attributes (src, &attributes); @@ -923,8 +874,8 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, boxes = pixman_region_rects (region); for (i = 0; i < n_boxes; i++) { - rects[i].x = boxes[i].x1 + surface->x_offset; - rects[i].y = boxes[i].y1 + surface->y_offset; + rects[i].x = boxes[i].x1; + rects[i].y = boxes[i].y1; rects[i].width = boxes[i].x2 - boxes[i].x1; rects[i].height = boxes[i].y2 - boxes[i].y1; } @@ -999,8 +950,6 @@ _cairo_xlib_surface_create_internal (Display *dpy, surface->owns_pixmap = FALSE; surface->width = -1; surface->height = -1; - surface->x_offset = 0; - surface->y_offset = 0; if (visual) { int i, j, k; @@ -1204,34 +1153,6 @@ cairo_xlib_surface_set_size (cairo_surface_t *surface, xlib_surface->height = height; } -/** - * cairo_xlib_surface_set_device_offset: - * @surface: a #cairo_surface_t for the XLib backend - * @x_offset: offset in the X direction, in pixels - * @y_offset: offset in the Y direction, in pixels - * - * Sets an offset that is added to the device coordinates determined - * by the CTM when drawing to @surface. This is useful when we want - * to redirect drawing to a window to a backing pixmap for a portion - * of the window in a way that is completely invisible to the user - * of the Cairo API. Setting a transformation via cairo_translate() isn't - * sufficient to do this, since functions like - * cairo_inverse_transform_point() will expose the hidden offset. - * - * Note that the offset only affects drawing to the surface, not using - * the surface in a surface pattern. - **/ -void -cairo_xlib_surface_set_device_offset (cairo_surface_t *surface, - int x_offset, - int y_offset) -{ - cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *)surface; - - xlib_surface->x_offset = x_offset; - xlib_surface->y_offset = y_offset; -} - /* RENDER glyphset cache code */ typedef struct glyphset_cache { @@ -1488,8 +1409,8 @@ _cairo_xlib_surface_show_glyphs32 (cairo_font_t *font, elts[i].chars = &(chars[i]); elts[i].nchars = 1; elts[i].glyphset = g->glyphset; - thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset; - thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset; + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; elts[i].yOff = thisY - lastY; lastX = thisX; @@ -1565,8 +1486,8 @@ _cairo_xlib_surface_show_glyphs16 (cairo_font_t *font, elts[i].chars = &(chars[i]); elts[i].nchars = 1; elts[i].glyphset = g->glyphset; - thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset; - thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset; + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; elts[i].yOff = thisY - lastY; lastX = thisX; @@ -1641,8 +1562,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo_font_t *font, elts[i].chars = &(chars[i]); elts[i].nchars = 1; elts[i].glyphset = g->glyphset; - thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset; - thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset; + thisX = (int) floor (glyphs[i].x + 0.5); + thisY = (int) floor (glyphs[i].y + 0.5); elts[i].xOff = thisX - lastX; elts[i].yOff = thisY - lastY; lastX = thisX; diff --git a/src/cairoint.h b/src/cairoint.h index 1c3ad6e62..d6c1b8e7f 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -673,6 +673,9 @@ struct _cairo_surface { cairo_matrix_t matrix; cairo_filter_t filter; int repeat; + + double device_x_offset; + double device_y_offset; }; struct _cairo_image_surface {