src/cairo-xlib.h src/cairo_xlib_surface.c: Rework set of contructors for XLib surfaces. Add cairo_xlib_surface_set_size().

src/cairo-xlib.h src/cairo_xlib_surface.c: Add cairo_xlib_surface_set_device_offset().
Rewrite for clarity and efficiency.
Use a temporary pixmap to avoid possible BadMatch when fetch from windows.
src/cairo.[ch] src/cairo-xlib.h: Fix some parameter names for the docs.
Update
This commit is contained in:
Owen Taylor 2005-03-15 16:25:30 +00:00
parent 30e771d811
commit 5fecf69e2c
9 changed files with 957 additions and 340 deletions

View file

@ -1,3 +1,24 @@
2005-03-15 Owen Taylor <otaylor@redhat.com>
* src/cairo-xlib.h src/cairo_xlib_surface.c: Rework set
of contructors for XLib surfaces. Add
cairo_xlib_surface_set_size().
* src/cairo-xlib.h src/cairo_xlib_surface.c: Add
cairo_xlib_surface_set_device_offset().
* src/cairo_xlib_surface.c (cairo_xlib_surface_set_clip_region):
Rewrite for clarity and efficiency.
* src/cairo_xlib_surface.c (_get_image_surface): Use a
temporary pixmap to avoid possible BadMatch when fetch
from windows.
* src/cairo.[ch] src/cairo-xlib.h: Fix some parameter names
for the docs.
* doc/public/cairo-sections.txt: Update
2005-03-14 Carl Worth <cworth@cworth.org>
* test/path_data-ref.png: Add reference image.

View file

@ -71,6 +71,11 @@ cairo_set_target_xcb
<TITLE>XLib Backend</TITLE>
cairo_set_target_drawable
cairo_xlib_surface_create
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>

View file

@ -120,9 +120,11 @@ cairo_surface_t
@surface:
@key:
@data:
@user_data:
@destroy:
@Returns:
<!-- # Unused Parameters # -->
@data:
<!-- ##### FUNCTION cairo_surface_get_user_data ##### -->

View file

@ -40,3 +40,58 @@ XLib Backend
@Returns:
<!-- ##### FUNCTION cairo_xlib_surface_create_for_pixmap ##### -->
<para>
</para>
@dpy:
@pixmap:
@format:
@Returns:
<!-- # Unused Parameters # -->
@drawable:
<!-- ##### FUNCTION cairo_xlib_surface_create_for_pixmap_with_visual ##### -->
<para>
</para>
@dpy:
@pixmap:
@visual:
@Returns:
<!-- ##### FUNCTION cairo_xlib_surface_create_for_window_with_visual ##### -->
<para>
</para>
@dpy:
@window:
@visual:
@Returns:
<!-- ##### FUNCTION cairo_xlib_surface_set_size ##### -->
<para>
</para>
@surface:
@width:
@height:
<!-- ##### FUNCTION cairo_xlib_surface_set_device_offset ##### -->
<para>
</para>
@surface:
@x_offset:
@y_offset:

View file

