summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-xlib-surface.c')
-rw-r--r--src/cairo-xlib-surface.c1909
1 files changed, 1130 insertions, 779 deletions
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 67b4ca6..81f2ec3 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -39,25 +39,78 @@
* Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
*/
+/* Heed well the words of Owen Taylor:
+ * "Any patch that works around a render bug, or claims to, without a
+ * specific reference to the bug filed in bugzilla.freedesktop.org will
+ * never pass approval."
+ */
+
#include "cairoint.h"
#include "cairo-xlib-private.h"
#include "cairo-xlib-surface-private.h"
#include "cairo-clip-private.h"
#include "cairo-scaled-font-private.h"
+#include "cairo-region-private.h"
#include <X11/Xutil.h> /* for XDestroyImage */
#define XLIB_COORD_MAX 32767
+#define DEBUG 0
+
+#if DEBUG
+#define UNSUPPORTED(reason) \
+ fprintf (stderr, \
+ "cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \
+ __FUNCTION__, __LINE__, reason), \
+ CAIRO_INT_STATUS_UNSUPPORTED
+#else
+#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
+#endif
+
+#if DEBUG
+#include <X11/Xlibint.h>
+static void CAIRO_PRINTF_FORMAT (2, 3)
+_x_bread_crumb (Display *dpy,
+ const char *fmt,
+ ...)
+{
+ xReq *req;
+ char buf[2048];
+ unsigned int len, len_dwords;
+ va_list ap;
+
+ va_start (ap, fmt);
+ len = vsnprintf (buf, sizeof (buf), fmt, ap);
+ va_end (ap);
+
+ buf[len++] = '\0';
+ while (len & 3)
+ buf[len++] = '\0';
+
+ LockDisplay (dpy);
+ GetEmptyReq (NoOperation, req);
+
+ len_dwords = len >> 2;
+ SetReqLen (req, len_dwords, len_dwords);
+ Data (dpy, buf, len);
+
+ UnlockDisplay (dpy);
+ SyncHandle ();
+}
+#define X_DEBUG(x) _x_bread_crumb x
+#else
+#define X_DEBUG(x)
+#endif
+
/* Xlib doesn't define a typedef, so define one ourselves */
typedef int (*cairo_xlib_error_func_t) (Display *display,
XErrorEvent *event);
static cairo_surface_t *
-_cairo_xlib_surface_create_internal (Display *dpy,
+_cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen,
Drawable drawable,
- Screen *screen,
Visual *visual,
XRenderPictFormat *xrender_format,
int width,
@@ -65,7 +118,10 @@ _cairo_xlib_surface_create_internal (Display *dpy,
int depth);
static cairo_status_t
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
+_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc);
+
+static void
+_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc);
static void
_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface);
@@ -86,8 +142,12 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents);
+ cairo_clip_t *clip,
+ int *remaining_glyphs);
+
+/* XXX temporarily used by cairo-qt-surface.c */
+slim_hidden_proto (cairo_xlib_surface_create);
+slim_hidden_proto (cairo_xlib_surface_create_with_xrender_format);
/*
* Instead of taking two round trips for each blending request,
@@ -124,51 +184,70 @@ static const XTransform identity = { {
#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_surface_t *
-_cairo_xlib_surface_create_similar_with_format (void *abstract_src,
- cairo_format_t format,
- int width,
- int height)
+#define CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
+#define CAIRO_SURFACE_RENDER_HAS_GRADIENTS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
+
+#define CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 11)
+
+#define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op) \
+ ((op) <= CAIRO_OPERATOR_SATURATE || \
+ (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) && \
+ (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY))
+
+static cairo_status_t
+_cairo_xlib_surface_set_clip_region (cairo_xlib_surface_t *surface,
+ cairo_region_t *region)
{
- cairo_xlib_surface_t *src = abstract_src;
- Display *dpy = src->dpy;
- Pixmap pix;
- cairo_xlib_surface_t *surface;
- XRenderPictFormat *xrender_format;
+ cairo_bool_t had_clip_rects = surface->clip_region != NULL;
- assert (width <= XLIB_COORD_MAX && height <= XLIB_COORD_MAX);
+ if (had_clip_rects == FALSE && region == NULL)
+ return CAIRO_STATUS_SUCCESS;
- /* As a good first approximation, if the display doesn't have even
- * the most elementary RENDER operation, then we're better off
- * using image surfaces for all temporary operations, so return NULL
- * and let the fallback code happen.
- */
- if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
- return NULL;
+ if (surface->clip_region == region)
+ return CAIRO_STATUS_SUCCESS;
- xrender_format = _cairo_xlib_display_get_xrender_format (src->display,
- format);
- if (xrender_format == NULL)
- return NULL;
+ if (cairo_region_equal (surface->clip_region, region))
+ return CAIRO_STATUS_SUCCESS;
- pix = XCreatePixmap (dpy, src->drawable,
- width <= 0 ? 1 : width, height <= 0 ? 1 : height,
- xrender_format->depth);
+ cairo_region_destroy (surface->clip_region);
+ surface->clip_region = cairo_region_reference (region);
- surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_internal (dpy, pix,
- src->screen, NULL,
- xrender_format,
- width, height,
- xrender_format->depth);
- if (surface->base.status) {
- XFreePixmap (dpy, pix);
- return &surface->base;
+ if (surface->clip_rects != surface->embedded_clip_rects) {
+ free (surface->clip_rects);
+ surface->clip_rects = surface->embedded_clip_rects;
}
+ surface->num_clip_rects = 0;
- surface->owns_pixmap = TRUE;
+ if (region != NULL) {
+ XRectangle *rects = NULL;
+ int n_rects, i;
- return &surface->base;
+ n_rects = cairo_region_num_rectangles (region);
+ if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
+ rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
+ if (unlikely (rects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else {
+ rects = surface->embedded_clip_rects;
+ }
+
+ for (i = 0; i < n_rects; i++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ rects[i].x = rect.x;
+ rects[i].y = rect.y;
+ rects[i].width = rect.width;
+ rects[i].height = rect.height;
+ }
+
+ surface->clip_rects = rects;
+ surface->num_clip_rects = n_rects;
+ }
+
+ surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_content_t
@@ -203,48 +282,79 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
int height)
{
cairo_xlib_surface_t *src = abstract_src;
- XRenderPictFormat *xrender_format = src->xrender_format;
+ XRenderPictFormat *xrender_format;
cairo_xlib_surface_t *surface;
Pixmap pix;
if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
return NULL;
- _cairo_xlib_display_notify (src->display);
+ if (! CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (src))
+ return NULL;
- /* Start by examining the surface's XRenderFormat, or if it
- * doesn't have one, then look one up through its visual (in the
- * case of a bitmap, it won't even have that). */
- if (xrender_format == NULL && src->visual != NULL)
- xrender_format = XRenderFindVisualFormat (src->dpy, src->visual);
+ _cairo_xlib_display_notify (src->display);
/* If we never found an XRenderFormat or if it isn't compatible
* with the content being requested, then we fallback to just
* constructing a cairo_format_t instead, (which will fairly
* arbitrarily pick a visual/depth for the similar surface.
*/
- if (xrender_format == NULL ||
- _xrender_format_to_content (xrender_format) != content)
+ xrender_format = src->xrender_format;
+ if ((xrender_format != NULL &&
+ _xrender_format_to_content (xrender_format) == content) ||
+ (xrender_format =
+ _cairo_xlib_display_get_xrender_format (src->display,
+ _cairo_format_from_content (content))))
{
- return _cairo_xlib_surface_create_similar_with_format (abstract_src,
- _cairo_format_from_content (content),
- width, height);
+ Visual *visual;
+
+ /* We've got a compatible XRenderFormat now, which means the
+ * similar surface will match the existing surface as closely in
+ * visual/depth etc. as possible. */
+ pix = XCreatePixmap (src->dpy, src->drawable,
+ width <= 0 ? 1 : width, height <= 0 ? 1 : height,
+ xrender_format->depth);
+
+ visual = NULL;
+ if (xrender_format == src->xrender_format)
+ visual = src->visual;
+
+ surface = (cairo_xlib_surface_t *)
+ _cairo_xlib_surface_create_internal (src->screen, pix,
+ visual,
+ xrender_format,
+ width, height,
+ xrender_format->depth);
+ }
+ else
+ {
+#ifdef DEBUG_FORCE_FALLBACKS
+ Screen *screen = src->screen->screen;
+ int depth;
+
+ /* No compatabile XRenderFormat, see if we can make an ordinary pixmap,
+ * so that we can still accelerate blits with XCopyArea(). */
+ if (content != CAIRO_CONTENT_COLOR)
+ return NULL;
+
+ depth = DefaultDepthOfScreen (screen);
+
+ pix = XCreatePixmap (src->dpy, RootWindowOfScreen (screen),
+ width <= 0 ? 1 : width, height <= 0 ? 1 : height,
+ depth);
+
+ surface = (cairo_xlib_surface_t *)
+ _cairo_xlib_surface_create_internal (src->screen, pix,
+ DefaultVisualOfScreen (screen),
+ NULL,
+ width, height, depth);
+#else
+ /* No compatabile XRenderFormat, just say no. */
+ return NULL;
+#endif
}
- /* We've got a compatible XRenderFormat now, which means the
- * similar surface will match the existing surface as closely in
- * visual/depth etc. as possible. */
- pix = XCreatePixmap (src->dpy, src->drawable,
- width <= 0 ? 1 : width, height <= 0 ? 1 : height,
- xrender_format->depth);
-
- surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_internal (src->dpy, pix,
- src->screen, src->visual,
- xrender_format,
- width, height,
- xrender_format->depth);
- if (surface->base.status != CAIRO_STATUS_SUCCESS) {
+ if (unlikely (surface->base.status)) {
XFreePixmap (src->dpy, pix);
return &surface->base;
}
@@ -261,6 +371,8 @@ _cairo_xlib_surface_finish (void *abstract_surface)
cairo_xlib_display_t *display = surface->display;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ X_DEBUG ((surface->dpy, "finish (drawable=%x)", (unsigned int) surface->drawable));
+
if (surface->owns_pixmap) {
cairo_status_t status2;
@@ -268,9 +380,7 @@ _cairo_xlib_surface_finish (void *abstract_surface)
status2 = _cairo_xlib_display_queue_resource (display,
XRenderFreePicture,
surface->dst_picture);
- if (status2 == CAIRO_STATUS_SUCCESS)
- surface->dst_picture = None;
- else if (status == CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_STATUS_SUCCESS)
status = status2;
}
@@ -278,19 +388,14 @@ _cairo_xlib_surface_finish (void *abstract_surface)
status2 = _cairo_xlib_display_queue_resource (display,
XRenderFreePicture,
surface->src_picture);
- if (status2 == CAIRO_STATUS_SUCCESS)
- surface->src_picture = None;
- else if (status == CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_STATUS_SUCCESS)
status = status2;
}
status2 = _cairo_xlib_display_queue_resource (display,
(cairo_xlib_notify_resource_func) XFreePixmap,
surface->drawable);
- if (status2 == CAIRO_STATUS_SUCCESS) {
- surface->owns_pixmap = FALSE;
- surface->drawable = None;
- } else if (status == CAIRO_STATUS_SUCCESS)
+ if (status == CAIRO_STATUS_SUCCESS)
status = status2;
} else {
if (surface->dst_picture != None)
@@ -300,30 +405,18 @@ _cairo_xlib_surface_finish (void *abstract_surface)
XRenderFreePicture (surface->dpy, surface->src_picture);
}
- if (surface->gc != NULL) {
- cairo_status_t status2;
- status2 = _cairo_xlib_screen_put_gc (surface->screen_info,
- surface->depth,
- surface->gc,
- surface->gc_has_clip_rects);
- surface->gc = NULL;
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
- }
-
if (surface->clip_rects != surface->embedded_clip_rects)
free (surface->clip_rects);
- if (surface->screen_info != NULL)
- _cairo_xlib_screen_info_destroy (surface->screen_info);
-
- if (surface->display != NULL) {
+ if (surface->dpy != NULL) {
_cairo_xlib_remove_close_display_hook (surface->display,
&surface->close_display_hook);
- _cairo_xlib_display_destroy (surface->display);
+ surface->dpy = NULL;
}
- surface->dpy = NULL;
+ _cairo_xlib_screen_destroy (surface->screen);
+
+ cairo_region_destroy (surface->clip_region);
return status;
}
@@ -658,9 +751,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
ximage = NULL;
}
- if (!ximage)
- {
-
+ if (ximage == NULL) {
/* 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
@@ -668,8 +759,9 @@ _get_image_surface (cairo_xlib_surface_t *surface,
* temporary pixmap
*/
Pixmap pixmap;
+ GC gc;
- status = _cairo_xlib_surface_ensure_gc (surface);
+ status = _cairo_xlib_surface_get_gc (surface, &gc);
if (unlikely (status))
return status;
@@ -678,7 +770,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
extents.width, extents.height,
surface->depth);
if (pixmap) {
- XCopyArea (surface->dpy, surface->drawable, pixmap, surface->gc,
+ XCopyArea (surface->dpy, surface->drawable, pixmap, gc,
extents.x, extents.y,
extents.width, extents.height,
0, 0);
@@ -691,9 +783,12 @@ _get_image_surface (cairo_xlib_surface_t *surface,
XFreePixmap (surface->dpy, pixmap);
}
+
+ _cairo_xlib_surface_put_gc (surface, gc);
+
+ if (ximage == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- if (!ximage)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_swap_ximage_to_native (ximage);
@@ -703,10 +798,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
xlib_masks.green_mask = surface->g_mask;
xlib_masks.blue_mask = surface->b_mask;
- if (_pixman_format_from_masks (&xlib_masks, &pixman_format) &&
- xlib_masks.bpp >= 24 &&
- ximage->bitmap_unit == 32 &&
- ximage->bitmap_pad == 32)
+ /* We can't use pixman to simply write to image if:
+ * (a) the pixels are not appropriately aligned,
+ * (b) pixman does not the pixel format, or
+ * (c) if the image is palettized and we need to convert.
+ */
+ if (ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
+ _pixman_format_from_masks (&xlib_masks, &pixman_format) &&
+ (surface->visual == NULL || surface->visual->class == TrueColor))
{
image = (cairo_image_surface_t*)
_cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
@@ -735,7 +834,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
int a_width=0, r_width=0, g_width=0, b_width=0;
int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
int x, y, x0, y0, x_off, y_off;
- cairo_xlib_visual_info_t *visual_info;
+ cairo_xlib_visual_info_t *visual_info = NULL;
if (surface->visual == NULL || surface->visual->class == TrueColor) {
cairo_bool_t has_alpha;
@@ -773,7 +872,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
} else {
format = CAIRO_FORMAT_RGB24;
- status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
+ status = _cairo_xlib_screen_get_visual_info (surface->screen,
surface->visual,
&visual_info);
if (unlikely (status))
@@ -801,7 +900,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
int dither_adjustment = dither_row[x_off];
in_pixel = XGetPixel (ximage, x, y);
- if (surface->visual == NULL || surface->visual->class == TrueColor) {
+ if (visual_info == NULL) {
out_pixel = (
_field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
_field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
@@ -833,8 +932,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
static void
_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface)
{
- if (!surface->src_picture)
- {
+ if (!surface->src_picture) {
XRenderPictureAttributes pa;
int mask = 0;
@@ -851,7 +949,7 @@ _cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface)
static void
_cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
{
- if (surface->have_clip_rects) {
+ if (surface->clip_region != NULL) {
XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
0, 0,
surface->clip_rects,
@@ -867,21 +965,6 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
}
static void
-_cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface)
-{
- surface->gc_has_clip_rects = surface->have_clip_rects;
- if (surface->have_clip_rects) {
- XSetClipRectangles(surface->dpy, surface->gc,
- 0, 0,
- surface->clip_rects,
- surface->num_clip_rects, YXSorted);
- } else
- XSetClipMask (surface->dpy, surface->gc, None);
-
- surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC;
-}
-
-static void
_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface)
{
if (!surface->dst_picture) {
@@ -896,29 +979,25 @@ _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface)
}
static cairo_status_t
-_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
+_cairo_xlib_surface_get_gc (cairo_xlib_surface_t *surface, GC *gc)
{
- XGCValues gcv;
-
- if (surface->gc == NULL) {
- surface->gc = _cairo_xlib_screen_get_gc (surface->screen_info,
- surface->depth,
- &surface->clip_dirty);
- if (surface->gc == NULL) {
- gcv.graphics_exposures = False;
- surface->gc = XCreateGC (surface->dpy, surface->drawable,
- GCGraphicsExposures, &gcv);
- if (unlikely (surface->gc == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
- }
-
- if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC)
- _cairo_xlib_surface_set_gc_clip_rects (surface);
+ *gc = _cairo_xlib_screen_get_gc (surface->screen,
+ surface->depth,
+ surface->drawable);
+ if (unlikely (*gc == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
}
+static void
+_cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc)
+{
+ _cairo_xlib_screen_put_gc (surface->screen,
+ surface->depth,
+ gc);
+}
+
static cairo_status_t
_draw_image_surface (cairo_xlib_surface_t *surface,
cairo_image_surface_t *image,
@@ -932,10 +1011,10 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
XImage ximage;
cairo_format_masks_t image_masks;
int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
+ pixman_image_t *pixman_image = NULL;
cairo_status_t status;
cairo_bool_t own_data;
-
- _pixman_format_to_masks (image->pixman_format, &image_masks);
+ GC gc;
ximage.width = image->width;
ximage.height = image->height;
@@ -950,10 +1029,48 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
ximage.blue_mask = surface->b_mask;
ximage.xoffset = 0;
- if ((image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
- (image_masks.red_mask == surface->r_mask || surface->r_mask == 0) &&
- (image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
- (image_masks.blue_mask == surface->b_mask || surface->b_mask == 0))
+ if (!_pixman_format_to_masks (image->pixman_format, &image_masks))
+ {
+ pixman_format_code_t intermediate_format;
+ int ret;
+
+ image_masks.alpha_mask = surface->a_mask;
+ image_masks.red_mask = surface->r_mask;
+ image_masks.green_mask = surface->g_mask;
+ image_masks.blue_mask = surface->b_mask;
+ image_masks.bpp = surface->depth;
+ ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
+ assert (ret);
+
+ pixman_image = pixman_image_create_bits (intermediate_format,
+ image->width,
+ image->height,
+ NULL,
+ 0);
+ if (pixman_image == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pixman_image_composite (PIXMAN_OP_SRC,
+ image->pixman_image,
+ NULL,
+ pixman_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ image->width, image->height);
+
+ ximage.bits_per_pixel = image_masks.bpp;
+ ximage.data = (char *) pixman_image_get_data (pixman_image);
+ ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
+ own_data = FALSE;
+
+ ret = XInitImage (&ximage);
+ assert (ret != 0);
+ }
+ else if ((image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
+ (image_masks.red_mask == surface->r_mask || surface->r_mask == 0) &&
+ (image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
+ (image_masks.blue_mask == surface->b_mask || surface->b_mask == 0))
{
int ret;
@@ -964,7 +1081,9 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
ret = XInitImage (&ximage);
assert (ret != 0);
- } else {
+ }
+ else
+ {
unsigned int stride, rowstride;
int x, y, x0, y0, x_off, y_off;
uint32_t in_pixel, out_pixel, *row;
@@ -976,15 +1095,14 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
cairo_bool_t true_color;
int ret;
- if (surface->depth > 16) {
+ if (surface->depth > 16)
ximage.bits_per_pixel = 32;
- } else if (surface->depth > 8) {
+ else if (surface->depth > 8)
ximage.bits_per_pixel = 16;
- } else if (surface->depth > 1) {
+ else if (surface->depth > 1)
ximage.bits_per_pixel = 8;
- } else {
+ else
ximage.bits_per_pixel = 1;
- }
stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width,
ximage.bits_per_pixel);
ximage.bytes_per_line = stride;
@@ -1010,7 +1128,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
_characterize_field (surface->g_mask, &o_g_width, &o_g_shift);
_characterize_field (surface->b_mask, &o_b_width, &o_b_shift);
} else {
- status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
+ status = _cairo_xlib_screen_get_visual_info (surface->screen,
surface->visual,
&visual_info);
if (unlikely (status))
@@ -1038,6 +1156,16 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
in_pixel = ((uint8_t*)row)[x];
else if (image_masks.bpp <= 16)
in_pixel = ((uint16_t*)row)[x];
+ else if (image_masks.bpp <= 24)
+#ifdef WORDS_BIGENDIAN
+ in_pixel = ((uint8_t*)row)[3 * x] << 16 |
+ ((uint8_t*)row)[3 * x + 1] << 8 |
+ ((uint8_t*)row)[3 * x + 2];
+#else
+ in_pixel = ((uint8_t*)row)[3 * x] |
+ ((uint8_t*)row)[3 * x + 1] << 8 |
+ ((uint8_t*)row)[3 * x + 2] << 16;
+#endif
else
in_pixel = row[x];
@@ -1069,19 +1197,23 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
}
}
- status = _cairo_xlib_surface_ensure_gc (surface);
+ status = _cairo_xlib_surface_get_gc (surface, &gc);
if (unlikely (status))
goto BAIL;
- XPutImage(surface->dpy, surface->drawable, surface->gc,
- &ximage, src_x, src_y, dst_x, dst_y,
- width, height);
+ XPutImage (surface->dpy, surface->drawable, gc,
+ &ximage, src_x, src_y, dst_x, dst_y,
+ width, height);
+
+ _cairo_xlib_surface_put_gc (surface, gc);
BAIL:
if (own_data)
free (ximage.data);
+ if (pixman_image)
+ pixman_image_unref (pixman_image);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -1175,11 +1307,11 @@ _cairo_xlib_surface_release_dest_image (void *abstract_surfac
* screen. Both core and Render drawing require this
* when using multiple drawables in an operation.
*/
-static cairo_bool_t
+static inline cairo_bool_t
_cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
cairo_xlib_surface_t *src)
{
- return dst->dpy == src->dpy && dst->screen == src->screen;
+ return dst->screen == src->screen;
}
static cairo_status_t
@@ -1212,25 +1344,18 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface,
}
} else if (_cairo_surface_is_image (src)) {
cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
- cairo_format_t format;
if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("roi too large for xlib");
- format = image_src->format;
- if (format == CAIRO_FORMAT_INVALID ||
- (_cairo_content_from_format (format) & ~content))
- {
- format = _cairo_format_from_content (image_src->base.content & content);
- }
clone = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_similar_with_format (surface,
- format,
- width, height);
+ _cairo_xlib_surface_create_similar (surface,
+ image_src->base.content & content,
+ width, height);
if (clone == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unhandled image format, no similar surface");
- if (clone->base.status)
+ if (unlikely (clone->base.status))
return clone->base.status;
status = _draw_image_surface (clone, image_src,
@@ -1277,9 +1402,6 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
return NULL;
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
- return NULL;
-
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_content (solid_pattern->content,
width, height);
@@ -1293,9 +1415,9 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
other->depth);
surface = (cairo_xlib_surface_t *)
- _cairo_xlib_surface_create_internal (other->dpy,
+ _cairo_xlib_surface_create_internal (other->screen,
pixmap,
- other->screen, other->visual,
+ other->visual,
other->xrender_format,
width, height,
other->depth);
@@ -1305,7 +1427,8 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
status = _cairo_surface_paint (&image->base,
CAIRO_OPERATOR_SOURCE,
- &solid_pattern->base, NULL);
+ &solid_pattern->base,
+ NULL);
if (unlikely (status))
goto BAIL;
@@ -1339,7 +1462,6 @@ _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface,
return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other);
}
-
static cairo_status_t
_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
cairo_matrix_t *matrix,
@@ -1348,9 +1470,6 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
{
XTransform xtransform;
- if (!surface->src_picture)
- return CAIRO_STATUS_SUCCESS;
-
/* Casting between pixman_transform_t and XTransform is safe because
* they happen to be the exact same type.
*/
@@ -1361,8 +1480,8 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
return CAIRO_STATUS_SUCCESS;
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ return UNSUPPORTED ("XRender does not support picture transforms");
XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
surface->xtransform = xtransform;
@@ -1376,18 +1495,14 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
{
const char *render_filter;
- if (!surface->src_picture)
- return CAIRO_STATUS_SUCCESS;
-
if (surface->filter == filter)
return CAIRO_STATUS_SUCCESS;
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
+ if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) {
if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
return CAIRO_STATUS_SUCCESS;
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("XRender does not support filter");
}
switch (filter) {
@@ -1424,23 +1539,48 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
+static cairo_status_t
+_cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
+ cairo_extend_t extend)
{
XRenderPictureAttributes pa;
unsigned long mask;
+ int repeat;
- if (!surface->src_picture)
- return;
+ if (surface->extend == extend)
+ return CAIRO_STATUS_SUCCESS;
- if (surface->repeat == repeat)
- return;
+ switch (extend) {
+ case CAIRO_EXTEND_NONE:
+ repeat = RepeatNone;
+ break;
+ case CAIRO_EXTEND_REPEAT:
+ repeat = RepeatNormal;
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ if (surface->buggy_pad_reflect)
+ return UNSUPPORTED ("buggy reflect");
+
+ repeat = RepeatReflect;
+ break;
+ case CAIRO_EXTEND_PAD:
+ if (surface->buggy_pad_reflect)
+ return UNSUPPORTED ("buggy pad");
+
+ repeat = RepeatPad;
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
mask = CPRepeat;
pa.repeat = repeat;
XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
- surface->repeat = repeat;
+ surface->extend = extend;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -1458,26 +1598,9 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
if (unlikely (status))
return status;
- switch (attributes->extend) {
- case CAIRO_EXTEND_NONE:
- _cairo_xlib_surface_set_repeat (surface, RepeatNone);
- break;
- case CAIRO_EXTEND_REPEAT:
- _cairo_xlib_surface_set_repeat (surface, RepeatNormal);
- break;
- case CAIRO_EXTEND_REFLECT:
- if (surface->buggy_pad_reflect)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_xlib_surface_set_repeat (surface, RepeatReflect);
- break;
- case CAIRO_EXTEND_PAD:
- if (surface->buggy_pad_reflect)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- _cairo_xlib_surface_set_repeat (surface, RepeatPad);
- break;
- default:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
+ status = _cairo_xlib_surface_set_repeat (surface, attributes->extend);
+ if (unlikely (status))
+ return status;
status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
if (unlikely (status))
@@ -1495,7 +1618,7 @@ _surfaces_compatible (cairo_xlib_surface_t *dst,
cairo_xlib_surface_t *src)
{
/* same screen */
- if (!_cairo_xlib_surface_same_screen (dst, src))
+ if (! _cairo_xlib_surface_same_screen (dst, src))
return FALSE;
/* same depth (for core) */
@@ -1525,7 +1648,6 @@ _surface_has_alpha (cairo_xlib_surface_t *surface)
else
return FALSE;
} else {
-
/* In the no-render case, we never have alpha */
return FALSE;
}
@@ -1585,27 +1707,38 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst,
cairo_bool_t have_mask)
{
- if (!dst->buggy_repeat)
+ if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (dst, op))
+ return DO_UNSUPPORTED;
+
+ if (! dst->buggy_repeat)
return DO_RENDER;
- if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
+ if (src_pattern->type != CAIRO_PATTERN_TYPE_SOLID &&
+ src_pattern->extend == CAIRO_EXTEND_REPEAT)
{
- cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
+ /* Check for the bug with repeat patterns nad general transforms. */
+ if (! _cairo_matrix_is_integer_translation (&src_pattern->matrix,
+ NULL, NULL))
+ {
+ return DO_UNSUPPORTED;
+ }
- if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
- src_pattern->extend == CAIRO_EXTEND_REPEAT)
+ if (have_mask ||
+ !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
{
+ return DO_UNSUPPORTED;
+ }
+
+ if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) src_pattern;
+
/* This is the case where we have the bug involving
* untransformed repeating source patterns with off-screen
* video memory; reject some cases where a core protocol
* fallback is impossible.
*/
- if (have_mask ||
- !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
- return DO_UNSUPPORTED;
-
if (_cairo_surface_is_xlib (surface_pattern->surface)) {
- cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)surface_pattern->surface;
+ cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) surface_pattern->surface;
if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
return DO_UNSUPPORTED;
@@ -1616,15 +1749,11 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst,
*/
if (_cairo_xlib_surface_same_screen (dst, src) &&
!_surfaces_compatible (dst, src))
+ {
return DO_UNSUPPORTED;
+ }
}
}
-
- /* Check for the other bug involving repeat patterns with general
- * transforms. */
- if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
- src_pattern->extend == CAIRO_EXTEND_REPEAT)
- return DO_UNSUPPORTED;
}
return DO_RENDER;
@@ -1645,41 +1774,24 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst,
cairo_surface_attributes_t *src_attr,
cairo_bool_t have_mask)
{
- cairo_bool_t is_integer_translation =
- _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
- cairo_bool_t needs_alpha_composite;
-
- if (! _cairo_surface_is_xlib (&src->base))
- return DO_UNSUPPORTED;
-
- needs_alpha_composite =
- _operator_needs_alpha_composite (op,
- _surface_has_alpha (dst),
- _surface_has_alpha (src));
-
+ /* Can we use the core protocol? */
if (! have_mask &&
- is_integer_translation &&
- src_attr->extend == CAIRO_EXTEND_NONE &&
- ! needs_alpha_composite &&
- _surfaces_compatible (src, dst))
+ src->owns_pixmap &&
+ src->depth == dst->depth &&
+ _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
+ ! _operator_needs_alpha_composite (op,
+ _surface_has_alpha (dst),
+ _surface_has_alpha (src)))
{
- return DO_XCOPYAREA;
- }
+ if (src_attr->extend == CAIRO_EXTEND_NONE)
+ return DO_XCOPYAREA;
- if (dst->buggy_repeat &&
- is_integer_translation &&
- src_attr->extend == CAIRO_EXTEND_REPEAT &&
- (src->width != 1 || src->height != 1))
- {
- if (! have_mask &&
- ! needs_alpha_composite &&
- _surfaces_compatible (dst, src))
- {
+ if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
return DO_XTILE;
- }
+ }
+ if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
return DO_UNSUPPORTED;
- }
if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
return DO_UNSUPPORTED;
@@ -1725,12 +1837,293 @@ _render_operator (cairo_operator_t op)
return PictOpAdd;
case CAIRO_OPERATOR_SATURATE:
return PictOpSaturate;
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ return PictOpMultiply;
+ case CAIRO_OPERATOR_SCREEN:
+ return PictOpScreen;
+ case CAIRO_OPERATOR_OVERLAY:
+ return PictOpOverlay;
+ case CAIRO_OPERATOR_DARKEN:
+ return PictOpDarken;
+ case CAIRO_OPERATOR_LIGHTEN:
+ return PictOpLighten;
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ return PictOpColorDodge;
+ case CAIRO_OPERATOR_COLOR_BURN:
+ return PictOpColorBurn;
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ return PictOpHardLight;
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ return PictOpSoftLight;
+ case CAIRO_OPERATOR_DIFFERENCE:
+ return PictOpDifference;
+ case CAIRO_OPERATOR_EXCLUSION:
+ return PictOpExclusion;
+ case CAIRO_OPERATOR_HSL_HUE:
+ return PictOpHSLHue;
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ return PictOpHSLSaturation;
+ case CAIRO_OPERATOR_HSL_COLOR:
+ return PictOpHSLColor;
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ return PictOpHSLLuminosity;
+
default:
+ ASSERT_NOT_REACHED;
return PictOpOver;
}
}
static cairo_int_status_t
+_cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_surface_t *dst,
+ const cairo_pattern_t *pattern,
+ cairo_content_t content,
+ int x, int y,
+ int width, int height,
+ cairo_xlib_surface_t **surface_out,
+ cairo_surface_attributes_t *attributes)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ {
+ cairo_gradient_pattern_t *gradient =
+ (cairo_gradient_pattern_t *) pattern;
+ cairo_matrix_t matrix = pattern->matrix;
+ cairo_xlib_surface_t *surface;
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ XFixed *stops;
+ XRenderColor *colors;
+ XRenderPictFormat *format;
+ Picture picture;
+ unsigned int i;
+
+ if (dst->buggy_gradients)
+ break;
+
+ if (gradient->n_stops < 2) /* becomes a solid */
+ break;
+
+ if (gradient->n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
+ {
+ stops = (XFixed *) buf;
+ }
+ else
+ {
+ stops =
+ _cairo_malloc_ab (gradient->n_stops,
+ sizeof (XFixed) + sizeof (XRenderColor));
+ if (unlikely (stops == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ colors = (XRenderColor *) (stops + gradient->n_stops);
+ for (i = 0; i < gradient->n_stops; i++) {
+ stops[i] =
+ _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
+
+ colors[i].red = gradient->stops[i].color.red_short;
+ colors[i].green = gradient->stops[i].color.green_short;
+ colors[i].blue = gradient->stops[i].color.blue_short;
+ colors[i].alpha = gradient->stops[i].color.alpha_short;
+ }
+
+#if 0
+ /* For some weird reason the X server is sometimes getting
+ * CreateGradient requests with bad length. So far I've only seen
+ * XRenderCreateLinearGradient request with 4 stops sometime end up
+ * with length field matching 0 stops at the server side. I've
+ * looked at the libXrender code and I can't see anything that
+ * could cause this behavior. However, for some reason having a
+ * XSync call here seems to avoid the issue so I'll keep it here
+ * until it's solved.
+ */
+ XSync (dst->dpy, False);
+#endif
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
+ cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
+ XLinearGradient grad;
+
+ cairo_fixed_t xdim, ydim;
+
+ xdim = linear->p2.x - linear->p1.x;
+ ydim = linear->p2.y - linear->p1.y;
+
+ /*
+ * Transform the matrix to avoid overflow when converting between
+ * cairo_fixed_t and pixman_fixed_t (without incurring performance
+ * loss when the transformation is unnecessary).
+ *
+ * XXX: Consider converting out-of-range co-ordinates and transforms.
+ * Having a function to compute the required transformation to
+ * "normalize" a given bounding box would be generally useful -
+ * cf linear patterns, gradient patterns, surface patterns...
+ */
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+ if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
+ _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
+ {
+ double sf;
+
+ if (xdim > ydim)
+ sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
+ else
+ sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
+
+ grad.p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
+ grad.p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
+ grad.p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
+ grad.p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
+
+ cairo_matrix_scale (&matrix, sf, sf);
+ }
+ else
+ {
+ grad.p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
+ grad.p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
+ grad.p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
+ grad.p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
+ }
+
+ picture = XRenderCreateLinearGradient (dst->dpy, &grad,
+ stops, colors,
+ gradient->n_stops);
+ } else {
+ cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
+ XRadialGradient grad;
+
+ grad.inner.x = _cairo_fixed_to_16_16 (radial->c1.x);
+ grad.inner.y = _cairo_fixed_to_16_16 (radial->c1.y);
+ grad.inner.radius = _cairo_fixed_to_16_16 (radial->r1);
+
+ grad.outer.x = _cairo_fixed_to_16_16 (radial->c2.x);
+ grad.outer.y = _cairo_fixed_to_16_16 (radial->c2.y);
+ grad.outer.radius = _cairo_fixed_to_16_16 (radial->r2);
+
+ picture = XRenderCreateRadialGradient (dst->dpy, &grad,
+ stops, colors,
+ gradient->n_stops);
+
+ }
+
+ if (stops != (XFixed *) buf)
+ free (stops);
+
+ if (unlikely (picture == None))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ /* Wrap the remote Picture in an xlib surface. */
+ format = _cairo_xlib_display_get_xrender_format (dst->display,
+ CAIRO_FORMAT_ARGB32);
+
+ surface = (cairo_xlib_surface_t *)
+ _cairo_xlib_surface_create_internal (dst->screen, None,
+ NULL, format,
+ 0, 0, 32);
+ if (unlikely (surface->base.status)) {
+ XRenderFreePicture (dst->dpy, picture);
+ return surface->base.status;
+ }
+
+ surface->src_picture = picture;
+
+ attributes->matrix = matrix;
+ attributes->extend = pattern->extend;
+ attributes->filter = CAIRO_FILTER_NEAREST;
+ attributes->x_offset = 0;
+ attributes->y_offset = 0;
+
+ *surface_out = surface;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_PATTERN_TYPE_SOLID:
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ break;
+ }
+
+ return _cairo_pattern_acquire_surface (pattern, &dst->base,
+ content,
+ x, y, width, height,
+ dst->buggy_pad_reflect ?
+ CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
+ CAIRO_PATTERN_ACQUIRE_NONE,
+ (cairo_surface_t **) surface_out,
+ attributes);
+}
+
+static cairo_int_status_t
+_cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_surface_t *dst,
+ const cairo_pattern_t *src,
+ const cairo_pattern_t *mask,
+ cairo_content_t src_content,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ unsigned int width,
+ unsigned int height,
+ cairo_xlib_surface_t **src_out,
+ cairo_xlib_surface_t **mask_out,
+ cairo_surface_attributes_t *src_attr,
+ cairo_surface_attributes_t *mask_attr)
+{
+ if (! dst->buggy_gradients &&
+ (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
+ src->type == CAIRO_PATTERN_TYPE_RADIAL ||
+ (mask && (mask->type == CAIRO_PATTERN_TYPE_LINEAR ||
+ mask->type == CAIRO_PATTERN_TYPE_RADIAL))))
+ {
+ cairo_int_status_t status;
+
+ status = _cairo_xlib_surface_acquire_pattern_surface (dst, src,
+ src_content,
+ src_x, src_y,
+ width, height,
+ src_out,
+ src_attr);
+ if (unlikely (status))
+ return status;
+
+ if (mask) {
+ status = _cairo_xlib_surface_acquire_pattern_surface (dst, mask,
+ CAIRO_CONTENT_ALPHA,
+ mask_x,
+ mask_y,
+ width,
+ height,
+ mask_out,
+ mask_attr);
+ if (unlikely (status)) {
+ _cairo_pattern_release_surface (src, &(*src_out)->base,
+ src_attr);
+ return status;
+ }
+ } else {
+ *mask_out = NULL;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ return _cairo_pattern_acquire_surfaces (src, mask,
+ &dst->base,
+ src_content,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ dst->buggy_pad_reflect ?
+ CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
+ CAIRO_PATTERN_ACQUIRE_NONE,
+ (cairo_surface_t **) src_out,
+ (cairo_surface_t **) mask_out,
+ src_attr, mask_attr);
+}
+
+static cairo_int_status_t
_cairo_xlib_surface_composite (cairo_operator_t op,
const cairo_pattern_t *src_pattern,
const cairo_pattern_t *mask_pattern,
@@ -1742,7 +2135,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
int dst_x,
int dst_y,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ cairo_region_t *clip_region)
{
cairo_surface_attributes_t src_attr, mask_attr;
cairo_xlib_surface_t *dst = abstract_dst;
@@ -1754,13 +2148,17 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
cairo_bool_t is_integer_translation;
cairo_bool_t needs_alpha_composite;
cairo_content_t src_content;
+ GC gc;
- _cairo_xlib_display_notify (dst->display);
+ if (mask_pattern != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
+ return UNSUPPORTED ("no support for masks");
operation = _categorize_composite_operation (dst, op, src_pattern,
mask_pattern != NULL);
if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unsupported operation");
+
+ X_DEBUG ((dst->dpy, "composite (dst=%x)", (unsigned int) dst->drawable));
needs_alpha_composite =
_operator_needs_alpha_composite (op,
@@ -1770,38 +2168,33 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
if (! needs_alpha_composite)
src_content &= ~CAIRO_CONTENT_ALPHA;
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_content,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- dst->buggy_pad_reflect ?
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
+ _cairo_xlib_display_notify (dst->display);
+
+ status =
+ _cairo_xlib_surface_acquire_pattern_surfaces (dst,
+ src_pattern, mask_pattern,
+ src_content,
+ src_x, src_y,
+ mask_x, mask_y,
+ width, height,
+ &src, &mask,
+ &src_attr, &mask_attr);
if (unlikely (status))
return status;
/* check for fallback surfaces that we cannot handle ... */
- if (!_cairo_surface_is_xlib (&src->base)) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
- if (mask != NULL &&
- (! _cairo_surface_is_xlib (&mask->base) ||
- ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)))
- {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ assert (_cairo_surface_is_xlib (&src->base));
+ assert (mask == NULL || _cairo_surface_is_xlib (&mask->base));
+
+ if (mask != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (mask)) {
+ status = UNSUPPORTED ("unsupported mask");
goto BAIL;
}
operation = _recategorize_composite_operation (dst, op, src, &src_attr,
mask_pattern != NULL);
if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = UNSUPPORTED ("unsupported operation");
goto BAIL;
}
@@ -1814,6 +2207,10 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
if (unlikely (status))
goto BAIL;
+ status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ goto BAIL;
+
_cairo_xlib_surface_ensure_dst_picture (dst);
if (mask) {
status = _cairo_xlib_surface_set_attributes (mask, &mask_attr,
@@ -1849,23 +2246,40 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
break;
case DO_XCOPYAREA:
- status = _cairo_xlib_surface_ensure_gc (dst);
+ status = _cairo_xlib_surface_get_gc (dst, &gc);
if (unlikely (status))
goto BAIL;
- is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
- &itx, &ity);
+ is_integer_translation =
+ _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
/* This is a pre-condition for DO_XCOPYAREA. */
assert (is_integer_translation);
- XCopyArea (dst->dpy,
- src->drawable,
- dst->drawable,
- dst->gc,
- src_x + src_attr.x_offset + itx,
- src_y + src_attr.y_offset + ity,
- width, height,
- dst_x, dst_y);
+ if (clip_region == NULL) {
+ XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+ src_x + src_attr.x_offset + itx,
+ src_y + src_attr.y_offset + ity,
+ width, height,
+ dst_x, dst_y);
+ } else {
+ int n, num_rects;
+
+ src_x += src_attr.x_offset + itx - dst_x;
+ src_y += src_attr.y_offset + ity - dst_y;
+
+ num_rects = cairo_region_num_rectangles (clip_region);
+ for (n = 0; n < num_rects; n++) {
+ cairo_rectangle_int_t rect;
+
+ cairo_region_get_rectangle (clip_region, n, &rect);
+ XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+ rect.x + src_x, rect.y + src_y,
+ rect.width, rect.height,
+ rect.x, rect.y);
+ }
+ }
+
+ _cairo_xlib_surface_put_gc (dst, gc);
break;
case DO_XTILE:
@@ -1877,21 +2291,36 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
* _recategorize_composite_operation.
*/
- status = _cairo_xlib_surface_ensure_gc (dst);
+ status = _cairo_xlib_surface_get_gc (dst, &gc);
if (unlikely (status))
goto BAIL;
- is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
- &itx, &ity);
+
+ is_integer_translation =
+ _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
/* This is a pre-condition for DO_XTILE. */
assert (is_integer_translation);
- XSetTSOrigin (dst->dpy, dst->gc,
+ XSetTSOrigin (dst->dpy, gc,
- (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
- XSetTile (dst->dpy, dst->gc, src->drawable);
- XSetFillStyle (dst->dpy, dst->gc, FillTiled);
+ XSetTile (dst->dpy, gc, src->drawable);
+
+ if (clip_region == NULL) {
+ XFillRectangle (dst->dpy, dst->drawable, gc,
+ dst_x, dst_y, width, height);
+ } else {
+ int n, num_rects;
+
+ num_rects = cairo_region_num_rectangles (clip_region);
+ for (n = 0; n < num_rects; n++) {
+ cairo_rectangle_int_t rect;
- XFillRectangle (dst->dpy, dst->drawable, dst->gc,
- dst_x, dst_y, width, height);
+ cairo_region_get_rectangle (clip_region, n, &rect);
+ XFillRectangle (dst->dpy, dst->drawable, gc,
+ rect.x, rect.y, rect.width, rect.height);
+ }
+ }
+
+ _cairo_xlib_surface_put_gc (dst, gc);
break;
case DO_UNSUPPORTED:
@@ -1907,7 +2336,8 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
mask ? mask->height : 0,
src_x, src_y,
mask_x, mask_y,
- dst_x, dst_y, width, height);
+ dst_x, dst_y, width, height,
+ clip_region);
BAIL:
if (mask)
@@ -1918,6 +2348,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
return status;
}
+/* XXX move this out of core and into acquire_pattern_surface() above. */
static cairo_int_status_t
_cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
const cairo_color_t *color,
@@ -1928,14 +2359,17 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
cairo_solid_pattern_t solid;
cairo_surface_t *solid_surface = NULL;
cairo_surface_attributes_t attrs;
+ GC gc;
int i;
_cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR);
- status = _cairo_xlib_surface_ensure_gc (surface);
+ status = _cairo_xlib_surface_get_gc (surface, &gc);
if (unlikely (status))
return status;
+ X_DEBUG ((surface->dpy, "solid_fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
+
status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
0, 0,
@@ -1944,31 +2378,30 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
CAIRO_PATTERN_ACQUIRE_NONE,
&solid_surface,
&attrs);
- if (unlikely (status))
- return status;
-
- if (! _cairo_surface_is_xlib (solid_surface)) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
+ if (unlikely (status)) {
+ _cairo_xlib_surface_put_gc (surface, gc);
+ return status;
}
- XSetTSOrigin (surface->dpy, surface->gc,
+ assert (_cairo_surface_is_xlib (solid_surface));
+
+ XSetTSOrigin (surface->dpy, gc,
- (surface->base.device_transform.x0 + attrs.x_offset),
- (surface->base.device_transform.y0 + attrs.y_offset));
- XSetTile (surface->dpy, surface->gc,
+ XSetTile (surface->dpy, gc,
((cairo_xlib_surface_t *) solid_surface)->drawable);
- XSetFillStyle (surface->dpy, surface->gc, FillTiled);
for (i = 0; i < num_rects; i++) {
- XFillRectangle (surface->dpy, surface->drawable, surface->gc,
+ XFillRectangle (surface->dpy, surface->drawable, gc,
rects[i].x, rects[i].y,
rects[i].width, rects[i].height);
}
- BAIL:
+ _cairo_xlib_surface_put_gc (surface, gc);
+
_cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -1980,11 +2413,15 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
{
cairo_xlib_surface_t *surface = abstract_surface;
XRenderColor render_color;
+ cairo_status_t status;
int i;
_cairo_xlib_display_notify (surface->display);
- if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
+ if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (surface, op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
if (op == CAIRO_OPERATOR_CLEAR ||
((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
CAIRO_COLOR_IS_OPAQUE (color)))
@@ -1993,14 +2430,19 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
rects, num_rects);
}
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("no support for FillRectangles with this op");
}
+ X_DEBUG ((surface->dpy, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
+
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
+ status = _cairo_xlib_surface_set_clip_region (surface, NULL);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
_cairo_xlib_surface_ensure_dst_picture (surface);
if (num_rects == 1) {
/* Take advantage of the protocol compaction that libXrender performs
@@ -2043,117 +2485,41 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-/* Creates an A8 picture of size @width x @height, initialized with @color
- */
-static Picture
-_create_a8_picture (cairo_xlib_surface_t *surface,
- XRenderColor *color,
- int width,
- int height,
- cairo_bool_t repeat)
-{
- XRenderPictureAttributes pa;
- unsigned long mask = 0;
-
- Pixmap pixmap;
- Picture picture;
- XRenderPictFormat *xrender_format;
-
- if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
- return None;
-
- xrender_format =
- _cairo_xlib_display_get_xrender_format (surface->display,
- CAIRO_FORMAT_A8);
- if (xrender_format == NULL)
- return None;
-
- pixmap = XCreatePixmap (surface->dpy, surface->drawable,
- width <= 0 ? 1 : width,
- height <= 0 ? 1 : height,
- 8);
-
- if (repeat) {
- pa.repeat = TRUE;
- mask = CPRepeat;
- }
+#define CAIRO_FIXED_16_16_MIN -32768
+#define CAIRO_FIXED_16_16_MAX 32767
- picture = XRenderCreatePicture (surface->dpy, pixmap,
- xrender_format, mask, &pa);
- XRenderFillRectangle (surface->dpy, PictOpSrc, picture, color,
- 0, 0, width, height);
- XFreePixmap (surface->dpy, pixmap);
-
- return picture;
+static cairo_bool_t
+_line_exceeds_16_16 (const cairo_line_t *line)
+{
+ return
+ line->p1.x < CAIRO_FIXED_16_16_MIN ||
+ line->p1.x > CAIRO_FIXED_16_16_MAX ||
+ line->p2.x < CAIRO_FIXED_16_16_MIN ||
+ line->p2.x > CAIRO_FIXED_16_16_MAX ||
+ line->p1.y < CAIRO_FIXED_16_16_MIN ||
+ line->p1.y > CAIRO_FIXED_16_16_MAX ||
+ line->p2.y < CAIRO_FIXED_16_16_MIN ||
+ line->p2.y > CAIRO_FIXED_16_16_MAX;
}
-/* Creates a temporary mask for the trapezoids covering the area
- * [@dst_x, @dst_y, @width, @height] of the destination surface.
- */
-static Picture
-_create_trapezoid_mask (cairo_xlib_surface_t *dst,
- cairo_trapezoid_t *traps,
- int num_traps,
- int dst_x,
- int dst_y,
- int width,
- int height,
- XRenderPictFormat *pict_format)
+static void
+_project_line_x_onto_16_16 (const cairo_line_t *line,
+ cairo_fixed_t top,
+ cairo_fixed_t bottom,
+ XLineFixed *out)
{
- XRenderColor transparent = { 0, 0, 0, 0 };
- XRenderColor solid = { 0xffff, 0xffff, 0xffff, 0xffff };
- Picture mask_picture, solid_picture;
- XTrapezoid *offset_traps;
- int i;
-
- /* This would be considerably simpler using XRenderAddTraps(), but since
- * we are only using this in the unbounded-operator case, we stick with
- * XRenderCompositeTrapezoids, which is available on older versions
- * of RENDER rather than conditionalizing. We should still hit an
- * optimization that avoids creating another intermediate surface on
- * the servers that have XRenderAddTraps().
- */
- mask_picture = _create_a8_picture (dst, &transparent, width, height, FALSE);
- if (mask_picture == None || num_traps == 0)
- return mask_picture;
-
- offset_traps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
- if (!offset_traps) {
- XRenderFreePicture (dst->dpy, mask_picture);
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- return None;
- }
+ cairo_point_double_t p1, p2;
+ double m;
- for (i = 0; i < num_traps; i++) {
- offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
- offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
- offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
- offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
- offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
- offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
- offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
- offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
- offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
- offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
- }
+ p1.x = _cairo_fixed_to_double (line->p1.x);
+ p1.y = _cairo_fixed_to_double (line->p1.y);
- solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
- if (solid_picture == None) {
- XRenderFreePicture (dst->dpy, mask_picture);
- free (offset_traps);
- return None;
- }
+ p2.x = _cairo_fixed_to_double (line->p2.x);
+ p2.y = _cairo_fixed_to_double (line->p2.y);
- XRenderCompositeTrapezoids (dst->dpy, PictOpAdd,
- solid_picture, mask_picture,
- pict_format,
- 0, 0,
- offset_traps, num_traps);
-
- XRenderFreePicture (dst->dpy, solid_picture);
- free (offset_traps);
-
- return mask_picture;
+ m = (p2.x - p1.x) / (p2.y - p1.y);
+ out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+ out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
}
static cairo_int_status_t
@@ -2168,7 +2534,8 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
unsigned int width,
unsigned int height,
cairo_trapezoid_t *traps,
- int num_traps)
+ int num_traps,
+ cairo_region_t *clip_region)
{
cairo_surface_attributes_t attributes;
cairo_xlib_surface_t *dst = abstract_dst;
@@ -2178,31 +2545,34 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
int render_reference_x, render_reference_y;
int render_src_x, render_src_y;
XRenderPictFormat *pict_format;
+ XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
+ XTrapezoid *xtraps = xtraps_stack;
+ int i;
_cairo_xlib_display_notify (dst->display);
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
+ return UNSUPPORTED ("XRender does not support CompositeTrapezoids");
operation = _categorize_composite_operation (dst, op, pattern, TRUE);
if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unsupported operation");
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- CAIRO_CONTENT_COLOR_ALPHA,
- src_x, src_y, width, height,
- dst->buggy_pad_reflect ?
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- &attributes);
+ X_DEBUG ((dst->dpy, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
+
+ status = _cairo_xlib_surface_acquire_pattern_surface (dst,
+ pattern,
+ CAIRO_CONTENT_COLOR_ALPHA,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
if (unlikely (status))
return status;
operation = _recategorize_composite_operation (dst, op, src,
&attributes, TRUE);
if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = UNSUPPORTED ("unsupported operation");
goto BAIL;
}
@@ -2233,204 +2603,108 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
render_src_x = src_x + render_reference_x - dst_x;
render_src_y = src_y + render_reference_y - dst_y;
+ status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ goto BAIL;
+
_cairo_xlib_surface_ensure_dst_picture (dst);
+
status = _cairo_xlib_surface_set_attributes (src, &attributes,
dst_x + width / 2.,
dst_y + height / 2.);
if (unlikely (status))
goto BAIL;
- if (!_cairo_operator_bounded_by_mask (op)) {
- /* XRenderCompositeTrapezoids() creates a mask only large enough for the
- * trapezoids themselves, but if the operator is unbounded, then we need
- * to actually composite all the way out to the bounds, so we create
- * the mask and composite ourselves. There actually would
- * be benefit to doing this in all cases, since RENDER implementations
- * will frequently create a too temporary big mask, ignoring destination
- * bounds and clip. (XRenderAddTraps() could be used to make creating
- * the mask somewhat cheaper.)
- */
- Picture mask_picture = _create_trapezoid_mask (dst, traps, num_traps,
- dst_x, dst_y, width, height,
- pict_format);
- if (!mask_picture) {
+ if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
+ xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
+ if (unlikely (xtraps == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
-
- XRenderComposite (dst->dpy,
- _render_operator (op),
- src->src_picture,
- mask_picture,
- dst->dst_picture,
- src_x + attributes.x_offset,
- src_y + attributes.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
-
- XRenderFreePicture (dst->dpy, mask_picture);
-
- status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
- &attributes, src->width, src->height,
- width, height,
- src_x, src_y,
- 0, 0,
- dst_x, dst_y, width, height);
-
- } else {
- XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
- XTrapezoid *xtraps = xtraps_stack;
- int i;
-
- if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
- xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
- if (unlikely (xtraps == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- }
-
- for (i = 0; i < num_traps; i++) {
- xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
- xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
- xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
- xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
- xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
- xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
- xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
- xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
- xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
- xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
- }
-
- XRenderCompositeTrapezoids (dst->dpy,
- _render_operator (op),
- src->src_picture, dst->dst_picture,
- pict_format,
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- xtraps, num_traps);
-
- if (xtraps != xtraps_stack)
- free(xtraps);
}
- BAIL:
- _cairo_pattern_release_surface (pattern, &src->base, &attributes);
-
- return status;
-}
-
-static cairo_region_t *
-_surface_maybe_clip_region (cairo_xlib_surface_t *surface,
- cairo_region_t *clip,
- cairo_region_t *bounded)
-{
- cairo_rectangle_int_t rect;
-
- cairo_region_get_extents (clip, &rect);
- if (rect.x >= 0 &&
- rect.y >= 0 &&
- rect.x + rect.width <= surface->width &&
- rect.y + rect.height <= surface->height)
- {
- return clip;
- }
-
- rect.x = rect.y = 0;
- rect.width = surface->width;
- rect.height = surface->height;
- _cairo_region_init_rectangle (bounded, &rect);
-
- bounded->status = cairo_region_intersect (bounded, clip);
-
- return bounded;
-}
-
-static cairo_int_status_t
-_cairo_xlib_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_bool_t had_clip_rects = surface->have_clip_rects;
-
- if (had_clip_rects == FALSE && region == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- if (surface->clip_rects != surface->embedded_clip_rects) {
- free (surface->clip_rects);
- surface->clip_rects = surface->embedded_clip_rects;
- }
-
- surface->have_clip_rects = FALSE;
- surface->num_clip_rects = 0;
-
- if (region != NULL) {
- XRectangle *rects = NULL;
- int n_rects, i;
- cairo_region_t bounded;
+ for (i = 0; i < num_traps; i++) {
+ /* top/bottom will be clamped to surface bounds */
+ xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
+ xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
- /* Intersect the region with the bounds of the surface. This
- * is necessary so we don't wrap around when we convert cairo's
- * 32 bit region into 16 bit rectangles.
+ /* However, all the other coordinates will have been left untouched so
+ * as not to introduce numerical error. Recompute them if they
+ * exceed the 16.16 limits.
*/
- region = _surface_maybe_clip_region (surface, region, &bounded);
- if (unlikely (region->status))
- return region->status;
-
- n_rects = cairo_region_num_rectangles (region);
- if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
- rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
- if (unlikely (rects == NULL)) {
- if (unlikely (region == &bounded))
- _cairo_region_fini (&bounded);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (unlikely (_line_exceeds_16_16 (&traps[i].left))) {
+ _project_line_x_onto_16_16 (&traps[i].left,
+ traps[i].top,
+ traps[i].bottom,
+ &xtraps[i].left);
+ xtraps[i].left.p1.y = xtraps[i].top;
+ xtraps[i].left.p2.y = xtraps[i].bottom;
} else {
- rects = surface->embedded_clip_rects;
+ xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
+ xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
+ xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
+ xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
}
- for (i = 0; i < n_rects; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (region, i, &rect);
-
- rects[i].x = rect.x;
- rects[i].y = rect.y;
- rects[i].width = rect.width;
- rects[i].height = rect.height;
+ if (unlikely (_line_exceeds_16_16 (&traps[i].right))) {
+ _project_line_x_onto_16_16 (&traps[i].right,
+ traps[i].top,
+ traps[i].bottom,
+ &xtraps[i].right);
+ xtraps[i].right.p1.y = xtraps[i].top;
+ xtraps[i].right.p2.y = xtraps[i].bottom;
+ } else {
+ xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
+ xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
+ xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
+ xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
}
+ }
- if (unlikely (region == &bounded))
- _cairo_region_fini (&bounded);
+ XRenderCompositeTrapezoids (dst->dpy,
+ _render_operator (op),
+ src->src_picture, dst->dst_picture,
+ pict_format,
+ render_src_x + attributes.x_offset,
+ render_src_y + attributes.y_offset,
+ xtraps, num_traps);
- surface->have_clip_rects = TRUE;
- surface->clip_rects = rects;
- surface->num_clip_rects = n_rects;
+ if (xtraps != xtraps_stack)
+ free (xtraps);
- /* Discard the trivial clip rectangle that covers the entire surface */
- if (n_rects == 1 &&
- rects[0].x == 0 &&
- rects[0].y == 0 &&
- rects[0].width == surface->width &&
- rects[0].height == surface->height)
- {
- surface->have_clip_rects = FALSE;
- surface->num_clip_rects = 0;
+ if (! _cairo_operator_bounded_by_mask (op)) {
+ cairo_traps_t _traps;
+ cairo_box_t box;
+ cairo_rectangle_int_t extents;
- if (! had_clip_rects)
- goto DONE;
- }
+ /* XRenderCompositeTrapezoids() creates a mask only large enough for the
+ * trapezoids themselves, but if the operator is unbounded, then we need
+ * to actually composite all the way out to the bounds.
+ */
+ /* XXX: update the interface to pass composite rects */
+ _traps.traps = traps;
+ _traps.num_traps = num_traps;
+ _cairo_traps_extents (&_traps, &box);
+ _cairo_box_round_to_rectangle (&box, &extents);
+
+ status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
+ &attributes,
+ src->width, src->height,
+ extents.width, extents.height,
+ src_x, src_y,
+ -extents.x + dst_x, -extents.y + dst_y,
+ dst_x, dst_y,
+ width, height,
+ clip_region);
}
- surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
- DONE:
+ BAIL:
+ _cairo_pattern_release_surface (pattern, &src->base, &attributes);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
-static cairo_int_status_t
+static cairo_bool_t
_cairo_xlib_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -2442,7 +2716,7 @@ _cairo_xlib_surface_get_extents (void *abstract_surface,
rectangle->width = surface->width;
rectangle->height = surface->height;
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
static void
@@ -2451,7 +2725,7 @@ _cairo_xlib_surface_get_font_options (void *abstract_surface,
{
cairo_xlib_surface_t *surface = abstract_surface;
- *options = *_cairo_xlib_screen_get_font_options (surface->screen_info);
+ *options = *_cairo_xlib_screen_get_font_options (surface->screen);
}
static void
@@ -2470,7 +2744,7 @@ _cairo_xlib_surface_is_similar (void *surface_a,
cairo_xlib_surface_t *b = surface_b;
XRenderPictFormat *xrender_format = b->xrender_format;
- if (!_cairo_xlib_surface_same_screen (a, b))
+ if (! _cairo_xlib_surface_same_screen (a, b))
return FALSE;
/* now inspect the content to check that a is similar to b */
@@ -2489,19 +2763,6 @@ _cairo_xlib_surface_is_similar (void *surface_a,
return a->xrender_format == xrender_format;
}
-static cairo_status_t
-_cairo_xlib_surface_reset (void *abstract_surface)
-{
- cairo_xlib_surface_t *surface = abstract_surface;
- cairo_status_t status;
-
- status = _cairo_xlib_surface_set_clip_region (surface, NULL);
- if (unlikely (status))
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
CAIRO_SURFACE_TYPE_XLIB,
_cairo_xlib_surface_create_similar,
@@ -2518,8 +2779,6 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
NULL, /* check_span_renderer */
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_xlib_surface_set_clip_region,
- NULL, /* intersect_clip_path */
_cairo_xlib_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_xlib_surface_get_font_options,
@@ -2535,10 +2794,10 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
_cairo_xlib_surface_show_glyphs,
_cairo_xlib_surface_snapshot,
-
_cairo_xlib_surface_is_similar,
- _cairo_xlib_surface_reset,
+
NULL, /* fill_stroke */
+
_cairo_xlib_surface_create_solid_pattern_surface,
_cairo_xlib_surface_can_repaint_solid_pattern_surface
};
@@ -2569,6 +2828,8 @@ _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
dpy = surface->dpy;
surface->dpy = NULL;
+ X_DEBUG ((dpy, "detach (drawable=%x)", (unsigned int) surface->drawable));
+
if (surface->dst_picture != None) {
XRenderFreePicture (dpy, surface->dst_picture);
surface->dst_picture = None;
@@ -2584,96 +2845,83 @@ _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
surface->drawable = None;
surface->owns_pixmap = FALSE;
}
-
- if (surface->gc != NULL) {
- XFreeGC (dpy, surface->gc);
- surface->gc = NULL;
- }
}
static cairo_surface_t *
-_cairo_xlib_surface_create_internal (Display *dpy,
- Drawable drawable,
- Screen *screen,
- Visual *visual,
- XRenderPictFormat *xrender_format,
- int width,
- int height,
- int depth)
+_cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen,
+ Drawable drawable,
+ Visual *visual,
+ XRenderPictFormat *xrender_format,
+ int width,
+ int height,
+ int depth)
{
cairo_xlib_surface_t *surface;
- cairo_xlib_display_t *display;
- cairo_xlib_screen_info_t *screen_info;
- cairo_status_t status;
CAIRO_MUTEX_INITIALIZE ();
- if (xrender_format) {
- depth = xrender_format->depth;
+ if (depth == 0) {
+ if (xrender_format) {
+ depth = xrender_format->depth;
- /* XXX find matching visual for core/dithering fallbacks? */
- } else if (visual) {
- int j, k;
+ /* XXX find matching visual for core/dithering fallbacks? */
+ } else if (visual) {
+ Screen *scr = screen->screen;
- /* This is ugly, but we have to walk over all visuals
- * for the display to find the correct depth.
- */
- depth = 0;
- for (j = 0; j < screen->ndepths; j++) {
- Depth *d = &screen->depths[j];
- for (k = 0; k < d->nvisuals; k++) {
- if (&d->visuals[k] == visual) {
- depth = d->depth;
- goto found;
+ if (visual == DefaultVisualOfScreen (scr)) {
+ depth = DefaultDepthOfScreen (scr);
+ } else {
+ int j, k;
+
+ /* This is ugly, but we have to walk over all visuals
+ * for the display to find the correct depth.
+ */
+ depth = 0;
+ for (j = 0; j < scr->ndepths; j++) {
+ Depth *d = &scr->depths[j];
+ for (k = 0; k < d->nvisuals; k++) {
+ if (&d->visuals[k] == visual) {
+ depth = d->depth;
+ goto found;
+ }
+ }
}
}
}
- found:
- ;
- }
- if (depth == 0)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
+ if (depth == 0)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
- status = _cairo_xlib_display_get (dpy, &display);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- status = _cairo_xlib_screen_info_get (display, screen, &screen_info);
- if (unlikely (status)) {
- _cairo_xlib_display_destroy (display);
- return _cairo_surface_create_in_error (status);
+found:
+ ;
}
surface = malloc (sizeof (cairo_xlib_surface_t));
- if (unlikely (surface == NULL)) {
- _cairo_xlib_screen_info_destroy (screen_info);
- _cairo_xlib_display_destroy (display);
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
+
+ surface->dpy = _cairo_xlib_display_get_dpy (screen->display);
/* initialize and hook into the CloseDisplay callback */
surface->close_display_hook.func = _cairo_xlib_surface_detach_display;
- _cairo_xlib_add_close_display_hook (display, &surface->close_display_hook);
+ _cairo_xlib_add_close_display_hook (screen->display,
+ &surface->close_display_hook);
- surface->render_major = display->render_major;
- surface->render_minor = display->render_minor;
+ _cairo_xlib_display_get_xrender_version (screen->display,
+ &surface->render_major,
+ &surface->render_minor);
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
if (!xrender_format) {
if (visual) {
- xrender_format = XRenderFindVisualFormat (dpy, visual);
+ xrender_format = XRenderFindVisualFormat (surface->dpy, visual);
} else if (depth == 1) {
xrender_format =
- _cairo_xlib_display_get_xrender_format (display,
+ _cairo_xlib_display_get_xrender_format (screen->display,
CAIRO_FORMAT_A1);
}
}
} else {
- xrender_format = NULL;
- }
-
- /* we cannot use XRender for this surface, so ensure we don't try */
- if (xrender_format == NULL) {
+ /* we cannot use XRender for this surface, so ensure we don't try */
surface->render_major = -1;
surface->render_minor = -1;
}
@@ -2681,24 +2929,28 @@ _cairo_xlib_surface_create_internal (Display *dpy,
_cairo_surface_init (&surface->base, &cairo_xlib_surface_backend,
_xrender_format_to_content (xrender_format));
- surface->dpy = dpy;
- surface->display = display;
- surface->screen_info = screen_info;
+ surface->screen = _cairo_xlib_screen_reference (screen);
+ surface->display = screen->display;
- surface->gc = NULL;
surface->drawable = drawable;
- surface->screen = screen;
surface->owns_pixmap = FALSE;
surface->use_pixmap = 0;
surface->width = width;
surface->height = height;
- surface->buggy_repeat = screen_info->display->buggy_repeat;
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
+ surface->buggy_repeat = ! _cairo_xlib_display_has_repeat (surface->display);
+ if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
/* so we can use the XTile fallback */
surface->buggy_repeat = TRUE;
}
- surface->buggy_pad_reflect = screen_info->display->buggy_pad_reflect;
+
+ surface->buggy_pad_reflect = ! _cairo_xlib_display_has_reflect (surface->display);
+ if (! CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT (surface))
+ surface->buggy_pad_reflect = TRUE;
+
+ surface->buggy_gradients = ! _cairo_xlib_display_has_gradients (surface->display);
+ if (! CAIRO_SURFACE_RENDER_HAS_GRADIENTS (surface))
+ surface->buggy_gradients = TRUE;
surface->dst_picture = None;
surface->src_picture = None;
@@ -2707,11 +2959,10 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->xrender_format = xrender_format;
surface->depth = depth;
surface->filter = CAIRO_FILTER_NEAREST;
- surface->repeat = FALSE;
+ surface->extend = CAIRO_EXTEND_NONE;
surface->xtransform = identity;
- surface->have_clip_rects = FALSE;
- surface->gc_has_clip_rects = FALSE;
+ surface->clip_region = NULL;
surface->clip_rects = surface->embedded_clip_rects;
surface->num_clip_rects = 0;
surface->clip_dirty = 0;
@@ -2750,29 +3001,31 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->b_mask = 0;
}
- return (cairo_surface_t *) surface;
+ return &surface->base;
}
static Screen *
_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
{
- int s;
- int d;
- int v;
- Screen *screen;
- Depth *depth;
+ int s, d, v;
for (s = 0; s < ScreenCount (dpy); s++) {
+ Screen *screen;
+
screen = ScreenOfDisplay (dpy, s);
if (visual == DefaultVisualOfScreen (screen))
return screen;
+
for (d = 0; d < screen->ndepths; d++) {
+ Depth *depth;
+
depth = &screen->depths[d];
for (v = 0; v < depth->nvisuals; v++)
if (visual == &depth->visuals[v])
return screen;
}
}
+
return NULL;
}
@@ -2808,14 +3061,34 @@ cairo_xlib_surface_create (Display *dpy,
int width,
int height)
{
- Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual);
+ Screen *scr;
+ cairo_xlib_screen_t *screen;
+ cairo_surface_t *surface;
+ cairo_status_t status;
- if (screen == NULL)
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
+ /* you're lying, and you know it! */
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+ }
+
+ scr = _cairo_xlib_screen_from_visual (dpy, visual);
+ if (scr == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
- return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
- visual, NULL, width, height, 0);
+ status = _cairo_xlib_screen_get (dpy, scr, &screen);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ X_DEBUG ((dpy, "create (drawable=%x)", (unsigned int) drawable));
+
+ surface = _cairo_xlib_surface_create_internal (screen, drawable,
+ visual, NULL,
+ width, height, 0);
+ _cairo_xlib_screen_destroy (screen);
+
+ return surface;
}
+slim_hidden_def (cairo_xlib_surface_create);
/**
* cairo_xlib_surface_create_for_bitmap:
@@ -2833,12 +3106,29 @@ cairo_xlib_surface_create (Display *dpy,
cairo_surface_t *
cairo_xlib_surface_create_for_bitmap (Display *dpy,
Pixmap bitmap,
- Screen *screen,
+ Screen *scr,
int width,
int height)
{
- return _cairo_xlib_surface_create_internal (dpy, bitmap, screen,
- NULL, NULL, width, height, 1);
+ cairo_xlib_screen_t *screen;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ status = _cairo_xlib_screen_get (dpy, scr, &screen);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ X_DEBUG ((dpy, "create_for_bitmap (drawable=%x)", (unsigned int) bitmap));
+
+ surface = _cairo_xlib_surface_create_internal (screen, bitmap,
+ NULL, NULL,
+ width, height, 1);
+ _cairo_xlib_screen_destroy (screen);
+
+ return surface;
}
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
@@ -2865,14 +3155,32 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy,
cairo_surface_t *
cairo_xlib_surface_create_with_xrender_format (Display *dpy,
Drawable drawable,
- Screen *screen,
+ Screen *scr,
XRenderPictFormat *format,
int width,
int height)
{
- return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
- NULL, format, width, height, 0);
+ cairo_xlib_screen_t *screen;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ status = _cairo_xlib_screen_get (dpy, scr, &screen);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ X_DEBUG ((dpy, "create_with_xrender_format (drawable=%x)", (unsigned int) drawable));
+
+ surface = _cairo_xlib_surface_create_internal (screen, drawable,
+ NULL, format,
+ width, height, 0);
+ _cairo_xlib_screen_destroy (screen);
+
+ return surface;
}
+slim_hidden_def (cairo_xlib_surface_create_with_xrender_format);
/**
* cairo_xlib_surface_get_xrender_format:
@@ -2934,6 +3242,12 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
return;
}
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
+ status = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_INVALID_SIZE);
+ return;
+ }
+
surface->width = width;
surface->height = height;
}
@@ -2966,11 +3280,19 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
return;
}
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
+ status = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_INVALID_SIZE);
+ return;
+ }
+
/* XXX: and what about this case? */
if (surface->owns_pixmap)
return;
if (surface->drawable != drawable) {
+ X_DEBUG ((surface->dpy, "set_drawable (drawable=%x)", (unsigned int) drawable));
+
if (surface->dst_picture != None) {
status = _cairo_xlib_display_queue_resource (
surface->display,
@@ -3069,7 +3391,7 @@ cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
return NULL;
}
- return surface->screen;
+ return surface->screen->screen;
}
/**
@@ -3135,7 +3457,7 @@ cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
- return -1;
+ return 0;
}
return surface->width;
@@ -3158,7 +3480,7 @@ cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
- return -1;
+ return 0;
}
return surface->height;
@@ -3215,7 +3537,7 @@ _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t *display,
Display *dpy;
int i;
- dpy = display->display;
+ dpy = _cairo_xlib_display_get_dpy (display);
for (i = 0; i < NUM_GLYPHSETS; i++) {
cairo_xlib_font_glyphset_info_t *glyphset_info;
@@ -3417,8 +3739,8 @@ _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scale
glyphset_info->xrender_format =
_cairo_xlib_display_get_xrender_format (display,
glyphset_info->format);
- glyphset_info->glyphset = XRenderCreateGlyphSet (display->display,
- glyphset_info->xrender_format);
+ glyphset_info->glyphset = XRenderCreateGlyphSet (_cairo_xlib_display_get_dpy (display),
+ glyphset_info->xrender_format);
}
return glyphset_info;
@@ -3545,14 +3867,13 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
sz_xGlyphInfo -
8;
if (len >= max_request_size)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("glyph too large for XRequest");
}
/* If the glyph surface has zero height or width, we create
* a clear 1x1 surface, to avoid various X server bugs.
*/
if (glyph_surface->width == 0 || glyph_surface->height == 0) {
- cairo_t *cr;
cairo_surface_t *tmp_surface;
tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
@@ -3560,19 +3881,10 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
if (unlikely (status))
goto BAIL;
- cr = cairo_create (tmp_surface);
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- cairo_paint (cr);
- status = cairo_status (cr);
- cairo_destroy (cr);
-
tmp_surface->device_transform = glyph_surface->base.device_transform;
tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
glyph_surface = (cairo_image_surface_t *) tmp_surface;
-
- if (unlikely (status))
- goto BAIL;
}
/* If the glyph format does not match the font format, then we
@@ -3580,7 +3892,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
* format.
*/
if (glyph_surface->format != glyphset_info->format) {
- cairo_t *cr;
+ cairo_surface_pattern_t pattern;
cairo_surface_t *tmp_surface;
tmp_surface = cairo_image_surface_create (glyphset_info->format,
@@ -3593,12 +3905,11 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
tmp_surface->device_transform = glyph_surface->base.device_transform;
tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
- cr = cairo_create (tmp_surface);
- cairo_set_source_surface (cr, &glyph_surface->base, 0, 0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
- status = cairo_status (cr);
- cairo_destroy (cr);
+ _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
+ status = _cairo_surface_paint (tmp_surface,
+ CAIRO_OPERATOR_SOURCE, &pattern.base,
+ NULL);
+ _cairo_pattern_fini (&pattern.base);
glyph_surface = (cairo_image_surface_t *) tmp_surface;
@@ -3830,7 +4141,6 @@ _emit_glyphs_chunk (cairo_xlib_surface_t *dst,
if (n) {
elts[nelt].nchars = n;
nelt++;
- n = 0;
}
/* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
@@ -3896,7 +4206,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (status != CAIRO_STATUS_SUCCESS)
+ if (unlikely (status))
return status;
this_x = _cairo_lround (glyphs[i].d.x);
@@ -3976,7 +4286,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
status = _emit_glyphs_chunk (dst, glyphs, i,
scaled_font, op, src, attributes,
num_elts, old_width, glyphset_info);
- if (status != CAIRO_STATUS_SUCCESS)
+ if (unlikely (status))
return status;
glyphs += i;
@@ -4015,13 +4325,14 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
request_size += width;
}
- if (num_elts)
+ if (num_elts) {
status = _emit_glyphs_chunk (dst, glyphs, i,
scaled_font, op, src, attributes,
num_elts, width, glyphset_info);
+ }
*remaining_glyphs = num_glyphs - i;
- if (*remaining_glyphs && status == CAIRO_STATUS_SUCCESS)
+ if (*remaining_glyphs != 0 && status == CAIRO_STATUS_SUCCESS)
status = CAIRO_INT_STATUS_UNSUPPORTED;
return status;
@@ -4051,8 +4362,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip,
+ int *remaining_glyphs)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst;
@@ -4060,16 +4371,17 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
composite_operation_t operation;
cairo_surface_attributes_t attributes;
cairo_xlib_surface_t *src = NULL;
+ cairo_region_t *clip_region = NULL;
cairo_solid_pattern_t solid_pattern;
if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("XRender does not support CompositeText");
/* Just let unbounded operators go through the fallback code
* instead of trying to do the fixups here */
- if (!_cairo_operator_bounded_by_mask (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! _cairo_operator_bounded_by_mask (op))
+ return UNSUPPORTED ("unsupported unbounded op");
/* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
* the solid source seems to be multiplied by the glyph mask, and
@@ -4077,25 +4389,58 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
* including the fully transparent "background" of the rectangular
* glyph surface. */
if (op == CAIRO_OPERATOR_SOURCE &&
- !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ ! CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
+ {
+ return UNSUPPORTED ("known bug in Render");
+ }
/* We can only use our code if we either have no clip or
* have a real native clip region set. If we're using
* fallback clip masking, we have to go through the full
* fallback path.
*/
- if (dst->base.clip &&
- (dst->base.clip->mode != CAIRO_CLIP_MODE_REGION ||
- dst->base.clip->surface != NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
+ if (status)
+ return status;
+ }
operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unsupported op");
if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return UNSUPPORTED ("unowned font");
+
+ X_DEBUG ((dst->dpy, "show_glyphs (dst=%x)", (unsigned int) dst->drawable));
+
+ if (clip_region != NULL &&
+ cairo_region_num_rectangles (clip_region) == 1)
+ {
+ cairo_rectangle_int_t glyph_extents;
+ const cairo_rectangle_int_t *clip_extents;
+
+ /* Can we do without the clip?
+ * Around 50% of the time the clip is redundant (firefox).
+ */
+ _cairo_scaled_font_glyph_approximate_extents (scaled_font,
+ glyphs, num_glyphs,
+ &glyph_extents);
+
+ clip_extents = &clip->path->extents;
+ if (clip_extents->x <= glyph_extents.x &&
+ clip_extents->y <= glyph_extents.y &&
+ clip_extents->x + clip_extents->width >= glyph_extents.x + glyph_extents.width &&
+ clip_extents->y + clip_extents->height >= glyph_extents.y + glyph_extents.height)
+ {
+ clip_region = NULL;
+ }
+ }
+
+ status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
/* After passing all those tests, we're now committed to rendering
* these glyphs or to fail trying. We first upload any glyphs to
@@ -4130,19 +4475,26 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
- &glyph_extents);
+ &glyph_extents,
+ NULL);
if (unlikely (status))
goto BAIL0;
- status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
- CAIRO_CONTENT_COLOR_ALPHA,
- glyph_extents.x, glyph_extents.y,
- glyph_extents.width, glyph_extents.height,
- dst->buggy_pad_reflect ?
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- &attributes);
+ if (clip != NULL) {
+ if (! _cairo_rectangle_intersect (&glyph_extents,
+ _cairo_clip_get_extents (clip)))
+ {
+ goto BAIL0;
+ }
+ }
+
+ status = _cairo_xlib_surface_acquire_pattern_surface (dst, src_pattern,
+ dst->base.content,
+ glyph_extents.x,
+ glyph_extents.y,
+ glyph_extents.width,
+ glyph_extents.height,
+ &src, &attributes);
if (unlikely (status))
goto BAIL0;
}
@@ -4150,7 +4502,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
operation = _recategorize_composite_operation (dst, op, src,
&attributes, TRUE);
if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = UNSUPPORTED ("unsupported op");
goto BAIL1;
}
@@ -4168,15 +4520,14 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
src,
&attributes,
remaining_glyphs);
- } else
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ } else {
+ status = UNSUPPORTED ("unowned font");
+ }
_cairo_scaled_font_thaw_cache (scaled_font);
BAIL1:
if (src)
_cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
- if (src_pattern == &solid_pattern.base)
- _cairo_pattern_fini (&solid_pattern.base);
BAIL0:
_cairo_xlib_display_notify (dst->display);