diff options
Diffstat (limited to 'src/cairo-xlib-surface.c')
-rw-r--r-- | src/cairo-xlib-surface.c | 770 |
1 files changed, 505 insertions, 265 deletions
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 3eaef57e5..41fb00c44 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -36,66 +36,47 @@ #include "cairoint.h" #include "cairo-xlib.h" +#include "cairo-xlib-xrender.h" +#include "cairo-xlib-test.h" +#include <X11/extensions/Xrender.h> -/** - * cairo_set_target_drawable: - * @cr: a #cairo_t - * @dpy: an X display - * @drawable: a window or pixmap on the default screen of @dpy - * - * Directs output for a #cairo_t to an Xlib drawable. @drawable must - * be a Window or Pixmap on the default screen of @dpy using the - * default colormap and visual. Using this function is slow because - * the function must retrieve information about @drawable from the X - * server. - - * The combination of cairo_xlib_surface_create() and - * cairo_set_target_surface() is somewhat more flexible, although - * it still is slow. - **/ -void -cairo_set_target_drawable (cairo_t *cr, - Display *dpy, - Drawable drawable) -{ - cairo_surface_t *surface; +/* Xlib doesn't define a typedef, so define one ourselves */ +typedef int (*cairo_xlib_error_func_t) (Display *display, + XErrorEvent *event); - if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE) - return; +typedef struct _cairo_xlib_surface cairo_xlib_surface_t; - surface = cairo_xlib_surface_create (dpy, drawable, - DefaultVisual (dpy, DefaultScreen (dpy)), - 0, - DefaultColormap (dpy, DefaultScreen (dpy))); - if (surface == NULL) { - cr->status = CAIRO_STATUS_NO_MEMORY; - return; - } +static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface); - cairo_set_target_surface (cr, surface); +/* + * Instead of taking two round trips for each blending request, + * assume that if a particular drawable fails GetImage that it will + * fail for a "while"; use temporary pixmaps to avoid the errors + */ - /* cairo_set_target_surface takes a reference, so we must destroy ours */ - cairo_surface_destroy (surface); -} +#define CAIRO_ASSUME_PIXMAP 20 -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 use_pixmap; int render_major; int render_minor; int width; int height; + int depth; Picture picture; -} cairo_xlib_surface_t; + XRenderPictFormat *format; +}; #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \ (((surface)->render_major > major) || \ @@ -120,6 +101,25 @@ typedef struct _cairo_xlib_surface { #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6) +static cairo_bool_t cairo_xlib_render_disabled = FALSE; + +/** + * cairo_test_xlib_disable_render: + * + * Disables the use of the RENDER extension. + * + * <note> + * This function is <emphasis>only</emphasis> intended for internal + * testing use within the cairo distribution. It is not installed in + * any public header file. + * </note> + **/ +void +cairo_test_xlib_disable_render (void) +{ + cairo_xlib_render_disabled = TRUE; +} + static int _CAIRO_FORMAT_DEPTH (cairo_format_t format) { @@ -136,15 +136,23 @@ _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 XRenderPictFormat * +_CAIRO_FORMAT_XRENDER_FORMAT(Display *dpy, cairo_format_t format) +{ + int pict_format; + switch (format) { + case CAIRO_FORMAT_A1: + pict_format = PictStandardA1; break; + case CAIRO_FORMAT_A8: + pict_format = PictStandardA8; break; + case CAIRO_FORMAT_RGB24: + pict_format = PictStandardRGB24; break; + case CAIRO_FORMAT_ARGB32: + default: + pict_format = PictStandardARGB32; break; + } + return XRenderFindStandardFormat (dpy, pict_format); +} static cairo_surface_t * _cairo_xlib_surface_create_similar (void *abstract_src, @@ -158,6 +166,9 @@ _cairo_xlib_surface_create_similar (void *abstract_src, int scr; Pixmap pix; cairo_xlib_surface_t *surface; + int depth = _CAIRO_FORMAT_DEPTH (format); + XRenderPictFormat *xrender_format = _CAIRO_FORMAT_XRENDER_FORMAT (dpy, + format); /* As a good first approximation, if the display doesn't have COMPOSITE, * we're better off using image surfaces for all temporary operations @@ -170,22 +181,20 @@ _cairo_xlib_surface_create_similar (void *abstract_src, pix = XCreatePixmap (dpy, DefaultRootWindow (dpy), width <= 0 ? 1 : width, height <= 0 ? 1 : height, - _CAIRO_FORMAT_DEPTH (format)); + depth); 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_with_xrender_format (dpy, pix, + xrender_format, + width, height); + + surface->owns_pixmap = TRUE; return &surface->base; } -static void -_cairo_xlib_surface_destroy (void *abstract_surface) +static cairo_status_t +_cairo_xlib_surface_finish (void *abstract_surface) { cairo_xlib_surface_t *surface = abstract_surface; if (surface->picture) @@ -197,16 +206,56 @@ _cairo_xlib_surface_destroy (void *abstract_surface) if (surface->gc) XFreeGC (surface->dpy, surface->gc); - surface->dpy = 0; + surface->dpy = NULL; + + return CAIRO_STATUS_SUCCESS; +} - free (surface); +static int +_noop_error_handler (Display *display, + XErrorEvent *event) +{ + return False; /* return value is ignored */ } -static double -_cairo_xlib_surface_pixels_per_inch (void *abstract_surface) +static cairo_bool_t +_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format) { - /* XXX: We should really get this value from somewhere like Xft.dpy */ - return 96.0; + switch (masks->bpp) { + case 32: + if (masks->alpha_mask == 0xff000000 && + masks->red_mask == 0x00ff0000 && + masks->green_mask == 0x0000ff00 && + masks->blue_mask == 0x000000ff) + { + *format = CAIRO_FORMAT_ARGB32; + return True; + } + if (masks->alpha_mask == 0x00000000 && + masks->red_mask == 0x00ff0000 && + masks->green_mask == 0x0000ff00 && + masks->blue_mask == 0x000000ff) + { + *format = CAIRO_FORMAT_RGB24; + return True; + } + break; + case 8: + if (masks->alpha_mask == 0xff) + { + *format = CAIRO_FORMAT_A8; + return True; + } + break; + case 1: + if (masks->alpha_mask == 0x1) + { + *format = CAIRO_FORMAT_A1; + return True; + } + break; + } + return False; } static cairo_status_t @@ -217,15 +266,9 @@ _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); + cairo_format_masks_t masks; + cairo_format_t format; x1 = 0; y1 = 0; @@ -233,14 +276,21 @@ _get_image_surface (cairo_xlib_surface_t *surface, y2 = surface->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; + rect.y = interest_rect->y; + 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; @@ -255,36 +305,118 @@ _get_image_surface (cairo_xlib_surface_t *surface, 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->visual) { - cairo_format_masks_t masks; + if (surface->use_pixmap == 0) + { + cairo_xlib_error_func_t old_handler; - /* XXX: Add support here for pictures with external alpha? */ + old_handler = XSetErrorHandler (_noop_error_handler); + + ximage = XGetImage (surface->dpy, + surface->drawable, + x1, y1, + x2 - x1, y2 - y1, + AllPlanes, ZPixmap); + XSetErrorHandler (old_handler); + + /* If we get an error, the surface must have been a window, + * so retry with the safe code path. + */ + if (!ximage) + surface->use_pixmap = CAIRO_ASSUME_PIXMAP; + } + else + { + surface->use_pixmap--; + ximage = 0; + } + + if (!ximage) + { + + /* 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); + } + if (!ximage) + return CAIRO_STATUS_NO_MEMORY; + + /* + * Compute the pixel format masks from either a visual or a + * XRenderFormat, failing we assume the drawable is an + * alpha-only pixmap as it could only have been created + * that way through the cairo_xlib_surface_create_for_bitmap + * function. + */ + if (surface->visual) { masks.bpp = ximage->bits_per_pixel; masks.alpha_mask = 0; masks.red_mask = surface->visual->red_mask; masks.green_mask = surface->visual->green_mask; masks.blue_mask = surface->visual->blue_mask; + } else if (surface->format) { + masks.bpp = ximage->bits_per_pixel; + masks.red_mask = surface->format->direct.redMask << surface->format->direct.red; + masks.green_mask = surface->format->direct.greenMask << surface->format->direct.green; + masks.blue_mask = surface->format->direct.blueMask << surface->format->direct.blue; + masks.alpha_mask = surface->format->direct.alphaMask << surface->format->direct.alpha; + } else { + masks.bpp = ximage->bits_per_pixel; + masks.red_mask = 0; + masks.green_mask = 0; + masks.blue_mask = 0; + if (surface->depth < 32) + masks.alpha_mask = (1 << surface->depth) - 1; + else + masks.alpha_mask = 0xffffffff; + } - image = _cairo_image_surface_create_with_masks (ximage->data, + /* + * Prefer to use a standard pixman format instead of the + * general masks case. + */ + if (_CAIRO_MASK_FORMAT (&masks, &format)) + { + image = (cairo_image_surface_t *) cairo_image_surface_create_for_data ((unsigned char *) ximage->data, + format, + ximage->width, + ximage->height, + ximage->bytes_per_line); + } + else + { + /* + * XXX This can't work. We must convert the data to one of the + * supported pixman formats. Pixman needs another function + * which takes data in an arbitrary format and converts it + * to something supported by that library. + */ + image = _cairo_image_surface_create_with_masks ((unsigned char *) ximage->data, &masks, ximage->width, ximage->height, ximage->bytes_per_line); - } else { - image = (cairo_image_surface_t *) - cairo_image_surface_create_for_data (ximage->data, - surface->format, - ximage->width, - ximage->height, - ximage->bytes_per_line); } /* Let the surface take ownership of the data */ @@ -303,10 +435,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 @@ -318,6 +454,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, XImage *ximage; unsigned bitmap_pad; + /* XXX this is wrong */ if (image->depth > 16) bitmap_pad = 32; else if (image->depth > 8) @@ -330,7 +467,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface, image->depth, ZPixmap, 0, - image->data, + (char *) image->data, image->width, image->height, bitmap_pad, @@ -362,13 +499,8 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf cairo_status_t status; status = _get_image_surface (surface, NULL, &image, NULL); - if (status == CAIRO_STATUS_SUCCESS) { - cairo_surface_set_filter (&image->base, surface->base.filter); - cairo_surface_set_matrix (&image->base, &surface->base.matrix); - cairo_surface_set_repeat (&image->base, surface->base.repeat); - + if (status == CAIRO_STATUS_SUCCESS) *image_out = image; - } return status; } @@ -459,13 +591,13 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface, if (!surface->picture) return CAIRO_STATUS_SUCCESS; - xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]); - xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]); - xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]); + xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx); + xtransform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy); + xtransform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0); - xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]); - xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]); - xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]); + xtransform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx); + xtransform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy); + xtransform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0); xtransform.matrix[2][0] = 0; xtransform.matrix[2][1] = 0; @@ -585,26 +717,29 @@ _render_operator (cairo_operator_t operator) switch (operator) { case CAIRO_OPERATOR_CLEAR: return PictOpClear; - case CAIRO_OPERATOR_SRC: + + case CAIRO_OPERATOR_SOURCE: return PictOpSrc; - case CAIRO_OPERATOR_DST: - return PictOpDst; case CAIRO_OPERATOR_OVER: return PictOpOver; - case CAIRO_OPERATOR_OVER_REVERSE: - return PictOpOverReverse; case CAIRO_OPERATOR_IN: return PictOpIn; - case CAIRO_OPERATOR_IN_REVERSE: - return PictOpInReverse; case CAIRO_OPERATOR_OUT: return PictOpOut; - case CAIRO_OPERATOR_OUT_REVERSE: - return PictOpOutReverse; case CAIRO_OPERATOR_ATOP: return PictOpAtop; - case CAIRO_OPERATOR_ATOP_REVERSE: + + case CAIRO_OPERATOR_DEST: + return PictOpDst; + case CAIRO_OPERATOR_DEST_OVER: + return PictOpOverReverse; + case CAIRO_OPERATOR_DEST_IN: + return PictOpInReverse; + case CAIRO_OPERATOR_DEST_OUT: + return PictOpOutReverse; + case CAIRO_OPERATOR_DEST_ATOP: return PictOpAtopReverse; + case CAIRO_OPERATOR_XOR: return PictOpXor; case CAIRO_OPERATOR_ADD: @@ -651,10 +786,8 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, return status; status = _cairo_xlib_surface_set_attributes (src, &src_attr); - if (CAIRO_OK (status)) - { - if (mask) - { + if (CAIRO_OK (status)) { + if (mask) { status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); if (CAIRO_OK (status)) XRenderComposite (dst->dpy, @@ -668,9 +801,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, mask_y + mask_attr.y_offset, dst_x, dst_y, width, height); - } - else - { + } else { XRenderComposite (dst->dpy, _render_operator (operator), src->picture, @@ -777,83 +908,75 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator, } static cairo_int_status_t -_cairo_xlib_surface_copy_page (void *abstract_surface) +_cairo_xlib_surface_set_clip_region (void *abstract_surface, + pixman_region16_t *region) { - return CAIRO_INT_STATUS_UNSUPPORTED; -} + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; -static cairo_int_status_t -_cairo_xlib_surface_show_page (void *abstract_surface) -{ - return CAIRO_INT_STATUS_UNSUPPORTED; + if (region == NULL) { + if (surface->gc) + XSetClipMask (surface->dpy, surface->gc, None); + + 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; + rects[i].y = boxes[i].y1; + 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); + } + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t -_cairo_xlib_surface_set_clip_region (void *abstract_surface, - pixman_region16_t *region) +_cairo_xlib_surface_get_extents (void *abstract_surface, + cairo_rectangle_t *rectangle) { + cairo_xlib_surface_t *surface = abstract_surface; - 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; + rectangle->x = 0; + rectangle->y = 0; - 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; + rectangle->width = surface->width; + rectangle->height = surface->height; - } 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(); - - 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); - } - } - - _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; } -static cairo_status_t -_cairo_xlib_surface_show_glyphs (cairo_font_t *font, +static cairo_int_status_t +_cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_surface, @@ -868,8 +991,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font, static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, - _cairo_xlib_surface_destroy, - _cairo_xlib_surface_pixels_per_inch, + _cairo_xlib_surface_finish, _cairo_xlib_surface_acquire_source_image, _cairo_xlib_surface_release_source_image, _cairo_xlib_surface_acquire_dest_image, @@ -878,23 +1000,37 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = { _cairo_xlib_surface_composite, _cairo_xlib_surface_fill_rectangles, _cairo_xlib_surface_composite_trapezoids, - _cairo_xlib_surface_copy_page, - _cairo_xlib_surface_show_page, + NULL, /* copy_page */ + NULL, /* show_page */ _cairo_xlib_surface_set_clip_region, + _cairo_xlib_surface_get_extents, _cairo_xlib_surface_show_glyphs }; +/** + * _cairo_surface_is_xlib: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_xlib_surface_t + * + * Return value: True if the surface is an xlib surface + **/ +static cairo_bool_t +_cairo_surface_is_xlib (cairo_surface_t *surface) +{ + return surface->backend == &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, + Visual *visual, + XRenderPictFormat *format, + int width, + int height, + int depth) { cairo_xlib_surface_t *surface; - int render_standard; surface = malloc (sizeof (cairo_xlib_surface_t)); if (surface == NULL) @@ -902,76 +1038,180 @@ _cairo_xlib_surface_create_with_size (Display *dpy, _cairo_surface_init (&surface->base, &cairo_xlib_surface_backend); - surface->visual = visual; - surface->format = format; - surface->dpy = dpy; - surface->gc = 0; + surface->gc = NULL; surface->drawable = drawable; - surface->owns_pixmap = 0; + surface->owns_pixmap = FALSE; surface->visual = visual; + surface->format = format; + surface->use_pixmap = 0; surface->width = width; surface->height = height; + surface->depth = depth; - if (! XRenderQueryVersion (dpy, &surface->render_major, &surface->render_minor)) { + if (format) { + surface->depth = format->depth; + } else if (visual) { + int i, j, k; + + /* 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: + ; + } + + if (cairo_xlib_render_disabled || + ! 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; - } + surface->picture = None; - /* 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; + if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) { + + if (!format) { + if (visual) { + format = XRenderFindVisualFormat (dpy, visual); + } else if (depth == 1) + format = XRenderFindStandardFormat (dpy, PictStandardA1); + } + + if (format) + surface->picture = XRenderCreatePicture (dpy, drawable, + format, 0, NULL); + } return (cairo_surface_t *) surface; } +/** + * cairo_xlib_surface_create: + * @dpy: an X Display + * @drawable: an X Drawable, (a Pixmap or a Window) + * @visual: the visual to use for drawing to @drawable. The depth + * of the visual must match the depth of the drawable. + * Currently, only TrueColor visuals are fully supported. + * @width: the current width of @drawable. + * @height: the current height of @drawable. + * + * Creates an Xlib surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided visual. + * + * NOTE: If @drawable is a Window, then the function + * cairo_xlib_surface_set_size must be called whenever the size of the + * window changes. + * + * Return value: the newly created surface + **/ cairo_surface_t * -cairo_xlib_surface_create (Display *dpy, - Drawable drawable, - Visual *visual, - cairo_format_t format, - Colormap colormap) +cairo_xlib_surface_create (Display *dpy, + Drawable drawable, + Visual *visual, + int width, + int height) { - Window window_ignore; - unsigned int int_ignore; - unsigned int width, height; + return _cairo_xlib_surface_create_internal (dpy, drawable, + visual, NULL, width, height, 0); +} - /* 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. - */ - XGetGeometry(dpy, drawable, - &window_ignore, &int_ignore, &int_ignore, - &width, &height, - &int_ignore, &int_ignore); +/** + * cairo_xlib_surface_create_for_bitmap: + * @dpy: an X Display + * @bitmap: an X Drawable, (a depth-1 Pixmap) + * @width: the current width of @bitmap. + * @height: the current height of @bitmap. + * + * Creates an Xlib surface that draws to the given bitmap. + * This will be drawn to as a CAIRO_FORMAT_A1 object. + * + * Return value: the newly created surface + **/ +cairo_surface_t * +cairo_xlib_surface_create_for_bitmap (Display *dpy, + Pixmap bitmap, + int width, + int height) +{ + return _cairo_xlib_surface_create_internal (dpy, bitmap, + NULL, NULL, width, height, 1); +} + +/** + * cairo_xlib_surface_create_with_xrender_format: + * @dpy: an X Display + * @drawable: an X Drawable, (a Pixmap or a Window) + * @format: the picture format to use for drawing to @drawable. The depth + * of @format must match the depth of the drawable. + * @width: the current width of @drawable. + * @height: the current height of @drawable. + * + * Creates an Xlib surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided picture format. + * + * NOTE: If @drawable is a Window, then the function + * cairo_xlib_surface_set_size must be called whenever the size of the + * window changes. + * + * Return value: the newly created surface + **/ +cairo_surface_t * +cairo_xlib_surface_create_with_xrender_format (Display *dpy, + Drawable drawable, + XRenderPictFormat *format, + int width, + int height) +{ + return _cairo_xlib_surface_create_internal (dpy, drawable, + NULL, format, width, height, 0); +} - return _cairo_xlib_surface_create_with_size (dpy, drawable, visual, format, - colormap, width, height); +/** + * 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 new size of the X Drawable underlying the + * surface. For a surface created for a Window (rather than a Pixmap), + * this function must be called each time the size of the window + * changes. (For a subwindow, you are normally resizing the window + * yourself, but for a toplevel window, it is necessary to listen for + * ConfigureNotify events.) + * + * A Pixmap can never change size, so it is never necessary to call + * this function on a surface created for a Pixmap. + **/ +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; + + /* XXX: How do we want to handle this error case? */ + if (! _cairo_surface_is_xlib (surface)) + return; + + xlib_surface->width = width; + xlib_surface->height = height; } -DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create); /* RENDER glyphset cache code */ @@ -1079,7 +1319,7 @@ _xlib_glyphset_cache_create_entry (void *cache, XRenderAddGlyphs (g->display, g->glyphset, &(v->glyph), &(v->info), 1, - im->image ? im->image->data : NULL, + im->image ? (char *) im->image->data : NULL, im->image ? v->info.height * v->info.width : 0); v->key.base.memory = im->image ? im->image->width * im->image->stride : 0; @@ -1186,7 +1426,7 @@ _get_glyphset_cache (Display *d) #define N_STACK_BUF 1024 static cairo_status_t -_cairo_xlib_surface_show_glyphs32 (cairo_font_t *font, +_cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, glyphset_cache_t *g, cairo_glyph_cache_key_t *key, @@ -1263,7 +1503,7 @@ _cairo_xlib_surface_show_glyphs32 (cairo_font_t *font, static cairo_status_t -_cairo_xlib_surface_show_glyphs16 (cairo_font_t *font, +_cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, glyphset_cache_t *g, cairo_glyph_cache_key_t *key, @@ -1339,7 +1579,7 @@ _cairo_xlib_surface_show_glyphs16 (cairo_font_t *font, } static cairo_status_t -_cairo_xlib_surface_show_glyphs8 (cairo_font_t *font, +_cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, glyphset_cache_t *g, cairo_glyph_cache_key_t *key, @@ -1415,8 +1655,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo_font_t *font, } -static cairo_status_t -_cairo_xlib_surface_show_glyphs (cairo_font_t *font, +static cairo_int_status_t +_cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t operator, cairo_pattern_t *pattern, void *abstract_surface, @@ -1471,7 +1711,7 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font, /* Work out the index size to use. */ elt_size = 8; - _cairo_font_get_glyph_cache_key (font, &key); + _cairo_scaled_font_get_glyph_cache_key (scaled_font, &key); for (i = 0; i < num_glyphs; ++i) { key.index = glyphs[i].index; @@ -1499,17 +1739,17 @@ _cairo_xlib_surface_show_glyphs (cairo_font_t *font, /* Call the appropriate sub-function. */ if (elt_size == 8) - status = _cairo_xlib_surface_show_glyphs8 (font, operator, g, &key, src, self, + status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, g, &key, src, self, source_x + attributes.x_offset, source_y + attributes.y_offset, glyphs, entries, num_glyphs); else if (elt_size == 16) - status = _cairo_xlib_surface_show_glyphs16 (font, operator, g, &key, src, self, + status = _cairo_xlib_surface_show_glyphs16 (scaled_font, operator, g, &key, src, self, source_x + attributes.x_offset, source_y + attributes.y_offset, glyphs, entries, num_glyphs); else - status = _cairo_xlib_surface_show_glyphs32 (font, operator, g, &key, src, self, + status = _cairo_xlib_surface_show_glyphs32 (scaled_font, operator, g, &key, src, self, source_x + attributes.x_offset, source_y + attributes.y_offset, glyphs, entries, num_glyphs); |