@ -37,6 +37,15 @@
#include "cairoint.h"
#include "cairo-xlib.h"
typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
typedef enum {
CAIRO_XLIB_PIXMAP,
CAIRO_XLIB_WINDOW
} cairo_xlib_drawable_type_t;
static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
/**
* cairo_set_target_drawable:
* @cr: a #cairo_t
@ -78,24 +87,29 @@ cairo_set_target_drawable (cairo_t *cr,
cairo_surface_destroy (surface);
}
typedef struct _cairo_xlib_surface {
struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
GC gc;
Drawable drawable;
int owns_pixmap;
cairo_bool_t owns_pixmap;
Visual *visual;
cairo_format_t format;
int render_major;
int render_minor;
cairo_xlib_drawable_type_t type;
int width;
int height;
int depth;
int x_offset;
int y_offset;
Picture picture;
} cairo_xlib_surface_t;
};
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
(((surface)->render_major > major) || \
@ -136,16 +150,6 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
}
}
static cairo_surface_t *
_cairo_xlib_surface_create_with_size (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap,
int width,
int height);
static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
@ -173,13 +177,10 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface_t *)
_cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
DefaultColormap (dpy, scr),
width, height);
surface->owns_pixmap = 1;
surface->width = width;
surface->height = height;
cairo_xlib_surface_create_for_pixmap (dpy, pix, format);
cairo_xlib_surface_set_size (&surface->base, width, height);
surface->owns_pixmap = TRUE;
return &surface->base;
}
@ -197,7 +198,7 @@ _cairo_xlib_surface_destroy (void *abstract_surface)
if (surface->gc)
XFreeGC (surface->dpy, surface->gc);
surface->dpy = 0;
surface->dpy = NULL;
free (surface);
}
@ -217,30 +218,53 @@ _get_image_surface (cairo_xlib_surface_t *surface,
{
cairo_image_surface_t *image;
XImage *ximage;
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
int x1, y1, x2, y2;
XGetGeometry (surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
x1 = 0;
y1 = 0;
x2 = surface->width;
y2 = surface->height;
if (surface->width >= 0 && surface->height >= 0) {
x2 = surface->width;
y2 = surface->height;
} else {
int width, height;
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
XGetGeometry (surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&width, &height,
&bwidth_ignore, &depth_ignore);
/* The size of a pixmap can't change, so we store
* the information to avoid having to get it again
*/
if (surface->type == CAIRO_XLIB_PIXMAP) {
surface->width = width;
surface->height = height;
}
x2 = width;
y2 = height;
}
if (interest_rect) {
if (interest_rect->x > x1)
x1 = interest_rect->x;
if (interest_rect->y > y1)
y1 = interest_rect->y;
if (interest_rect->x + interest_rect->width < x2)
x2 = interest_rect->x + interest_rect->width;
if (interest_rect->y + interest_rect->height < y2)
y2 = interest_rect->y + interest_rect->height;
cairo_rectangle_t rect;
rect.x = interest_rect->x + surface->x_offset;
rect.y = interest_rect->y + surface->x_offset;
rect.width = interest_rect->width;
rect.height = interest_rect->width;
if (rect.x > x1)
x1 = rect.x;
if (rect.y > y1)
y1 = rect.y;
if (rect.x + rect.width < x2)
x2 = rect.x + rect.width;
if (rect.y + rect.height < y2)
y2 = rect.y + rect.height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
@ -249,18 +273,46 @@ _get_image_surface (cairo_xlib_surface_t *surface,
}
if (image_rect) {
image_rect->x = x1;
image_rect->y = y1;
image_rect->x = x1 - surface->x_offset;
image_rect->y = y1 - surface->y_offset;
image_rect->width = x2 - x1;
image_rect->height = y2 - y1;
}
/* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
x1, y1,
x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
/* XXX: This should try to use the XShm extension if available */
if (surface->type == CAIRO_XLIB_WINDOW) {
/* XGetImage from a window is dangerous because it can
* produce errors if the window is unmapped or partially
* outside the screen. We could check for errors and
* retry, but to keep things simple, we just create a
* temporary pixmap
*/
Pixmap pixmap = XCreatePixmap (surface->dpy,
surface->drawable,
x2 - x1, y2 - y1,
surface->depth);
_cairo_xlib_surface_ensure_gc (surface);
XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
x1, y1, x2 - x1, y2 - y1, 0, 0);
ximage = XGetImage (surface->dpy,
pixmap,
0, 0,
x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
XFreePixmap (surface->dpy, pixmap);
} else {
ximage = XGetImage (surface->dpy,
surface->drawable,
x1, y1,
x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
}
if (surface->visual) {
cairo_format_masks_t masks;
@ -303,10 +355,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
static void
_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
{
XGCValues gcv;
if (surface->gc)
return;
surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
gcv.graphics_exposures = False;
surface->gc = XCreateGC (surface->dpy, surface->drawable,
GCGraphicsExposures, &gcv);
}
static cairo_status_t
@ -340,7 +396,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, dst_y,
ximage, 0, 0, dst_x + surface->x_offset, dst_y + surface->y_offset,
image->width, image->height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
@ -679,7 +735,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_y,
dst_x + dst->x_offset, dst_y + dst->y_offset,
width, height);
}
}
@ -692,6 +748,20 @@ _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,
@ -710,6 +780,10 @@ _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),
@ -719,6 +793,31 @@ _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,
@ -749,6 +848,9 @@ _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);
@ -757,8 +859,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;
render_src_y = src_y + render_reference_y - dst_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);
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
status = _cairo_xlib_surface_set_attributes (src, &attributes);
@ -789,66 +891,55 @@ _cairo_xlib_surface_show_page (void *abstract_surface)
}
static cairo_int_status_t
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
Region xregion;
XRectangle xr;
XRectangle *rects = NULL;
XGCValues gc_values;
pixman_box16_t *box;
cairo_xlib_surface_t *surf;
int n, m;
surf = (cairo_xlib_surface_t *) abstract_surface;
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (region == NULL) {
/* NULL region == reset the clip */
xregion = XCreateRegion();
xr.x = 0;
xr.y = 0;
xr.width = surf->width;
xr.height = surf->height;
XUnionRectWithRegion (&xr, xregion, xregion);
rects = malloc(sizeof(XRectangle));
if (rects == NULL)
return CAIRO_STATUS_NO_MEMORY;
rects[0] = xr;
m = 1;
} else {
n = pixman_region_num_rects (region);
/* XXX: Are we sure these are the semantics we want for an
* empty, (not null) region? */
if (n == 0)
return CAIRO_STATUS_SUCCESS;
rects = malloc(sizeof(XRectangle) * n);
if (rects == NULL)
return CAIRO_STATUS_NO_MEMORY;
box = pixman_region_rects (region);
xregion = XCreateRegion();
if (surface->gc)
XSetClipMask (surface->dpy, surface->gc, None);
m = n;
for (; n > 0; --n, ++box) {
xr.x = (short) box->x1;
xr.y = (short) box->y1;
xr.width = (unsigned short) (box->x2 - box->x1);
xr.height = (unsigned short) (box->y2 - box->y1);
rects[n-1] = xr;
XUnionRectWithRegion (&xr, xregion, xregion);
}
if (surface->picture) {
XRenderPictureAttributes pa;
pa.clip_mask = None;
XRenderChangePicture (surface->dpy, surface->picture,
CPClipMask, &pa);
}
} else {
pixman_box16_t *boxes;
XRectangle *rects = NULL;
int n_boxes, i;
n_boxes = pixman_region_num_rects (region);
if (n_boxes > 0) {
rects = malloc (sizeof(XRectangle) * n_boxes);
if (rects == NULL)
return CAIRO_STATUS_NO_MEMORY;
} else {
rects = NULL;
}
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].width = boxes[i].x2 - boxes[i].x1;
rects[i].height = boxes[i].y2 - boxes[i].y1;
}
if (surface->gc)
XSetClipRectangles(surface->dpy, surface->gc,
0, 0, rects, n_boxes, YXSorted);
if (surface->picture)
XRenderSetPictureClipRectangles (surface->dpy, surface->picture,
0, 0, rects, n_boxes);
if (rects)
free (rects);
}
_cairo_xlib_surface_ensure_gc (surf);
XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
XSetGraphicsExposures(surf->dpy, surf->gc, False);
XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
free(rects);
if (surf->picture)
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
XDestroyRegion(xregion);
XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
@ -885,16 +976,13 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
};
static cairo_surface_t *
_cairo_xlib_surface_create_with_size (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap,
int width,
int height)
_cairo_xlib_surface_create_internal (Display *dpy,
Drawable drawable,
cairo_xlib_drawable_type_t type,
Visual *visual,
cairo_format_t format)
{
cairo_xlib_surface_t *surface;
int render_standard;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@ -902,48 +990,85 @@ _cairo_xlib_surface_create_with_size (Display *dpy,
_cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
surface->visual = visual;
surface->format = format;
surface->type = type;
surface->dpy = dpy;
surface->gc = 0;
surface->gc = NULL;
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
surface->width = width;
surface->height = height;
surface->owns_pixmap = FALSE;
surface->width = -1;
surface->height = -1;
surface->x_offset = 0;
surface->y_offset = 0;
if (visual) {
int i, j, k;
surface->format = (cairo_format_t)-1;
/* This is ugly, but we have to walk over all visuals
* for the display to find the depth.
*/
for (i = 0; i < ScreenCount (dpy); i++) {
Screen *screen = ScreenOfDisplay (dpy, i);
for (j = 0; j < screen->ndepths; j++) {
Depth *depth = &screen->depths[j];
for (k = 0; k < depth->nvisuals; k++) {
if (&depth->visuals[k] == visual)
surface->depth = depth->depth;
goto found;
}
}
}
found:
surface->visual = visual;
} else {
surface->format = format;
surface->depth = _CAIRO_FORMAT_DEPTH (format);
surface->visual = NULL;
}
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
switch (format) {
case CAIRO_FORMAT_A1:
render_standard = PictStandardA1;
break;
case CAIRO_FORMAT_A8:
render_standard = PictStandardA8;
break;
case CAIRO_FORMAT_RGB24:
render_standard = PictStandardRGB24;
break;
case CAIRO_FORMAT_ARGB32:
default:
render_standard = PictStandardARGB32;
break;
}
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
XRenderPictFormat *render_format;
if (visual) {
render_format = XRenderFindVisualFormat (dpy, visual);
} else {
int render_standard;
switch (format) {
case CAIRO_FORMAT_A1:
render_standard = PictStandardA1;
break;
case CAIRO_FORMAT_A8:
render_standard = PictStandardA8;
break;
case CAIRO_FORMAT_RGB24:
render_standard = PictStandardRGB24;
break;
case CAIRO_FORMAT_ARGB32:
default:
render_standard = PictStandardARGB32;
break;
}
render_format = XRenderFindStandardFormat (dpy, render_standard);
}
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
visual ?
XRenderFindVisualFormat (dpy, visual) :
XRenderFindStandardFormat (dpy, render_standard),
0, NULL);
else
surface->picture = 0;
render_format, 0, NULL);
} else
surface->picture = None;
return (cairo_surface_t *) surface;
}
@ -955,24 +1080,158 @@ cairo_xlib_surface_create (Display *dpy,
cairo_format_t format,
Colormap colormap)
{
Window window_ignore;
unsigned int int_ignore;
unsigned int width, height;
/* XXX: This call is a round-trip. We probably want to instead (or
* also?) export a version that accepts width/height. Then, we'll
* likely also need a resize function too.
/* Just assume a window ... slow but safe. This function is
* going away anyways
*/
XGetGeometry(dpy, drawable,
&window_ignore, &int_ignore, &int_ignore,
&width, &height,
&int_ignore, &int_ignore);
return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format,
colormap, width, height);
return _cairo_xlib_surface_create_internal (dpy, drawable,
CAIRO_XLIB_WINDOW,
visual,
format);
}
DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
/**
* cairo_xlib_surface_create_for_pixmap:
* @dpy: an X display
* @pixmap: an X pixmap
* @format: a standard Cairo pixel data format. The depth (number of
* of bits used) for the format must match the depth of
* @pixmap.
*
* Creates an Xlib surface that draws to the given pixmap.
* The way that colors are represented in the pixmap is specified
* by giving one of Cairo's standard pixel data formats.
*
* For maximum efficiency, if you know the size of the pixmap,
* you should call cairo_xlib_surface_set_size().
*
* Return value: the newly created surface
**/
cairo_surface_t *
cairo_xlib_surface_create_for_pixmap (Display *dpy,
Pixmap pixmap,
cairo_format_t format)
{
return _cairo_xlib_surface_create_internal (dpy, pixmap,
CAIRO_XLIB_PIXMAP,
NULL, format);
}
/**
* cairo_xlib_surface_create_for_pixmap_with_visual:
* @dpy: an X display
* @pixmap: an X pixmap
* @visual: the visual to use for drawing to @pixmap. The depth
* of the visual must match the depth of the pixmap.
* Currently, only TrueColor visuals are fully supported.
*
* Creates an Xlib surface that draws to the given pixmap.
* The way that colors are represented in the pixmap is specified
* by an X visual.
*
* Normally, you would use this function instead of
* cairo_xlib_surface_create_for_pixmap() when you double-buffering by
* using Cairo to draw to pixmap and then XCopyArea() to copy the
* results to a window. In that case, @visual is the visual of the
* window.
*
* For maximum efficiency, if you know the size of the pixmap,
* you should call cairo_xlib_surface_set_size().
*
* Return value: the newly created surface
**/
cairo_surface_t *
cairo_xlib_surface_create_for_pixmap_with_visual (Display *dpy,
Pixmap pixmap,
Visual *visual)
{
return _cairo_xlib_surface_create_internal (dpy, pixmap,
CAIRO_XLIB_PIXMAP,
visual,
(cairo_format_t)-1);
}
/**
* cairo_xlib_surface_create_for_window_with_visual:
* @dpy: an X display
* @window: an X window
* @visual: the visual of @window. Currently, only TrueColor visuals
* are fully supported.
*
* Creates a new XLib backend surface that draws to the given Window.
*
* For maximum efficiency, you should use cairo_xlib_surface_set_size()
* to inform Cairo of the size of the window.
*
* Return value: the newly created surface.
**/
cairo_surface_t *
cairo_xlib_surface_create_for_window_with_visual (Display *dpy,
Window window,
Visual *visual)
{
return _cairo_xlib_surface_create_internal (dpy, window,
CAIRO_XLIB_WINDOW,
visual,
(cairo_format_t)-1);
}
/**
* cairo_xlib_surface_set_size:
* @surface: a #cairo_surface_t for the XLib backend
* @width: the new width of the surface
* @height: the new height of the surface
*
* Informs Cairo of the size of the X drawable underlying the
* surface. This allows Cairo to avoid querying the server for the
* size, which can be a significant performance bottleneck.
*
* For a surface created for a pixmap, it is only necessary to call
* this function once, since pixmaps have a fixed size. For a surface
* created for a window, you should call this function each time the
* window changes size. (For a subwindow, you are normally resizing
* the window yourself, but for a toplevel window, it is necessary
* to listen for ConfigureNotify events.)
**/
void
cairo_xlib_surface_set_size (cairo_surface_t *surface,
int width,
int height)
{
cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *)surface;
xlib_surface->width = width;
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 {
@ -1229,8 +1488,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);
thisY = (int) floor (glyphs[i].y + 0.5);
thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset;
thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset;
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;
@ -1306,8 +1565,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);
thisY = (int) floor (glyphs[i].y + 0.5);
thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset;
thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset;
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;
@ -1382,8 +1641,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);
thisY = (int) floor (glyphs[i].y + 0.5);
thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset;
thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset;
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;

