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().

Take the surface's device offset into account.
Update.
This commit is contained in:
Owen Taylor 2005-03-17 12:57:42 +00:00
parent 0b09748296
commit e66e4c7b8c
15 changed files with 350 additions and 276 deletions

View file

@ -1,3 +1,14 @@
2005-03-17 Owen Taylor <otaylor@redhat.com>
* 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 <otaylor@redhat.com>
* src/cairo_matrix.c: Fix the docs to to correctly describe

View file

@ -25,7 +25,9 @@ cairo_glitz_surface_create
<FILE>cairo-pdf</FILE>
<TITLE>PDF Backend</TITLE>
cairo_set_target_pdf
cairo_set_target_pdf_as_file
cairo_pdf_surface_create
cairo_pdf_surface_create_for_file
</SECTION>
<SECTION>
@ -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
</SECTION>
<SECTION>
@ -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
</SECTION>
<SECTION>
@ -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
<SUBSECTION Private>
CAIRO_API_SHAKEUP_FLAG_DAY
CAIRO_BEGIN_DECLS

View file

@ -23,7 +23,24 @@ PDF Backend
</para>
@cr:
@write_func:
@destroy_closure_func:
@closure:
@width_inches:
@height_inches:
@x_pixels_per_inch:
@y_pixels_per_inch:
<!-- # Unused Parameters # -->
@file:
<!-- ##### FUNCTION cairo_set_target_pdf_as_file ##### -->
<para>
</para>
@cr:
@fp:
@width_inches:
@height_inches:
@x_pixels_per_inch:
@ -35,7 +52,24 @@ PDF Backend
</para>
@write_func:
@destroy_closure_func:
@closure:
@width_inches:
@height_inches:
@x_pixels_per_inch:
@y_pixels_per_inch:
@Returns:
<!-- # Unused Parameters # -->
@file:
<!-- ##### FUNCTION cairo_pdf_surface_create_for_file ##### -->
<para>
</para>
@fp:
@width_inches:
@height_inches:
@x_pixels_per_inch:

View file

@ -64,6 +64,15 @@ cairo_surface_t
@surface:
<!-- ##### FUNCTION cairo_surface_finish ##### -->
<para>
</para>
@surface:
@Returns:
<!-- ##### FUNCTION cairo_surface_set_repeat ##### -->
<para>
@ -137,3 +146,13 @@ cairo_surface_t
@Returns:
<!-- ##### FUNCTION cairo_surface_set_device_offset ##### -->
<para>
</para>
@surface:
@x_offset:
@y_offset:

View file

@ -85,13 +85,3 @@ XLib Backend
@height:
<!-- ##### FUNCTION cairo_xlib_surface_set_device_offset ##### -->
<para>
</para>
@surface:
@x_offset:
@y_offset:

View file

@ -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:
<!-- ##### FUNCTION cairo_status ##### -->
<para>
@ -1074,3 +1076,14 @@ End:
@unused:
<!-- ##### USER_FUNCTION cairo_write_func_t ##### -->
<para>
</para>
@closure:
@data:
@length:
@Returns:

View file

@ -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,

View file

@ -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)
{

View file

@ -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;

View file

@ -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 */

View file

@ -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 *

View file

@ -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,

View file

@ -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)
{

View file

@ -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;

View file

@ -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 {