View file

@ -45,29 +45,45 @@
CAIRO_BEGIN_DECLS
/* XXX: This shold be renamed to cairo_set_target_xlib to match the
/* XXX: This should be renamed to cairo_set_target_xlib to match the
* other backends */
void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable);
/* XXX: This is a mess from the user's POV. Should the Visual or the
cairo_format_t control what render format is used? Maybe I can have
cairo_surface_create_for_window with a visual, and
cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
*/
cairo_surface_t *
cairo_xlib_surface_create_for_pixmap (Display *dpy,
Pixmap pixmap,
cairo_format_t format);
cairo_surface_t *
cairo_xlib_surface_create_for_pixmap_with_visual (Display *dpy,
Pixmap pixmap,
Visual *visual);
cairo_surface_t *
cairo_xlib_surface_create_for_window_with_visual (Display *dpy,
Window window,
Visual *visual);
/* Deprecated in favor of the more specific functions above */
cairo_surface_t *
cairo_xlib_surface_create (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap);
/* XXX: This has been proposed
cairo_status_t
cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height);
*/
void
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

View file

@ -1525,7 +1525,7 @@ DEPRECATE (cairo_current_tolerance, cairo_get_tolerance);
* @x: return value for X coordinate of the current point
* @y: return value for Y coordinate of the current point
*
* Returns the current point of the current path, which is
* Gets the current point of the current path, which is
* conceptually the final point reached by the path so far.
*
* The current point is returned in the user-space coordinate

View file

@ -875,7 +875,7 @@ cairo_surface_get_user_data (cairo_surface_t *surface,
cairo_status_t
cairo_surface_set_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key,
void *data,
void *user_data,
cairo_destroy_func_t destroy);
/* Image-surface functions */

View file

@ -37,6 +37,15 @@
#include "cairoint.h"
#include "cairo-xlib.h"
typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
typedef enum {
CAIRO_XLIB_PIXMAP,
CAIRO_XLIB_WINDOW
} cairo_xlib_drawable_type_t;
static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
/**
* cairo_set_target_drawable:
* @cr: a #cairo_t
@ -78,24 +87,29 @@ cairo_set_target_drawable (cairo_t *cr,
cairo_surface_destroy (surface);
}
typedef struct _cairo_xlib_surface {
struct _cairo_xlib_surface {
cairo_surface_t base;
Display *dpy;
GC gc;
Drawable drawable;
int owns_pixmap;
cairo_bool_t owns_pixmap;
Visual *visual;
cairo_format_t format;
int render_major;
int render_minor;
cairo_xlib_drawable_type_t type;
int width;
int height;
int depth;
int x_offset;
int y_offset;
Picture picture;
} cairo_xlib_surface_t;
};
#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
(((surface)->render_major > major) || \
@ -136,16 +150,6 @@ _CAIRO_FORMAT_DEPTH (cairo_format_t format)
}
}
static cairo_surface_t *
_cairo_xlib_surface_create_with_size (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap,
int width,
int height);
static cairo_surface_t *
_cairo_xlib_surface_create_similar (void *abstract_src,
cairo_format_t format,
@ -173,13 +177,10 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
_CAIRO_FORMAT_DEPTH (format));
surface = (cairo_xlib_surface_t *)
_cairo_xlib_surface_create_with_size (dpy, pix, NULL, format,
DefaultColormap (dpy, scr),
width, height);
surface->owns_pixmap = 1;
surface->width = width;
surface->height = height;
cairo_xlib_surface_create_for_pixmap (dpy, pix, format);
cairo_xlib_surface_set_size (&surface->base, width, height);
surface->owns_pixmap = TRUE;
return &surface->base;
}
@ -197,7 +198,7 @@ _cairo_xlib_surface_destroy (void *abstract_surface)
if (surface->gc)
XFreeGC (surface->dpy, surface->gc);
surface->dpy = 0;
surface->dpy = NULL;
free (surface);
}
@ -217,30 +218,53 @@ _get_image_surface (cairo_xlib_surface_t *surface,
{
cairo_image_surface_t *image;
XImage *ximage;
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
int x1, y1, x2, y2;
XGetGeometry (surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&surface->width, &surface->height,
&bwidth_ignore, &depth_ignore);
x1 = 0;
y1 = 0;
x2 = surface->width;
y2 = surface->height;
if (surface->width >= 0 && surface->height >= 0) {
x2 = surface->width;
y2 = surface->height;
} else {
int width, height;
Window root_ignore;
int x_ignore, y_ignore, bwidth_ignore, depth_ignore;
XGetGeometry (surface->dpy,
surface->drawable,
&root_ignore, &x_ignore, &y_ignore,
&width, &height,
&bwidth_ignore, &depth_ignore);
/* The size of a pixmap can't change, so we store
* the information to avoid having to get it again
*/
if (surface->type == CAIRO_XLIB_PIXMAP) {
surface->width = width;
surface->height = height;
}
x2 = width;
y2 = height;
}
if (interest_rect) {
if (interest_rect->x > x1)
x1 = interest_rect->x;
if (interest_rect->y > y1)
y1 = interest_rect->y;
if (interest_rect->x + interest_rect->width < x2)
x2 = interest_rect->x + interest_rect->width;
if (interest_rect->y + interest_rect->height < y2)
y2 = interest_rect->y + interest_rect->height;
cairo_rectangle_t rect;
rect.x = interest_rect->x + surface->x_offset;
rect.y = interest_rect->y + surface->x_offset;
rect.width = interest_rect->width;
rect.height = interest_rect->width;
if (rect.x > x1)
x1 = rect.x;
if (rect.y > y1)
y1 = rect.y;
if (rect.x + rect.width < x2)
x2 = rect.x + rect.width;
if (rect.y + rect.height < y2)
y2 = rect.y + rect.height;
if (x1 >= x2 || y1 >= y2) {
*image_out = NULL;
@ -249,18 +273,46 @@ _get_image_surface (cairo_xlib_surface_t *surface,
}
if (image_rect) {
image_rect->x = x1;
image_rect->y = y1;
image_rect->x = x1 - surface->x_offset;
image_rect->y = y1 - surface->y_offset;
image_rect->width = x2 - x1;
image_rect->height = y2 - y1;
}
/* XXX: This should try to use the XShm extension if availible */
ximage = XGetImage (surface->dpy,
surface->drawable,
x1, y1,
x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
/* XXX: This should try to use the XShm extension if available */
if (surface->type == CAIRO_XLIB_WINDOW) {
/* XGetImage from a window is dangerous because it can
* produce errors if the window is unmapped or partially
* outside the screen. We could check for errors and
* retry, but to keep things simple, we just create a
* temporary pixmap
*/
Pixmap pixmap = XCreatePixmap (surface->dpy,
surface->drawable,
x2 - x1, y2 - y1,
surface->depth);
_cairo_xlib_surface_ensure_gc (surface);
XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
x1, y1, x2 - x1, y2 - y1, 0, 0);
ximage = XGetImage (surface->dpy,
pixmap,
0, 0,
x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
XFreePixmap (surface->dpy, pixmap);
} else {
ximage = XGetImage (surface->dpy,
surface->drawable,
x1, y1,
x2 - x1, y2 - y1,
AllPlanes, ZPixmap);
}
if (surface->visual) {
cairo_format_masks_t masks;
@ -303,10 +355,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
static void
_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
{
XGCValues gcv;
if (surface->gc)
return;
surface->gc = XCreateGC (surface->dpy, surface->drawable, 0, NULL);
gcv.graphics_exposures = False;
surface->gc = XCreateGC (surface->dpy, surface->drawable,
GCGraphicsExposures, &gcv);
}
static cairo_status_t
@ -340,7 +396,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, dst_y,
ximage, 0, 0, dst_x + surface->x_offset, dst_y + surface->y_offset,
image->width, image->height);
/* Foolish XDestroyImage thinks it can free my data, but I won't
@ -679,7 +735,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_y,
dst_x + dst->x_offset, dst_y + dst->y_offset,
width, height);
}
}
@ -692,6 +748,20 @@ _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,
@ -710,6 +780,10 @@ _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),
@ -719,6 +793,31 @@ _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,
@ -749,6 +848,9 @@ _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);
@ -757,8 +859,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;
render_src_y = src_y + render_reference_y - dst_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);
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
status = _cairo_xlib_surface_set_attributes (src, &attributes);
@ -789,66 +891,55 @@ _cairo_xlib_surface_show_page (void *abstract_surface)
}
static cairo_int_status_t
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
Region xregion;
XRectangle xr;
XRectangle *rects = NULL;
XGCValues gc_values;
pixman_box16_t *box;
cairo_xlib_surface_t *surf;
int n, m;
surf = (cairo_xlib_surface_t *) abstract_surface;
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (region == NULL) {
/* NULL region == reset the clip */
xregion = XCreateRegion();
xr.x = 0;
xr.y = 0;
xr.width = surf->width;
xr.height = surf->height;
XUnionRectWithRegion (&xr, xregion, xregion);
rects = malloc(sizeof(XRectangle));
if (rects == NULL)
return CAIRO_STATUS_NO_MEMORY;
rects[0] = xr;
m = 1;
} else {
n = pixman_region_num_rects (region);
/* XXX: Are we sure these are the semantics we want for an
* empty, (not null) region? */
if (n == 0)
return CAIRO_STATUS_SUCCESS;
rects = malloc(sizeof(XRectangle) * n);
if (rects == NULL)
return CAIRO_STATUS_NO_MEMORY;
box = pixman_region_rects (region);
xregion = XCreateRegion();
if (surface->gc)
XSetClipMask (surface->dpy, surface->gc, None);
m = n;
for (; n > 0; --n, ++box) {
xr.x = (short) box->x1;
xr.y = (short) box->y1;
xr.width = (unsigned short) (box->x2 - box->x1);
xr.height = (unsigned short) (box->y2 - box->y1);
rects[n-1] = xr;
XUnionRectWithRegion (&xr, xregion, xregion);
}
if (surface->picture) {
XRenderPictureAttributes pa;
pa.clip_mask = None;
XRenderChangePicture (surface->dpy, surface->picture,
CPClipMask, &pa);
}
} else {
pixman_box16_t *boxes;
XRectangle *rects = NULL;
int n_boxes, i;
n_boxes = pixman_region_num_rects (region);
if (n_boxes > 0) {
rects = malloc (sizeof(XRectangle) * n_boxes);
if (rects == NULL)
return CAIRO_STATUS_NO_MEMORY;
} else {
rects = NULL;
}
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].width = boxes[i].x2 - boxes[i].x1;
rects[i].height = boxes[i].y2 - boxes[i].y1;
}
if (surface->gc)
XSetClipRectangles(surface->dpy, surface->gc,
0, 0, rects, n_boxes, YXSorted);
if (surface->picture)
XRenderSetPictureClipRectangles (surface->dpy, surface->picture,
0, 0, rects, n_boxes);
if (rects)
free (rects);
}
_cairo_xlib_surface_ensure_gc (surf);
XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
XSetGraphicsExposures(surf->dpy, surf->gc, False);
XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
free(rects);
if (surf->picture)
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
XDestroyRegion(xregion);
XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
@ -885,16 +976,13 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
};
static cairo_surface_t *
_cairo_xlib_surface_create_with_size (Display *dpy,
Drawable drawable,
Visual *visual,
cairo_format_t format,
Colormap colormap,
int width,
int height)
_cairo_xlib_surface_create_internal (Display *dpy,
Drawable drawable,
cairo_xlib_drawable_type_t type,
Visual *visual,
cairo_format_t format)
{
cairo_xlib_surface_t *surface;
int render_standard;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@ -902,48 +990,85 @@ _cairo_xlib_surface_create_with_size (Display *dpy,
_cairo_surface_init (&surface->base, &cairo_xlib_surface_backend);
surface->visual = visual;
surface->format = format;
surface->type = type;
surface->dpy = dpy;
surface->gc = 0;
surface->gc = NULL;
surface->drawable = drawable;
surface->owns_pixmap = 0;
surface->visual = visual;
surface->width = width;
surface->height = height;
surface->owns_pixmap = FALSE;
surface->width = -1;
surface->height = -1;
surface->x_offset = 0;
surface->y_offset = 0;
if (visual) {
int i, j, k;
surface->format = (cairo_format_t)-1;
/* This is ugly, but we have to walk over all visuals
* for the display to find the depth.
*/
for (i = 0; i < ScreenCount (dpy); i++) {
Screen *screen = ScreenOfDisplay (dpy, i);
for (j = 0; j < screen->ndepths; j++) {
Depth *depth = &screen->depths[j];
for (k = 0; k < depth->nvisuals; k++) {
if (&depth->visuals[k] == visual)
surface->depth = depth->depth;
goto found;
}
}
}
found:
surface->visual = visual;
} else {
surface->format = format;
surface->depth = _CAIRO_FORMAT_DEPTH (format);
surface->visual = NULL;
}
if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) {
surface->render_major = -1;
surface->render_minor = -1;
}
switch (format) {
case CAIRO_FORMAT_A1:
render_standard = PictStandardA1;
break;
case CAIRO_FORMAT_A8:
render_standard = PictStandardA8;
break;
case CAIRO_FORMAT_RGB24:
render_standard = PictStandardRGB24;
break;
case CAIRO_FORMAT_ARGB32:
default:
render_standard = PictStandardARGB32;
break;
}
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
XRenderPictFormat *render_format;
if (visual) {
render_format = XRenderFindVisualFormat (dpy, visual);
} else {
int render_standard;
switch (format) {
case CAIRO_FORMAT_A1:
render_standard = PictStandardA1;
break;
case CAIRO_FORMAT_A8:
render_standard = PictStandardA8;
break;
case CAIRO_FORMAT_RGB24:
render_standard = PictStandardRGB24;
break;
case CAIRO_FORMAT_ARGB32:
default:
render_standard = PictStandardARGB32;
break;
}
render_format = XRenderFindStandardFormat (dpy, render_standard);
}
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
visual ?
XRenderFindVisualFormat (dpy, visual) :
XRenderFindStandardFormat (dpy, render_standard),
0, NULL);
else
surface->picture = 0;
render_format, 0, NULL);
} else
surface->picture = None;
return (cairo_surface_t *) surface;
}
@ -955,24 +1080,158 @@ cairo_xlib_surface_create (Display *dpy,
cairo_format_t format,
Colormap colormap)
{
Window window_ignore;
unsigned int int_ignore;
unsigned int width, height;
/* XXX: This call is a round-trip. We probably want to instead (or
* also?) export a version that accepts width/height. Then, we'll
* likely also need a resize function too.
/* Just assume a window ... slow but safe. This function is
* going away anyways
*/
XGetGeometry(dpy, drawable,
&window_ignore, &int_ignore, &int_ignore,
&width, &height,
&int_ignore, &int_ignore);
return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format,
colormap, width, height);
return _cairo_xlib_surface_create_internal (dpy, drawable,
CAIRO_XLIB_WINDOW,
visual,
format);
}
DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create);
/**
* cairo_xlib_surface_create_for_pixmap:
* @dpy: an X display
* @pixmap: an X pixmap
* @format: a standard Cairo pixel data format. The depth (number of
* of bits used) for the format must match the depth of
* @pixmap.
*
* Creates an Xlib surface that draws to the given pixmap.
* The way that colors are represented in the pixmap is specified
* by giving one of Cairo's standard pixel data formats.
*
* For maximum efficiency, if you know the size of the pixmap,
* you should call cairo_xlib_surface_set_size().
*
* Return value: the newly created surface
**/
cairo_surface_t *
cairo_xlib_surface_create_for_pixmap (Display *dpy,
Pixmap pixmap,
cairo_format_t format)
{
return _cairo_xlib_surface_create_internal (dpy, pixmap,
CAIRO_XLIB_PIXMAP,
NULL, format);
}
/**
* cairo_xlib_surface_create_for_pixmap_with_visual:
* @dpy: an X display
* @pixmap: an X pixmap
* @visual: the visual to use for drawing to @pixmap. The depth
* of the visual must match the depth of the pixmap.
* Currently, only TrueColor visuals are fully supported.
*
* Creates an Xlib surface that draws to the given pixmap.
* The way that colors are represented in the pixmap is specified
* by an X visual.
*
* Normally, you would use this function instead of
* cairo_xlib_surface_create_for_pixmap() when you double-buffering by
* using Cairo to draw to pixmap and then XCopyArea() to copy the
* results to a window. In that case, @visual is the visual of the
* window.
*
* For maximum efficiency, if you know the size of the pixmap,
* you should call cairo_xlib_surface_set_size().
*
* Return value: the newly created surface
**/
cairo_surface_t *
cairo_xlib_surface_create_for_pixmap_with_visual (Display *dpy,
Pixmap pixmap,
Visual *visual)
{
return _cairo_xlib_surface_create_internal (dpy, pixmap,
CAIRO_XLIB_PIXMAP,
visual,
(cairo_format_t)-1);
}
/**
* cairo_xlib_surface_create_for_window_with_visual:
* @dpy: an X display
* @window: an X window
* @visual: the visual of @window. Currently, only TrueColor visuals
* are fully supported.
*
* Creates a new XLib backend surface that draws to the given Window.
*
* For maximum efficiency, you should use cairo_xlib_surface_set_size()
* to inform Cairo of the size of the window.
*
* Return value: the newly created surface.
**/
cairo_surface_t *
cairo_xlib_surface_create_for_window_with_visual (Display *dpy,
Window window,
Visual *visual)
{
return _cairo_xlib_surface_create_internal (dpy, window,
CAIRO_XLIB_WINDOW,
visual,
(cairo_format_t)-1);
}
/**
* cairo_xlib_surface_set_size:
* @surface: a #cairo_surface_t for the XLib backend
* @width: the new width of the surface
* @height: the new height of the surface
*
* Informs Cairo of the size of the X drawable underlying the
* surface. This allows Cairo to avoid querying the server for the
* size, which can be a significant performance bottleneck.
*
* For a surface created for a pixmap, it is only necessary to call
* this function once, since pixmaps have a fixed size. For a surface
* created for a window, you should call this function each time the
* window changes size. (For a subwindow, you are normally resizing
* the window yourself, but for a toplevel window, it is necessary
* to listen for ConfigureNotify events.)
**/
void
cairo_xlib_surface_set_size (cairo_surface_t *surface,
int width,
int height)
{
cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *)surface;
xlib_surface->width = width;
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 {
@ -1229,8 +1488,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);
thisY = (int) floor (glyphs[i].y + 0.5);
thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset;
thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset;
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;
@ -1306,8 +1565,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);
thisY = (int) floor (glyphs[i].y + 0.5);
thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset;
thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset;
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;
@ -1382,8 +1641,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);
thisY = (int) floor (glyphs[i].y + 0.5);
thisX = (int) floor (glyphs[i].x + 0.5) + self->x_offset;
thisY = (int) floor (glyphs[i].y + 0.5) + self->y_offset;
elts[i].xOff = thisX - lastX;
elts[i].yOff = thisY - lastY;
lastX = thisX;