summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-01-22 21:26:26 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2010-01-22 23:01:52 +0000
commit1236c41072a7966eda7db48a381fd0508e5289be (patch)
treea381bd7fc6d8b0ea95fc0b57cc9af92ce2c32873
parent77afe8491ed7038a8399c01f10d8f062a7239225 (diff)
xcb: Refresh.
Still an experimental backend, it's now a little too late to stabilise for 1.10, but this should represent a major step forward in its feature set and an attempt to catch up with all the bug fixes that have been performed on xlib. Notably not tested yet (and expected to be broken) are mixed-endian connections and low bitdepth servers (the dithering support has not been copied over for instance). However, it seems robust enough for daily use... Of particular note in this update is that the xcb surface is now capable of subverting the xlib surface through the ./configure --enable-xlib-xcb option. This replaces the xlib surface with a proxy that forwards all operations to an equivalent xcb surface whilst preserving the cairo-xlib API that is required for compatibility with the existing applications, for instance GTK+ and Mozilla. Also you can experiment with enabling a DRM bypass, though you need to be extremely foolhardy to do so.
-rw-r--r--boilerplate/Makefile.win32.features20
-rw-r--r--boilerplate/cairo-boilerplate-xcb.c522
-rw-r--r--build/Makefile.win32.features2
-rw-r--r--build/Makefile.win32.features-h6
-rw-r--r--build/configure.ac.features2
-rw-r--r--configure.ac26
-rw-r--r--src/Makefile.sources22
-rw-r--r--src/Makefile.win32.features28
-rw-r--r--src/cairo-list-private.h7
-rw-r--r--src/cairo-mutex-list-private.h4
-rw-r--r--src/cairo-pattern.c41
-rw-r--r--src/cairo-xcb-connection-core.c482
-rw-r--r--src/cairo-xcb-connection-render.c969
-rw-r--r--src/cairo-xcb-connection-shm.c194
-rw-r--r--src/cairo-xcb-connection.c867
-rw-r--r--src/cairo-xcb-private.h760
-rw-r--r--src/cairo-xcb-screen.c518
-rw-r--r--src/cairo-xcb-shm.c576
-rw-r--r--src/cairo-xcb-surface-cairo.c94
-rw-r--r--src/cairo-xcb-surface-core.c613
-rw-r--r--src/cairo-xcb-surface-private.h (renamed from src/cairo-xcb-xrender.h)42
-rw-r--r--src/cairo-xcb-surface-render.c4471
-rw-r--r--src/cairo-xcb-surface.c3344
-rw-r--r--src/cairo-xcb.h41
-rw-r--r--src/cairo-xlib-xcb-surface.c515
-rw-r--r--src/cairoint.h16
-rw-r--r--test/xcb-surface-source.c1
27 files changed, 11660 insertions, 2523 deletions
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 5c1e01197..8d5641189 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -49,6 +49,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_sources)
endif
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+endif
+
unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_qt_private)
@@ -159,6 +169,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_gallium_private)
enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gallium_sources)
endif
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+endif
+
supported_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
all_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
all_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
diff --git a/boilerplate/cairo-boilerplate-xcb.c b/boilerplate/cairo-boilerplate-xcb.c
index 0ab2026f9..ed173e68b 100644
--- a/boilerplate/cairo-boilerplate-xcb.c
+++ b/boilerplate/cairo-boilerplate-xcb.c
@@ -26,15 +26,16 @@
#include "cairo-boilerplate-private.h"
-#include <cairo-xcb-xrender.h>
-
-#include <xcb/xcb_renderutil.h>
+#include <cairo-xcb.h>
static const cairo_user_data_key_t xcb_closure_key;
typedef struct _xcb_target_closure {
xcb_connection_t *c;
- xcb_pixmap_t pixmap;
+ cairo_device_t *device;
+ uint32_t drawable;
+ cairo_bool_t is_pixmap;
+ cairo_surface_t *surface;
} xcb_target_closure_t;
static void
@@ -42,8 +43,17 @@ _cairo_boilerplate_xcb_cleanup (void *closure)
{
xcb_target_closure_t *xtc = closure;
- xcb_free_pixmap (xtc->c, xtc->pixmap);
+ if (xtc->is_pixmap)
+ xcb_free_pixmap (xtc->c, xtc->drawable);
+ else
+ xcb_destroy_window (xtc->c, xtc->drawable);
+ cairo_surface_destroy (xtc->surface);
+
+ cairo_device_finish (xtc->device);
+ cairo_device_destroy (xtc->device);
+
xcb_disconnect (xtc->c);
+
free (xtc);
}
@@ -53,10 +63,42 @@ _cairo_boilerplate_xcb_synchronize (void *closure)
xcb_target_closure_t *xtc = closure;
free (xcb_get_image_reply (xtc->c,
xcb_get_image (xtc->c, XCB_IMAGE_FORMAT_Z_PIXMAP,
- xtc->pixmap, 0, 0, 1, 1, /* AllPlanes */ ~0UL),
+ xtc->drawable, 0, 0, 1, 1, /* AllPlanes */ -1),
0));
}
+static xcb_render_pictforminfo_t *
+find_depth (xcb_connection_t *connection, int depth, void **formats_out)
+{
+ xcb_render_query_pict_formats_reply_t *formats;
+ xcb_render_query_pict_formats_cookie_t cookie;
+ xcb_render_pictforminfo_iterator_t i;
+
+ cookie = xcb_render_query_pict_formats (connection);
+ xcb_flush (connection);
+
+ formats = xcb_render_query_pict_formats_reply (connection, cookie, 0);
+ if (formats == NULL)
+ return NULL;
+
+ for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+ i.rem;
+ xcb_render_pictforminfo_next (&i))
+ {
+ if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
+ continue;
+
+ if (depth != i.data->depth)
+ continue;
+
+ *formats_out = formats;
+ return i.data;
+ }
+
+ free (formats);
+ return NULL;
+}
+
static cairo_surface_t *
_cairo_boilerplate_xcb_create_surface (const char *name,
cairo_content_t content,
@@ -72,10 +114,11 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
xcb_target_closure_t *xtc;
xcb_connection_t *c;
xcb_render_pictforminfo_t *render_format;
- xcb_pict_standard_t format;
+ int depth;
xcb_void_cookie_t cookie;
cairo_surface_t *surface;
cairo_status_t status;
+ void *formats;
*closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
@@ -85,32 +128,279 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
height = 1;
xtc->c = c = xcb_connect(NULL,NULL);
- if (xcb_connection_has_error(c)) {
- fprintf (stderr, "Failed to connect to X server through XCB\n");
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
+
+ xtc->surface = NULL;
+ xtc->is_pixmap = TRUE;
+ xtc->drawable = xcb_generate_id (c);
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ depth = 24;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
+ width, height);
+ break;
+
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ depth = 32;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
+ width, height);
+ break;
+
+ case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
+ default:
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ render_format = find_depth (c, depth, &formats);
+ if (render_format == NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
+ render_format,
+ width, height);
+ free (formats);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static xcb_visualtype_t *
+lookup_visual (xcb_screen_t *s, xcb_visualid_t visual)
+{
+ xcb_depth_iterator_t d;
+
+ d = xcb_screen_allowed_depths_iterator (s);
+ for (; d.rem; xcb_depth_next (&d)) {
+ xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
+ for (; v.rem; xcb_visualtype_next (&v)) {
+ if (v.data->visual_id == visual)
+ return v.data;
+ }
+ }
+
+ return 0;
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ xtc->surface = NULL;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window_db (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
+ xtc->surface = NULL;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
}
+ xtc->surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ surface = cairo_surface_create_similar (xtc->surface, content, width, height);
+
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_render_0_0 (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_screen_t *root;
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_render_pictforminfo_t *render_format;
+ int depth;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *surface, *tmp;
+ cairo_status_t status;
+ void *formats;
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect(NULL,NULL);
+ if (xcb_connection_has_error(c))
+ return NULL;
+
root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
- xtc->pixmap = xcb_generate_id (c);
+ xtc->surface = NULL;
+ xtc->is_pixmap = TRUE;
+ xtc->drawable = xcb_generate_id (c);
switch (content) {
case CAIRO_CONTENT_COLOR:
- cookie = xcb_create_pixmap_checked (c, 24,
- xtc->pixmap, root->root,
+ depth = 24;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
width, height);
- format = XCB_PICT_STANDARD_RGB_24;
break;
case CAIRO_CONTENT_COLOR_ALPHA:
- cookie = xcb_create_pixmap_checked (c, 32,
- xtc->pixmap, root->root,
+ depth = 32;
+ cookie = xcb_create_pixmap_checked (c, depth,
+ xtc->drawable, root->root,
width, height);
- format = XCB_PICT_STANDARD_ARGB_32;
break;
case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */
default:
- fprintf (stderr, "Invalid content for XCB test: %d\n", content);
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
}
@@ -121,24 +411,127 @@ _cairo_boilerplate_xcb_create_surface (const char *name,
return NULL;
}
- render_format = xcb_render_util_find_standard_format (xcb_render_util_query_formats (c), format);
- if (render_format->id == 0)
+ render_format = find_depth (c, depth, &formats);
+ if (render_format == NULL) {
+ xcb_disconnect (c);
+ free (xtc);
return NULL;
+ }
- surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->pixmap, root,
+ tmp = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
+ render_format,
+ width, height);
+
+ cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+ 0, 0);
+ /* recreate with impaired connection */
+ surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+ xtc->drawable,
render_format,
width, height);
+ free (formats);
+ cairo_surface_destroy (tmp);
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
if (status == CAIRO_STATUS_SUCCESS)
return surface;
cairo_surface_destroy (surface);
- surface = cairo_boilerplate_surface_create_in_error (status);
_cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_fallback (const char *name,
+ cairo_content_t content,
+ double width,
+ double height,
+ double max_width,
+ double max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ xcb_target_closure_t *xtc;
+ xcb_connection_t *c;
+ xcb_screen_t *s;
+ xcb_void_cookie_t cookie;
+ cairo_surface_t *tmp, *surface;
+ cairo_status_t status;
+ uint32_t values[] = { 1 };
+
+ *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ xtc->c = c = xcb_connect (NULL,NULL);
+ if (xcb_connection_has_error(c)) {
+ free (xtc);
+ return NULL;
+ }
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+ if (width > s->width_in_pixels || height > s->height_in_pixels) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ xtc->surface = NULL;
+ xtc->is_pixmap = FALSE;
+ xtc->drawable = xcb_generate_id (c);
+ cookie = xcb_create_window_checked (c,
+ s->root_depth,
+ xtc->drawable,
+ s->root,
+ 0, 0, width, height, 0,
+ XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ s->root_visual,
+ XCB_CW_OVERRIDE_REDIRECT,
+ values);
+ xcb_map_window (c, xtc->drawable);
+
+ /* slow, but sure */
+ if (xcb_request_check (c, cookie) != NULL) {
+ xcb_disconnect (c);
+ free (xtc);
+ return NULL;
+ }
+
+ tmp = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ if (cairo_surface_status (tmp)) {
+ xcb_disconnect (c);
+ free (xtc);
+ return tmp;
+ }
+
+ cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+ -1, -1);
+ /* recreate with impaired connection */
+ surface = cairo_xcb_surface_create (c,
+ xtc->drawable,
+ lookup_visual (s, s->root_visual),
+ width, height);
+ cairo_surface_destroy (tmp);
- return surface;
+ xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+ status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+
+ _cairo_boilerplate_xcb_cleanup (xtc);
+ return cairo_boilerplate_surface_create_in_error (status);
}
static cairo_status_t
@@ -148,20 +541,39 @@ _cairo_boilerplate_xcb_finish_surface (cairo_surface_t *surface)
&xcb_closure_key);
xcb_generic_event_t *ev;
- cairo_surface_flush (surface);
+ if (xtc->surface != NULL) {
+ cairo_t *cr;
+
+ cr = cairo_create (xtc->surface);
+ cairo_surface_set_device_offset (surface, 0, 0);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ surface = xtc->surface;
+ }
+ cairo_surface_flush (surface);
if (cairo_surface_status (surface))
return cairo_surface_status (surface);
while ((ev = xcb_poll_for_event (xtc->c)) != NULL) {
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
if (ev->response_type == 0 /* trust me! */) {
xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
- fprintf (stderr, "Detected error during xcb run: %d major=%d, minor=%d\n",
+ fprintf (stderr,
+ "Detected error during xcb run: %d major=%d, minor=%d\n",
error->error_code, error->major_code, error->minor_code);
+ free (error);
- return CAIRO_STATUS_WRITE_ERROR;
+ status = CAIRO_STATUS_WRITE_ERROR;
}
+
+ if (status)
+ return status;
}
if (xcb_connection_has_error (xtc->c))
@@ -197,5 +609,65 @@ static const cairo_boilerplate_target_t targets[] = {
_cairo_boilerplate_xcb_cleanup,
_cairo_boilerplate_xcb_synchronize
},
+ {
+ "xcb-window", "xlib", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_window,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-window&", "xlib", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_window_db,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-render-0.0", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_render_0_0,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-render-0.0", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_render_0_0,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
+ {
+ "xcb-fallback", "xlib-fallback", NULL, NULL,
+ CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+ "cairo_xcb_surface_create_with_xrender_format",
+ _cairo_boilerplate_xcb_create_fallback,
+ NULL,
+ _cairo_boilerplate_xcb_finish_surface,
+ _cairo_boilerplate_get_image_surface,
+ cairo_surface_write_to_png,
+ _cairo_boilerplate_xcb_cleanup,
+ _cairo_boilerplate_xcb_synchronize
+ },
};
CAIRO_BOILERPLATE (xcb, targets)
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index bd314e9f7..b8c40a85d 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -3,6 +3,7 @@
CAIRO_HAS_XLIB_SURFACE=0
CAIRO_HAS_XLIB_XRENDER_SURFACE=0
CAIRO_HAS_XCB_SURFACE=0
+CAIRO_HAS_XLIB_XCB_FUNCTIONS=0
CAIRO_HAS_QT_SURFACE=0
CAIRO_HAS_QUARTZ_SURFACE=0
CAIRO_HAS_QUARTZ_FONT=0
@@ -14,6 +15,7 @@ CAIRO_HAS_OS2_SURFACE=0
CAIRO_HAS_BEOS_SURFACE=0
CAIRO_HAS_DRM_SURFACE=0
CAIRO_HAS_GALLIUM_SURFACE=0
+CAIRO_HAS_XCB_DRM_FUNCTIONS=0
CAIRO_HAS_PNG_FUNCTIONS=1
CAIRO_HAS_GL_SURFACE=0
CAIRO_HAS_GLITZ_SURFACE=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index 7e49cd63c..95e9386d9 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -14,6 +14,9 @@ endif
ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
@echo "#define CAIRO_HAS_XCB_SURFACE 1" >> src/cairo-features.h
endif
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+ @echo "#define CAIRO_HAS_XLIB_XCB_FUNCTIONS 1" >> src/cairo-features.h
+endif
ifeq ($(CAIRO_HAS_QT_SURFACE),1)
@echo "#define CAIRO_HAS_QT_SURFACE 1" >> src/cairo-features.h
endif
@@ -47,6 +50,9 @@ endif
ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1)
@echo "#define CAIRO_HAS_GALLIUM_SURFACE 1" >> src/cairo-features.h
endif
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+ @echo "#define CAIRO_HAS_XCB_DRM_FUNCTIONS 1" >> src/cairo-features.h
+endif
ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
@echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h
endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index e057e2c83..c55b4efa8 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -393,6 +393,8 @@ AC_DEFUN([CAIRO_REPORT],
echo " GLX functions: $use_glx"
echo " EGL functions: $use_egl"
echo " Eagle functions: $use_eagle"
+ echo " X11-xcb functions: $use_xlib_xcb"
+ echo " XCB-drm functions: $use_xcb_drm"
echo ""
echo "The following features and utilies:"
echo " cairo-trace: $use_trace"
diff --git a/configure.ac b/configure.ac
index d704353f6..f94d9c17e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,10 +109,22 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(xcb, XCB, no, [
- xcb_REQUIRES="xcb >= 0.9.92 xcb-render >= 0.9.92 xcb-renderutil"
- PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, , [AC_MSG_RESULT(no)
- use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+ xcb_REQUIRES="xcb >= 0.9.92 xcb-render >= 0.9.92 xcb-shm xcb-dri2"
+ PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, ,
+ [AC_MSG_RESULT(no)
+ use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+])
+
+CAIRO_ENABLE_FUNCTIONS(xlib_xcb, Xlib/XCB, no, [
+ if test "x$use_xcb" == "xyes" -a "x$use_xlib" == "xyes"; then
+ xlib_xcb_REQUIRES="x11-xcb"
+ PKG_CHECK_MODULES(xlib_xcb, $xlib_xcb_REQUIRES, ,
+ [use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"])
+ else
+ use_xlib_xcb="no (requires both --enable-xlib and --enable-xcb)"
+ fi
])
+AM_CONDITIONAL(BUILD_XLIB_XCB, test "x$use_xlib_xcb" = "xyes")
dnl ===========================================================================
@@ -241,6 +253,14 @@ CAIRO_ENABLE_SURFACE_BACKEND(gallium, Gallium3D, no, [
fi
])
+CAIRO_ENABLE_FUNCTIONS(xcb_drm, XCB/DRM, no, [
+ if test "x$use_xcb" == "xyes" -a "x$use_drm" == "xyes"; then
+ use_xcb_drm="yes"
+ else
+ use_xcb_drm="no (requires both --enable-xcb and --enable-drm)"
+ fi
+])
+
dnl ===========================================================================
CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, [
diff --git a/src/Makefile.sources b/src/Makefile.sources
index f6d4fe30c..0f77f0ed8 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -250,19 +250,33 @@ cairo_xlib_private = \
cairo-xlib-surface-private.h \
cairo-xlib-xrender-private.h \
$(NULL)
+if BUILD_XLIB_XCB
+cairo_xlib_sources = cairo-xlib-xcb-surface.c
+else
cairo_xlib_sources = \
cairo-xlib-display.c \
cairo-xlib-screen.c \
cairo-xlib-surface.c \
cairo-xlib-visual.c \
$(NULL)
+endif
cairo_xlib_xrender_headers = cairo-xlib-xrender.h
-# XXX split xcb-xrender. or better yet, merge it into xcb. xcb is so recent
-# that it's hard to imagine having xcb but not render.
-cairo_xcb_headers = cairo-xcb.h cairo-xcb-xrender.h
-cairo_xcb_sources = cairo-xcb-surface.c
+cairo_xcb_headers = cairo-xcb.h
+cairo_xcb_private = cairo-xcb-private.h
+cairo_xcb_sources = \
+ cairo-xcb-connection.c \
+ cairo-xcb-connection-core.c \
+ cairo-xcb-connection-render.c \
+ cairo-xcb-connection-shm.c \
+ cairo-xcb-screen.c \
+ cairo-xcb-shm.c \
+ cairo-xcb-surface.c \
+ cairo-xcb-surface-cairo.c \
+ cairo-xcb-surface-core.c \
+ cairo-xcb-surface-render.c \
+ $(NULL)
cairo_qt_headers = cairo-qt.h
cairo_qt_sources = cairo-qt-surface.cpp
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 048c92111..357505793 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -63,6 +63,20 @@ ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
enabled_cairo_pkgconf += cairo-xcb.pc
endif
+unsupported_cairo_headers += $(cairo_xlib_xcb_headers)
+all_cairo_headers += $(cairo_xlib_xcb_headers)
+all_cairo_private += $(cairo_xlib_xcb_private)
+all_cairo_sources += $(cairo_xlib_xcb_sources)
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_xlib_xcb_headers)
+enabled_cairo_private += $(cairo_xlib_xcb_private)
+enabled_cairo_sources += $(cairo_xlib_xcb_sources)
+endif
+all_cairo_pkgconf += cairo-xlib-xcb.pc
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-xlib-xcb.pc
+endif
+
unsupported_cairo_headers += $(cairo_qt_headers)
all_cairo_headers += $(cairo_qt_headers)
all_cairo_private += $(cairo_qt_private)
@@ -217,6 +231,20 @@ ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1)
enabled_cairo_pkgconf += cairo-gallium.pc
endif
+unsupported_cairo_headers += $(cairo_xcb_drm_headers)
+all_cairo_headers += $(cairo_xcb_drm_headers)
+all_cairo_private += $(cairo_xcb_drm_private)
+all_cairo_sources += $(cairo_xcb_drm_sources)
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_xcb_drm_headers)
+enabled_cairo_private += $(cairo_xcb_drm_private)
+enabled_cairo_sources += $(cairo_xcb_drm_sources)
+endif
+all_cairo_pkgconf += cairo-xcb-drm.pc
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-xcb-drm.pc
+endif
+
supported_cairo_headers += $(cairo_png_headers)
all_cairo_headers += $(cairo_png_headers)
all_cairo_private += $(cairo_png_private)
diff --git a/src/cairo-list-private.h b/src/cairo-list-private.h
index b8254bb74..6d65bf1c0 100644
--- a/src/cairo-list-private.h
+++ b/src/cairo-list-private.h
@@ -186,4 +186,11 @@ cairo_list_is_empty (const cairo_list_t *head)
return head->next == head;
}
+static inline cairo_bool_t
+cairo_list_is_singular (const cairo_list_t *head)
+{
+ cairo_list_validate (head);
+ return head->next == head || head->next == head->prev;
+}
+
#endif /* CAIRO_LIST_PRIVATE_H */
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index c84cebf62..aa2c8f809 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -54,6 +54,10 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
#endif
+#if CAIRO_HAS_XCB_SURFACE
+CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex)
+#endif
+
#if CAIRO_HAS_GL_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
#endif
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e77f1531d..aae1aa570 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2628,23 +2628,20 @@ _cairo_gradient_color_stops_hash (unsigned long hash,
return hash;
}
-static unsigned long
+unsigned long
_cairo_linear_pattern_hash (unsigned long hash,
- const cairo_pattern_t *pattern)
+ const cairo_linear_pattern_t *linear)
{
- const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
-
hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
return _cairo_gradient_color_stops_hash (hash, &linear->base);
}
-static unsigned long
-_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern)
+unsigned long
+_cairo_radial_pattern_hash (unsigned long hash,
+ const cairo_radial_pattern_t *radial)
{
- const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-
hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
@@ -2689,9 +2686,9 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_hash (hash, pattern);
case CAIRO_PATTERN_TYPE_LINEAR:
- return _cairo_linear_pattern_hash (hash, pattern);
+ return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_RADIAL:
- return _cairo_radial_pattern_hash (hash, pattern);
+ return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_hash (hash, pattern);
default:
@@ -2768,13 +2765,10 @@ _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
return TRUE;
}
-static cairo_bool_t
-_cairo_linear_pattern_equal (const cairo_pattern_t *A,
- const cairo_pattern_t *B)
+cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
+ const cairo_linear_pattern_t *b)
{
- const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A;
- const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B;
-
if (a->p1.x != b->p1.x)
return FALSE;
@@ -2790,13 +2784,10 @@ _cairo_linear_pattern_equal (const cairo_pattern_t *A,
return _cairo_gradient_color_stops_equal (&a->base, &b->base);
}
-static cairo_bool_t
-_cairo_radial_pattern_equal (const cairo_pattern_t *A,
- const cairo_pattern_t *B)
+cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
+ const cairo_radial_pattern_t *b)
{
- const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A;
- const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B;
-
if (a->c1.x != b->c1.x)
return FALSE;
@@ -2858,9 +2849,11 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
case CAIRO_PATTERN_TYPE_SOLID:
return _cairo_solid_pattern_equal (a, b);
case CAIRO_PATTERN_TYPE_LINEAR:
- return _cairo_linear_pattern_equal (a, b);
+ return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
+ (cairo_linear_pattern_t *) b);
case CAIRO_PATTERN_TYPE_RADIAL:
- return _cairo_radial_pattern_equal (a, b);
+ return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
+ (cairo_radial_pattern_t *) b);
case CAIRO_PATTERN_TYPE_SURFACE:
return _cairo_surface_pattern_equal (a, b);
default:
diff --git a/src/cairo-xcb-connection-core.c b/src/cairo-xcb-connection-core.c
new file mode 100644
index 000000000..22a340dff
--- /dev/null
+++ b/src/cairo-xcb-connection-core.c
@@ -0,0 +1,482 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+
+xcb_pixmap_t
+_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
+ uint8_t depth,
+ xcb_drawable_t drawable,
+ uint16_t width,
+ uint16_t height)
+{
+ struct {
+ uint8_t req;
+ uint8_t depth;
+ uint16_t len;
+ uint32_t pixmap;
+ uint32_t drawable;
+ uint16_t width, height;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 53;
+ req.depth = depth;
+ req.len = sizeof (req) >> 2;
+
+ req.pixmap = _cairo_xcb_connection_get_xid (connection);
+ req.drawable = drawable;
+ req.width = width;
+ req.height = height;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+
+ return req.pixmap;
+}
+
+void
+_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
+ xcb_pixmap_t pixmap)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t pixmap;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 54;
+ req.len = sizeof (req) >> 2;
+ req.pixmap = pixmap;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, pixmap);
+}
+
+xcb_gcontext_t
+_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
+ xcb_drawable_t drawable,
+ uint32_t value_mask,
+ uint32_t *values)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t gc;
+ uint32_t drawable;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ req.req = 55;
+ req.len = (sizeof (req) + len) >> 2;
+ req.gc = _cairo_xcb_connection_get_xid (connection);
+ req.drawable = drawable;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = values;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+
+ return req.gc;
+}
+
+void
+_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t gc;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 60;
+ req.len = sizeof (req) >> 2;
+ req.gc = gc;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, gc);
+}
+
+void
+_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc,
+ uint32_t value_mask,
+ uint32_t *values)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t gc;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ req.req = 56;
+ req.len = (sizeof (req) + len) >> 2;
+ req.gc = gc;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = values;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t gc;
+ int16_t src_x;
+ int16_t src_y;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint16_t width;
+ uint16_t height;
+ } req;
+ struct iovec vec[1];
+
+ req.req = 62;
+ req.len = sizeof (req) >> 2;
+ req.src = src;
+ req.dst = dst;
+ req.gc = gc;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.width = width;
+ req.height = height;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint32_t num_rectangles,
+ xcb_rectangle_t *rectangles)
+{
+ struct {
+ uint8_t req;
+ uint8_t pad;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ } req;
+ struct iovec vec[2];
+
+ req.req = 70;
+ req.len = (sizeof (req) + num_rectangles * sizeof (xcb_rectangle_t)) >> 2;
+ req.dst = dst;
+ req.gc = gc;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = rectangles;
+ vec[1].iov_len = num_rectangles * sizeof (xcb_rectangle_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t stride,
+ void *data)
+{
+ struct {
+ uint8_t req;
+ uint8_t format;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ uint16_t width;
+ uint16_t height;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint8_t left;
+ uint8_t depth;
+ uint16_t pad;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ uint32_t length = height * stride;
+ uint32_t len = (sizeof (req) + length) >> 2;
+
+ req.req = 72;
+ req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+ req.len = 0;
+ req.dst = dst;
+ req.gc = gc;
+ req.width = width;
+ req.height = height;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.left = 0;
+ req.depth = depth;
+
+ if (len < connection->root->maximum_request_length) {
+ req.len = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = data;
+ vec[1].iov_len = length;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+ } else if (len < connection->maximum_request_length) {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = data;
+ vec[2].iov_len = length;
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+ } else {
+ int rows;
+
+ rows = (connection->maximum_request_length - sizeof (req) - 4) / stride;
+ if (rows > 0) {
+ do {
+ if (rows > height)
+ rows = height;
+
+ length = rows * stride;
+ len = (sizeof (req) + 4 + length) >> 2;
+
+ req.height = rows;
+
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len;
+
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = data;
+ vec[2].iov_len = length;
+
+ /* note may modify vec */
+ _cairo_xcb_connection_write (connection, vec, 3);
+
+ height -= rows;
+ req.dst_y += rows;
+ data = (char *) data + length;
+ } while (height);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+}
+
+void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ uint16_t stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *_data)
+{
+ struct {
+ uint8_t req;
+ uint8_t format;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ uint16_t width;
+ uint16_t height;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint8_t left;
+ uint8_t depth;
+ uint16_t pad;
+ } req;
+ struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)];
+ struct iovec *vec = vec_stack;
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + cpp*width*height) >> 2;
+ uint8_t *data = _data;
+ int n;
+
+ req.req = 72;
+ req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+ req.len = 0;
+ req.dst = dst;
+ req.gc = gc;
+ req.width = width;
+ req.height = height;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.left = 0;
+ req.depth = depth;
+
+ if (height + 2 > ARRAY_LENGTH (vec_stack)) {
+ vec = _cairo_malloc_ab (height+2, sizeof (struct iovec));
+ if (unlikely (vec == NULL)) {
+ /* XXX loop over ARRAY_LENGTH (vec_stack) */
+ return;
+ }
+ }
+
+ data += src_y * stride + src_x * cpp;
+ if (len < connection->root->maximum_request_length) {
+ req.len = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ n = 1;
+ } else if (len < connection->maximum_request_length) {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ n = 2;
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+
+ while (height--) {
+ vec[n].iov_base = data;
+ vec[n].iov_len = cpp * width;
+ data += stride;
+ n++;
+ }
+
+ _cairo_xcb_connection_write (connection, vec, n);
+
+ if (vec != vec_stack)
+ free (vec);
+}
+
+cairo_status_t
+_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ xcb_get_image_reply_t **reply)
+{
+ xcb_generic_error_t *error;
+ cairo_status_t status;
+
+ *reply = xcb_get_image_reply (connection->xcb_connection,
+ xcb_get_image (connection->xcb_connection,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ src,
+ src_x, src_y,
+ width, height,
+ (uint32_t) -1),
+
+ &error);
+ if (error) {
+ free (error);
+
+ if (*reply)
+ free (*reply);
+ *reply = NULL;
+ }
+
+ status = _cairo_xcb_connection_take_socket (connection);
+ if (unlikely (status)) {
+ if (*reply)
+ free (*reply);
+ *reply = NULL;
+ }
+
+ return status;
+}
diff --git a/src/cairo-xcb-connection-render.c b/src/cairo-xcb-connection-render.c
new file mode 100644
index 000000000..2ebd6b47e
--- /dev/null
+++ b/src/cairo-xcb-connection-render.c
@@ -0,0 +1,969 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+
+#define X_RenderSpans 99
+#define XLIB_COORD_MAX 32767
+
+void
+_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_drawable_t drawable,
+ xcb_render_pictformat_t format,
+ uint32_t value_mask,
+ uint32_t *value_list)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint32_t drawable;
+ uint32_t format;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 20);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 4;
+ req.length = (sizeof (req) + len) >> 2;
+ req.picture = picture;
+ req.drawable = drawable;
+ req.format = format;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = value_list;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 1 + (len != 0));
+}
+
+void
+_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint32_t value_mask,
+ uint32_t *value_list)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint32_t mask;
+ } req;
+ struct iovec vec[2];
+ int len = _cairo_popcount (value_mask) * 4;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 5;
+ req.length = (sizeof (req) + len) >> 2;
+ req.picture = picture;
+ req.mask = value_mask;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = value_list;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ int16_t clip_x_origin,
+ int16_t clip_y_origin,
+ uint32_t rectangles_len,
+ xcb_rectangle_t *rectangles)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint16_t x;
+ uint16_t y;
+ } req;
+ struct iovec vec[2];
+ int len = sizeof (xcb_rectangle_t) * rectangles_len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+ assert ((len + sizeof (req)) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 6;
+ req.length = (sizeof (req) + len) >> 2;
+ req.picture = picture;
+ req.x = clip_x_origin;
+ req.y = clip_y_origin;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = rectangles;
+ vec[1].iov_len = len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 7;
+ req.length = sizeof (req) >> 2;
+ req.picture = picture;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, picture);
+}
+
+void
+_cairo_xcb_connection_render_composite (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t mask,
+ xcb_render_picture_t dst,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t mask_x,
+ int16_t mask_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t mask;
+ uint32_t dst;
+ int16_t src_x;
+ int16_t src_y;
+ int16_t mask_x;
+ int16_t mask_y;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint16_t width;
+ uint16_t height;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 36);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 8;
+ req.length = sizeof (req) >> 2;
+ req.op = op;
+ req.src = src;
+ req.mask = mask;
+ req.dst = dst;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.mask_x = mask_x;
+ req.mask_y = mask_y;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.width = width;
+ req.height = height;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t traps_len,
+ xcb_render_trapezoid_t *traps)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + traps_len * sizeof (xcb_render_trapezoid_t)) >> 2;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 24);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 10;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = traps;
+ vec[1].iov_len = traps_len * sizeof (xcb_render_trapezoid_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = traps;
+ vec[2].iov_len = traps_len * sizeof (xcb_render_trapezoid_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+ }
+}
+
+void
+_cairo_xcb_connection_render_spans (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t dst,
+ int op,
+ xcb_render_picture_t src,
+ int16_t src_x, int16_t src_y,
+ int16_t dst_x, int16_t dst_y,
+ int16_t width, int16_t height,
+ uint32_t num_spans,
+ uint16_t *spans)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ int16_t src_x;
+ int16_t src_y;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint16_t width;
+ uint16_t height;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + num_spans * sizeof (uint16_t)) >> 2;
+
+ req.major = connection->render->major_opcode;
+ req.minor = X_RenderSpans;
+ req.length = 0;
+
+ req.dst = dst;
+ req.op = op;
+ req.src = src;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.width = width;
+ req.height = height;
+
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = spans;
+ vec[1].iov_len = num_spans * sizeof (uint16_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+ vec[2].iov_base = spans;
+ vec[2].iov_len = num_spans * sizeof (uint16_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+ }
+}
+
+void
+_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t id,
+ xcb_render_pictformat_t format)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ uint32_t format;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 17;
+ req.length = sizeof (req) >> 2;
+ req.gsid = id;
+ req.format = format;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 19;
+ req.length = sizeof (req) >> 2;
+ req.gsid = glyphset;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, glyphset);
+}
+
+void
+_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ uint32_t *glyphs_id,
+ xcb_render_glyphinfo_t *glyphs,
+ uint32_t data_len,
+ uint8_t *data)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ uint32_t num_glyphs;
+ } req;
+ struct iovec vec[5];
+ uint32_t prefix[2];
+ uint32_t len = (sizeof (req) + num_glyphs * (sizeof (uint32_t) + sizeof (xcb_render_glyphinfo_t)) + data_len) >> 2;
+ int cnt;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 20;
+ req.length = 0;
+ req.gsid = glyphset;
+ req.num_glyphs = num_glyphs;
+
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ cnt = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ cnt = 2;
+ }
+
+ vec[cnt].iov_base = glyphs_id;
+ vec[cnt].iov_len = num_glyphs * sizeof (uint32_t);
+ cnt++;
+
+ vec[cnt].iov_base = glyphs;
+ vec[cnt].iov_len = num_glyphs * sizeof (xcb_render_glyphinfo_t);
+ cnt++;
+
+ vec[cnt].iov_base = data;
+ vec[cnt].iov_len = data_len;
+ cnt++;
+
+ _cairo_xcb_connection_write (connection, vec, cnt);
+}
+
+void
+_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ xcb_render_glyph_t *glyphs)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t gsid;
+ } req;
+ struct iovec vec[2];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+ assert ( (sizeof (req) + num_glyphs * sizeof (uint32_t)) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 22;
+ req.length = (sizeof (req) + num_glyphs * sizeof (uint32_t)) >> 2;
+ req.gsid = glyphset;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = glyphs;
+ vec[1].iov_len = num_glyphs * sizeof (uint32_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ uint32_t glyphset;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ int len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 23;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.glyphset = glyphset;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ len = (sizeof (req) + glyphcmds_len) >> 2;
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ len = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ len = 2;
+ }
+
+ vec[len].iov_base = glyphcmds;
+ vec[len].iov_len = glyphcmds_len;
+ len++;
+
+ _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ uint32_t glyphset;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[3];
+ uint32_t prefix[2];
+ int len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 24;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.glyphset = glyphset;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ len = (sizeof (req) + glyphcmds_len) >> 2;
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ len = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ len = 2;
+ }
+
+ vec[len].iov_base = glyphcmds;
+ vec[len].iov_len = glyphcmds_len;
+ len++;
+
+ _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t mask_format;
+ uint32_t glyphset;
+ int16_t src_x;
+ int16_t src_y;
+ } req;
+ struct iovec vec[2];
+ uint32_t prefix[2];
+ int len;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 25;
+ req.length = 0;
+ req.op = op;
+ req.src = src;
+ req.dst = dst;
+ req.mask_format = mask_format;
+ req.glyphset = glyphset;
+ req.src_x = src_x;
+ req.src_y = src_y;
+
+ len = (sizeof (req) + glyphcmds_len) >> 2;
+ if (len < connection->root->maximum_request_length) {
+ req.length = len;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ len = 1;
+ } else {
+ prefix[0] = *(uint32_t *) &req;
+ prefix[1] = len + 1;
+ vec[0].iov_base = prefix;
+ vec[0].iov_len = sizeof (prefix);
+ vec[1].iov_base = (uint32_t *) &req + 1;
+ vec[1].iov_len = sizeof (req) - 4;
+
+ len = 2;
+ }
+
+ vec[len].iov_base = glyphcmds;
+ vec[len].iov_len = glyphcmds_len;
+ len++;
+
+ _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t dst,
+ xcb_render_color_t color,
+ uint32_t num_rects,
+ xcb_rectangle_t *rects)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint8_t op;
+ uint8_t pad1;
+ uint16_t pad2;
+ uint32_t dst;
+ xcb_render_color_t color;
+ } req;
+ struct iovec vec[2];
+ uint32_t len = (sizeof (req) + num_rects * sizeof (xcb_rectangle_t)) >> 2;
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 20);
+ assert(len < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 26;
+ req.length = (sizeof (req) + num_rects * sizeof (xcb_rectangle_t)) >> 2;
+ req.op = op;
+ req.dst = dst;
+ req.color = color;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = rects;
+ vec[1].iov_len = num_rects * sizeof (xcb_rectangle_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_transform_t *transform)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ } req;
+ struct iovec vec[2];
+
+ req.major = connection->render->major_opcode;
+ req.minor = 28;
+ req.length = (sizeof (req) + sizeof (xcb_render_transform_t)) >> 2;
+ req.picture = picture;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = transform;
+ vec[1].iov_len = sizeof (xcb_render_transform_t);
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint16_t filter_len,
+ char *filter)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ uint16_t nbytes;
+ uint16_t pad;
+ } req;
+ struct iovec vec[2];
+
+ req.nbytes = filter_len;
+ filter_len = (filter_len + 3) & ~3;
+
+ req.major = connection->render->major_opcode;
+ req.minor = 30;
+ req.length = (sizeof (req) + filter_len) >> 2;
+ req.picture = picture;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = filter;
+ vec[1].iov_len = filter_len;
+
+ _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_color_t color)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_color_t color;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 16);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 33;
+ req.length = sizeof (req) >> 2;
+ req.picture = picture;
+ req.color = color;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t p1,
+ xcb_render_pointfix_t p2,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_pointfix_t p1, p2;
+ uint32_t num_stops;
+ } req;
+ struct iovec vec[3];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 28);
+ assert((sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 34;
+ req.length = (sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+ req.picture = picture;
+ req.p1 = p1;
+ req.p2 = p2;
+ req.num_stops = num_stops;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = stops;
+ vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+ vec[2].iov_base = colors;
+ vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+}
+
+void
+_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t inner,
+ xcb_render_pointfix_t outer,
+ xcb_render_fixed_t inner_radius,
+ xcb_render_fixed_t outer_radius,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_pointfix_t inner;
+ xcb_render_pointfix_t outer;
+ xcb_render_fixed_t inner_radius;
+ xcb_render_fixed_t outer_radius;
+ uint32_t num_stops;
+ } req;
+ struct iovec vec[3];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 36);
+ assert((sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 35;
+ req.length = (sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+ req.picture = picture;
+ req.inner = inner;
+ req.outer = outer;
+ req.inner_radius = inner_radius;
+ req.outer_radius = outer_radius;
+ req.num_stops = num_stops;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = stops;
+ vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+ vec[2].iov_base = colors;
+ vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+}
+
+void
+_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t center,
+ xcb_render_fixed_t angle,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors)
+{
+ struct {
+ uint8_t major;
+ uint8_t minor;
+ uint16_t length;
+ uint32_t picture;
+ xcb_render_pointfix_t center;
+ xcb_render_fixed_t angle;
+ uint32_t num_stops;
+ } req;
+ struct iovec vec[3];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 24);
+ assert((sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+ req.major = connection->render->major_opcode;
+ req.minor = 36;
+ req.length = (sizeof (req) + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+ req.picture = picture;
+ req.center = center;
+ req.angle = angle;
+ req.num_stops = num_stops;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+ vec[1].iov_base = stops;
+ vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+ vec[2].iov_base = colors;
+ vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+ _cairo_xcb_connection_write (connection, vec, 3);
+}
diff --git a/src/cairo-xcb-connection-shm.c b/src/cairo-xcb-connection-shm.c
new file mode 100644
index 000000000..2c13b1ba8
--- /dev/null
+++ b/src/cairo-xcb-connection-shm.c
@@ -0,0 +1,194 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+#include <xcb/shm.h>
+
+uint32_t
+_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection,
+ uint32_t id,
+ cairo_bool_t readonly)
+{
+ struct {
+ uint8_t req;
+ uint8_t shm_req;
+ uint16_t length;
+ uint32_t segment;
+ uint32_t id;
+ uint8_t readonly;
+ uint8_t pad1;
+ uint16_t pad2;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 16);
+
+ req.req = connection->shm->major_opcode;
+ req.shm_req = 1;
+ req.length = sizeof (req) >> 2;
+ req.segment = _cairo_xcb_connection_get_xid (connection);
+ req.id = id;
+ req.readonly = readonly;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ return req.segment;
+}
+
+uint64_t
+_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t total_width,
+ uint16_t total_height,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t shm,
+ uint32_t offset)
+{
+ struct {
+ uint8_t req;
+ uint8_t shm_req;
+ uint16_t len;
+ uint32_t dst;
+ uint32_t gc;
+ uint16_t total_width;
+ uint16_t total_height;
+ int16_t src_x;
+ int16_t src_y;
+ uint16_t src_width;
+ uint16_t src_height;
+ int16_t dst_x;
+ int16_t dst_y;
+ uint8_t depth;
+ uint8_t format;
+ uint8_t send_event;
+ uint8_t pad;
+ uint32_t shm;
+ uint32_t offset;
+ } req;
+ struct iovec vec[2];
+
+ req.req = connection->shm->major_opcode;
+ req.shm_req = 3;
+ req.len = sizeof (req) >> 2;
+ req.dst = dst;
+ req.gc = gc;
+ req.total_width = total_width;
+ req.total_height = total_height;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.src_width = width;
+ req.src_height = height;
+ req.dst_x = dst_x;
+ req.dst_y = dst_y;
+ req.depth = depth;
+ req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+ req.send_event = 0;
+ req.shm = shm;
+ req.offset = offset;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ return connection->seqno;
+}
+
+cairo_status_t
+_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint32_t shmseg,
+ uint32_t offset)
+{
+ xcb_shm_get_image_reply_t *reply;
+ xcb_generic_error_t *error;
+
+ reply = xcb_shm_get_image_reply (connection->xcb_connection,
+ xcb_shm_get_image (connection->xcb_connection,
+ src,
+ src_x, src_y,
+ width, height,
+ (uint32_t) -1,
+ XCB_IMAGE_FORMAT_Z_PIXMAP,
+ shmseg, offset),
+ &error);
+ free (reply);
+
+ if (error) {
+ /* an error here should be impossible */
+ free (error);
+ return _cairo_error (CAIRO_STATUS_READ_ERROR);
+ }
+
+ return _cairo_xcb_connection_take_socket (connection);
+}
+
+void
+_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection,
+ uint32_t segment)
+{
+ struct {
+ uint8_t req;
+ uint8_t shm_req;
+ uint16_t length;
+ uint32_t segment;
+ } req;
+ struct iovec vec[1];
+
+ COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+ req.req = connection->shm->major_opcode;
+ req.shm_req = 2;
+ req.length = sizeof (req) >> 2;
+ req.segment = segment;
+
+ vec[0].iov_base = &req;
+ vec[0].iov_len = sizeof (req);
+
+ _cairo_xcb_connection_write (connection, vec, 1);
+ _cairo_xcb_connection_put_xid (connection, segment);
+}
diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c
new file mode 100644
index 000000000..6721e9230
--- /dev/null
+++ b/src/cairo-xcb-connection.c
@@ -0,0 +1,867 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+#include "cairo-hash-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <xcb/xcbext.h>
+#include <xcb/bigreq.h>
+#include <xcb/dri2.h>
+#include <xcb/shm.h>
+#include <errno.h>
+
+typedef struct _cairo_xcb_xrender_format {
+ cairo_hash_entry_t key;
+ xcb_render_pictformat_t xrender_format;
+} cairo_xcb_xrender_format_t;
+
+typedef struct _cairo_xcb_xid {
+ cairo_list_t link;
+ uint32_t xid;
+} cairo_xcb_xid_t;
+
+#define XCB_RENDER_AT_LEAST(V, major, minor) \
+ (((V)->major_version > major) || \
+ (((V)->major_version == major) && ((V)->minor_version >= minor)))
+
+#define XCB_RENDER_HAS_CREATE_PICTURE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
+#define XCB_RENDER_HAS_COMPOSITE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
+#define XCB_RENDER_HAS_COMPOSITE_TEXT(surface) XCB_RENDER_AT_LEAST((surface), 0, 0)
+
+#define XCB_RENDER_HAS_FILL_RECTANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 1)
+
+#define XCB_RENDER_HAS_DISJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2)
+#define XCB_RENDER_HAS_CONJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2)
+
+#define XCB_RENDER_HAS_TRAPEZOIDS(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRIANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRISTRIP(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRIFAN(surface) XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_SPANS(surface) XCB_RENDER_AT_LEAST((surface), 0, 12)
+
+#define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface) XCB_RENDER_AT_LEAST((surface), 0, 6)
+#define XCB_RENDER_HAS_FILTERS(surface) XCB_RENDER_AT_LEAST((surface), 0, 6)
+
+#define XCB_RENDER_HAS_EXTENDED_REPEAT(surface) XCB_RENDER_AT_LEAST((surface), 0, 10)
+#define XCB_RENDER_HAS_GRADIENTS(surface) XCB_RENDER_AT_LEAST((surface), 0, 10)
+
+#define XCB_RENDER_HAS_PDF_OPERATORS(surface) XCB_RENDER_AT_LEAST((surface), 0, 11)
+
+static cairo_list_t connections;
+
+static cairo_status_t
+_cairo_xcb_connection_find_visual_formats (cairo_xcb_connection_t *connection,
+ const xcb_render_query_pict_formats_reply_t *formats)
+{
+ xcb_render_pictscreen_iterator_t screens;
+ xcb_render_pictdepth_iterator_t depths;
+ xcb_render_pictvisual_iterator_t visuals;
+
+ for (screens = xcb_render_query_pict_formats_screens_iterator (formats);
+ screens.rem;
+ xcb_render_pictscreen_next (&screens))
+ {
+ for (depths = xcb_render_pictscreen_depths_iterator (screens.data);
+ depths.rem;
+ xcb_render_pictdepth_next (&depths))
+ {
+ for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data);
+ visuals.rem;
+ xcb_render_pictvisual_next (&visuals))
+ {
+ cairo_xcb_xrender_format_t *f;
+ cairo_status_t status;
+
+ f = malloc (sizeof (cairo_xcb_xrender_format_t));
+ if (unlikely (f == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ f->key.hash = visuals.data->visual;
+ f->xrender_format = visuals.data->format;
+ status = _cairo_hash_table_insert (connection->visual_to_xrender_format,
+ &f->key);
+ if (unlikely (status))
+ return status;
+ }
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+#if 0
+static xcb_format_t *
+find_format_for_depth (const xcb_setup_t *setup, uint8_t depth)
+{
+ xcb_format_t *fmt = xcb_setup_pixmap_formats (setup);
+ xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length (setup);
+
+ for (; fmt != fmtend; ++fmt)
+ if (fmt->depth == depth)
+ return fmt;
+
+ return 0;
+}
+#endif
+
+static cairo_status_t
+_cairo_xcb_connection_parse_xrender_formats (cairo_xcb_connection_t *connection,
+ const xcb_render_query_pict_formats_reply_t *formats)
+{
+ xcb_render_pictforminfo_iterator_t i;
+ cairo_status_t status;
+
+ for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+ i.rem;
+ xcb_render_pictforminfo_next (&i))
+ {
+ cairo_format_masks_t masks;
+ pixman_format_code_t pixman_format;
+
+ if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT)
+ continue;
+
+ masks.alpha_mask =
+ (unsigned long) i.data->direct.alpha_mask << i.data->direct.alpha_shift;
+ masks.red_mask =
+ (unsigned long) i.data->direct.red_mask << i.data->direct.red_shift;
+ masks.green_mask =
+ (unsigned long) i.data->direct.green_mask << i.data->direct.green_shift;
+ masks.blue_mask =
+ (unsigned long) i.data->direct.blue_mask << i.data->direct.blue_shift;
+ masks.bpp = i.data->depth;
+
+ if (_pixman_format_from_masks (&masks, &pixman_format)) {
+ cairo_hash_entry_t key;
+
+ key.hash = pixman_format;
+ if (! _cairo_hash_table_lookup (connection->xrender_formats, &key)) {
+ cairo_xcb_xrender_format_t *f;
+
+ f = malloc (sizeof (cairo_xcb_xrender_format_t));
+ if (unlikely (f == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ f->key.hash = pixman_format;
+ f->xrender_format = i.data->id;
+ status = _cairo_hash_table_insert (connection->xrender_formats,
+ &f->key);
+ if (unlikely (status))
+ return status;
+
+#if 0
+ printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n",
+ i.data->id,
+ masks.alpha_mask,
+ masks.red_mask,
+ masks.green_mask,
+ masks.blue_mask,
+ masks.bpp,
+ pixman_format,
+ PIXMAN_FORMAT_DEPTH(pixman_format),
+ PIXMAN_FORMAT_BPP(pixman_format));
+#endif
+ }
+ }
+ }
+
+ status = _cairo_xcb_connection_find_visual_formats (connection, formats);
+ if (unlikely (status))
+ return status;
+
+ connection->standard_formats[CAIRO_FORMAT_A1] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a1);
+
+ connection->standard_formats[CAIRO_FORMAT_A8] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8);
+
+ connection->standard_formats[CAIRO_FORMAT_RGB24] =
+ _cairo_xcb_connection_get_xrender_format (connection,
+ PIXMAN_FORMAT (24,
+ PIXMAN_TYPE_ARGB,
+ 0, 8, 8, 8));
+ if (connection->standard_formats[CAIRO_FORMAT_RGB24] == XCB_NONE) {
+ connection->standard_formats[CAIRO_FORMAT_RGB24] =
+ _cairo_xcb_connection_get_xrender_format (connection,
+ PIXMAN_FORMAT (24, PIXMAN_TYPE_ABGR,
+ 0, 8, 8, 8));
+ }
+
+ connection->standard_formats[CAIRO_FORMAT_ARGB32] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8r8g8b8);
+ if (connection->standard_formats[CAIRO_FORMAT_ARGB32] == XCB_NONE) {
+ connection->standard_formats[CAIRO_FORMAT_ARGB32] =
+ _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8b8g8r8);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/*
+ * We require support for depth 1, 8, 24 and 32 pixmaps
+ */
+#define DEPTH_MASK(d) (1 << ((d) - 1))
+#define REQUIRED_DEPTHS (DEPTH_MASK(1) | \
+ DEPTH_MASK(8) | \
+ DEPTH_MASK(24) | \
+ DEPTH_MASK(32))
+static cairo_bool_t
+pixmap_depths_usable (cairo_xcb_connection_t *connection,
+ uint32_t missing,
+ xcb_drawable_t root)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_void_cookie_t create_cookie[32];
+ xcb_pixmap_t pixmap;
+ cairo_bool_t success = TRUE;
+ int depth, i, j;
+
+ pixmap = _cairo_xcb_connection_get_xid (connection);
+
+ for (depth = 1, i = 0; depth <= 32; depth++) {
+ if (missing & DEPTH_MASK(depth)) {
+ create_cookie[i] = xcb_create_pixmap_checked (c, depth, pixmap, root, 1, 1);
+ xcb_free_pixmap (c, pixmap);
+ if (!create_cookie[i].sequence) {
+ success = FALSE;
+ break;
+ }
+ i++;
+ }
+ }
+
+ for (j = 0; j < i; j++) {
+ xcb_generic_error_t *create_error = xcb_request_check (c, create_cookie[j]);
+ success &= create_error == NULL;
+ free (create_error);
+ }
+
+ _cairo_xcb_connection_put_xid (connection, pixmap);
+
+ return success;
+}
+
+static cairo_bool_t
+has_required_depths (cairo_xcb_connection_t *connection)
+{
+ xcb_screen_iterator_t screens;
+
+ for (screens = xcb_setup_roots_iterator (connection->root);
+ screens.rem;
+ xcb_screen_next (&screens))
+ {
+ xcb_depth_iterator_t depths;
+ uint32_t missing = REQUIRED_DEPTHS;
+
+ for (depths = xcb_screen_allowed_depths_iterator (screens.data);
+ depths.rem;
+ xcb_depth_next (&depths))
+ {
+ missing &= ~DEPTH_MASK (depths.data->depth);
+ }
+ if (missing == 0)
+ continue;
+
+ /*
+ * Ok, this is ugly. It should be sufficient at this
+ * point to just return false, but Xinerama is broken at
+ * this point and only advertises depths which have an
+ * associated visual. Of course, the other depths still
+ * work, but the only way to find out is to try them.
+ */
+ if (! pixmap_depths_usable (connection, missing, screens.data->root))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static cairo_status_t
+_cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_render_query_version_cookie_t version_cookie;
+ xcb_render_query_pict_formats_cookie_t formats_cookie;
+ xcb_render_query_version_reply_t *version;
+ xcb_render_query_pict_formats_reply_t *formats;
+ cairo_status_t status;
+ cairo_bool_t present;
+
+ version_cookie = xcb_render_query_version (c, 0, 10);
+ formats_cookie = xcb_render_query_pict_formats (c);
+
+ present = has_required_depths (connection);
+ version = xcb_render_query_version_reply (c, version_cookie, 0);
+ formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0);
+ if (! present || version == NULL || formats == NULL) {
+ free (version);
+ free (formats);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ /* always true if the extension is present (i.e. >= 0.0) */
+ connection->flags |= CAIRO_XCB_HAS_RENDER;
+ connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE;
+ connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS;
+
+ if (XCB_RENDER_HAS_FILL_RECTANGLES (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
+
+ if (XCB_RENDER_HAS_TRAPEZOIDS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
+
+ if (XCB_RENDER_HAS_PICTURE_TRANSFORM (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
+
+ if (XCB_RENDER_HAS_FILTERS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS;
+
+ if (XCB_RENDER_HAS_PDF_OPERATORS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+
+ if (XCB_RENDER_HAS_EXTENDED_REPEAT (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
+
+ if (XCB_RENDER_HAS_GRADIENTS (version))
+ connection->flags |= CAIRO_XCB_RENDER_HAS_GRADIENTS;
+
+ free (version);
+
+ status = _cairo_xcb_connection_parse_xrender_formats (connection, formats);
+ free (formats);
+
+ return status;
+}
+
+#if 0
+static void
+_cairo_xcb_connection_query_cairo (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_cairo_query_version_reply_t *version;
+
+ version = xcb_cairo_query_version_reply (c,
+ xcb_cairo_query_version (c, 0, 0),
+ 0);
+
+ free (version);
+}
+#endif
+
+static cairo_bool_t
+can_use_shm (cairo_xcb_connection_t *connection)
+{
+ cairo_bool_t success = TRUE;
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_void_cookie_t cookie[2];
+ xcb_generic_error_t *error;
+ int shmid;
+ uint32_t shmseg;
+ void *ptr;
+
+ shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+ if (shmid == -1)
+ return FALSE;
+
+ ptr = shmat (shmid, NULL, 0);
+ if (ptr == (char *) -1) {
+ shmctl (shmid, IPC_RMID, NULL);
+ return FALSE;
+ }
+
+ shmseg = _cairo_xcb_connection_get_xid (connection);
+ cookie[0] = xcb_shm_attach_checked (c, shmseg, shmid, FALSE);
+ cookie[1] = xcb_shm_detach_checked (c, shmseg);
+ _cairo_xcb_connection_put_xid (connection, shmseg);
+
+ error = xcb_request_check (c, cookie[0]);
+ if (error != NULL)
+ success = FALSE;
+
+ error = xcb_request_check (c, cookie[1]);
+ if (error != NULL)
+ success = FALSE;
+
+ shmctl (shmid, IPC_RMID, NULL);
+ shmdt (ptr);
+
+ return success;
+}
+
+static void
+_cairo_xcb_connection_query_shm (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_shm_query_version_reply_t *version;
+
+ version = xcb_shm_query_version_reply (c, xcb_shm_query_version (c), 0);
+ if (version == NULL)
+ return;
+
+ free (version);
+
+ if (can_use_shm (connection))
+ connection->flags |= CAIRO_XCB_HAS_SHM;
+}
+
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+static void
+_cairo_xcb_connection_query_dri2 (cairo_xcb_connection_t *connection)
+{
+ xcb_connection_t *c = connection->xcb_connection;
+ xcb_dri2_query_version_reply_t *version;
+
+ version = xcb_dri2_query_version_reply (c,
+ xcb_dri2_query_version (c,
+ XCB_DRI2_MAJOR_VERSION,
+ XCB_DRI2_MINOR_VERSION),
+ 0);
+ if (version == NULL)
+ return;
+
+ free (version);
+
+ connection->flags |= CAIRO_XCB_HAS_DRI2;
+}
+#endif
+
+static void
+_device_flush (void *device)
+{
+ cairo_xcb_connection_t *connection = device;
+ cairo_xcb_screen_t *screen;
+ cairo_status_t status;
+
+ status = cairo_device_acquire (&connection->device);
+ if (unlikely (status))
+ return;
+
+ CAIRO_MUTEX_LOCK (connection->screens_mutex);
+ cairo_list_foreach_entry (screen, cairo_xcb_screen_t,
+ &connection->screens, link)
+ {
+ if (screen->device != NULL)
+ cairo_device_flush (screen->device);
+ }
+ CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+ xcb_flush (connection->xcb_connection);
+
+ cairo_device_release (&connection->device);
+}
+
+static cairo_bool_t
+_xrender_formats_equal (const void *A, const void *B)
+{
+ const cairo_xcb_xrender_format_t *a = A, *b = B;
+ return a->key.hash == b->key.hash;
+}
+
+static void
+_pluck_xrender_format (void *entry,
+ void *closure)
+{
+ _cairo_hash_table_remove (closure, entry);
+ free (entry);
+}
+
+static void
+_device_finish (void *device)
+{
+ cairo_xcb_connection_t *connection = device;
+
+ if (! cairo_list_is_empty (&connection->link)) {
+ CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
+ cairo_list_del (&connection->link);
+ CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
+ }
+
+ while (! cairo_list_is_empty (&connection->fonts)) {
+ cairo_xcb_font_t *font;
+
+ font = cairo_list_first_entry (&connection->fonts,
+ cairo_xcb_font_t,
+ link);
+ _cairo_xcb_font_finish (font);
+ }
+
+ while (! cairo_list_is_empty (&connection->screens)) {
+ cairo_xcb_screen_t *screen;
+
+ screen = cairo_list_first_entry (&connection->screens,
+ cairo_xcb_screen_t,
+ link);
+ _cairo_xcb_screen_finish (screen);
+ }
+}
+
+static void
+_device_destroy (void *device)
+{
+ cairo_xcb_connection_t *connection = device;
+
+ _cairo_hash_table_foreach (connection->xrender_formats,
+ _pluck_xrender_format, connection->xrender_formats);
+ _cairo_hash_table_destroy (connection->xrender_formats);
+
+ _cairo_hash_table_foreach (connection->visual_to_xrender_format,
+ _pluck_xrender_format,
+ connection->visual_to_xrender_format);
+ _cairo_hash_table_destroy (connection->visual_to_xrender_format);
+
+ _cairo_xcb_connection_shm_mem_pools_fini (connection);
+ _cairo_freepool_fini (&connection->shm_info_freelist);
+
+ _cairo_freepool_fini (&connection->xid_pool);
+
+ CAIRO_MUTEX_FINI (connection->shm_mutex);
+ CAIRO_MUTEX_FINI (connection->screens_mutex);
+
+ free (connection);
+}
+
+static const cairo_device_backend_t _cairo_xcb_device_backend = {
+ CAIRO_DEVICE_TYPE_XCB,
+
+ NULL, NULL, /* lock, unlock */
+
+ _device_flush,
+ _device_finish,
+ _device_destroy,
+};
+
+cairo_xcb_connection_t *
+_cairo_xcb_connection_get (xcb_connection_t *xcb_connection)
+{
+ cairo_xcb_connection_t *connection;
+ const xcb_query_extension_reply_t *ext;
+ cairo_status_t status;
+
+ CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
+ if (connections.next == NULL) {
+ /* XXX _cairo_init () */
+ cairo_list_init (&connections);
+ }
+
+ cairo_list_foreach_entry (connection,
+ cairo_xcb_connection_t,
+ &connections,
+ link)
+ {
+ if (connection->xcb_connection == xcb_connection) {
+ /* Maintain MRU order. */
+ if (connections.next != &connection->link)
+ cairo_list_move (&connection->link, &connections);
+
+ goto unlock;
+ }
+ }
+
+ connection = malloc (sizeof (cairo_xcb_connection_t));
+ if (unlikely (connection == NULL))
+ goto unlock;
+
+ _cairo_device_init (&connection->device, &_cairo_xcb_device_backend);
+ CAIRO_MUTEX_INIT (connection->shm_mutex);
+ CAIRO_MUTEX_INIT (connection->screens_mutex);
+
+ connection->xcb_connection = xcb_connection;
+ connection->has_socket = FALSE;
+
+ xcb_prefetch_extension_data (xcb_connection, &xcb_big_requests_id);
+ xcb_prefetch_extension_data (xcb_connection, &xcb_shm_id);
+ xcb_prefetch_extension_data (xcb_connection, &xcb_render_id);
+#if 0
+ xcb_prefetch_extension_data (xcb_connection, &xcb_cairo_id);
+#endif
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+ xcb_prefetch_extension_data (xcb_connection, &xcb_dri2_id);
+#endif
+
+ xcb_prefetch_maximum_request_length (xcb_connection);
+
+ cairo_list_init (&connection->fonts);
+ cairo_list_init (&connection->screens);
+ cairo_list_add (&connection->link, &connections);
+ connection->xrender_formats = _cairo_hash_table_create (_xrender_formats_equal);
+ connection->visual_to_xrender_format = _cairo_hash_table_create (_xrender_formats_equal);
+
+ cairo_list_init (&connection->free_xids);
+ _cairo_freepool_init (&connection->xid_pool,
+ sizeof (cairo_xcb_xid_t));
+
+ cairo_list_init (&connection->shm_pools);
+ _cairo_freepool_init (&connection->shm_info_freelist,
+ sizeof (cairo_xcb_shm_info_t));
+
+ connection->maximum_request_length =
+ xcb_get_maximum_request_length (xcb_connection);
+
+ connection->flags = 0;
+
+ connection->root = xcb_get_setup (xcb_connection);
+ connection->render = NULL;
+ ext = xcb_get_extension_data (xcb_connection, &xcb_render_id);
+ if (ext != NULL && ext->present) {
+ status = _cairo_xcb_connection_query_render (connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_destroy (connection);
+ connection = NULL;
+ goto unlock;
+ }
+
+ connection->render = ext;
+ }
+
+#if 0
+ ext = xcb_get_extension_data (connection, &xcb_cairo_id);
+ if (ext != NULL && ext->present)
+ _cairo_xcb_connection_query_cairo (connection);
+#endif
+
+ connection->shm = NULL;
+ ext = xcb_get_extension_data (xcb_connection, &xcb_shm_id);
+ if (ext != NULL && ext->present) {
+ _cairo_xcb_connection_query_shm (connection);
+ connection->shm = ext;
+ }
+
+ connection->dri2 = NULL;
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+ ext = xcb_get_extension_data (xcb_connection, &xcb_dri2_id);
+ if (ext != NULL && ext->present) {
+ _cairo_xcb_connection_query_dri2 (connection);
+ connection->dri2 = ext;
+ }
+#endif
+
+unlock:
+ CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
+
+ return connection;
+}
+
+xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format)
+{
+ cairo_hash_entry_t key;
+ cairo_xcb_xrender_format_t *format;
+
+ key.hash = pixman_format;
+ format = _cairo_hash_table_lookup (connection->xrender_formats, &key);
+ return format ? format->xrender_format : XCB_NONE;
+}
+
+xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
+ const xcb_visualid_t visual)
+{
+ cairo_hash_entry_t key;
+ cairo_xcb_xrender_format_t *format;
+
+ key.hash = visual;
+ format = _cairo_hash_table_lookup (connection->visual_to_xrender_format, &key);
+ return format ? format->xrender_format : XCB_NONE;
+}
+
+void
+_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
+ uint32_t xid)
+{
+ cairo_xcb_xid_t *cache;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+ cache = _cairo_freepool_alloc (&connection->xid_pool);
+ if (likely (cache != NULL)) {
+ cache->xid = xid;
+ cairo_list_add (&cache->link, &connection->free_xids);
+ }
+}
+
+uint32_t
+_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection)
+{
+ uint32_t xid;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+ if (! cairo_list_is_empty (&connection->free_xids)) {
+ cairo_xcb_xid_t *cache;
+
+ cache = cairo_list_first_entry (&connection->free_xids,
+ cairo_xcb_xid_t,
+ link);
+ xid = cache->xid;
+
+ cairo_list_del (&cache->link);
+ _cairo_freepool_free (&connection->xid_pool, cache);
+ } else {
+ xid = xcb_generate_id (connection->xcb_connection);
+ }
+
+ return xid;
+}
+
+static void
+_cairo_xcb_return_socket (void *closure)
+{
+ cairo_xcb_connection_t *connection = closure;
+
+ CAIRO_MUTEX_LOCK (connection->device.mutex);
+ connection->has_socket = FALSE;
+ CAIRO_MUTEX_UNLOCK (connection->device.mutex);
+}
+
+cairo_status_t
+_cairo_xcb_connection_take_socket (cairo_xcb_connection_t *connection)
+{
+ assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+
+ if (unlikely (connection->device.status))
+ return connection->device.status;
+
+ if (! connection->has_socket) {
+ if (! xcb_take_socket (connection->xcb_connection,
+ _cairo_xcb_return_socket,
+ connection,
+ 0, &connection->seqno))
+ {
+ return connection->device.status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
+ }
+
+ connection->has_socket = TRUE;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* public (debug) interface */
+
+void
+cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
+ int major_version,
+ int minor_version)
+{
+ cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+ cairo_status_t status;
+
+ if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+ status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+ return;
+ }
+
+ /* clear any flags that are inappropriate for the desired version */
+ if (major_version < 0 && minor_version < 0) {
+ connection->flags &= ~(CAIRO_XCB_HAS_SHM);
+ }
+}
+
+void
+cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
+ int major_version,
+ int minor_version)
+{
+ cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+ cairo_status_t status;
+
+ if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+ status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+ return;
+ }
+
+ /* clear any flags that are inappropriate for the desired version */
+ if (major_version < 0 && minor_version < 0) {
+ connection->flags &= ~(CAIRO_XCB_HAS_RENDER |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS |
+ CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM |
+ CAIRO_XCB_RENDER_HAS_FILTERS |
+ CAIRO_XCB_RENDER_HAS_PDF_OPERATORS |
+ CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT |
+ CAIRO_XCB_RENDER_HAS_GRADIENTS);
+ } else {
+ xcb_render_query_version_reply_t version;
+
+ version.major_version = major_version;
+ version.minor_version = minor_version;
+
+ if (! XCB_RENDER_HAS_FILL_RECTANGLES (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
+
+ if (! XCB_RENDER_HAS_TRAPEZOIDS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
+
+ if (! XCB_RENDER_HAS_PICTURE_TRANSFORM (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
+
+ if (! XCB_RENDER_HAS_FILTERS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILTERS;
+
+ if (! XCB_RENDER_HAS_PDF_OPERATORS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+
+ if (! XCB_RENDER_HAS_EXTENDED_REPEAT (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
+
+ if (! XCB_RENDER_HAS_GRADIENTS (&version))
+ connection->flags &= ~CAIRO_XCB_RENDER_HAS_GRADIENTS;
+ }
+}
+
+#if 0
+void
+cairo_xcb_device_debug_cap_xcairo_version (cairo_device_t *device,
+ int major_version,
+ int minor_version)
+{
+ cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+ cairo_status_t status;
+
+ if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+ status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+ return;
+ }
+
+ /* clear any flags that are inappropriate for the desired version */
+ if (major_version < 0 && minor_version < 0) {
+ connection->flags &= ~(CAIRO_XCB_HAS_CAIRO);
+ }
+}
+#endif
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
new file mode 100644
index 000000000..18a485cf0
--- /dev/null
+++ b/src/cairo-xcb-private.h
@@ -0,0 +1,760 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributors(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_XCB_PRIVATE_H
+#define CAIRO_XCB_PRIVATE_H
+
+#include "cairo-xcb.h"
+
+#include "cairo-cache-private.h"
+#include "cairo-compiler-private.h"
+#include "cairo-device-private.h"
+#include "cairo-error-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+#include "cairo-mutex-private.h"
+#include "cairo-reference-count-private.h"
+#include "cairo-spans-private.h"
+#include "cairo-surface-private.h"
+
+#include <xcb/xcb.h>
+#include <xcb/render.h>
+#include <xcb/xcbext.h>
+#include <pixman.h>
+
+typedef struct _cairo_xcb_connection cairo_xcb_connection_t;
+typedef struct _cairo_xcb_font cairo_xcb_font_t;
+typedef struct _cairo_xcb_screen cairo_xcb_screen_t;
+typedef struct _cairo_xcb_surface cairo_xcb_surface_t;
+typedef struct _cairo_xcb_shm_mem_pool cairo_xcb_shm_mem_pool_t;
+typedef struct _cairo_xcb_shm_info cairo_xcb_shm_info_t;
+
+struct _cairo_xcb_shm_info {
+ cairo_xcb_connection_t *connection;
+ uint32_t shm;
+ uint32_t offset;
+ uint64_t seqno;
+ void *mem;
+ cairo_xcb_shm_mem_pool_t *pool;
+};
+
+struct _cairo_xcb_surface {
+ cairo_surface_t base;
+ cairo_surface_t *fallback;
+
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+
+ cairo_surface_t *drm;
+ cairo_bool_t marked_dirty;
+
+ xcb_drawable_t drawable;
+ cairo_bool_t owns_pixmap;
+ int use_pixmap;
+
+ int width;
+ int height;
+ int depth;
+
+ unsigned int flags;
+ xcb_render_picture_t picture;
+ xcb_render_pictformat_t xrender_format;
+ pixman_format_code_t pixman_format;
+
+ cairo_list_t link;
+};
+
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+typedef struct _cairo_xlib_xcb_surface {
+ cairo_surface_t base;
+
+ cairo_xcb_surface_t *xcb;
+
+ /* original settings for query */
+ void *display;
+ void *screen;
+ void *visual;
+ void *format;
+} cairo_xlib_xcb_surface_t;
+#endif
+
+
+enum {
+ GLYPHSET_INDEX_ARGB32,
+ GLYPHSET_INDEX_A8,
+ GLYPHSET_INDEX_A1,
+ NUM_GLYPHSETS
+};
+
+typedef struct _cairo_xcb_font_glyphset_free_glyphs {
+ xcb_render_glyphset_t glyphset;
+ int glyph_count;
+ xcb_render_glyph_t glyph_indices[128];
+} cairo_xcb_font_glyphset_free_glyphs_t;
+
+typedef struct _cairo_xcb_font_glyphset_info {
+ xcb_render_glyphset_t glyphset;
+ cairo_format_t format;
+ xcb_render_pictformat_t xrender_format;
+ cairo_xcb_font_glyphset_free_glyphs_t *pending_free_glyphs;
+} cairo_xcb_font_glyphset_info_t;
+
+struct _cairo_xcb_font {
+ cairo_scaled_font_t *scaled_font;
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
+ cairo_list_t link;
+};
+
+struct _cairo_xcb_screen {
+ cairo_xcb_connection_t *connection;
+
+ xcb_screen_t *xcb_screen;
+ cairo_device_t *device;
+
+ xcb_gcontext_t gc[4];
+ int gc_depths; /* 4 x uint8_t */
+
+ cairo_surface_t *stock_colors[CAIRO_STOCK_NUM_COLORS];
+ struct {
+ cairo_surface_t *picture;
+ cairo_color_t color;
+ } solid_cache[16];
+ int solid_cache_size;
+
+ cairo_cache_t surface_pattern_cache;
+ cairo_cache_t linear_pattern_cache;
+ cairo_cache_t radial_pattern_cache;
+ cairo_freelist_t pattern_cache_entry_freelist;
+
+ cairo_list_t link;
+ cairo_list_t surfaces;
+};
+
+struct _cairo_xcb_connection {
+ cairo_device_t device;
+
+ xcb_connection_t *xcb_connection;
+ cairo_bool_t has_socket;
+
+ xcb_render_pictformat_t standard_formats[5];
+ cairo_hash_table_t *xrender_formats;
+ cairo_hash_table_t *visual_to_xrender_format;
+
+ unsigned int maximum_request_length;
+ unsigned int flags;
+
+ const xcb_setup_t *root;
+ const xcb_query_extension_reply_t *render;
+ const xcb_query_extension_reply_t *shm;
+ const xcb_query_extension_reply_t *dri2;
+ uint64_t seqno;
+
+ cairo_list_t free_xids;
+ cairo_freepool_t xid_pool;
+
+ cairo_mutex_t shm_mutex;
+ cairo_list_t shm_pools;
+ cairo_freepool_t shm_info_freelist;
+
+ cairo_mutex_t screens_mutex;
+ cairo_list_t screens;
+
+ cairo_list_t fonts;
+
+ cairo_list_t link;
+};
+
+enum {
+ CAIRO_XCB_HAS_RENDER = 0x0001,
+ CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES = 0x0002,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE = 0x0004,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS = 0x0008,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS = 0x0010,
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS = 0x0020,
+ CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM = 0x0040,
+ CAIRO_XCB_RENDER_HAS_FILTERS = 0x0080,
+ CAIRO_XCB_RENDER_HAS_PDF_OPERATORS = 0x0100,
+ CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT = 0x0200,
+ CAIRO_XCB_RENDER_HAS_GRADIENTS = 0x0400,
+
+ CAIRO_XCB_HAS_CAIRO = 0x10000,
+
+ CAIRO_XCB_HAS_DRI2 = 0x40000000,
+ CAIRO_XCB_HAS_SHM = 0x80000000
+};
+
+#define CAIRO_XCB_SHM_SMALL_IMAGE 8192
+
+cairo_private extern const cairo_surface_backend_t _cairo_xcb_surface_backend;
+
+cairo_private cairo_xcb_connection_t *
+_cairo_xcb_connection_get (xcb_connection_t *connection);
+
+static inline cairo_xcb_connection_t *
+_cairo_xcb_connection_reference (cairo_xcb_connection_t *connection)
+{
+ return (cairo_xcb_connection_t *) cairo_device_reference (&connection->device);
+}
+
+cairo_private xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format);
+
+cairo_private xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
+ const xcb_visualid_t visual);
+
+static inline cairo_status_t cairo_warn
+_cairo_xcb_connection_acquire (cairo_xcb_connection_t *connection)
+{
+ return cairo_device_acquire (&connection->device);
+}
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_take_socket (cairo_xcb_connection_t *connection);
+
+cairo_private uint32_t
+_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection);
+
+cairo_private void
+_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
+ uint32_t xid);
+
+static inline void
+_cairo_xcb_connection_release (cairo_xcb_connection_t *connection)
+{
+ cairo_device_release (&connection->device);
+}
+
+static inline void
+_cairo_xcb_connection_destroy (cairo_xcb_connection_t *connection)
+{
+ cairo_device_destroy (&connection->device);
+}
+
+cairo_private cairo_int_status_t
+_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *display,
+ size_t size,
+ cairo_xcb_shm_info_t **shm_info_out);
+
+cairo_private void
+_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info);
+
+cairo_private void
+_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection);
+
+cairo_private void
+_cairo_xcb_font_finish (cairo_xcb_font_t *font);
+
+cairo_private cairo_xcb_screen_t *
+_cairo_xcb_screen_get (xcb_connection_t *connection,
+ xcb_screen_t *screen);
+
+cairo_private void
+_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen);
+
+cairo_private xcb_gcontext_t
+_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ int depth);
+
+cairo_private void
+_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture,
+ unsigned int size);
+cairo_private void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear,
+ cairo_surface_t *picture);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial,
+ cairo_surface_t *picture);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
+ cairo_content_t content,
+ int width, int height);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_similar (void *abstract_other,
+ cairo_content_t content,
+ int width,
+ int height);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ cairo_bool_t owns_pixmap,
+ pixman_format_code_t pixman_format,
+ xcb_render_pictformat_t xrender_format,
+ int width,
+ int height);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip);
+cairo_private void
+_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font);
+
+cairo_private cairo_status_t
+_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst,
+ const cairo_pattern_t *src_pattern,
+ const cairo_rectangle_int_t *extents,
+ const cairo_boxes_t *boxes);
+
+cairo_private cairo_status_t
+_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes);
+
+static inline void
+_cairo_xcb_connection_write (cairo_xcb_connection_t *connection,
+ struct iovec *vec,
+ int count)
+{
+ if (unlikely (connection->device.status))
+ return;
+
+ connection->seqno++;
+ if (unlikely (! xcb_writev (connection->xcb_connection, vec, count, 1)))
+ connection->device.status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
+}
+
+cairo_private xcb_pixmap_t
+_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
+ uint8_t depth,
+ xcb_drawable_t drawable,
+ uint16_t width,
+ uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
+ xcb_pixmap_t pixmap);
+
+cairo_private xcb_gcontext_t
+_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
+ xcb_drawable_t drawable,
+ uint32_t value_mask,
+ uint32_t *values);
+
+cairo_private void
+_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc);
+
+cairo_private void
+_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
+ xcb_gcontext_t gc,
+ uint32_t value_mask,
+ uint32_t *values);
+
+cairo_private void
+_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t length,
+ void *data);
+
+cairo_private void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ uint16_t stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *data);
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ xcb_get_image_reply_t **reply);
+
+cairo_private void
+_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint32_t num_rectangles,
+ xcb_rectangle_t *rectangles);
+
+cairo_private uint32_t
+_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection,
+ uint32_t id,
+ cairo_bool_t readonly);
+
+cairo_private uint64_t
+_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ uint16_t total_width,
+ uint16_t total_height,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ uint32_t shm,
+ uint32_t offset);
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection,
+ xcb_drawable_t src,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint32_t shmseg,
+ uint32_t offset);
+
+cairo_private void
+_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection,
+ uint32_t segment);
+
+cairo_private void
+_cairo_xcb_connection_render_spans (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t dst,
+ int op,
+ xcb_render_picture_t src,
+ int16_t src_x, int16_t src_y,
+ int16_t dst_x, int16_t dst_y,
+ int16_t width, int16_t height,
+ unsigned int length,
+ uint16_t *spans);
+cairo_private void
+_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_drawable_t drawable,
+ xcb_render_pictformat_t format,
+ uint32_t value_mask,
+ uint32_t *value_list);
+
+cairo_private void
+_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint32_t value_mask,
+ uint32_t *value_list);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ int16_t clip_x_origin,
+ int16_t clip_y_origin,
+ uint32_t rectangles_len,
+ xcb_rectangle_t *rectangles);
+
+cairo_private void
+_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture);
+
+cairo_private void
+_cairo_xcb_connection_render_composite (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t mask,
+ xcb_render_picture_t dst,
+ int16_t src_x,
+ int16_t src_y,
+ int16_t mask_x,
+ int16_t mask_y,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint16_t width,
+ uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t traps_len,
+ xcb_render_trapezoid_t *traps);
+
+cairo_private void
+_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t id,
+ xcb_render_pictformat_t format);
+
+cairo_private void
+_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset);
+
+cairo_private void
+_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ uint32_t *glyphs_id,
+ xcb_render_glyphinfo_t *glyphs,
+ uint32_t data_len,
+ uint8_t *data);
+
+cairo_private void
+_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t *connection,
+ xcb_render_glyphset_t glyphset,
+ uint32_t num_glyphs,
+ xcb_render_glyph_t *glyphs);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t glyphcmds_len,
+ uint8_t *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t dst,
+ xcb_render_color_t color,
+ uint32_t num_rects,
+ xcb_rectangle_t *rects);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_transform_t *transform);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ uint16_t filter_len,
+ char *filter);
+
+cairo_private void
+_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_color_t color);
+
+cairo_private void
+_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t p1,
+ xcb_render_pointfix_t p2,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors);
+
+cairo_private void
+_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t *connection,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t inner,
+ xcb_render_pointfix_t outer,
+ xcb_render_fixed_t inner_radius,
+ xcb_render_fixed_t outer_radius,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors);
+
+cairo_private void
+_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t *c,
+ xcb_render_picture_t picture,
+ xcb_render_pointfix_t center,
+ xcb_render_fixed_t angle,
+ uint32_t num_stops,
+ xcb_render_fixed_t *stops,
+ xcb_render_color_t *colors);
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_proto (cairo_xcb_surface_create);
+slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
+slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
+slim_hidden_proto (cairo_xcb_surface_set_size);
+#endif
+
+#endif /* CAIRO_XCB_PRIVATE_H */
diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c
new file mode 100644
index 000000000..06c07a55c
--- /dev/null
+++ b/src/cairo-xcb-screen.c
@@ -0,0 +1,518 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Chris Wilson
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+struct pattern_cache_entry {
+ cairo_cache_entry_t key;
+ cairo_xcb_screen_t *screen;
+ cairo_pattern_union_t pattern;
+ cairo_surface_t *picture;
+};
+
+void
+_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen)
+{
+ int i;
+
+ CAIRO_MUTEX_LOCK (screen->connection->screens_mutex);
+ cairo_list_del (&screen->link);
+ CAIRO_MUTEX_UNLOCK (screen->connection->screens_mutex);
+
+ while (! cairo_list_is_empty (&screen->surfaces)) {
+ cairo_surface_t *surface;
+
+ surface = &cairo_list_first_entry (&screen->surfaces,
+ cairo_xcb_surface_t,
+ link)->base;
+
+ cairo_surface_reference (surface);
+ cairo_surface_finish (surface);
+ cairo_surface_destroy (surface);
+ }
+
+ for (i = 0; i < screen->solid_cache_size; i++)
+ cairo_surface_destroy (screen->solid_cache[i].picture);
+
+ for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
+ cairo_surface_destroy (screen->stock_colors[i]);
+
+ _cairo_cache_fini (&screen->surface_pattern_cache);
+ _cairo_cache_fini (&screen->linear_pattern_cache);
+ _cairo_cache_fini (&screen->radial_pattern_cache);
+ _cairo_freelist_fini (&screen->pattern_cache_entry_freelist);
+
+ cairo_device_finish (screen->device);
+ cairo_device_destroy (screen->device);
+
+ free (screen);
+}
+
+static cairo_bool_t
+_surface_pattern_cache_entry_equal (const void *A, const void *B)
+{
+ const struct pattern_cache_entry *a = A, *b = B;
+
+ return a->key.hash == b->key.hash;
+}
+
+static cairo_bool_t
+_linear_pattern_cache_entry_equal (const void *A, const void *B)
+{
+ const struct pattern_cache_entry *a = A, *b = B;
+
+ if (a->key.hash != b->key.hash)
+ return FALSE;
+
+ return _cairo_linear_pattern_equal (&a->pattern.gradient.linear,
+ &b->pattern.gradient.linear);
+}
+
+static cairo_bool_t
+_radial_pattern_cache_entry_equal (const void *A, const void *B)
+{
+ const struct pattern_cache_entry *a = A, *b = B;
+
+ if (a->key.hash != b->key.hash)
+ return FALSE;
+
+ return _cairo_radial_pattern_equal (&a->pattern.gradient.radial,
+ &b->pattern.gradient.radial);
+}
+
+static void
+_surface_cache_entry_destroy (void *closure)
+{
+ struct pattern_cache_entry *entry = closure;
+
+ cairo_surface_finish (entry->picture);
+ cairo_surface_destroy (entry->picture);
+ _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry);
+}
+
+static void
+_pattern_cache_entry_destroy (void *closure)
+{
+ struct pattern_cache_entry *entry = closure;
+
+ _cairo_pattern_fini (&entry->pattern.base);
+ cairo_surface_destroy (entry->picture);
+ _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry);
+}
+
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+#include "drm/cairo-drm-private.h"
+
+#include <drm/drm.h>
+#include <sys/ioctl.h>
+#include <xcb/dri2.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static int drm_magic (int fd, uint32_t *magic)
+{
+ drm_auth_t auth;
+
+ if (ioctl (fd, DRM_IOCTL_GET_MAGIC, &auth))
+ return -errno;
+
+ *magic = auth.magic;
+ return 0;
+}
+
+static cairo_device_t *
+_xcb_drm_device (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen)
+{
+ cairo_device_t *device = NULL;
+ xcb_dri2_connect_reply_t *connect;
+ drm_magic_t magic;
+ int fd;
+
+ connect = xcb_dri2_connect_reply (xcb_connection,
+ xcb_dri2_connect (xcb_connection,
+ xcb_screen->root,
+ 0),
+ 0);
+ if (connect == NULL)
+ return NULL;
+
+ fd = open (xcb_dri2_connect_device_name (connect), O_RDWR);
+ free (connect);
+
+ if (fd < 0)
+ return NULL;
+
+ device = cairo_drm_device_get_for_fd (fd);
+ close (fd);
+
+ if (device != NULL) {
+ xcb_dri2_authenticate_reply_t *authenticate;
+
+ if (drm_magic (((cairo_drm_device_t *) device)->fd, &magic) < 0) {
+ cairo_device_destroy (device);
+ return NULL;
+ }
+
+ authenticate = xcb_dri2_authenticate_reply (xcb_connection,
+ xcb_dri2_authenticate (xcb_connection,
+ xcb_screen->root,
+ magic),
+ 0);
+ if (authenticate == NULL) {
+ cairo_device_destroy (device);
+ return NULL;
+ }
+
+ free (authenticate);
+ }
+
+ return device;
+}
+#else
+static cairo_device_t *
+_xcb_drm_device (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen)
+{
+ return NULL;
+}
+#endif
+
+cairo_xcb_screen_t *
+_cairo_xcb_screen_get (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen)
+{
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+ cairo_status_t status;
+ int i;
+
+ connection = _cairo_xcb_connection_get (xcb_connection);
+ if (unlikely (connection == NULL))
+ return NULL;
+
+ CAIRO_MUTEX_LOCK (connection->screens_mutex);
+
+ cairo_list_foreach_entry (screen,
+ cairo_xcb_screen_t,
+ &connection->screens,
+ link)
+ {
+ if (screen->xcb_screen == xcb_screen) {
+ /* Maintain list in MRU order */
+ if (&screen->link != connection->screens.next)
+ cairo_list_move (&screen->link, &connection->screens);
+
+ goto unlock;
+ }
+ }
+
+ screen = malloc (sizeof (cairo_xcb_screen_t));
+ if (unlikely (screen == NULL))
+ goto unlock;
+
+ screen->connection = connection;
+ screen->xcb_screen = xcb_screen;
+
+ if (connection->flags & CAIRO_XCB_HAS_DRI2)
+ screen->device = _xcb_drm_device (xcb_connection, xcb_screen);
+ else
+ screen->device = NULL;
+
+ screen->gc_depths = 0;
+ memset (screen->gc, 0, sizeof (screen->gc));
+
+ screen->solid_cache_size = 0;
+ for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
+ screen->stock_colors[i] = NULL;
+
+ status = _cairo_cache_init (&screen->surface_pattern_cache,
+ _surface_pattern_cache_entry_equal,
+ NULL,
+ _surface_cache_entry_destroy,
+ 16*1024*1024);
+ if (unlikely (status))
+ goto error_screen;
+
+ status = _cairo_cache_init (&screen->linear_pattern_cache,
+ _linear_pattern_cache_entry_equal,
+ NULL,
+ _pattern_cache_entry_destroy,
+ 16);
+ if (unlikely (status))
+ goto error_surface;
+
+ status = _cairo_cache_init (&screen->radial_pattern_cache,
+ _radial_pattern_cache_entry_equal,
+ NULL,
+ _pattern_cache_entry_destroy,
+ 4);
+ if (unlikely (status))
+ goto error_linear;
+
+ _cairo_freelist_init (&screen->pattern_cache_entry_freelist,
+ sizeof (struct pattern_cache_entry));
+
+ cairo_list_add (&screen->link, &connection->screens);
+ cairo_list_init (&screen->surfaces);
+
+unlock:
+ CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+ return screen;
+
+error_surface:
+ _cairo_cache_fini (&screen->surface_pattern_cache);
+error_linear:
+ _cairo_cache_fini (&screen->linear_pattern_cache);
+error_screen:
+ cairo_device_destroy (screen->device);
+ free (screen);
+ CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+ return NULL;
+}
+
+static xcb_gcontext_t
+_create_gc (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable)
+{
+ uint32_t values[] = { 0 };
+
+ return _cairo_xcb_connection_create_gc (screen->connection, drawable,
+ XCB_GC_GRAPHICS_EXPOSURES,
+ values);
+}
+
+xcb_gcontext_t
+_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ int depth)
+{
+ int i;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
+ if (((screen->gc_depths >> (8*i)) & 0xff) == depth) {
+ screen->gc_depths &= ~(0xff << (8*i));
+ return screen->gc[i];
+ }
+ }
+
+ return _create_gc (screen, drawable);
+}
+
+void
+_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc)
+{
+ int i;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
+ if (((screen->gc_depths >> (8*i)) & 0xff) == 0)
+ break;
+ }
+
+ if (i == ARRAY_LENGTH (screen->gc)) {
+ /* perform random substitution to ensure fair caching over depths */
+ i = rand () % ARRAY_LENGTH (screen->gc);
+ _cairo_xcb_connection_free_gc (screen->connection, screen->gc[i]);
+ }
+
+ screen->gc[i] = gc;
+ screen->gc_depths &= ~(0xff << (8*i));
+ screen->gc_depths |= depth << (8*i);
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture,
+ unsigned int size)
+{
+ struct pattern_cache_entry *entry;
+ cairo_status_t status;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+ if (unlikely (entry == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ entry->key.hash = picture->unique_id;
+ entry->key.size = size;
+
+ entry->picture = cairo_surface_reference (picture);
+ entry->screen = screen;
+
+ status = _cairo_cache_insert (&screen->surface_pattern_cache,
+ &entry->key);
+ if (unlikely (status)) {
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+ cairo_surface_t *picture)
+{
+ struct pattern_cache_entry tmpl;
+ struct pattern_cache_entry *entry;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ tmpl.key.hash = picture->unique_id;
+
+ entry = _cairo_cache_lookup (&screen->surface_pattern_cache, &tmpl.key);
+ if (entry != NULL)
+ _cairo_cache_remove (&screen->surface_pattern_cache, &entry->key);
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear,
+ cairo_surface_t *picture)
+{
+ struct pattern_cache_entry *entry;
+ cairo_status_t status;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+ if (unlikely (entry == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ entry->key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
+ entry->key.size = 1;
+
+ status = _cairo_pattern_init_copy (&entry->pattern.base, &linear->base.base);
+ if (unlikely (status)) {
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ entry->picture = cairo_surface_reference (picture);
+ entry->screen = screen;
+
+ status = _cairo_cache_insert (&screen->linear_pattern_cache,
+ &entry->key);
+ if (unlikely (status)) {
+ cairo_surface_destroy (picture);
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
+ const cairo_linear_pattern_t *linear)
+{
+ cairo_surface_t *picture = NULL;
+ struct pattern_cache_entry tmpl;
+ struct pattern_cache_entry *entry;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ tmpl.key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
+ _cairo_pattern_init_static_copy (&tmpl.pattern.base, &linear->base.base);
+
+ entry = _cairo_cache_lookup (&screen->linear_pattern_cache, &tmpl.key);
+ if (entry != NULL)
+ picture = cairo_surface_reference (entry->picture);
+
+ return picture;
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial,
+ cairo_surface_t *picture)
+{
+ struct pattern_cache_entry *entry;
+ cairo_status_t status;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+ if (unlikely (entry == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ entry->key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
+ entry->key.size = 1;
+
+ status = _cairo_pattern_init_copy (&entry->pattern.base, &radial->base.base);
+ if (unlikely (status)) {
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ entry->picture = cairo_surface_reference (picture);
+ entry->screen = screen;
+
+ status = _cairo_cache_insert (&screen->radial_pattern_cache, &entry->key);
+ if (unlikely (status)) {
+ cairo_surface_destroy (picture);
+ _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
+ const cairo_radial_pattern_t *radial)
+{
+ cairo_surface_t *picture = NULL;
+ struct pattern_cache_entry tmpl;
+ struct pattern_cache_entry *entry;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+ tmpl.key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
+ _cairo_pattern_init_static_copy (&tmpl.pattern.base, &radial->base.base);
+
+ entry = _cairo_cache_lookup (&screen->radial_pattern_cache, &tmpl.key);
+ if (entry != NULL)
+ picture = cairo_surface_reference (entry->picture);
+
+ return picture;
+}
diff --git a/src/cairo-xcb-shm.c b/src/cairo-xcb-shm.c
new file mode 100644
index 000000000..7a47f338b
--- /dev/null
+++ b/src/cairo-xcb-shm.c
@@ -0,0 +1,576 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributors(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/shm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <errno.h>
+
+/* a simple buddy allocator for memory pools
+ * XXX fragmentation? use Doug Lea's malloc?
+ */
+
+typedef struct _cairo_xcb_shm_mem_block cairo_xcb_shm_mem_block_t;
+
+struct _cairo_xcb_shm_mem_block {
+ unsigned int bits;
+ cairo_list_t link;
+};
+
+struct _cairo_xcb_shm_mem_pool {
+ int shmid;
+ uint32_t shmseg;
+
+ char *base;
+ unsigned int nBlocks;
+ cairo_xcb_shm_mem_block_t *blocks;
+ cairo_list_t free[32];
+ unsigned char *map;
+
+ unsigned int min_bits; /* Minimum block size is 1 << min_bits */
+ unsigned int num_sizes;
+
+ size_t free_bytes;
+ size_t max_bytes;
+ unsigned int max_free_bits;
+
+ cairo_list_t link;
+};
+
+#define BITTEST(p, n) ((p)->map[(n) >> 3] & (128 >> ((n) & 7)))
+#define BITSET(p, n) ((p)->map[(n) >> 3] |= (128 >> ((n) & 7)))
+#define BITCLEAR(p, n) ((p)->map[(n) >> 3] &= ~(128 >> ((n) & 7)))
+
+static void
+clear_bits (cairo_xcb_shm_mem_pool_t *pi, size_t first, size_t last)
+{
+ size_t i, n = last;
+ size_t first_full = (first + 7) & ~7;
+ size_t past_full = last & ~7;
+ size_t bytes;
+
+ if (n > first_full)
+ n = first_full;
+ for (i = first; i < n; i++)
+ BITCLEAR (pi, i);
+
+ if (past_full > first_full) {
+ bytes = past_full - first_full;
+ bytes = bytes >> 3;
+ memset (pi->map + (first_full >> 3), 0, bytes);
+ }
+
+ if (past_full < n)
+ past_full = n;
+ for (i = past_full; i < last; i++)
+ BITCLEAR (pi, i);
+}
+
+static void
+free_bits (cairo_xcb_shm_mem_pool_t *pi,
+ size_t start,
+ unsigned int bits,
+ cairo_bool_t clear)
+{
+ cairo_xcb_shm_mem_block_t *block;
+
+ if (clear)
+ clear_bits (pi, start, start + (1 << bits));
+
+ block = pi->blocks + start;
+ block->bits = bits;
+
+ cairo_list_add (&block->link, &pi->free[bits]);
+
+ pi->free_bytes += 1 << (bits + pi->min_bits);
+ if (bits > pi->max_free_bits)
+ pi->max_free_bits = bits;
+}
+
+/* Add a chunk to the free list */
+static void
+free_blocks (cairo_xcb_shm_mem_pool_t *pi,
+ size_t first,
+ size_t last,
+ cairo_bool_t clear)
+{
+ size_t i;
+ size_t bits = 0;
+ size_t len = 1;
+
+ i = first;
+ while (i < last) {
+ /* To avoid cost quadratic in the number of different
+ * blocks produced from this chunk of store, we have to
+ * use the size of the previous block produced from this
+ * chunk as the starting point to work out the size of the
+ * next block we can produce. If you look at the binary
+ * representation of the starting points of the blocks
+ * produced, you can see that you first of all increase the
+ * size of the blocks produced up to some maximum as the
+ * address dealt with gets offsets added on which zap out
+ * low order bits, then decrease as the low order bits of the
+ * final block produced get added in. E.g. as you go from
+ * 001 to 0111 you generate blocks
+ * of size 001 at 001 taking you to 010
+ * of size 010 at 010 taking you to 100
+ * of size 010 at 100 taking you to 110
+ * of size 001 at 110 taking you to 111
+ * So the maximum total cost of the loops below this comment
+ * is one trip from the lowest blocksize to the highest and
+ * back again.
+ */
+ while (bits < pi->num_sizes - 1) {
+ size_t next_bits = bits + 1;
+ size_t next_len = len << 1;
+
+ if (i + next_bits > last) {
+ /* off end of chunk to be freed */
+ break;
+ }
+
+ if (i & (next_len - 1)) /* block would not be on boundary */
+ break;
+
+ bits = next_bits;
+ len = next_len;
+ }
+
+ do {
+ if (i + len > last) /* off end of chunk to be freed */
+ continue;
+
+ if (i & (len - 1)) /* block would not be on boundary */
+ continue;
+
+ /* OK */
+ break;
+
+ bits--;
+ len >>=1;
+ } while (len > 0);
+
+ if (len == 0)
+ break;
+
+ free_bits (pi, i, bits, clear);
+ i += len;
+ }
+}
+
+static cairo_status_t
+_cairo_xcb_shm_mem_pool_init (cairo_xcb_shm_mem_pool_t *pi,
+ size_t bytes,
+ unsigned int min_bits,
+ unsigned int num_sizes)
+{
+ size_t setBits;
+ int i;
+
+ assert ((((unsigned long) pi->base) & ((1 << min_bits) - 1)) == 0);
+ assert (num_sizes < ARRAY_LENGTH (pi->free));
+
+ pi->free_bytes = 0;
+ pi->max_bytes = bytes;
+ pi->max_free_bits = 0;
+
+ setBits = bytes >> min_bits;
+ pi->blocks = calloc (setBits, sizeof (cairo_xcb_shm_mem_block_t));
+ if (pi->blocks == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ pi->nBlocks = setBits;
+ pi->min_bits = min_bits;
+ pi->num_sizes = num_sizes;
+
+ for (i = 0; i < ARRAY_LENGTH (pi->free); i++)
+ cairo_list_init (&pi->free[i]);
+
+ pi->map = malloc ((setBits + 7) >> 3);
+ if (pi->map == NULL) {
+ free (pi->blocks);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ memset (pi->map, -1, (setBits + 7) >> 3);
+ clear_bits (pi, 0, setBits);
+
+ /* Now add all blocks to the free list */
+ free_blocks (pi, 0, setBits, 1);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_shm_mem_block_t *
+get_buddy (cairo_xcb_shm_mem_pool_t *pi,
+ size_t offset,
+ unsigned int bits)
+{
+ cairo_xcb_shm_mem_block_t *block;
+
+ assert (offset + (1 << bits) <= pi->nBlocks);
+
+ if (BITTEST (pi, offset + (1 << bits) - 1))
+ return NULL; /* buddy is allocated */
+
+ block = pi->blocks + offset;
+ if (block->bits != bits)
+ return NULL; /* buddy is partially allocated */
+
+ return block;
+}
+
+static void
+merge_buddies (cairo_xcb_shm_mem_pool_t *pi,
+ cairo_xcb_shm_mem_block_t *block,
+ unsigned int max_bits)
+{
+ size_t block_offset = block_offset = block - pi->blocks;
+ unsigned int bits = block->bits;
+
+ while (bits < max_bits - 1) {
+ /* while you can, merge two blocks and get a legal block size */
+ size_t buddy_offset = block_offset ^ (1 << bits);
+
+ block = get_buddy (pi, buddy_offset, bits);
+ if (block == NULL)
+ break;
+
+ cairo_list_del (&block->link);
+
+ /* Merged block starts at buddy */
+ if (buddy_offset < block_offset)
+ block_offset = buddy_offset;
+
+ bits++;
+ }
+
+ block = pi->blocks + block_offset;
+ block->bits = bits;
+ cairo_list_add (&block->link, &pi->free[bits]);
+
+ if (bits > pi->max_free_bits)
+ pi->max_free_bits = bits;
+}
+
+/* attempt to merge all available buddies up to a particular size */
+static unsigned int
+merge_bits (cairo_xcb_shm_mem_pool_t *pi,
+ unsigned int max_bits)
+{
+ cairo_xcb_shm_mem_block_t *block, *buddy, *next;
+ unsigned int bits;
+
+ for (bits = 0; bits < max_bits - 1; bits++) {
+ cairo_list_foreach_entry_safe (block, next,
+ cairo_xcb_shm_mem_block_t,
+ &pi->free[bits],
+ link)
+ {
+ size_t buddy_offset = (block - pi->blocks) ^ (1 << bits);
+
+ buddy = get_buddy (pi, buddy_offset, bits);
+ if (buddy == NULL)
+ continue;
+
+ if (buddy == next) {
+ next = cairo_container_of (buddy->link.next,
+ cairo_xcb_shm_mem_block_t,
+ link);
+ }
+
+ cairo_list_del (&block->link);
+ merge_buddies (pi, block, max_bits);
+ }
+ }
+
+ return pi->max_free_bits;
+}
+
+/* find store for 1 << bits blocks */
+static void *
+buddy_malloc (cairo_xcb_shm_mem_pool_t *pi,
+ unsigned int bits)
+{
+ unsigned int b;
+ size_t offset;
+ size_t past;
+ cairo_xcb_shm_mem_block_t *block;
+
+ if (bits > pi->max_free_bits && bits > merge_bits (pi, bits))
+ return NULL;
+
+ /* Find a list with blocks big enough on it */
+ block = NULL;
+ for (b = bits; b <= pi->max_free_bits; b++) {
+ if (! cairo_list_is_empty (&pi->free[b])) {
+ block = cairo_list_first_entry (&pi->free[b],
+ cairo_xcb_shm_mem_block_t,
+ link);
+ break;
+ }
+ }
+ assert (block != NULL);
+
+ cairo_list_del (&block->link);
+
+ while (cairo_list_is_empty (&pi->free[pi->max_free_bits])) {
+ if (--pi->max_free_bits == 0)
+ break;
+ }
+
+ /* Mark end of allocated area */
+ offset = block - pi->blocks;
+ past = offset + (1 << bits);
+ BITSET (pi, past - 1);
+ block->bits = bits;
+
+ /* If we used a larger free block than we needed, free the rest */
+ pi->free_bytes -= 1 << (b + pi->min_bits);
+ free_blocks (pi, past, offset + (1 << b), 0);
+
+ return pi->base + ((block - pi->blocks) << pi->min_bits);
+}
+
+static void *
+_cairo_xcb_shm_mem_pool_malloc (cairo_xcb_shm_mem_pool_t *pi,
+ size_t bytes)
+{
+ unsigned int bits;
+ size_t size;
+
+ size = 1 << pi->min_bits;
+ for (bits = 0; size < bytes; bits++)
+ size <<= 1;
+ if (bits >= pi->num_sizes)
+ return NULL;
+
+ return buddy_malloc (pi, bits);
+}
+
+static void
+_cairo_xcb_shm_mem_pool_free (cairo_xcb_shm_mem_pool_t *pi,
+ char *storage)
+{
+ size_t block_offset;
+ cairo_xcb_shm_mem_block_t *block;
+
+ block_offset = (storage - pi->base) >> pi->min_bits;
+ block = pi->blocks + block_offset;
+
+ BITCLEAR (pi, block_offset + ((1 << block->bits) - 1));
+ pi->free_bytes += 1 << (block->bits + pi->min_bits);
+
+ merge_buddies (pi, block, pi->num_sizes);
+}
+
+static void
+_cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t *pool)
+{
+ shmdt (pool->base);
+ cairo_list_del (&pool->link);
+
+ free (pool->map);
+ free (pool->blocks);
+ free (pool);
+}
+
+cairo_int_status_t
+_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
+ size_t size,
+ cairo_xcb_shm_info_t **shm_info_out)
+{
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_xcb_shm_mem_pool_t *pool, *next;
+ size_t bytes, maxbits = 16, minbits = 8;
+ void *mem = NULL;
+ cairo_status_t status;
+
+ assert (connection->flags & CAIRO_XCB_HAS_SHM);
+
+ CAIRO_MUTEX_LOCK (connection->shm_mutex);
+ cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+ &connection->shm_pools, link)
+ {
+ if (pool->free_bytes > size) {
+ mem = _cairo_xcb_shm_mem_pool_malloc (pool, size);
+ if (mem != NULL) {
+ /* keep the active pools towards the front */
+ cairo_list_move (&pool->link, &connection->shm_pools);
+ goto allocate_shm_info;
+ }
+ }
+ /* scan for old, unused pools */
+ if (pool->free_bytes == pool->max_bytes) {
+ _cairo_xcb_connection_shm_detach (connection,
+ pool->shmseg);
+ _cairo_xcb_shm_mem_pool_destroy (pool);
+ }
+ }
+
+ pool = malloc (sizeof (cairo_xcb_shm_mem_pool_t));
+ if (unlikely (pool == NULL)) {
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ bytes = 1 << maxbits;
+ while (bytes <= size)
+ bytes <<= 1, maxbits++;
+ bytes <<= 3;
+
+ do {
+ pool->shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+ if (pool->shmid != -1)
+ break;
+
+ if (errno == EINVAL && bytes > size) {
+ bytes >>= 1;
+ continue;
+ }
+ } while (FALSE);
+ if (pool->shmid == -1) {
+ int err = errno;
+ if (! (err == EINVAL || err == ENOMEM))
+ connection->flags &= ~CAIRO_XCB_HAS_SHM;
+ free (pool);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ pool->base = shmat (pool->shmid, NULL, 0);
+ if (unlikely (pool->base == (char *) -1)) {
+ shmctl (pool->shmid, IPC_RMID, NULL);
+ free (pool);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ status = _cairo_xcb_shm_mem_pool_init (pool,
+ bytes,
+ minbits,
+ maxbits - minbits + 1);
+ if (unlikely (status)) {
+ shmdt (pool->base);
+ free (pool);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return status;
+ }
+
+ pool->shmseg = _cairo_xcb_connection_shm_attach (connection, pool->shmid, FALSE);
+ shmctl (pool->shmid, IPC_RMID, NULL);
+
+ cairo_list_add (&pool->link, &connection->shm_pools);
+ mem = _cairo_xcb_shm_mem_pool_malloc (pool, size);
+
+ allocate_shm_info:
+ shm_info = _cairo_freepool_alloc (&connection->shm_info_freelist);
+ if (unlikely (shm_info == NULL)) {
+ _cairo_xcb_shm_mem_pool_free (pool, mem);
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ shm_info->connection = connection;
+ shm_info->pool = pool;
+ shm_info->shm = pool->shmseg;
+ shm_info->offset = (char *) mem - (char *) pool->base;
+ shm_info->mem = mem;
+
+ /* scan for old, unused pools */
+ cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+ &connection->shm_pools, link)
+ {
+ if (pool->free_bytes == pool->max_bytes) {
+ _cairo_xcb_connection_shm_detach (connection,
+ pool->shmseg);
+ _cairo_xcb_shm_mem_pool_destroy (pool);
+ }
+ }
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info)
+{
+ cairo_xcb_connection_t *connection = shm_info->connection;
+
+ CAIRO_MUTEX_LOCK (connection->shm_mutex);
+
+ _cairo_xcb_shm_mem_pool_free (shm_info->pool, shm_info->mem);
+ _cairo_freepool_free (&connection->shm_info_freelist, shm_info);
+
+ /* scan for old, unused pools - hold at least one in reserve */
+ if (! cairo_list_is_singular (&connection->shm_pools) &&
+ _cairo_xcb_connection_take_socket (connection) == CAIRO_STATUS_SUCCESS)
+ {
+ cairo_xcb_shm_mem_pool_t *pool, *next;
+ cairo_list_t head;
+
+ cairo_list_init (&head);
+ cairo_list_move (connection->shm_pools.next, &head);
+
+ cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+ &connection->shm_pools, link)
+ {
+ if (pool->free_bytes == pool->max_bytes) {
+ _cairo_xcb_connection_shm_detach (connection, pool->shmseg);
+ _cairo_xcb_shm_mem_pool_destroy (pool);
+ }
+ }
+
+ cairo_list_move (head.next, &connection->shm_pools);
+ }
+
+ CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+}
+
+void
+_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection)
+{
+ while (! cairo_list_is_empty (&connection->shm_pools)) {
+ _cairo_xcb_shm_mem_pool_destroy (cairo_list_first_entry (&connection->shm_pools,
+ cairo_xcb_shm_mem_pool_t,
+ link));
+ }
+}
diff --git a/src/cairo-xcb-surface-cairo.c b/src/cairo-xcb-surface-cairo.c
new file mode 100644
index 000000000..c8305cf73
--- /dev/null
+++ b/src/cairo-xcb-surface-cairo.c
@@ -0,0 +1,94 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-clip-private.h"
+#include "cairo-xcb-private.h"
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
new file mode 100644
index 000000000..6f1002a8f
--- /dev/null
+++ b/src/cairo-xcb-surface-core.c
@@ -0,0 +1,613 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-xcb-private.h"
+
+/* XXX dithering */
+
+typedef struct _cairo_xcb_pixmap {
+ cairo_surface_t base;
+
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+
+ cairo_surface_t *owner;
+ xcb_pixmap_t pixmap;
+ int width;
+ int height;
+ int depth;
+ int x0, y0;
+ cairo_bool_t repeat;
+} cairo_xcb_pixmap_t;
+
+static cairo_status_t
+_cairo_xcb_pixmap_finish (void *abstract_surface)
+{
+ cairo_xcb_pixmap_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (surface->owner != NULL) {
+ cairo_surface_destroy (surface->owner);
+ } else {
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+ _cairo_xcb_connection_free_pixmap (surface->connection,
+ surface->pixmap);
+ }
+ _cairo_xcb_connection_release (surface->connection);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = {
+ CAIRO_SURFACE_TYPE_XCB,
+ NULL,
+ _cairo_xcb_pixmap_finish,
+};
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_create (cairo_xcb_surface_t *target,
+ int width, int height)
+{
+ cairo_xcb_pixmap_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_pixmap_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_pixmap_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_pixmap_backend,
+ NULL,
+ target->base.content);
+
+ surface->connection = target->connection;
+ surface->screen = target->screen;
+ surface->owner = NULL;
+ surface->width = width;
+ surface->height = height;
+ surface->depth = target->depth;
+ surface->x0 = surface->y0 = 0;
+ surface->repeat = FALSE;
+
+ surface->pixmap =
+ _cairo_xcb_connection_create_pixmap (surface->connection,
+ surface->depth,
+ target->drawable,
+ width, height);
+
+ return surface;
+}
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_copy (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_pixmap_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_pixmap_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_pixmap_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_pixmap_backend,
+ NULL,
+ target->base.content);
+
+ surface->connection = target->connection;
+ surface->screen = target->screen;
+ surface->pixmap = target->drawable;
+ surface->owner = cairo_surface_reference (&target->base);
+ surface->width = target->width;
+ surface->height = target->height;
+ surface->depth = target->depth;
+ surface->x0 = surface->y0 = 0;
+ surface->repeat = FALSE;
+
+ return surface;
+}
+
+static cairo_status_t
+_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format,
+ int width, int height,
+ cairo_image_surface_t **image_out,
+ cairo_xcb_shm_info_t **shm_info_out)
+{
+ cairo_surface_t *image = NULL;
+ cairo_xcb_shm_info_t *shm_info = NULL;
+ cairo_status_t status;
+
+ if ((connection->flags & CAIRO_XCB_HAS_SHM)) {
+ size_t size, stride;
+
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+ size = stride * height;
+ if (size > CAIRO_XCB_SHM_SMALL_IMAGE) {
+ status = _cairo_xcb_connection_allocate_shm_info (connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
+
+ image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ pixman_format,
+ width, height,
+ stride);
+ status = image->status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+
+ status = _cairo_user_data_array_set_data (&image->user_data,
+ (const cairo_user_data_key_t *) connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+ }
+ }
+
+ if (image == NULL) {
+ image = _cairo_image_surface_create_with_pixman_format (NULL,
+ pixman_format,
+ width, height,
+ 0);
+ status = image->status;
+ if (unlikely (status))
+ return status;
+ }
+
+
+ *image_out = (cairo_image_surface_t *) image;
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_pixmap_t *
+_pixmap_from_image (cairo_xcb_surface_t *target,
+ xcb_render_pictformat_t format,
+ cairo_image_surface_t *image,
+ cairo_xcb_shm_info_t *shm_info)
+{
+ xcb_gcontext_t gc;
+ cairo_xcb_pixmap_t *pixmap;
+
+ pixmap = _cairo_xcb_pixmap_create (target,
+ image->width,
+ image->height);
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth);
+
+ if (shm_info != NULL) {
+ shm_info->seqno =
+ _cairo_xcb_connection_shm_put_image (target->connection,
+ pixmap->pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ shm_info->shm,
+ shm_info->offset);
+ } else {
+ int len;
+
+ /* Do we need to trim the image? */
+ len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width,
+ PIXMAN_FORMAT_BPP (image->pixman_format));
+ if (len == image->stride) {
+ _cairo_xcb_connection_put_image (target->connection,
+ pixmap->pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ image->stride,
+ image->data);
+ } else {
+ _cairo_xcb_connection_put_subimage (target->connection,
+ pixmap->pixmap, gc,
+ 0, 0,
+ image->width, image->height,
+ PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+ image->stride,
+ 0, 0,
+ image->depth,
+ image->data);
+
+ }
+ }
+
+ _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
+
+ return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_render_to_pixmap (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_image_surface_t *image;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_pattern_union_t copy;
+ cairo_status_t status;
+ cairo_xcb_pixmap_t *pixmap;
+
+ status = _cairo_xcb_shm_image_create (target->screen->connection,
+ target->pixman_format,
+ extents->width, extents->height,
+ &image, &shm_info);
+ if (unlikely (status))
+ return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+
+ _cairo_pattern_init_static_copy (&copy.base, pattern);
+ cairo_matrix_translate (&copy.base.matrix, -extents->x, -extents->y);
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ &copy.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+ }
+
+ pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info);
+ cairo_surface_destroy (&image->base);
+
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ pixmap->x0 = -extents->x;
+ pixmap->y0 = -extents->y;
+ return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_copy_to_pixmap (cairo_xcb_surface_t *source)
+{
+ cairo_xcb_pixmap_t *pixmap;
+
+ /* If the source may be a window, we need to copy it and its children
+ * via a temporary pixmap so that we can IncludeInferiors on the source
+ * and use ClipByChildren on the destination.
+ */
+ if (source->owns_pixmap) {
+ pixmap = _cairo_xcb_pixmap_copy (source);
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+ } else {
+ uint32_t values[1];
+ xcb_gcontext_t gc;
+
+ pixmap = _cairo_xcb_pixmap_create (source,
+ source->width,
+ source->height);
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ gc = _cairo_xcb_screen_get_gc (source->screen,
+ pixmap->pixmap,
+ pixmap->depth);
+
+ values[0] = TRUE;
+ _cairo_xcb_connection_change_gc (pixmap->connection, gc,
+ XCB_GC_SUBWINDOW_MODE, values);
+
+ _cairo_xcb_connection_copy_area (pixmap->connection,
+ source->drawable,
+ pixmap->pixmap, gc,
+ 0, 0,
+ 0, 0,
+ source->width,
+ source->height);
+
+ values[0] = FALSE;
+ _cairo_xcb_connection_change_gc (pixmap->connection, gc,
+ XCB_GC_SUBWINDOW_MODE, values);
+
+ _cairo_xcb_screen_put_gc (source->screen,
+ pixmap->depth,
+ gc);
+ }
+
+ return pixmap;
+}
+static cairo_xcb_pixmap_t *
+_cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents,
+ int tx, int ty)
+{
+ cairo_surface_t *source;
+ cairo_xcb_pixmap_t *pixmap;
+ cairo_status_t status;
+
+ source = pattern->surface;
+ pixmap = (cairo_xcb_pixmap_t *)
+ _cairo_surface_has_snapshot (source, &_cairo_xcb_pixmap_backend);
+ if (pixmap != NULL && pixmap->screen == target->screen)
+ return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base);
+
+ if (source->type == CAIRO_SURFACE_TYPE_XCB &&
+ ((cairo_xcb_surface_t *) source)->screen == target->screen)
+ {
+ cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;
+
+ if (xcb_source->depth == target->depth)
+ pixmap = _copy_to_pixmap (xcb_source);
+ }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+ else if (source->type == CAIRO_SURFACE_TYPE_XLIB &&
+ ((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen)
+ {
+ cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;
+
+ if (xcb_source->depth == target->depth)
+ pixmap = _copy_to_pixmap (xcb_source);
+ }
+#endif
+
+ if (pixmap == NULL) {
+ cairo_rectangle_int_t rect;
+
+ if (! _cairo_surface_get_extents (source, &rect)) {
+ rect.x = rect.y = 0;
+ rect.width = target->width;
+ rect.height = target->height;
+ }
+
+ pixmap = _render_to_pixmap (target, &pattern->base, &rect);
+ }
+
+ if (unlikely (pixmap->base.status))
+ return pixmap;
+
+ status = _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&pixmap->base);
+ return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+ }
+
+ if (pattern->base.extend != CAIRO_EXTEND_NONE) {
+ if (extents->x < 0 || extents->y < 0 ||
+ extents->x + extents->width > pixmap->width ||
+ extents->y + extents->height > pixmap->height)
+ {
+ pixmap->repeat = TRUE;
+ }
+ }
+
+ pixmap->x0 += tx;
+ pixmap->y0 += ty;
+
+ return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_for_pattern (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ int tx, ty;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ /* Core can only perform a native, unscaled blit, but can handle tiles */
+ if (_cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty)) {
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_NONE:
+ case CAIRO_EXTEND_REPEAT:
+ return _cairo_xcb_surface_pixmap (target,
+ (cairo_surface_pattern_t *) pattern,
+ extents, tx, ty);
+
+ default:
+ case CAIRO_EXTEND_PAD:
+ case CAIRO_EXTEND_REFLECT:
+ break;
+ }
+ }
+ /* fallthrough */
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return _render_to_pixmap (target, pattern, extents);
+
+ default:
+ case CAIRO_PATTERN_TYPE_SOLID:
+ ASSERT_NOT_REACHED;
+ return NULL;
+ }
+}
+
+cairo_status_t
+_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst,
+ const cairo_pattern_t *src_pattern,
+ const cairo_rectangle_int_t *extents,
+ const cairo_boxes_t *boxes)
+{
+ cairo_xcb_pixmap_t *src;
+ const struct _cairo_boxes_chunk *chunk;
+ xcb_gcontext_t gc;
+ cairo_status_t status;
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status))
+ goto CLEANUP_CONNECTION;
+
+ src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents);
+ status = src->base.status;
+ if (unlikely (status))
+ goto CLEANUP_CONNECTION;
+
+ assert (src->depth == dst->depth);
+
+ gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth);
+
+ if (src->repeat) {
+ uint32_t mask =
+ XCB_GC_FILL_STYLE |
+ XCB_GC_TILE |
+ XCB_GC_TILE_STIPPLE_ORIGIN_X |
+ XCB_GC_TILE_STIPPLE_ORIGIN_Y;
+ uint32_t values[] = {
+ XCB_FILL_STYLE_TILED,
+ src->pixmap,
+ - src->x0, - src->y0,
+ };
+ xcb_rectangle_t *xcb_rects;
+
+ _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ xcb_rects = (xcb_rectangle_t *) chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ xcb_rects[i].x = x1;
+ xcb_rects[i].y = y1;
+ xcb_rects[i].width = x2 - x1;
+ xcb_rects[i].height = y2 - y1;
+ }
+ _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
+ dst->drawable,
+ gc, chunk->count, xcb_rects);
+ }
+
+ values[0] = 0;
+ _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values);
+ } else {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ _cairo_xcb_connection_copy_area (dst->connection,
+ src->pixmap,
+ dst->drawable, gc,
+ src->x0 + x1,
+ src->y0 + y1,
+ x1, y1,
+ x2 - x2, y2 - x2);
+ }
+ }
+ }
+
+ _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc);
+ cairo_surface_destroy (&src->base);
+
+ CLEANUP_CONNECTION:
+ _cairo_xcb_connection_release (dst->connection);
+
+ return status;
+}
+
+cairo_status_t
+_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ struct _cairo_boxes_chunk *chunk;
+ xcb_gcontext_t gc;
+ cairo_status_t status;
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (dst->connection);
+ return status;
+ }
+
+ gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
+
+#if 0
+ xcb_pixmap_t source;
+
+ source = _dither_source (dst, color);
+ XSetTSOrigin (surface->dpy, gc, 0, 0);
+ XSetTile (surface->dpy, gc, source);
+#endif
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ xcb_rectangle_t *xcb_rects;
+ int i;
+
+ xcb_rects = (xcb_rectangle_t *) chunk->base;
+ for (i = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ xcb_rects[i].x = x1;
+ xcb_rects[i].y = y1;
+ xcb_rects[i].width = x2 - x1;
+ xcb_rects[i].height = y2 - y1;
+ }
+
+ _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
+ dst->drawable, gc,
+ chunk->count, xcb_rects);
+ }
+
+ _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
+ _cairo_xcb_connection_release (dst->connection);
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-xcb-xrender.h b/src/cairo-xcb-surface-private.h
index 09c609738..1ef490034 100644
--- a/src/cairo-xcb-xrender.h
+++ b/src/cairo-xcb-surface-private.h
@@ -1,6 +1,6 @@
-/* cairo - a vector graphics library with display and print output
+/* Cairo - a vector graphics library with display and print output
*
- * Copyright © 2002 University of Southern California
+ * Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -25,39 +25,13 @@
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
+ * Contributors(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
*/
-#ifndef CAIRO_XCB_XRENDER_H
-#define CAIRO_XCB_XRENDER_H
-
-#include "cairo.h"
-
-#if CAIRO_HAS_XCB_SURFACE
-
-#include <xcb/xcb.h>
-#include <xcb/render.h>
-
-CAIRO_BEGIN_DECLS
-
-cairo_public cairo_surface_t *
-cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *c,
- xcb_drawable_t drawable,
- xcb_screen_t *screen,
- xcb_render_pictforminfo_t *format,
- int width,
- int height);
-
-CAIRO_END_DECLS
+#ifndef CAIRO_XCB_SURFACE_PRIVATE_H
+#define CAIRO_XCB_SURFACE_PRIVATE_H
-#else /* CAIRO_HAS_XCB_SURFACE */
-# error Cairo was not compiled with support for the xcb backend
-#endif /* CAIRO_HAS_XCB_SURFACE */
+#include "cairo-xcb-private.h"
-#endif /* CAIRO_XCB_XRENDER_H */
+#endif
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
new file mode 100644
index 000000000..e07f575cc
--- /dev/null
+++ b/src/cairo-xcb-surface-render.c
@@ -0,0 +1,4471 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-xcb-private.h"
+
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS && CAIRO_HAS_DRM_SURFACE
+#include "drm/cairo-drm-private.h"
+#endif
+
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
+typedef struct _cairo_xcb_picture {
+ cairo_surface_t base;
+
+ cairo_surface_t *owner;
+
+ cairo_xcb_connection_t *connection;
+ cairo_xcb_screen_t *screen;
+ xcb_render_picture_t picture;
+ xcb_render_pictformat_t xrender_format;
+ pixman_format_code_t pixman_format;
+
+ int width, height;
+
+ cairo_extend_t extend;
+ cairo_filter_t filter;
+ cairo_bool_t has_component_alpha;
+ xcb_render_transform_t transform;
+
+ int x0, y0;
+ int x, y;
+} cairo_xcb_picture_t;
+
+static void
+_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface);
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+ static uint32_t x;
+ return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static cairo_status_t
+_cairo_xcb_picture_finish (void *abstract_surface)
+{
+ cairo_xcb_picture_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (surface->owner != NULL) {
+ cairo_surface_destroy (surface->owner);
+ } else {
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+ _cairo_xcb_connection_render_free_picture (surface->connection,
+ surface->picture);
+ }
+ _cairo_xcb_connection_release (surface->connection);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
+ CAIRO_SURFACE_TYPE_XCB,
+ NULL,
+ _cairo_xcb_picture_finish,
+};
+
+static const struct xcb_render_transform_t identity_transform = {
+ 1 << 16, 0, 0,
+ 0, 1 << 16, 0,
+ 0, 0, 1 << 16,
+};
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_create (cairo_xcb_screen_t *screen,
+ pixman_format_code_t pixman_format,
+ xcb_render_pictformat_t xrender_format,
+ int width, int height)
+{
+ cairo_xcb_picture_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_picture_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_picture_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_picture_backend,
+ NULL,
+ _cairo_content_from_pixman_format (pixman_format));
+
+ surface->connection = screen->connection;
+ surface->screen = screen;
+ surface->owner = NULL;
+ surface->picture = _cairo_xcb_connection_get_xid (screen->connection);
+ surface->pixman_format = pixman_format;
+ surface->xrender_format = xrender_format;
+
+ surface->x0 = surface->y0 = 0;
+ surface->x = surface->y = 0;
+ surface->width = width;
+ surface->height = height;
+
+ surface->transform = identity_transform;
+ surface->extend = CAIRO_EXTEND_NONE;
+ surface->filter = CAIRO_FILTER_NEAREST;
+ surface->has_component_alpha = FALSE;
+
+ return surface;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_copy (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_picture_t));
+ if (unlikely (surface == NULL))
+ return (cairo_xcb_picture_t *)
+ _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xcb_picture_backend,
+ NULL,
+ target->base.content);
+
+ surface->connection = target->connection;
+ surface->screen = target->screen;
+ surface->owner = cairo_surface_reference (&target->base);
+ _cairo_xcb_surface_ensure_picture (target);
+ surface->picture = target->picture;
+ surface->pixman_format = target->pixman_format;
+ surface->xrender_format = target->xrender_format;
+
+ surface->x0 = surface->y0 = 0;
+ surface->x = surface->y = 0;
+ surface->width = target->width;
+ surface->height = target->height;
+
+ surface->transform = identity_transform;
+ surface->extend = CAIRO_EXTEND_NONE;
+ surface->filter = CAIRO_FILTER_NEAREST;
+ surface->has_component_alpha = FALSE;
+
+ return surface;
+}
+
+static inline cairo_bool_t
+_operator_is_supported (uint32_t flags, cairo_operator_t op)
+{
+ if (op <= CAIRO_OPERATOR_SATURATE)
+ return TRUE;
+
+ return flags & CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+}
+
+static int
+_render_operator (cairo_operator_t op)
+{
+#define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y
+ switch (op) {
+ C(CLEAR, CLEAR);
+ C(SOURCE, SRC);
+
+ C(OVER, OVER);
+ C(IN, IN);
+ C(OUT, OUT);
+ C(ATOP, ATOP);
+
+ C(DEST, DST);
+ C(DEST_OVER, OVER_REVERSE);
+ C(DEST_IN, IN_REVERSE);
+ C(DEST_OUT, OUT_REVERSE);
+ C(DEST_ATOP, ATOP_REVERSE);
+
+ C(XOR, XOR);
+ C(ADD, ADD);
+ C(SATURATE, SATURATE);
+
+ case CAIRO_OPERATOR_MULTIPLY:
+ case CAIRO_OPERATOR_SCREEN:
+ case CAIRO_OPERATOR_OVERLAY:
+ case CAIRO_OPERATOR_DARKEN:
+ case CAIRO_OPERATOR_LIGHTEN:
+ case CAIRO_OPERATOR_COLOR_DODGE:
+ case CAIRO_OPERATOR_COLOR_BURN:
+ case CAIRO_OPERATOR_HARD_LIGHT:
+ case CAIRO_OPERATOR_SOFT_LIGHT:
+ case CAIRO_OPERATOR_DIFFERENCE:
+ case CAIRO_OPERATOR_EXCLUSION:
+ case CAIRO_OPERATOR_HSL_HUE:
+ case CAIRO_OPERATOR_HSL_SATURATION:
+ case CAIRO_OPERATOR_HSL_COLOR:
+ case CAIRO_OPERATOR_HSL_LUMINOSITY:
+ default:
+ ASSERT_NOT_REACHED;
+ return XCB_RENDER_PICT_OP_OVER;
+ }
+}
+
+static void
+_cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t *surface,
+ cairo_region_t *region)
+{
+ xcb_rectangle_t rects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
+ int i, num_rects;
+
+ num_rects = cairo_region_num_rectangles (region);
+ assert (num_rects < ARRAY_LENGTH (rects)); /* XXX somebody will! */
+
+ for (i = 0; i < num_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;
+ }
+
+ _cairo_xcb_connection_render_set_picture_clip_rectangles (surface->connection,
+ surface->picture,
+ 0, 0,
+ num_rects, rects);
+}
+
+static void
+_cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface)
+{
+ uint32_t values[] = { XCB_NONE };
+ _cairo_xcb_connection_render_change_picture (surface->connection,
+ surface->picture,
+ XCB_RENDER_CP_CLIP_MASK, values);
+}
+
+static void
+_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface)
+{
+ if (surface->picture == XCB_NONE) {
+ surface->picture = _cairo_xcb_connection_get_xid (surface->connection);
+ _cairo_xcb_connection_render_create_picture (surface->connection,
+ surface->picture,
+ surface->drawable,
+ surface->xrender_format,
+ 0, NULL);
+ }
+}
+
+static cairo_xcb_picture_t *
+_picture_from_image (cairo_xcb_surface_t *target,
+ xcb_render_pictformat_t format,
+ cairo_image_surface_t *image,
+ cairo_xcb_shm_info_t *shm_info)
+{
+ xcb_pixmap_t pixmap;
+ xcb_gcontext_t gc;
+ cairo_xcb_picture_t *picture;
+
+ pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
+ image->depth,
+ target->drawable,
+ image->width, image->height);
+
+ gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, image->depth);
+
+ if (shm_info != NULL) {
+ shm_info->seqno =
+ _cairo_xcb_connection_shm_put_image (target->connection,
+ pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ shm_info->shm,
+ shm_info->offset);
+ } else {
+ int len;
+
+ /* Do we need to trim the image? */
+ len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
+ if (len == image->stride) {
+ _cairo_xcb_connection_put_image (target->connection,
+ pixmap, gc,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ image->stride,
+ image->data);
+ } else {
+ _cairo_xcb_connection_put_subimage (target->connection,
+ pixmap, gc,
+ 0, 0,
+ image->width, image->height,
+ PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+ image->stride,
+ 0, 0,
+ image->depth,
+ image->data);
+
+ }
+ }
+
+ _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
+
+ picture = _cairo_xcb_picture_create (target->screen,
+ image->pixman_format, format,
+ image->width, image->height);
+ if (likely (picture->base.status == CAIRO_STATUS_SUCCESS)) {
+ _cairo_xcb_connection_render_create_picture (target->connection,
+ picture->picture, pixmap, format,
+ 0, 0);
+ }
+
+ _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+
+ return picture;
+}
+
+static cairo_bool_t
+_pattern_is_supported (uint32_t flags,
+ const cairo_pattern_t *pattern)
+
+{
+ if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ return TRUE;
+
+ if (! _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) {
+ if ((flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) == 0)
+ return FALSE;
+ }
+
+ switch (pattern->extend) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_EXTEND_NONE:
+ case CAIRO_EXTEND_REPEAT:
+ break;
+ case CAIRO_EXTEND_PAD:
+ case CAIRO_EXTEND_REFLECT:
+ if ((flags & CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT) == 0)
+ return FALSE;
+ }
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_filter_t filter;
+
+ filter = pattern->filter;
+ if (_cairo_matrix_has_unity_scale (&pattern->matrix) &&
+ _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
+ {
+ filter = CAIRO_FILTER_NEAREST;
+ }
+
+ if (! (filter == CAIRO_FILTER_NEAREST || filter == CAIRO_FILTER_FAST)) {
+ if ((flags & CAIRO_XCB_RENDER_HAS_FILTERS) == 0)
+ return FALSE;
+ }
+ } else { /* gradient */
+ if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static double
+_pixman_nearest_sample (double d)
+{
+ return ceil (d - .5);
+}
+
+static cairo_bool_t
+_nearest_sample (const cairo_matrix_t *m,
+ cairo_filter_t filter,
+ double *tx, double *ty)
+{
+ *tx = m->x0;
+ *ty = m->y0;
+ if ((filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
+ && _cairo_matrix_has_unity_scale (m))
+ {
+ *tx = _pixman_nearest_sample (*tx);
+ *ty = _pixman_nearest_sample (*ty);
+ }
+ else
+ {
+ if (*tx != floor (*tx) || *ty != floor (*ty))
+ return FALSE;
+ }
+ return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
+}
+
+static void
+_cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
+ const cairo_matrix_t *matrix,
+ cairo_filter_t filter,
+ double xc, double yc)
+{
+ cairo_matrix_t m;
+ double tx, ty;
+
+ m = *matrix;
+ if (_nearest_sample (&m, filter, &tx, &ty))
+ m.x0 = m.y0 = 0;
+ else
+ tx = ty = 0;
+
+ if (! _cairo_matrix_is_identity (&m)) {
+ xcb_render_transform_t transform;
+ cairo_matrix_t inv;
+ cairo_status_t status;
+
+ inv = m;
+ status = cairo_matrix_invert (&inv);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ if (m.x0 != 0. || m.y0 != 0.) {
+ double x, y;
+
+ /* pixman also limits the [xy]_offset to 16 bits so evenly
+ * spread the bits between the two.
+ */
+ x = floor (inv.x0 / 2);
+ y = floor (inv.y0 / 2);
+ tx = -x;
+ ty = -y;
+ cairo_matrix_init_translate (&inv, x, y);
+ cairo_matrix_multiply (&m, &inv, &m);
+ } else {
+ if (tx != 0. || ty != 0.)
+ cairo_matrix_transform_point (&inv, &tx, &ty);
+ }
+
+ /* Casting between pixman_transform_t and XTransform is safe because
+ * they happen to be the exact same type.
+ */
+ _cairo_matrix_to_pixman_matrix (&m,
+ (pixman_transform_t *) &transform, xc, yc);
+
+ if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) {
+ _cairo_xcb_connection_render_set_picture_transform (picture->connection,
+ picture->picture,
+ &transform);
+
+ picture->transform = transform;
+ }
+ }
+
+ picture->x = picture->x0 + tx;
+ picture->y = picture->y0 + ty;
+}
+
+static void
+_cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture,
+ cairo_filter_t filter)
+{
+ const char *render_filter;
+ int len;
+
+ if (picture->filter == filter)
+ return;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ render_filter = "fast";
+ len = strlen ("fast");
+ break;
+
+ case CAIRO_FILTER_GOOD:
+ render_filter = "good";
+ len = strlen ("good");
+ break;
+
+ case CAIRO_FILTER_BEST:
+ render_filter = "best";
+ len = strlen ("best");
+ break;
+
+ case CAIRO_FILTER_NEAREST:
+ render_filter = "nearest";
+ len = strlen ("nearest");
+ break;
+
+ case CAIRO_FILTER_BILINEAR:
+ render_filter = "bilinear";
+ len = strlen ("bilinear");
+ break;
+
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_FILTER_GAUSSIAN:
+ render_filter = "best";
+ len = strlen ("best");
+ break;
+ }
+
+ _cairo_xcb_connection_render_set_picture_filter (picture->connection,
+ picture->picture,
+ len, (char *) render_filter);
+ picture->filter = filter;
+}
+
+static void
+_cairo_xcb_picture_set_extend (cairo_xcb_picture_t *picture,
+ cairo_extend_t extend)
+{
+ uint32_t pa[1];
+
+ if (picture->extend == extend)
+ return;
+
+ switch (extend) {
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_EXTEND_NONE:
+ pa[0] = XCB_RENDER_REPEAT_NONE;
+ break;
+
+ case CAIRO_EXTEND_REPEAT:
+ pa[0] = XCB_RENDER_REPEAT_NORMAL;
+ break;
+
+ case CAIRO_EXTEND_REFLECT:
+ pa[0] = XCB_RENDER_REPEAT_REFLECT;
+ break;
+
+ case CAIRO_EXTEND_PAD:
+ pa[0] = XCB_RENDER_REPEAT_PAD;
+ break;
+ }
+
+ _cairo_xcb_connection_render_change_picture (picture->connection,
+ picture->picture,
+ XCB_RENDER_CP_REPEAT, pa);
+ picture->extend = extend;
+}
+
+static void
+_cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t *picture,
+ cairo_bool_t ca)
+{
+ uint32_t pa[1];
+
+ if (picture->has_component_alpha == ca)
+ return;
+
+ pa[0] = ca;
+
+ _cairo_xcb_connection_render_change_picture (picture->connection,
+ picture->picture,
+ XCB_RENDER_CP_COMPONENT_ALPHA,
+ pa);
+ picture->has_component_alpha = ca;
+}
+
+static cairo_xcb_picture_t *
+_solid_picture (cairo_xcb_surface_t *target,
+ const cairo_color_t *color)
+{
+ xcb_render_color_t xcb_color;
+ xcb_render_pictformat_t xrender_format;
+ cairo_xcb_picture_t *picture;
+
+ xcb_color.red = color->red_short;
+ xcb_color.green = color->green_short;
+ xcb_color.blue = color->blue_short;
+ xcb_color.alpha = color->alpha_short;
+
+ xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
+ picture = _cairo_xcb_picture_create (target->screen,
+ PIXMAN_a8r8g8b8,
+ xrender_format,
+ -1, -1);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ if (target->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) {
+ _cairo_xcb_connection_render_create_solid_fill (target->connection,
+ picture->picture,
+ xcb_color);
+ } else {
+ xcb_pixmap_t pixmap;
+ uint32_t values[] = { XCB_RENDER_REPEAT_NORMAL };
+
+ pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
+ 32, target->drawable, 1, 1);
+ _cairo_xcb_connection_render_create_picture (target->connection,
+ picture->picture,
+ pixmap,
+ xrender_format,
+ XCB_RENDER_CP_REPEAT,
+ values);
+ if (target->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+ xcb_rectangle_t rect;
+
+ rect.x = rect.y = 0;
+ rect.width = rect.height = 1;
+
+ _cairo_xcb_connection_render_fill_rectangles (picture->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ picture->picture,
+ xcb_color, 1, &rect);
+ } else {
+ xcb_gcontext_t gc;
+ uint32_t pixel;
+
+ gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, 32);
+
+ /* XXX byte ordering? */
+ pixel = ((color->alpha_short >> 8) << 24) |
+ ((color->red_short >> 8) << 16) |
+ ((color->green_short >> 8) << 8) |
+ ((color->blue_short >> 8) << 0);
+
+ _cairo_xcb_connection_put_image (target->connection,
+ pixmap, gc,
+ 1, 1, 0, 0,
+ 32, 4, &pixel);
+
+ _cairo_xcb_screen_put_gc (target->screen, 32, gc);
+ }
+
+ _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+ }
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_transparent_picture (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *picture;
+
+ picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT];
+ if (picture == NULL) {
+ picture = _solid_picture (target, CAIRO_COLOR_TRANSPARENT);
+ target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT] = &picture->base;
+ }
+
+ return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_black_picture (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *picture;
+
+ picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_BLACK];
+ if (picture == NULL) {
+ picture = _solid_picture (target, CAIRO_COLOR_BLACK);
+ target->screen->stock_colors[CAIRO_STOCK_BLACK] = &picture->base;
+ }
+
+ return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_white_picture (cairo_xcb_surface_t *target)
+{
+ cairo_xcb_picture_t *picture;
+
+ picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_WHITE];
+ if (picture == NULL) {
+ picture = _solid_picture (target, CAIRO_COLOR_WHITE);
+ target->screen->stock_colors[CAIRO_STOCK_WHITE] = &picture->base;
+ }
+
+ return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_solid_picture (cairo_xcb_surface_t *target,
+ const cairo_solid_pattern_t *pattern)
+{
+ cairo_xcb_picture_t *picture;
+ cairo_xcb_screen_t *screen;
+ int i, n_cached;
+
+ if (pattern->color.alpha_short <= 0x00ff)
+ return _cairo_xcb_transparent_picture (target);
+
+ if (pattern->color.alpha_short >= 0xff00) {
+ if (pattern->color.red_short <= 0x00ff &&
+ pattern->color.green_short <= 0x00ff &&
+ pattern->color.blue_short <= 0x00ff)
+ {
+ return _cairo_xcb_black_picture (target);
+ }
+
+ if (pattern->color.red_short >= 0xff00 &&
+ pattern->color.green_short >= 0xff00 &&
+ pattern->color.blue_short >= 0xff00)
+ {
+ return _cairo_xcb_white_picture (target);
+ }
+ }
+
+ screen = target->screen;
+ n_cached = screen->solid_cache_size;
+ for (i = 0; i < n_cached; i++) {
+ if (_cairo_color_equal (&screen->solid_cache[i].color, &pattern->color)) {
+ return (cairo_xcb_picture_t *) cairo_surface_reference (screen->solid_cache[i].picture);
+ }
+ }
+
+ picture = _solid_picture (target, &pattern->color);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ if (screen->solid_cache_size < ARRAY_LENGTH (screen->solid_cache)) {
+ i = screen->solid_cache_size++;
+ } else {
+ i = hars_petruska_f54_1_random () % ARRAY_LENGTH (screen->solid_cache);
+ cairo_surface_destroy (screen->solid_cache[i].picture);
+ }
+ screen->solid_cache[i].picture = cairo_surface_reference (&picture->base);
+ screen->solid_cache[i].color = pattern->color;
+
+ return picture;
+}
+
+static cairo_status_t
+_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
+ pixman_format_code_t pixman_format,
+ int width, int height,
+ cairo_image_surface_t **image_out,
+ cairo_xcb_shm_info_t **shm_info_out)
+{
+ cairo_surface_t *image = NULL;
+ cairo_xcb_shm_info_t *shm_info = NULL;
+ cairo_status_t status;
+
+ if ((connection->flags & CAIRO_XCB_HAS_SHM)) {
+ size_t size, stride;
+
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+ size = stride * height;
+ if (size > CAIRO_XCB_SHM_SMALL_IMAGE) {
+ status = _cairo_xcb_connection_allocate_shm_info (connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
+
+ image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ pixman_format,
+ width, height,
+ stride);
+ status = image->status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+
+ status = _cairo_user_data_array_set_data (&image->user_data,
+ (const cairo_user_data_key_t *) connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+ }
+ }
+
+ if (image == NULL) {
+ image = _cairo_image_surface_create_with_pixman_format (NULL,
+ pixman_format,
+ width, height,
+ 0);
+ status = image->status;
+ if (unlikely (status))
+ return status;
+ }
+
+ *image_out = (cairo_image_surface_t *) image;
+ *shm_info_out = shm_info;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_picture_t *
+_render_to_picture (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_image_surface_t *image;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_pattern_union_t copy;
+ cairo_status_t status;
+ cairo_xcb_picture_t *picture;
+ pixman_format_code_t pixman_format;
+ xcb_render_pictformat_t xrender_format;
+
+ /* XXX handle extend modes via tiling? */
+ /* XXX alpha-only masks? */
+
+ pixman_format = PIXMAN_a8r8g8b8;
+ xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
+
+ status = _cairo_xcb_shm_image_create (target->screen->connection,
+ pixman_format,
+ extents->width, extents->height,
+ &image, &shm_info);
+ if (unlikely (status))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+
+ _cairo_pattern_init_static_copy (&copy.base, pattern);
+ cairo_matrix_translate (&copy.base.matrix, extents->x, extents->y);
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ &copy.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+ picture = _picture_from_image (target, xrender_format, image, shm_info);
+ cairo_surface_destroy (&image->base);
+
+ if (unlikely (picture->base.status))
+ return picture;
+
+ _cairo_xcb_picture_set_component_alpha (picture, pattern->has_component_alpha);
+ picture->x = -extents->x;
+ picture->y = -extents->y;
+
+ return picture;
+}
+
+static xcb_render_fixed_t *
+_gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
+ char *buf, unsigned int buflen)
+{
+ xcb_render_fixed_t *stops;
+ xcb_render_color_t *colors;
+ unsigned int i;
+
+ if (gradient->n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
+ {
+ stops = (xcb_render_fixed_t *) buf;
+ }
+ else
+ {
+ stops =
+ _cairo_malloc_ab (gradient->n_stops,
+ sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t));
+ if (unlikely (stops == NULL))
+ return NULL;
+ }
+
+ colors = (xcb_render_color_t *) (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;
+ }
+
+ return stops;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
+ const cairo_linear_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ cairo_fixed_t xdim, ydim;
+ xcb_render_fixed_t *stops;
+ xcb_render_color_t *colors;
+ xcb_render_pointfix_t p1, p2;
+ cairo_matrix_t matrix = pattern->base.base.matrix;
+ cairo_xcb_picture_t *picture;
+ cairo_status_t status;
+
+ picture = (cairo_xcb_picture_t *)
+ _cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
+ if (picture != NULL)
+ goto setup_picture;
+
+ stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
+ if (unlikely (stops == NULL))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ picture = _cairo_xcb_picture_create (target->screen,
+ target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
+ PIXMAN_a8r8g8b8,
+ -1, -1);
+ if (unlikely (picture->base.status)) {
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+ return picture;
+ }
+ picture->filter = CAIRO_FILTER_DEFAULT;
+
+ xdim = pattern->p2.x - pattern->p1.x;
+ ydim = pattern->p2.y - pattern->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 (unlikely (_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);
+
+ p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.x) * sf);
+ p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.y) * sf);
+ p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.x) * sf);
+ p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.y) * sf);
+
+ cairo_matrix_scale (&matrix, sf, sf);
+ }
+ else
+ {
+ p1.x = _cairo_fixed_to_16_16 (pattern->p1.x);
+ p1.y = _cairo_fixed_to_16_16 (pattern->p1.y);
+ p2.x = _cairo_fixed_to_16_16 (pattern->p2.x);
+ p2.y = _cairo_fixed_to_16_16 (pattern->p2.y);
+ }
+
+ colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
+ _cairo_xcb_connection_render_create_linear_gradient (target->connection,
+ picture->picture,
+ p1, p2,
+ pattern->base.n_stops,
+ stops, colors);
+
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+
+ status = _cairo_xcb_screen_store_linear_picture (target->screen,
+ pattern,
+ &picture->base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+setup_picture:
+ _cairo_xcb_picture_set_matrix (picture, &matrix,
+ pattern->base.base.filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+ _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
+ _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
+ _cairo_xcb_picture_set_component_alpha (picture,
+ pattern->base.base.has_component_alpha);
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
+ const cairo_radial_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ char buf[CAIRO_STACK_BUFFER_SIZE];
+ xcb_render_fixed_t *stops;
+ xcb_render_color_t *colors;
+ xcb_render_pointfix_t c1, c2;
+ xcb_render_fixed_t r1, r2;
+ cairo_xcb_picture_t *picture;
+ cairo_status_t status;
+
+ picture = (cairo_xcb_picture_t *)
+ _cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
+ if (picture != NULL)
+ goto setup_picture;
+
+ stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
+ if (unlikely (stops == NULL))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+ picture = _cairo_xcb_picture_create (target->screen,
+ target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
+ PIXMAN_a8r8g8b8,
+ -1, -1);
+ if (unlikely (picture->base.status)) {
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+ return picture;
+ }
+ picture->filter = CAIRO_FILTER_DEFAULT;
+
+ c1.x = _cairo_fixed_to_16_16 (pattern->c1.x);
+ c1.y = _cairo_fixed_to_16_16 (pattern->c1.y);
+ r1 = _cairo_fixed_to_16_16 (pattern->r1);
+ c2.x = _cairo_fixed_to_16_16 (pattern->c2.x);
+ c2.y = _cairo_fixed_to_16_16 (pattern->c2.y);
+ r2 = _cairo_fixed_to_16_16 (pattern->r2);
+
+ colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
+ _cairo_xcb_connection_render_create_radial_gradient (target->connection,
+ picture->picture,
+ c1, c2, r1, r2,
+ pattern->base.n_stops,
+ stops, colors);
+
+ if (stops != (xcb_render_fixed_t *) buf)
+ free (stops);
+
+ status = _cairo_xcb_screen_store_radial_picture (target->screen,
+ pattern,
+ &picture->base);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+setup_picture:
+ _cairo_xcb_picture_set_matrix (picture, &pattern->base.base.matrix,
+ pattern->base.base.filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+ _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
+ _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
+ _cairo_xcb_picture_set_component_alpha (picture,
+ pattern->base.base.has_component_alpha);
+
+ return picture;
+}
+
+static void
+_decouple_cached_picture (cairo_surface_t *surface)
+{
+ cairo_xcb_picture_t *picture = (cairo_xcb_picture_t *) surface;
+
+ if (! picture->base.finished)
+ _cairo_xcb_screen_remove_surface_picture (picture->screen, &picture->base);
+}
+
+static cairo_xcb_picture_t *
+_copy_to_picture (cairo_xcb_surface_t *source,
+ cairo_bool_t force)
+{
+ cairo_xcb_picture_t *picture;
+ uint32_t values[] = { 0, 1 };
+
+ /* XXX two level device locking, ensure we release the xcb device mutex? */
+ if (source->drm != NULL)
+ cairo_surface_flush (source->drm);
+
+ if (source->owns_pixmap && ! force) {
+ picture = _cairo_xcb_picture_copy (source);
+ } else {
+ picture = _cairo_xcb_picture_create (source->screen,
+ source->xrender_format,
+ source->pixman_format,
+ source->width,
+ source->height);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ _cairo_xcb_connection_render_create_picture (source->connection,
+ picture->picture,
+ source->drawable,
+ source->xrender_format,
+ XCB_RENDER_CP_GRAPHICS_EXPOSURE |
+ XCB_RENDER_CP_SUBWINDOW_MODE,
+ values);
+ }
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
+ const cairo_surface_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_surface_t *source;
+ cairo_xcb_picture_t *picture;
+ cairo_filter_t filter;
+ cairo_extend_t extend;
+ cairo_status_t status;
+
+ source = pattern->surface;
+ if (source->is_clear) {
+ if (source->content & CAIRO_CONTENT_ALPHA)
+ return _cairo_xcb_transparent_picture (target);
+ else
+ return _cairo_xcb_black_picture (target);
+ }
+
+ picture = (cairo_xcb_picture_t *)
+ _cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend);
+ if (picture != NULL) {
+ if (picture->screen == target->screen) {
+ picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+ goto setup_picture;
+ }
+ }
+
+ if (source->type == CAIRO_SURFACE_TYPE_XCB)
+ {
+ if (source->backend->type == CAIRO_SURFACE_TYPE_XCB) {
+ if (((cairo_xcb_surface_t *) source)->screen == target->screen) {
+ picture = _copy_to_picture ((cairo_xcb_surface_t *) source, FALSE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+ cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) sub->target;
+
+ /* XXX repeat interval with source clipping? */
+ if (FALSE && xcb->screen == target->screen) {
+ xcb_rectangle_t rect;
+
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ rect.x = sub->extents.x;
+ rect.y = sub->extents.y;
+ rect.width = sub->extents.width;
+ rect.height = sub->extents.height;
+
+ _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
+ picture->picture,
+ 0, 0,
+ 1, &rect);
+ picture->x0 = rect.x;
+ picture->y0 = rect.y;
+ picture->width = rect.width;
+ picture->height = rect.height;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
+ cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) snap->target;
+
+ if (xcb->screen == target->screen) {
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ }
+ }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+ else if (source->type == CAIRO_SURFACE_TYPE_XLIB)
+ {
+ if (source->backend->type == CAIRO_SURFACE_TYPE_XLIB) {
+ if (((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen) {
+ picture = _copy_to_picture (((cairo_xlib_xcb_surface_t *) source)->xcb,
+ FALSE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+ cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+ cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) sub->target)->xcb;
+
+ if (FALSE && xcb->screen == target->screen) {
+ xcb_rectangle_t rect;
+
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+
+ rect.x = sub->extents.x;
+ rect.y = sub->extents.y;
+ rect.width = sub->extents.width;
+ rect.height = sub->extents.height;
+
+ _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
+ picture->picture,
+ 0, 0,
+ 1, &rect);
+ picture->x0 = rect.x;
+ picture->y0 = rect.y;
+ picture->width = rect.width;
+ picture->height = rect.height;
+ }
+ } else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+ cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
+ cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) snap->target)->xcb;
+
+ if (xcb->screen == target->screen) {
+ picture = _copy_to_picture (xcb, TRUE);
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+ }
+ }
+#endif
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS && CAIRO_HAS_DRM_SURFACE
+ else if (source->type == CAIRO_SURFACE_TYPE_DRM &&
+ target->drm != NULL &&
+ target->drm->device == source->device)
+ {
+ cairo_drm_surface_t *drm = (cairo_drm_surface_t *) source;
+ cairo_xcb_surface_t *tmp;
+ xcb_pixmap_t pixmap;
+ pixman_format_code_t pixman_format;
+ cairo_surface_pattern_t pattern;
+
+ /* XXX XRenderCreatePictureForNative:
+ * Copy the source to a temporary pixmap if possible.
+ * Still cheaper than pushing the image via the CPU.
+ */
+
+ switch (drm->format) {
+ case CAIRO_FORMAT_A1:
+ pixman_format = PIXMAN_a1;
+ break;
+ case CAIRO_FORMAT_A8:
+ pixman_format = PIXMAN_a8;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
+ }
+
+ pixmap =
+ _cairo_xcb_connection_create_pixmap (target->connection,
+ PIXMAN_FORMAT_DEPTH (pixman_format),
+ target->drawable,
+ drm->width, drm->height);
+
+ tmp = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_internal (target->screen,
+ pixmap, TRUE,
+ pixman_format,
+ target->connection->standard_formats[drm->format],
+ drm->width, drm->height);
+ if (unlikely (tmp->base.status)) {
+ _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+ return (cairo_xcb_picture_t *) tmp;
+ }
+
+ _cairo_pattern_init_for_surface (&pattern, source);
+ status = _cairo_surface_paint (&tmp->base,
+ CAIRO_OPERATOR_SOURCE,
+ &pattern.base,
+ NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (&tmp->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+ picture = _copy_to_picture (tmp, FALSE);
+ cairo_surface_destroy (&tmp->base);
+
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+#endif
+#if CAIRO_HAS_GL_FUNCTIONS
+ else if (source->type == CAIRO_SURFACE_TYPE_GL)
+ {
+ /* pixmap from texture */
+ }
+#endif
+
+ if (picture == NULL) {
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+
+ status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
+ if (unlikely (status))
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+
+ if (image->format != CAIRO_FORMAT_INVALID) {
+ xcb_render_pictformat_t format;
+
+ format = target->screen->connection->standard_formats[image->format];
+
+ picture = _picture_from_image (target, format, image, NULL);
+ _cairo_surface_release_source_image (source, image, image_extra);
+ } else {
+ cairo_image_surface_t *conv;
+ cairo_format_t format;
+ xcb_render_pictformat_t render_format;
+
+ /* XXX XRenderPutImage! */
+
+ switch (image->base.content) {
+ case CAIRO_CONTENT_ALPHA:
+ format = CAIRO_FORMAT_A8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ format = CAIRO_FORMAT_RGB24;
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ format = CAIRO_FORMAT_ARGB32;
+ break;
+ }
+
+ conv = _cairo_image_surface_coerce (image, format);
+ _cairo_surface_release_source_image (source, image, image_extra);
+ if (unlikely (conv->base.status))
+ return (cairo_xcb_picture_t *) conv;
+
+ render_format = target->screen->connection->standard_formats[format];
+ picture = _picture_from_image (target, render_format, conv, NULL);
+ cairo_surface_destroy (&conv->base);
+ }
+
+ if (unlikely (picture->base.status))
+ return picture;
+ }
+
+ status = _cairo_xcb_screen_store_surface_picture (target->screen,
+ &picture->base,
+ CAIRO_STRIDE_FOR_WIDTH_BPP (picture->width,
+ PIXMAN_FORMAT_BPP (picture->pixman_format))
+ * picture->height);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+ status = _cairo_surface_attach_snapshot (source,
+ &picture->base,
+ _decouple_cached_picture);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&picture->base);
+ return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+ }
+
+setup_picture:
+ filter = pattern->base.filter;
+ if (filter != CAIRO_FILTER_NEAREST &&
+ _cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
+ _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.x0)) &&
+ _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.y0)))
+ {
+ filter = CAIRO_FILTER_NEAREST;
+ }
+ _cairo_xcb_picture_set_filter (picture, filter);
+
+ _cairo_xcb_picture_set_matrix (picture,
+ &pattern->base.matrix, filter,
+ extents->x + extents->width/2.,
+ extents->y + extents->height/2.);
+
+
+ extend = pattern->base.extend;
+ if (extents->x >= 0 && extents->x + extents->width <= picture->width &&
+ extents->y >= 0 && extents->y + extents->height <= picture->height)
+ {
+ extend = CAIRO_EXTEND_NONE;
+ }
+ _cairo_xcb_picture_set_extend (picture, extend);
+ _cairo_xcb_picture_set_component_alpha (picture, pattern->base.has_component_alpha);
+
+ return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target,
+ const cairo_pattern_t *pattern,
+ const cairo_rectangle_int_t *extents)
+{
+ if (pattern == NULL)
+ return _cairo_xcb_white_picture (target);
+
+ if (! _pattern_is_supported (target->flags, pattern))
+ return _render_to_picture (target, pattern, extents);
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return _cairo_xcb_solid_picture (target, (cairo_solid_pattern_t *) pattern);
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return _cairo_xcb_linear_picture (target,
+ (cairo_linear_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return _cairo_xcb_radial_picture (target,
+ (cairo_radial_pattern_t *) pattern,
+ extents);
+
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _cairo_xcb_surface_picture (target,
+ (cairo_surface_pattern_t *) pattern,
+ extents);
+ default:
+ ASSERT_NOT_REACHED;
+ return _render_to_picture (target, pattern, extents);
+ }
+}
+
+COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t));
+
+static cairo_status_t
+_render_fill_boxes (void *abstract_dst,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_xcb_surface_t *dst = abstract_dst;
+ xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (sizeof (xcb_rectangle_t))];
+ xcb_rectangle_t *xrects = stack_xrects;
+ xcb_render_color_t render_color;
+ int render_op = _render_operator (op);
+ struct _cairo_boxes_chunk *chunk;
+ int max_count;
+
+ render_color.red = color->red_short;
+ render_color.green = color->green_short;
+ render_color.blue = color->blue_short;
+ render_color.alpha = color->alpha_short;
+
+ max_count = 0;
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ if (chunk->count > max_count)
+ max_count = chunk->count;
+ }
+ if (max_count > ARRAY_LENGTH (stack_xrects)) {
+ xrects = _cairo_malloc_ab (max_count, sizeof (xcb_rectangle_t));
+ if (unlikely (xrects == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ int i, j;
+
+ for (i = j = 0; i < chunk->count; i++) {
+ int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+ int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+ int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+ int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+ if (x2 > x1 && y2 > y1) {
+ xrects[j].x = x1;
+ xrects[j].y = y1;
+ xrects[j].width = x2 - x1;
+ xrects[j].height = y2 - y1;
+ j++;
+ }
+ }
+
+ if (j) {
+ _cairo_xcb_connection_render_fill_rectangles
+ (dst->connection,
+ render_op, dst->picture,
+ render_color, j, xrects);
+ }
+ }
+
+ if (xrects != stack_xrects)
+ free (xrects);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_render_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ const cairo_pattern_t *mask_pattern,
+ const cairo_rectangle_int_t *extents,
+ const cairo_boxes_t *boxes)
+{
+ cairo_xcb_picture_t *src, *mask;
+ const struct _cairo_boxes_chunk *chunk;
+ int render_op;
+
+ render_op = _render_operator (op);
+
+ if (src_pattern == NULL) {
+ src_pattern = mask_pattern;
+ mask_pattern = NULL;
+ }
+
+ src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ if (mask_pattern != NULL) {
+ mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+ if (unlikely (mask->base.status)) {
+ cairo_surface_destroy (&src->base);
+ return mask->base.status;
+ }
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x = _cairo_fixed_integer_round (box[i].p1.x);
+ int y = _cairo_fixed_integer_round (box[i].p1.y);
+ int width = _cairo_fixed_integer_round (box[i].p2.x) - x;
+ int height = _cairo_fixed_integer_round (box[i].p2.y) - y;
+
+ if (width && height) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ render_op,
+ src->picture,
+ mask->picture,
+ dst->picture,
+ x + src->x,
+ y + src->y,
+ x + mask->x,
+ y + mask->y,
+ x, y,
+ width, height);
+ }
+ }
+ }
+
+ cairo_surface_destroy (&mask->base);
+ } else {
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ const cairo_box_t *box = chunk->base;
+ int i;
+
+ for (i = 0; i < chunk->count; i++) {
+ int x = _cairo_fixed_integer_round (box[i].p1.x);
+ int y = _cairo_fixed_integer_round (box[i].p1.y);
+ int width = _cairo_fixed_integer_round (box[i].p2.x) - x;
+ int height = _cairo_fixed_integer_round (box[i].p2.y) - y;
+
+ if (width && height) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ render_op,
+ src->picture,
+ XCB_NONE,
+ dst->picture,
+ x + src->x,
+ y + src->y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+ }
+ }
+ }
+
+ cairo_surface_destroy (&src->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
+#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
+
+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;
+}
+
+static void
+_project_line_x_onto_16_16 (const cairo_line_t *line,
+ cairo_fixed_t top,
+ cairo_fixed_t bottom,
+ xcb_render_linefix_t *out)
+{
+ cairo_point_double_t p1, p2;
+ double m;
+
+ p1.x = _cairo_fixed_to_double (line->p1.x);
+ p1.y = _cairo_fixed_to_double (line->p1.y);
+
+ p2.x = _cairo_fixed_to_double (line->p2.x);
+ p2.y = _cairo_fixed_to_double (line->p2.y);
+
+ 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));
+}
+
+typedef struct {
+ cairo_traps_t traps;
+ cairo_antialias_t antialias;
+} composite_traps_info_t;
+
+COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t));
+
+static cairo_status_t
+_composite_traps (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x, int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_traps_info_t *info = closure;
+ const cairo_traps_t *traps = &info->traps;
+ cairo_xcb_picture_t *src;
+ cairo_format_t format;
+ xcb_render_pictformat_t xrender_format;
+ xcb_render_trapezoid_t *xtraps;
+ int render_reference_x, render_reference_y;
+ int i;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ if (info->antialias == CAIRO_ANTIALIAS_NONE)
+ format = CAIRO_FORMAT_A1;
+ else
+ format = CAIRO_FORMAT_A8;
+ xrender_format = dst->screen->connection->standard_formats[format];
+
+ xtraps = (xcb_render_trapezoid_t *) traps->traps;
+ for (i = 0; i < traps->num_traps; i++) {
+ cairo_trapezoid_t t = traps->traps[i];
+
+ /* top/bottom will be clamped to surface bounds */
+ xtraps[i].top = _cairo_fixed_to_16_16 (t.top);
+ xtraps[i].top -= dst_y << 16;
+ xtraps[i].bottom = _cairo_fixed_to_16_16 (t.bottom);
+ xtraps[i].bottom -= dst_y << 16;
+
+ /* 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.
+ */
+ if (unlikely (_line_exceeds_16_16 (&t.left))) {
+ _project_line_x_onto_16_16 (&t.left,
+ t.top,
+ t.bottom,
+ &xtraps[i].left);
+ xtraps[i].left.p1.y = xtraps[i].top;
+ xtraps[i].left.p2.y = xtraps[i].bottom;
+ } else {
+ xtraps[i].left.p1.x = _cairo_fixed_to_16_16 (t.left.p1.x);
+ xtraps[i].left.p1.y = _cairo_fixed_to_16_16 (t.left.p1.y);
+ xtraps[i].left.p2.x = _cairo_fixed_to_16_16 (t.left.p2.x);
+ xtraps[i].left.p2.y = _cairo_fixed_to_16_16 (t.left.p2.y);
+ }
+ xtraps[i].left.p1.x -= dst_x << 16;
+ xtraps[i].left.p1.y -= dst_y << 16;
+ xtraps[i].left.p2.x -= dst_x << 16;
+ xtraps[i].left.p2.y -= dst_y << 16;
+
+ if (unlikely (_line_exceeds_16_16 (&t.right))) {
+ _project_line_x_onto_16_16 (&t.right,
+ t.top,
+ t.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 (t.right.p1.x);
+ xtraps[i].right.p1.y = _cairo_fixed_to_16_16 (t.right.p1.y);
+ xtraps[i].right.p2.x = _cairo_fixed_to_16_16 (t.right.p2.x);
+ xtraps[i].right.p2.y = _cairo_fixed_to_16_16 (t.right.p2.y);
+ }
+ xtraps[i].right.p1.x -= dst_x << 16;
+ xtraps[i].right.p1.y -= dst_y << 16;
+ xtraps[i].right.p2.x -= dst_x << 16;
+ xtraps[i].right.p2.y -= dst_y << 16;
+ }
+
+ if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
+ render_reference_x = xtraps[0].left.p1.x >> 16;
+ render_reference_y = xtraps[0].left.p1.y >> 16;
+ } else {
+ render_reference_x = xtraps[0].left.p2.x >> 16;
+ render_reference_y = xtraps[0].left.p2.y >> 16;
+ }
+
+ _cairo_xcb_connection_render_trapezoids (dst->connection,
+ _render_operator (op),
+ src->picture,
+ dst->picture,
+ xrender_format,
+ src->x + render_reference_x,
+ src->y + render_reference_y,
+ traps->num_traps, xtraps);
+
+ cairo_surface_destroy (&src->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* low-level composite driver */
+
+typedef cairo_status_t
+(*xcb_draw_func_t) (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region);
+
+static cairo_xcb_surface_t *
+_create_composite_mask (cairo_clip_t *clip,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t*extents)
+{
+ cairo_xcb_surface_t *surface;
+ cairo_bool_t clip_surface = FALSE;
+ cairo_status_t status;
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (! _cairo_status_is_error (status));
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ surface = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
+ extents->width, extents->height);
+ if (unlikely (surface->base.status))
+ return surface;
+
+ _cairo_xcb_surface_ensure_picture (surface);
+
+ if (surface->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+ xcb_render_color_t clear;
+ xcb_rectangle_t xrect;
+
+ clear.red = clear.green = clear.blue = clear.alpha = 0;
+
+ xrect.x = xrect.y = 0;
+ xrect.width = extents->width;
+ xrect.height = extents->height;
+
+ _cairo_xcb_connection_render_fill_rectangles (surface->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ surface->picture,
+ clear, 1, &xrect);
+ } else {
+ status = _cairo_xcb_surface_render_paint (surface,
+ CAIRO_OPERATOR_CLEAR,
+ &_cairo_pattern_clear.base,
+ NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+ }
+ }
+
+ /* Is it worth setting the clip region here? */
+ status = draw_func (draw_closure, surface,
+ CAIRO_OPERATOR_ADD, NULL,
+ extents->x, extents->y,
+ extents, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+ }
+
+ if (clip_surface) {
+ status = _cairo_clip_combine_with_surface (clip, &surface->base,
+ extents->x, extents->y);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+ }
+ }
+
+ return surface;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+_clip_and_composite_with_mask (cairo_clip_t *clip,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t*extents)
+{
+ cairo_xcb_surface_t *mask;
+ cairo_xcb_picture_t *src;
+
+ mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ if (pattern != NULL || dst->base.content != CAIRO_CONTENT_ALPHA) {
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status)) {
+ cairo_surface_destroy (&mask->base);
+ return src->base.status;
+ }
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ cairo_surface_destroy (&src->base);
+ } else {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ mask->picture,
+ XCB_NONE,
+ dst->picture,
+ 0, 0,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+ cairo_surface_destroy (&mask->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+_clip_and_composite_combine (cairo_clip_t *clip,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t*extents)
+{
+ cairo_xcb_surface_t *tmp;
+ cairo_surface_t *clip_surface;
+ xcb_render_picture_t clip_picture;
+ cairo_status_t status;
+
+ tmp = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (dst, dst->base.content,
+ extents->width, extents->height);
+ if (unlikely (tmp->base.status))
+ return tmp->base.status;
+
+ _cairo_xcb_surface_ensure_picture (tmp);
+
+ if (pattern == NULL) {
+ status = (*draw_func) (draw_closure, tmp,
+ CAIRO_OPERATOR_ADD, NULL,
+ extents->x, extents->y,
+ extents, NULL);
+ } else {
+ /* Initialize the temporary surface from the destination surface */
+ if (! dst->base.is_clear ||
+ (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) == 0)
+ {
+ /* XCopyArea may actually be quicker here.
+ * A good driver should translate if appropriate.
+ */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ dst->picture,
+ XCB_NONE,
+ tmp->picture,
+ extents->x, extents->y,
+ 0, 0,
+ 0, 0,
+ extents->width, extents->height);
+ }
+ else
+ {
+ xcb_render_color_t clear;
+ xcb_rectangle_t xrect;
+
+ clear.red = clear.green = clear.blue = clear.alpha = 0;
+
+ xrect.x = xrect.y = 0;
+ xrect.width = extents->width;
+ xrect.height = extents->height;
+
+ _cairo_xcb_connection_render_fill_rectangles (dst->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ dst->picture,
+ clear, 1, &xrect);
+ }
+
+ status = (*draw_func) (draw_closure, tmp, op, pattern,
+ extents->x, extents->y,
+ extents, NULL);
+ }
+ if (unlikely (status))
+ goto CLEANUP_SURFACE;
+
+ clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (clip_surface->status))
+ goto CLEANUP_SURFACE;
+
+ clip_picture = ((cairo_xcb_surface_t *) clip_surface)->picture;
+ assert (clip_picture != XCB_NONE);
+
+ if (dst->base.is_clear) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ tmp->picture, clip_picture, dst->picture,
+ 0, 0,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ } else {
+ /* Punch the clip out of the destination */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ clip_picture, XCB_NONE, dst->picture,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ /* Now add the two results together */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_ADD,
+ tmp->picture, clip_picture, dst->picture,
+ 0, 0,
+ extents->x - clip->path->extents.x,
+ extents->y - clip->path->extents.y,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+
+ CLEANUP_SURFACE:
+ cairo_surface_destroy (&tmp->base);
+
+ return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+_clip_and_composite_source (cairo_clip_t *clip,
+ const cairo_pattern_t *pattern,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ cairo_xcb_surface_t *dst,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_xcb_surface_t *mask;
+ cairo_xcb_picture_t *src;
+
+ /* Create a surface that is mask IN clip */
+ mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status)) {
+ cairo_surface_destroy (&mask->base);
+ return src->base.status;
+ }
+
+ if (dst->base.is_clear) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_SRC,
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ } else {
+ /* Compute dest' = dest OUT (mask IN clip) */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture,
+ XCB_NONE,
+ dst->picture,
+ 0, 0, 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+
+ /* Now compute (src IN (mask IN clip)) ADD dest' */
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_ADD,
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x, extents->y,
+ extents->width, extents->height);
+ }
+
+ cairo_surface_destroy (&src->base);
+ cairo_surface_destroy (&mask->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+can_reduce_alpha_op (cairo_operator_t op)
+{
+ int iop = op;
+ switch (iop) {
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_SOURCE:
+ case CAIRO_OPERATOR_ADD:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static cairo_bool_t
+reduce_alpha_op (cairo_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
+{
+ return dst->is_clear &&
+ dst->content == CAIRO_CONTENT_ALPHA &&
+ _cairo_pattern_is_opaque_solid (pattern) &&
+ can_reduce_alpha_op (op);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t *dst,
+ const cairo_composite_rectangles_t *rects)
+{
+ xcb_rectangle_t xrects[4];
+ int n;
+
+ if (rects->bounded.width == rects->unbounded.width &&
+ rects->bounded.height == rects->unbounded.height)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ n = 0;
+ /* top */
+ if (rects->bounded.y != rects->unbounded.y) {
+ xrects[n].x = rects->unbounded.x;
+ xrects[n].width = rects->unbounded.width;
+ xrects[n].y = rects->unbounded.y;
+ xrects[n].height = rects->bounded.y - rects->unbounded.y;
+ n++;
+ }
+ /* left */
+ if (rects->bounded.x != rects->unbounded.x) {
+ xrects[n].x = rects->unbounded.x;
+ xrects[n].width = rects->bounded.x - rects->unbounded.x;
+ xrects[n].y = rects->bounded.y;
+ xrects[n].height = rects->bounded.height;
+ n++;
+ }
+ /* right */
+ if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
+ xrects[n].x = rects->bounded.x + rects->bounded.width;
+ xrects[n].width = rects->unbounded.x + rects->unbounded.width - xrects[n].x;
+ xrects[n].y = rects->bounded.y;
+ xrects[n].height = rects->bounded.height;
+ n++;
+ }
+ /* bottom */
+ if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
+ xrects[n].x = rects->unbounded.x;
+ xrects[n].width = rects->unbounded.width;
+ xrects[n].y = rects->bounded.y + rects->bounded.height;
+ xrects[n].height = rects->unbounded.y + rects->unbounded.height - xrects[n].y;
+ n++;
+ }
+
+ if (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+ xcb_render_color_t color;
+
+ color.red = 0;
+ color.green = 0;
+ color.blue = 0;
+ color.alpha = 0;
+
+ _cairo_xcb_connection_render_fill_rectangles (dst->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ dst->picture,
+ color, n, xrects);
+ } else {
+ int i;
+ cairo_xcb_picture_t *src;
+
+ src = _cairo_xcb_transparent_picture (dst);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ for (i = 0; i < n; i++) {
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_CLEAR,
+ src->picture, XCB_NONE, dst->picture,
+ 0, 0,
+ 0, 0,
+ xrects[i].x, xrects[i].y,
+ xrects[i].width, xrects[i].height);
+ }
+ cairo_surface_destroy (&src->base);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst,
+ const cairo_composite_rectangles_t *rects,
+ cairo_clip_t *clip)
+{
+ cairo_xcb_surface_t *mask;
+ int mask_x, mask_y;
+
+ mask = (cairo_xcb_surface_t *) _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (mask->base.status))
+ return mask->base.status;
+
+ mask_x = - clip->path->extents.x;
+ mask_y = - clip->path->extents.y;
+
+ /* top */
+ if (rects->bounded.y != rects->unbounded.y) {
+ int x = rects->unbounded.x;
+ int y = rects->unbounded.y;
+ int width = rects->unbounded.width;
+ int height = rects->bounded.y - y;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* left */
+ if (rects->bounded.x != rects->unbounded.x) {
+ int x = rects->unbounded.x;
+ int y = rects->bounded.y;
+ int width = rects->bounded.x - x;
+ int height = rects->bounded.height;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* right */
+ if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
+ int x = rects->bounded.x + rects->bounded.width;
+ int y = rects->bounded.y;
+ int width = rects->unbounded.x + rects->unbounded.width - x;
+ int height = rects->bounded.height;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ /* bottom */
+ if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
+ int x = rects->unbounded.x;
+ int y = rects->bounded.y + rects->bounded.height;
+ int width = rects->unbounded.width;
+ int height = rects->unbounded.y + rects->unbounded.height - y;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ XCB_RENDER_PICT_OP_OUT_REVERSE,
+ mask->picture, XCB_NONE, dst->picture,
+ x + mask_x, y + mask_y,
+ 0, 0,
+ x, y,
+ width, height);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst,
+ const cairo_composite_rectangles_t *extents,
+ cairo_region_t *clip_region,
+ cairo_boxes_t *boxes)
+{
+ cairo_boxes_t clear;
+ cairo_box_t box;
+ cairo_status_t status;
+ struct _cairo_boxes_chunk *chunk;
+ int i;
+
+ if (boxes->num_boxes <= 1 && clip_region == NULL)
+ return _cairo_xcb_surface_fixup_unbounded (dst, extents);
+
+ _cairo_boxes_init (&clear);
+
+ box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+ box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+ box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+ box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+ if (clip_region == NULL) {
+ cairo_boxes_t tmp;
+
+ _cairo_boxes_init (&tmp);
+
+ status = _cairo_boxes_add (&tmp, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ tmp.chunks.next = &boxes->chunks;
+ tmp.num_boxes += boxes->num_boxes;
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+
+ tmp.chunks.next = NULL;
+ } else {
+ pixman_box32_t *pbox;
+
+ pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+ _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+ status = _cairo_boxes_add (&clear, &box);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+ for (i = 0; i < chunk->count; i++) {
+ status = _cairo_boxes_add (&clear, &chunk->base[i]);
+ if (unlikely (status)) {
+ _cairo_boxes_fini (&clear);
+ return status;
+ }
+ }
+ }
+
+ status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+ CAIRO_FILL_RULE_WINDING,
+ &clear);
+ }
+
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _render_fill_boxes (dst,
+ CAIRO_OPERATOR_CLEAR,
+ CAIRO_COLOR_TRANSPARENT,
+ boxes);
+ }
+
+ _cairo_boxes_fini (&clear);
+
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ xcb_draw_func_t draw_func,
+ void *draw_closure,
+ const cairo_composite_rectangles_t*extents,
+ cairo_clip_t *clip)
+{
+ cairo_status_t status;
+ cairo_region_t *clip_region = NULL;
+ cairo_bool_t need_clip_surface = FALSE;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+ return CAIRO_STATUS_SUCCESS;
+
+ assert (! _cairo_status_is_error (status));
+ need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (dst->connection);
+ return status;
+ }
+
+ _cairo_xcb_surface_ensure_picture (dst);
+
+ if (clip_region != NULL)
+ _cairo_xcb_surface_set_clip_region (dst, clip_region);
+
+ if (reduce_alpha_op (&dst->base, op, src)) {
+ op = CAIRO_OPERATOR_ADD;
+ src = NULL;
+ }
+
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ status = _clip_and_composite_source (clip, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ } else {
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ op = CAIRO_OPERATOR_DEST_OUT;
+ src = NULL;
+ }
+
+ if (need_clip_surface) {
+ if (extents->is_bounded) {
+ status = _clip_and_composite_with_mask (clip, op, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ } else {
+ status = _clip_and_composite_combine (clip, op, src,
+ draw_func, draw_closure,
+ dst, &extents->bounded);
+ }
+ } else {
+ status = draw_func (draw_closure,
+ dst, op, src,
+ 0, 0,
+ &extents->bounded,
+ clip_region);
+ }
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+ if (need_clip_surface)
+ status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, clip);
+ else
+ status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
+ }
+
+ if (clip_region != NULL)
+ _cairo_xcb_surface_clear_clip_region (dst);
+
+ _cairo_xcb_connection_release (dst->connection);
+
+ return status;
+}
+
+static cairo_status_t
+_core_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
+ cairo_status_t status;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (op == CAIRO_OPERATOR_CLEAR)
+ return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes);
+
+ if (op == CAIRO_OPERATOR_OVER) {
+ if (_cairo_pattern_is_opaque (src, &extents->bounded))
+ op = CAIRO_OPERATOR_SOURCE;
+ }
+ if (op != CAIRO_OPERATOR_SOURCE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
+ return _cairo_xcb_surface_core_fill_boxes (dst,
+ &((cairo_solid_pattern_t *) src)->color,
+ boxes);
+ }
+
+ return _cairo_xcb_surface_core_copy_boxes (dst, src, &extents->bounded, boxes);
+}
+
+static cairo_status_t
+_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_bool_t need_clip_mask = FALSE;
+ cairo_region_t *clip_region = NULL;
+ cairo_status_t status;
+
+ /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+ if (antialias != CAIRO_ANTIALIAS_NONE) {
+ if (! boxes->is_pixel_aligned)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+
+ need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ if (need_clip_mask &&
+ (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ status = _cairo_xcb_connection_acquire (dst->connection);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_xcb_connection_take_socket (dst->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (dst->connection);
+ return status;
+ }
+
+ _cairo_xcb_surface_ensure_picture (dst);
+ if (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES && ! need_clip_mask &&
+ (op == CAIRO_OPERATOR_CLEAR || src->type == CAIRO_PATTERN_TYPE_SOLID))
+ {
+ const cairo_color_t *color;
+
+ if (op == CAIRO_OPERATOR_CLEAR)
+ color = CAIRO_COLOR_TRANSPARENT;
+ else
+ color = &((cairo_solid_pattern_t *) src)->color;
+
+ if (! (op == CAIRO_OPERATOR_IN && color->alpha >= 0xff00))
+ status = _render_fill_boxes (dst, op, color, boxes);
+ }
+ else
+ {
+ cairo_surface_pattern_t mask;
+
+ if (need_clip_mask) {
+ cairo_surface_t *clip_surface;
+
+ clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+ if (unlikely (clip_surface->status))
+ return clip_surface->status;
+
+ _cairo_pattern_init_for_surface (&mask, clip_surface);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+ cairo_matrix_init_translate (&mask.base.matrix,
+ -clip->path->extents.x,
+ -clip->path->extents.y);
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ src = NULL;
+ op = CAIRO_OPERATOR_DEST_OUT;
+ }
+ }
+
+ status = _render_composite_boxes (dst, op, src,
+ need_clip_mask ? &mask.base : NULL,
+ &extents->bounded, boxes);
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+ status =
+ _cairo_xcb_surface_fixup_unbounded_boxes (dst, extents,
+ clip_region, boxes);
+ }
+
+ _cairo_xcb_connection_release (dst->connection);
+
+ return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_antialias_t antialias,
+ const cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ composite_traps_info_t info;
+ cairo_status_t status;
+
+ if (boxes->num_boxes == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
+ return _core_boxes (dst, op, src, boxes, antialias, clip, extents);
+
+ /* Use a fast path if the boxes are pixel aligned */
+ status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Otherwise render via a mask and composite in the usual fashion. */
+ status = _cairo_traps_init_boxes (&info.traps, boxes);
+ if (unlikely (status))
+ return status;
+
+ info.antialias = antialias;
+ return _clip_and_composite (dst, op, src,
+ _composite_traps, &info,
+ extents, clip);
+}
+
+static cairo_bool_t
+_mono_edge_is_vertical (const cairo_line_t *line)
+{
+ return _cairo_fixed_integer_round (line->p1.x) == _cairo_fixed_integer_round (line->p2.x);
+}
+
+static cairo_bool_t
+_traps_are_pixel_aligned (cairo_traps_t *traps,
+ cairo_antialias_t antialias)
+{
+ int i;
+
+ if (antialias == CAIRO_ANTIALIAS_NONE) {
+ for (i = 0; i < traps->num_traps; i++) {
+ if (! _mono_edge_is_vertical (&traps->traps[i].left) ||
+ ! _mono_edge_is_vertical (&traps->traps[i].right))
+ {
+ traps->maybe_region = FALSE;
+ return FALSE;
+ }
+ }
+ } else {
+ for (i = 0; i < traps->num_traps; i++) {
+ if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x ||
+ traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
+ ! _cairo_fixed_is_integer (traps->traps[i].top) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].bottom) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) ||
+ ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
+ {
+ traps->maybe_region = FALSE;
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+_boxes_for_traps (cairo_boxes_t *boxes,
+ cairo_traps_t *traps)
+{
+ int i;
+
+ _cairo_boxes_init (boxes);
+
+ boxes->num_boxes = traps->num_traps;
+ boxes->chunks.base = (cairo_box_t *) traps->traps;
+ boxes->chunks.count = traps->num_traps;
+ boxes->chunks.size = traps->num_traps;
+
+ for (i = 0; i < traps->num_traps; i++) {
+ cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+ cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+ cairo_fixed_t y1 = traps->traps[i].top;
+ cairo_fixed_t y2 = traps->traps[i].bottom;
+
+ boxes->chunks.base[i].p1.x = x1;
+ boxes->chunks.base[i].p1.y = y1;
+ boxes->chunks.base[i].p2.x = x2;
+ boxes->chunks.base[i].p2.y = y2;
+
+ if (boxes->is_pixel_aligned) {
+ boxes->is_pixel_aligned =
+ _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
+ _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
+ }
+ }
+}
+
+typedef struct _cairo_xcb_surface_span_renderer {
+ cairo_span_renderer_t base;
+
+ void *spans;
+ unsigned len;
+ unsigned size;
+ uint16_t spans_embedded[1024];
+} cairo_xcb_surface_span_renderer_t;
+
+static cairo_status_t
+_cairo_xcb_surface_span_renderer_accumulate (void *abstract_renderer,
+ int y,
+ int height,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_xcb_surface_span_renderer_t *renderer = abstract_renderer;
+ uint16_t *u16;
+ int len;
+
+ len = 4 * (2 + num_spans);
+ if (renderer->size < renderer->len + len) {
+ char *new_spans;
+
+ do {
+ renderer->size <<= 1;
+ } while (renderer->size < renderer->len + len);
+
+ if (renderer->spans == renderer->spans_embedded) {
+ new_spans = malloc (renderer->size);
+ if (unlikely (new_spans == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ memcpy (new_spans, renderer->spans, renderer->len);
+ } else {
+ new_spans = realloc (renderer->spans, renderer->size);
+ if (unlikely (new_spans == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ renderer->spans = new_spans;
+ }
+
+ u16 = (uint16_t *) ((char *) renderer->spans + renderer->len);
+ *u16++ = y;
+ *u16++ = height;
+ *u16++ = num_spans;
+ *u16++ = 0;
+ while (num_spans--) {
+ *u16++ = spans->x;
+ *u16++ = spans->coverage * 0x0101;
+ spans++;
+ }
+ renderer->len += len;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct {
+ cairo_polygon_t *polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_spans_info_t;
+
+static cairo_status_t
+_composite_spans (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_spans_info_t *info = closure;
+ cairo_xcb_surface_span_renderer_t renderer;
+ cairo_scan_converter_t *converter;
+ cairo_status_t status;
+ cairo_xcb_picture_t *src;
+
+ renderer.base.render_rows = _cairo_xcb_surface_span_renderer_accumulate;
+ renderer.spans = renderer.spans_embedded;
+ renderer.size = ARRAY_LENGTH (renderer.spans_embedded);
+ renderer.len = 0;
+
+ converter = _cairo_tor_scan_converter_create (extents->x,
+ extents->x + extents->width,
+ extents->y,
+ extents->y + extents->height,
+ info->fill_rule);
+ status = converter->add_polygon (converter, info->polygon);
+ if (unlikely (status))
+ goto CLEANUP_RENDERER;
+
+ status = converter->generate (converter, &renderer.base);
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ status = src->base.status;
+ if (unlikely (status))
+ goto CLEANUP_CONVERTER;
+
+ _cairo_xcb_connection_render_spans (dst->connection,
+ dst->picture,
+ _render_operator (op),
+ src->picture,
+ extents->x + src->x, extents->y + src->y,
+ extents->x + dst_x, extents->y + dst_y,
+ extents->width, extents->height,
+ renderer.len >> 1, renderer.spans);
+ cairo_surface_destroy (&src->base);
+
+ CLEANUP_CONVERTER:
+ converter->destroy (converter);
+ CLEANUP_RENDERER:
+ if (renderer.spans != renderer.spans_embedded)
+ free (renderer.spans);
+
+ return status;
+}
+
+static cairo_status_t
+_composite_mask (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ const cairo_pattern_t *mask_pattern = closure;
+ cairo_xcb_picture_t *src, *mask = NULL;
+
+ if (src_pattern != NULL) {
+ src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+ if (unlikely (mask->base.status)) {
+ cairo_surface_destroy (&src->base);
+ return mask->base.status;
+ }
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ src->picture,
+ mask->picture,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ extents->x + mask->x, extents->y + mask->y,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ cairo_surface_destroy (&mask->base);
+ cairo_surface_destroy (&src->base);
+ } else {
+ src = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ _cairo_xcb_connection_render_composite (dst->connection,
+ _render_operator (op),
+ src->picture,
+ XCB_NONE,
+ dst->picture,
+ extents->x + src->x, extents->y + src->y,
+ 0, 0,
+ extents->x - dst_x, extents->y - dst_y,
+ extents->width, extents->height);
+ cairo_surface_destroy (&src->base);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* high level rasteriser -> compositor */
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+ return
+ _cairo_fixed_is_integer (box->p1.x) &&
+ _cairo_fixed_is_integer (box->p1.y) &&
+ _cairo_fixed_is_integer (box->p2.x) &&
+ _cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+ const cairo_composite_rectangles_t *extents,
+ cairo_box_t **boxes,
+ int *num_boxes)
+{
+ cairo_status_t status;
+ const cairo_rectangle_int_t *rect;
+
+ rect = extents->is_bounded ? &extents->bounded: &extents->unbounded;
+
+ if (*clip == NULL)
+ goto EXTENTS;
+
+ status = _cairo_clip_rectangle (*clip, rect);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+ switch ((int) status) {
+ case CAIRO_STATUS_SUCCESS:
+ if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+ *clip = NULL;
+ goto DONE;
+
+ case CAIRO_INT_STATUS_UNSUPPORTED:
+ goto EXTENTS;
+
+ default:
+ return status;
+ }
+
+ EXTENTS:
+ status = CAIRO_STATUS_SUCCESS;
+ _cairo_box_from_rectangle (&(*boxes)[0], rect);
+ *num_boxes = 1;
+ DONE:
+ return status;
+}
+
+static cairo_clip_path_t *
+_clip_get_single_path (cairo_clip_t *clip)
+{
+ cairo_clip_path_t *iter = clip->path;
+ cairo_clip_path_t *path = NULL;
+
+ do {
+ if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
+ if (path != NULL)
+ return FALSE;
+
+ path = iter;
+ }
+ iter = iter->prev;
+ } while (iter != NULL);
+
+ return path;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_boxes_t boxes;
+ cairo_box_t *clip_boxes = boxes.boxes_embedded;
+ cairo_clip_t local_clip;
+ cairo_clip_path_t *clip_path;
+ cairo_bool_t have_clip = FALSE;
+ int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded);
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_composite_rectangles_init_for_paint (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ if (clip != NULL &&
+ extents.is_bounded &&
+ (clip_path = _clip_get_single_path (clip)) != NULL)
+ {
+ status = _cairo_xcb_surface_render_fill (surface, op, source,
+ &clip_path->path,
+ clip_path->fill_rule,
+ clip_path->tolerance,
+ clip_path->antialias,
+ NULL);
+ }
+ else
+ {
+ _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, CAIRO_ANTIALIAS_DEFAULT,
+ &extents, clip);
+ if (clip_boxes != boxes.boxes_embedded)
+ free (clip_boxes);
+ }
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_composite_rectangles_init_for_mask (&extents,
+ surface->width, surface->height,
+ op, source, mask, clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status)) {
+ _cairo_clip_fini (&local_clip);
+ return status;
+ }
+ have_clip = TRUE;
+ }
+
+ status = _clip_and_composite (surface, op, source,
+ _composite_mask, (void *) mask,
+ &extents, clip);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+typedef struct {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+} composite_polygon_info_t;
+
+static cairo_status_t
+_cairo_xcb_surface_render_composite_polygon (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_polygon_t *polygon,
+ cairo_antialias_t antialias,
+ cairo_fill_rule_t fill_rule,
+ cairo_composite_rectangles_t *extents,
+ cairo_clip_t *clip)
+{
+ composite_traps_info_t traps;
+ cairo_bool_t clip_surface = FALSE;
+ cairo_status_t status;
+ cairo_bool_t is_not_empty;
+
+ if (polygon->num_edges == 0) {
+ status = CAIRO_STATUS_SUCCESS;
+
+ if (! extents->is_bounded) {
+ cairo_region_t *clip_region = NULL;
+
+ if (clip != NULL) {
+ status = _cairo_clip_get_region (clip, &clip_region);
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ clip_region = NULL;
+ }
+
+ if (clip_surface == FALSE) {
+ if (clip_region != NULL)
+ _cairo_xcb_surface_set_clip_region (dst, clip_region);
+
+ status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
+
+ if (clip_region != NULL)
+ _cairo_xcb_surface_clear_clip_region (dst);
+ } else {
+ status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
+ extents,
+ clip);
+ }
+ }
+
+ return status;
+ }
+
+ _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
+ is_not_empty = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
+ if (extents->is_bounded && ! is_not_empty)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS) {
+ composite_spans_info_t spans;
+
+ spans.polygon = polygon;
+ spans.fill_rule = CAIRO_FILL_RULE_WINDING;
+ spans.antialias = antialias;
+
+ return _clip_and_composite (dst, op, source,
+ _composite_spans, &spans,
+ extents, clip);
+ }
+
+ _cairo_traps_init (&traps.traps);
+
+ status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+
+ if (clip != NULL) {
+ cairo_region_t *clip_region;
+
+ status = _cairo_clip_get_region (clip, &clip_region);
+ clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ if (traps.traps.has_intersections) {
+ if (traps.traps.is_rectangular)
+ status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ else if (traps.traps.is_rectilinear)
+ status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ else
+ status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+ }
+
+ /* Use a fast path if the trapezoids consist of a simple region,
+ * but we can only do this if we do not have a clip surface, or can
+ * substitute the mask with the clip.
+ */
+ if (traps.traps.maybe_region &&
+ _traps_are_pixel_aligned (&traps.traps, antialias) &&
+ (! clip_surface ||
+ (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
+ {
+ cairo_boxes_t boxes;
+
+ _boxes_for_traps (&boxes, &traps.traps);
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, antialias,
+ extents, clip);
+ }
+ else
+ {
+ /* Otherwise render the trapezoids to a mask and composite in the usual
+ * fashion.
+ */
+ traps.antialias = antialias;
+ status = _clip_and_composite (dst, op, source,
+ _composite_traps, &traps,
+ extents, clip);
+ }
+
+CLEANUP_TRAPS:
+ _cairo_traps_fini (&traps.traps);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_box_t *clip_boxes,
+ int num_boxes,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_polygon_t polygon;
+ cairo_status_t status;
+
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_to_polygon (path,
+ stroke_style,
+ ctm, ctm_inverse,
+ tolerance,
+ &polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
+ &polygon, antialias,
+ CAIRO_FILL_RULE_WINDING,
+ extents, clip);
+ }
+
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+static void
+_clear_image (cairo_surface_t *surface)
+{
+ cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
+ memset (image->data, 0, image->stride * image->height);
+ surface->is_clear = TRUE;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_status_t status;
+ int x, y;
+
+ x = extents->bounded.x;
+ y = extents->bounded.y;
+ image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (image->status))
+ return image->status;
+
+ _clear_image (image);
+
+ status = _cairo_surface_offset_stroke (image, x, y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ path, stroke_style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ NULL);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_surface_pattern_t mask;
+
+ _cairo_pattern_init_for_surface (&mask, image);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+
+ cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+ status = _clip_and_composite (dst, op, source,
+ _composite_mask, (void *) &mask.base,
+ extents, clip);
+ _cairo_pattern_fini (&mask.base);
+ }
+
+ cairo_surface_finish (image);
+ cairo_surface_destroy (image);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_composite_rectangles_init_for_stroke (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ path, style, ctm,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (path->is_rectilinear) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+ style,
+ ctm,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS | CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)) {
+ status = _cairo_xcb_surface_render_stroke_as_polygon (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip, clip_boxes, num_boxes,
+ &extents);
+ } else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
+ status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ have_clip ? &local_clip : NULL,
+ &extents);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t*source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_box_t *clip_boxes,
+ int num_boxes,
+ cairo_composite_rectangles_t *extents)
+{
+ cairo_polygon_t polygon;
+ cairo_status_t status;
+
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
+ &polygon, antialias,
+ fill_rule,
+ extents, clip);
+ }
+
+ _cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_status_t status;
+ int x, y;
+
+ x = extents->bounded.x;
+ y = extents->bounded.y;
+ image = _cairo_xcb_surface_create_similar_image (dst,
+ CAIRO_CONTENT_ALPHA,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (image->status))
+ return image->status;
+
+ _clear_image (image);
+
+ status = _cairo_surface_offset_fill (image, x, y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ path, fill_rule, tolerance, antialias,
+ NULL);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_surface_pattern_t mask;
+
+ _cairo_pattern_init_for_surface (&mask, image);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+
+ cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+ status = _clip_and_composite (dst, op, source,
+ _composite_mask, (void *) &mask.base,
+ extents, clip);
+
+ _cairo_pattern_fini (&mask.base);
+ }
+
+ cairo_surface_finish (image);
+ cairo_surface_destroy (image);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+ int num_boxes = ARRAY_LENGTH (boxes_stack);
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+ CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_composite_rectangles_init_for_fill (&extents,
+ surface->width,
+ surface->height,
+ op, source, path,
+ clip);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+ if (unlikely (status)) {
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+ }
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+ cairo_boxes_t boxes;
+
+ _cairo_boxes_init (&boxes);
+ _cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+ status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+ fill_rule,
+ &boxes);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite_boxes (surface, op, source,
+ &boxes, antialias,
+ &extents, clip);
+ }
+
+ _cairo_boxes_fini (&boxes);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS | CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)) {
+ status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path,
+ fill_rule, tolerance, antialias,
+ clip, clip_boxes, num_boxes,
+ &extents);
+ } else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
+ status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path,
+ fill_rule, tolerance, antialias,
+ have_clip ? &local_clip : NULL,
+ &extents);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+
+ if (clip_boxes != boxes_stack)
+ free (clip_boxes);
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip,
+ const cairo_composite_rectangles_t *extents)
+{
+ cairo_surface_t *image;
+ cairo_content_t content;
+ cairo_status_t status;
+ int x, y;
+
+ content = CAIRO_CONTENT_ALPHA;
+ if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+ content = CAIRO_CONTENT_COLOR_ALPHA;
+
+ x = extents->bounded.x;
+ y = extents->bounded.y;
+ image = _cairo_xcb_surface_create_similar_image (dst, content,
+ extents->bounded.width,
+ extents->bounded.height);
+ if (unlikely (image->status))
+ return image->status;
+
+ _clear_image (image);
+
+ status = _cairo_surface_offset_glyphs (image, x, y,
+ CAIRO_OPERATOR_ADD,
+ &_cairo_pattern_white.base,
+ scaled_font, glyphs, num_glyphs,
+ NULL);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_surface_pattern_t mask;
+
+ _cairo_pattern_init_for_surface (&mask, image);
+ mask.base.filter = CAIRO_FILTER_NEAREST;
+ if (content & CAIRO_CONTENT_COLOR)
+ mask.base.has_component_alpha = TRUE;
+
+ cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+ status = _clip_and_composite (dst, op, source,
+ _composite_mask, (void *) &mask.base,
+ extents, clip);
+
+ _cairo_pattern_fini (&mask.base);
+ }
+
+ cairo_surface_finish (image);
+ cairo_surface_destroy (image);
+
+ return status;
+}
+
+/* Build a struct of the same size of #cairo_glyph_t that can be used both as
+ * an input glyph with double coordinates, and as "working" glyph with
+ * integer from-current-point offsets. */
+typedef union {
+ cairo_glyph_t d;
+ unsigned long index;
+ struct {
+ unsigned long index;
+ int x;
+ int y;
+ } i;
+} cairo_xcb_glyph_t;
+
+/* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */
+COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t) == sizeof (cairo_glyph_t));
+
+typedef struct {
+ cairo_scaled_font_t *font;
+ cairo_xcb_glyph_t *glyphs;
+ int num_glyphs;
+} composite_glyphs_info_t;
+
+static cairo_status_t
+_can_composite_glyphs (cairo_xcb_surface_t *dst,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs)
+{
+ cairo_status_t status;
+ const int max_glyph_size = dst->connection->maximum_request_length - 64;
+ int i;
+
+ /* first scan for oversized glyphs, and fallback in that case */
+ for (i = 0; i < num_glyphs; i++) {
+ cairo_scaled_glyph_t *scaled_glyph;
+ int width, height, len;
+
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[i].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ return status;
+
+ /* XRenderAddGlyph does not handle a glyph surface larger than
+ * the extended maximum XRequest size.
+ */
+ width =
+ _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x - scaled_glyph->bbox.p1.x);
+ height =
+ _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y - scaled_glyph->bbox.p1.y);
+ len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, 32) * height;
+ if (len >= max_glyph_size)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Start a new element for the first glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs
+ * (Xrender limits each element to 252 glyphs, we limit them to 128)
+ *
+ * These same conditions need to be mirrored between
+ * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks
+ */
+#define _start_new_glyph_elt(count, glyph) \
+ (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
+
+/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
+ * enough room for padding */
+typedef struct {
+ uint8_t len;
+ uint8_t pad1;
+ uint16_t pad2;
+ int16_t deltax;
+ int16_t deltay;
+} x_glyph_elt_t;
+#define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
+{
+ return scaled_glyph->surface_private;
+}
+
+static void
+_cairo_xcb_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_xcb_font_glyphset_info_t *glyphset_info)
+{
+ scaled_glyph->surface_private = glyphset_info;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_font_init (cairo_xcb_connection_t *connection,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_xcb_font_t *font_private;
+ int i;
+
+ font_private = malloc (sizeof (cairo_xcb_font_t));
+ if (unlikely (font_private == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ font_private->scaled_font = scaled_font;
+ font_private->connection = _cairo_xcb_connection_reference (connection);
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xcb_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
+ switch (i) {
+ case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
+ case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
+ case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
+ default: ASSERT_NOT_REACHED; break;
+ }
+ glyphset_info->xrender_format = 0;
+ glyphset_info->glyphset = XCB_NONE;
+ glyphset_info->pending_free_glyphs = NULL;
+ }
+
+ scaled_font->surface_private = font_private;
+ scaled_font->surface_backend = &_cairo_xcb_surface_backend;
+
+ cairo_list_add (&font_private->link, &connection->fonts);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_xcb_font_destroy (cairo_xcb_font_t *font)
+{
+ int i;
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ glyphset_info = &font->glyphset_info[i];
+
+ if (glyphset_info->pending_free_glyphs != NULL)
+ free (glyphset_info->pending_free_glyphs);
+ }
+
+ cairo_list_del (&font->link);
+ _cairo_xcb_connection_destroy (font->connection);
+
+ free (font);
+}
+
+void
+_cairo_xcb_font_finish (cairo_xcb_font_t *font)
+{
+ cairo_scaled_font_t *scaled_font;
+
+ scaled_font = font->scaled_font;
+
+ CAIRO_MUTEX_LOCK (scaled_font->mutex);
+ scaled_font->surface_private = NULL;
+ _cairo_scaled_font_reset_cache (scaled_font);
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+
+ _cairo_xcb_font_destroy (font);
+}
+
+void
+_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+{
+ cairo_xcb_font_t *font_private;
+ cairo_xcb_connection_t *connection;
+ cairo_bool_t have_connection;
+ cairo_status_t status;
+ int i;
+
+ font_private = scaled_font->surface_private;
+ if (font_private == NULL)
+ return;
+
+ connection = font_private->connection;
+
+ status = _cairo_xcb_connection_acquire (connection);
+ have_connection = status == CAIRO_STATUS_SUCCESS;
+ if (likely (have_connection))
+ status = _cairo_xcb_connection_take_socket (connection);
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ glyphset_info = &font_private->glyphset_info[i];
+ if (glyphset_info->glyphset && status == CAIRO_STATUS_SUCCESS) {
+ _cairo_xcb_connection_render_free_glyph_set (connection,
+ glyphset_info->glyphset);
+ }
+ }
+
+ if (have_connection)
+ _cairo_xcb_connection_release (connection);
+
+
+ _cairo_xcb_font_destroy (font_private);
+}
+
+static void
+_cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free)
+{
+ _cairo_xcb_connection_render_free_glyphs (connection,
+ to_free->glyphset,
+ to_free->glyph_count,
+ to_free->glyph_indices);
+}
+
+void
+_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_xcb_font_t *font_private;
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ if (scaled_font->finished)
+ return;
+
+ font_private = scaled_font->surface_private;
+ glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
+ if (font_private != NULL && glyphset_info != NULL) {
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+
+ to_free = glyphset_info->pending_free_glyphs;
+ if (to_free != NULL &&
+ to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
+ {
+ _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
+ to_free = glyphset_info->pending_free_glyphs = NULL;
+ }
+
+ if (to_free == NULL) {
+ to_free = malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
+ if (unlikely (to_free == NULL)) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return; /* XXX cannot propagate failure */
+ }
+
+ to_free->glyphset = glyphset_info->glyphset;
+ to_free->glyph_count = 0;
+ glyphset_info->pending_free_glyphs = to_free;
+ }
+
+ to_free->glyph_indices[to_free->glyph_count++] =
+ _cairo_scaled_glyph_index (scaled_glyph);
+ }
+}
+
+static cairo_bool_t
+_native_byte_order_lsb (void)
+{
+ int x = 1;
+
+ return *((char *) &x) == 1;
+}
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
+ cairo_format_t format)
+{
+ cairo_xcb_font_t *font_private;
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+ int glyphset_index;
+
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_ARGB32: glyphset_index = GLYPHSET_INDEX_ARGB32; break;
+ case CAIRO_FORMAT_A8: glyphset_index = GLYPHSET_INDEX_A8; break;
+ case CAIRO_FORMAT_A1: glyphset_index = GLYPHSET_INDEX_A1; break;
+ }
+
+ font_private = scaled_font->surface_private;
+ glyphset_info = &font_private->glyphset_info[glyphset_index];
+ if (glyphset_info->glyphset == XCB_NONE) {
+ cairo_xcb_connection_t *connection = font_private->connection;
+
+ glyphset_info->glyphset = _cairo_xcb_connection_get_xid (font_private->connection);
+ glyphset_info->xrender_format =
+ connection->standard_formats[glyphset_info->format];
+
+ _cairo_xcb_connection_render_create_glyph_set (font_private->connection,
+ glyphset_info->glyphset,
+ glyphset_info->xrender_format);
+ }
+
+ return glyphset_info;
+}
+
+static cairo_bool_t
+_cairo_xcb_glyphset_info_has_pending_free_glyph (
+ cairo_xcb_font_glyphset_info_t *glyphset_info,
+ unsigned long glyph_index)
+{
+ if (glyphset_info->pending_free_glyphs != NULL) {
+ cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+ int i;
+
+ to_free = glyphset_info->pending_free_glyphs;
+ for (i = 0; i < to_free->glyph_count; i++) {
+ if (to_free->glyph_indices[i] == glyph_index) {
+ to_free->glyph_count--;
+ memmove (&to_free->glyph_indices[i],
+ &to_free->glyph_indices[i+1],
+ (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index,
+ cairo_image_surface_t *surface)
+{
+ cairo_xcb_font_t *font_private;
+ int i;
+
+ font_private = scaled_font->surface_private;
+ if (font_private == NULL)
+ return NULL;
+
+ if (surface != NULL) {
+ switch (surface->format) {
+ default:
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_ARGB32: i = GLYPHSET_INDEX_ARGB32; break;
+ case CAIRO_FORMAT_A8: i = GLYPHSET_INDEX_A8; break;
+ case CAIRO_FORMAT_A1: i = GLYPHSET_INDEX_A1; break;
+ }
+
+ if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
+ &font_private->glyphset_info[i],
+ glyph_index))
+ {
+ return &font_private->glyphset_info[i];
+ }
+ } else {
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
+ &font_private->glyphset_info[i],
+ glyph_index))
+ {
+ return &font_private->glyphset_info[i];
+ }
+ }
+ }
+
+ return NULL;
+}
+static cairo_status_t
+_cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
+ cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t **scaled_glyph_out)
+{
+ xcb_render_glyphinfo_t glyph_info;
+ uint32_t glyph_index;
+ uint8_t *data;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out;
+ cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
+ cairo_bool_t already_had_glyph_surface;
+ cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+ glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
+
+ /* check to see if we have a pending XRenderFreeGlyph for this glyph */
+ glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
+ if (glyphset_info != NULL) {
+ _cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (glyph_surface == NULL) {
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS |
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ scaled_glyph_out);
+ if (unlikely (status))
+ return status;
+
+ scaled_glyph = *scaled_glyph_out;
+ glyph_surface = scaled_glyph->surface;
+ already_had_glyph_surface = FALSE;
+ } else {
+ already_had_glyph_surface = TRUE;
+ }
+
+ if (scaled_font->surface_private == NULL) {
+ status = _cairo_xcb_surface_font_init (connection, scaled_font);
+ if (unlikely (status))
+ return status;
+ }
+
+ glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (scaled_font,
+ glyph_surface->format);
+
+ /* 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_surface_t *tmp_surface;
+
+ tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
+ status = tmp_surface->status;
+ if (unlikely (status))
+ goto BAIL;
+
+ 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 the glyph format does not match the font format, then we
+ * create a temporary surface for the glyph image with the font's
+ * format.
+ */
+ if (glyph_surface->format != glyphset_info->format) {
+ glyph_surface = _cairo_image_surface_coerce (glyph_surface,
+ glyphset_info->format);
+ status = glyph_surface->base.status;
+ if (unlikely (status))
+ goto BAIL;
+ }
+
+ /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
+ glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
+ glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
+ glyph_info.width = glyph_surface->width;
+ glyph_info.height = glyph_surface->height;
+ glyph_info.x_off = scaled_glyph->x_advance;
+ glyph_info.y_off = scaled_glyph->y_advance;
+
+ data = glyph_surface->data;
+
+ /* flip formats around */
+ switch (scaled_glyph->surface->format) {
+ case CAIRO_FORMAT_A1:
+ /* local bitmaps are always stored with bit == byte */
+ if (_native_byte_order_lsb() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+ int c = glyph_surface->stride * glyph_surface->height;
+ const uint8_t *d;
+ uint8_t *new, *n;
+
+ new = malloc (c);
+ if (unlikely (new == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+
+ n = new;
+ d = data;
+ do {
+ uint8_t b = *d++;
+ b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
+ b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
+ b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
+ *n++ = b;
+ } while (--c);
+ data = new;
+ }
+ break;
+
+ case CAIRO_FORMAT_A8:
+ break;
+
+ case CAIRO_FORMAT_ARGB32:
+ if (_native_byte_order_lsb() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+ unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
+ const uint32_t *d;
+ uint32_t *new, *n;
+
+ new = malloc (4 * c);
+ if (unlikely (new == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+
+ n = new;
+ d = (uint32_t *) data;
+ do {
+ *n++ = bswap_32 (*d);
+ d++;
+ } while (--c);
+ data = (uint8_t *) new;
+ }
+ break;
+
+ case CAIRO_FORMAT_RGB24:
+ default:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ /* XXX assume X server wants pixman padding. Xft assumes this as well */
+
+ _cairo_xcb_connection_render_add_glyphs (connection,
+ glyphset_info->glyphset,
+ 1, &glyph_index, &glyph_info,
+ glyph_surface->stride * glyph_surface->height,
+ data);
+
+ if (data != glyph_surface->data)
+ free (data);
+
+ _cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+
+ BAIL:
+ if (glyph_surface != scaled_glyph->surface)
+ cairo_surface_destroy (&glyph_surface->base);
+
+ /* If the scaled glyph didn't already have a surface attached
+ * to it, release the created surface now that we have it
+ * uploaded to the X server. If the surface has already been
+ * there (e.g. because image backend requested it), leave it in
+ * the cache
+ */
+ if (! already_had_glyph_surface)
+ _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
+
+ return status;
+}
+
+typedef void (*cairo_xcb_render_composite_text_func_t)
+ (cairo_xcb_connection_t *connection,
+ uint8_t op,
+ xcb_render_picture_t src,
+ xcb_render_picture_t dst,
+ xcb_render_pictformat_t mask_format,
+ xcb_render_glyphset_t glyphset,
+ int16_t src_x,
+ int16_t src_y,
+ uint32_t len,
+ uint8_t *cmd);
+
+
+static cairo_status_t
+_emit_glyphs_chunk (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ cairo_xcb_picture_t *src,
+ /* info for this chunk */
+ cairo_xcb_glyph_t *glyphs,
+ int num_glyphs,
+ int width,
+ int estimated_req_size,
+ cairo_xcb_font_glyphset_info_t *glyphset_info)
+{
+ cairo_xcb_render_composite_text_func_t composite_text_func;
+ uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE];
+ uint8_t *buf = stack_buf;
+ x_glyph_elt_t *elt = NULL; /* silence compiler */
+ uint32_t len;
+ int i;
+
+ if (estimated_req_size > ARRAY_LENGTH (stack_buf)) {
+ buf = malloc (estimated_req_size);
+ if (unlikely (buf == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ len = 0;
+ for (i = 0; i < num_glyphs; i++) {
+ if (_start_new_glyph_elt (i, &glyphs[i])) {
+ if (len & 3)
+ len += 4 - (len & 3);
+
+ elt = (x_glyph_elt_t *) (buf + len);
+ elt->len = 0;
+ elt->deltax = glyphs[i].i.x;
+ elt->deltay = glyphs[i].i.y;
+ len += sizeof (x_glyph_elt_t);
+ }
+
+ switch (width) {
+ case 1: *(uint8_t *) (buf + len) = glyphs[i].index; break;
+ case 2: *(uint16_t *) (buf + len) = glyphs[i].index; break;
+ default:
+ case 4: *(uint32_t *) (buf + len) = glyphs[i].index; break;
+ }
+ len += width;
+ elt->len++;
+ }
+ if (len & 3)
+ len += 4 - (len & 3);
+
+ switch (width) {
+ case 1:
+ composite_text_func = _cairo_xcb_connection_render_composite_glyphs_8;
+ break;
+ case 2:
+ composite_text_func = _cairo_xcb_connection_render_composite_glyphs_16;
+ break;
+ default:
+ case 4:
+ composite_text_func = _cairo_xcb_connection_render_composite_glyphs_32;
+ break;
+ }
+ composite_text_func (dst->connection,
+ _render_operator (op),
+ src->picture,
+ dst->picture,
+ glyphset_info->xrender_format,
+ glyphset_info->glyphset,
+ src->x + glyphs[0].i.x,
+ src->y + glyphs[0].i.y,
+ len, buf);
+
+ if (buf != stack_buf)
+ free (buf);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_composite_glyphs (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern,
+ int dst_x, int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_region_t *clip_region)
+{
+ composite_glyphs_info_t *info = closure;
+ cairo_scaled_glyph_t *glyph_cache[64];
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_fixed_t x = 0, y = 0;
+ cairo_xcb_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
+ const unsigned int max_request_size = dst->connection->maximum_request_length - 64;
+ cairo_xcb_picture_t *src;
+
+ unsigned long max_index = 0;
+ int width = 1;
+
+ unsigned int request_size = 0;
+ int i;
+
+ src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+ if (unlikely (src->base.status))
+ return src->base.status;
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+
+ for (i = 0; i < info->num_glyphs; i++) {
+ cairo_scaled_glyph_t *scaled_glyph;
+ unsigned long glyph_index = info->glyphs[i].index;
+ int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+ int old_width = width;
+ int this_x, this_y;
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ {
+ status = _cairo_scaled_glyph_lookup (info->font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ return status;
+
+ /* Send unseen glyphs to the server */
+ if (_cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
+ status = _cairo_xcb_surface_add_glyph (dst->connection,
+ info->font,
+ &scaled_glyph);
+ if (unlikely (status))
+ return status;
+ }
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ /* Glyph skipping:
+ *
+ * We skip any glyphs that have troublesome coordinates. We want
+ * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
+ * a signed 16bit integer, otherwise it will overflow in the render
+ * protocol.
+ * To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
+ * a signed 15bit integer. The trivial option would be to allow
+ * coordinates -8192..8192, but that's kinda dull. It probably will
+ * take a decade or so to get monitors 8192x4096 or something. A
+ * negative value of -8192 on the other hand, is absolutely useless.
+ * Note that we do want to allow some negative positions. The glyph
+ * may start off the screen but part of it make it to the screen.
+ * Anyway, we will allow positions in the range -4096..122887. That
+ * will buy us a few more years before this stops working.
+ */
+ this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x;
+ this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y;
+ assert (! (((this_x+4096) | (this_y+4096)) & ~0x3fffu));
+
+ this_glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
+ if (glyphset_info == NULL)
+ glyphset_info = this_glyphset_info;
+
+ /* Update max glyph index */
+ if (glyph_index > max_index) {
+ max_index = glyph_index;
+ if (max_index >= 65536)
+ width = 4;
+ else if (max_index >= 256)
+ width = 2;
+ if (width != old_width)
+ request_size += (width - old_width) * i;
+ }
+
+ /* If we will pass the max request size by adding this glyph,
+ * flush current glyphs. Note that we account for a
+ * possible element being added below.
+ *
+ * Also flush if changing glyphsets, as Xrender limits one mask
+ * format per request, so we can either break up, or use a
+ * wide-enough mask format. We do the former. One reason to
+ * prefer the latter is the fact that Xserver ADDs all glyphs
+ * to the mask first, and then composes that to final surface,
+ * though it's not a big deal.
+ */
+ if (request_size + width > max_request_size - _cairo_sz_x_glyph_elt_t ||
+ this_glyphset_info != glyphset_info)
+ {
+ status = _emit_glyphs_chunk (dst, op, src,
+ info->glyphs, i,
+ old_width, request_size,
+ glyphset_info);
+ if (unlikely (status))
+ return status;
+
+ info->glyphs += i;
+ info->num_glyphs -= i;
+ i = 0;
+
+ max_index = info->glyphs[0].index;
+ width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
+
+ request_size = 0;
+
+ x = y = 0;
+ glyphset_info = this_glyphset_info;
+ }
+
+ /* Convert absolute glyph position to relative-to-current-point
+ * position */
+ info->glyphs[i].i.x = this_x - x;
+ info->glyphs[i].i.y = this_y - y;
+
+ /* Start a new element for the first glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs.
+ *
+ * These same conditions are mirrored in _emit_glyphs_chunk().
+ */
+ if (_start_new_glyph_elt (i, &info->glyphs[i]))
+ request_size += _cairo_sz_x_glyph_elt_t;
+
+ /* adjust current-position */
+ x = this_x + scaled_glyph->x_advance;
+ y = this_y + scaled_glyph->y_advance;
+
+ request_size += width;
+ }
+
+ if (i) {
+ status = _emit_glyphs_chunk (dst, op, src,
+ info->glyphs, i,
+ width, request_size,
+ glyphset_info);
+ }
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_clip_t *clip)
+{
+ cairo_composite_rectangles_t extents;
+ cairo_clip_t local_clip;
+ cairo_bool_t have_clip = FALSE;
+ cairo_status_t status;
+
+ if (unlikely (! _operator_is_supported (surface->flags, op)))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+ surface->width,
+ surface->height,
+ op, source,
+ scaled_font,
+ glyphs, num_glyphs,
+ clip, NULL);
+ if (unlikely (status))
+ return status;
+
+ if (_cairo_clip_contains_rectangle (clip, &extents))
+ clip = NULL;
+
+ if (clip != NULL) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ have_clip = TRUE;
+ }
+
+ if (clip != NULL && extents.is_bounded) {
+ clip = _cairo_clip_init_copy (&local_clip, clip);
+ status = _cairo_clip_rectangle (clip, &extents.bounded);
+ if (unlikely (status)) {
+ _cairo_clip_fini (&local_clip);
+ return status;
+ }
+ have_clip = TRUE;
+ }
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) {
+ _cairo_scaled_font_freeze_cache (scaled_font);
+
+ status = _can_composite_glyphs (surface, scaled_font, glyphs, num_glyphs);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ composite_glyphs_info_t info;
+
+ info.font = scaled_font;
+ info.glyphs = (cairo_xcb_glyph_t *) glyphs;
+ info.num_glyphs = num_glyphs;
+
+ status = _clip_and_composite (surface, op, source,
+ _composite_glyphs, &info,
+ &extents, clip);
+ }
+
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ }
+
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ assert (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE);
+ status =
+ _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source,
+ scaled_font, glyphs, num_glyphs,
+ have_clip ? &local_clip : NULL,
+ &extents);
+ }
+
+ if (have_clip)
+ _cairo_clip_fini (&local_clip);
+
+ return status;
+}
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 666abc994..2e08c6419 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -31,308 +32,215 @@
* California.
*
* Contributor(s):
+ * Behdad Esfahbod <behdad@behdad.org>
* Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
*/
#include "cairoint.h"
-#include "cairo-xcb.h"
-#include "cairo-xcb-xrender.h"
-#include "cairo-clip-private.h"
-#include "cairo-error-private.h"
-#include "cairo-freelist-private.h"
-#include "cairo-list-private.h"
-#include <xcb/xcb_renderutil.h>
-
-#define AllPlanes ((unsigned long)~0L)
-
-slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
-
-/*
- * 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
- */
-
-#define CAIRO_ASSUME_PIXMAP 20
-typedef struct cairo_xcb_surface {
- cairo_surface_t base;
-
- xcb_connection_t *dpy;
- xcb_screen_t *screen;
-
- xcb_gcontext_t gc;
- xcb_drawable_t drawable;
- cairo_bool_t owns_pixmap;
- xcb_visualtype_t *visual;
-
- int use_pixmap;
-
- int render_major;
- int render_minor;
-
- int width;
- int height;
- int depth;
-
- cairo_bool_t have_clip_rects;
- xcb_rectangle_t *clip_rects;
- int num_clip_rects;
- cairo_region_t *clip_region;
-
- xcb_render_picture_t src_picture, dst_picture;
- xcb_render_pictforminfo_t xrender_format;
-
- cairo_list_t to_be_checked;
- cairo_freepool_t cookie_pool;
-} cairo_xcb_surface_t;
-
-typedef struct _cairo_xcb_cookie {
- cairo_list_t link;
- xcb_void_cookie_t xcb;
-} cairo_xcb_cookie_t;
-
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
- (((surface)->render_major > major) || \
- (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+#include "cairo-xcb.h"
+#include "cairo-xcb-private.h"
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+#include <xcb/dri2.h>
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+#define AllPlanes ((unsigned) -1)
+#define CAIRO_ASSUME_PIXMAP 20
+#define XLIB_COORD_MAX 32767
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_proto (cairo_xcb_surface_create);
+slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
+slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
+#endif
-#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)
-#define CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
-#define CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+#include "drm/cairo-drm-private.h"
+#endif
static cairo_status_t
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
-
-static int
-_CAIRO_FORMAT_DEPTH (cairo_format_t format)
+_cairo_xcb_surface_create_similar_shm (cairo_xcb_surface_t *other,
+ pixman_format_code_t pixman_format,
+ int width, int height,
+ cairo_surface_t **out)
{
- switch (format) {
- case CAIRO_FORMAT_A1:
- return 1;
- case CAIRO_FORMAT_A8:
- return 8;
- case CAIRO_FORMAT_RGB24:
- return 24;
- case CAIRO_FORMAT_ARGB32:
- default:
- return 32;
- }
-}
+ size_t size, stride;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_status_t status;
+ cairo_surface_t *image;
-static cairo_status_t
-_cairo_xcb_add_cookie_to_be_checked (cairo_xcb_surface_t *surface,
- xcb_void_cookie_t xcb)
-{
- cairo_xcb_cookie_t *cookie;
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+ size = stride * height;
+ if (size < CAIRO_XCB_SHM_SMALL_IMAGE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- cookie = _cairo_freepool_alloc (&surface->cookie_pool);
- if (unlikely (cookie == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ status = _cairo_xcb_connection_allocate_shm_info (other->connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
+
+ image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ pixman_format,
+ width, height,
+ stride);
+ status = image->status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
- cookie->xcb = xcb;
- cairo_list_add_tail (&cookie->link, &surface->to_be_checked);
+ status = _cairo_user_data_array_set_data (&image->user_data,
+ (const cairo_user_data_key_t *) other->connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
+ }
+ *out = image;
return CAIRO_STATUS_SUCCESS;
}
-static xcb_render_pictforminfo_t *
-_CAIRO_FORMAT_TO_XRENDER_FORMAT(xcb_connection_t *dpy, cairo_format_t format)
+cairo_surface_t *
+_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
+ cairo_content_t content,
+ int width, int height)
{
- xcb_pict_standard_t std_format;
- switch (format) {
- case CAIRO_FORMAT_A1:
- std_format = XCB_PICT_STANDARD_A_1; break;
- case CAIRO_FORMAT_A8:
- std_format = XCB_PICT_STANDARD_A_8; break;
- case CAIRO_FORMAT_RGB24:
- std_format = XCB_PICT_STANDARD_RGB_24; break;
- case CAIRO_FORMAT_ARGB32:
+ cairo_surface_t *image = NULL;
+ pixman_format_code_t pixman_format;
+
+ /* XXX choose pixman_format from connection->image_formats */
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ pixman_format = PIXMAN_a8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
default:
- std_format = XCB_PICT_STANDARD_ARGB_32; break;
+ ASSERT_NOT_REACHED;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
}
- return xcb_render_util_find_standard_format (xcb_render_util_query_formats (dpy), std_format);
-}
-static cairo_content_t
-_xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format)
-{
- cairo_bool_t xrender_format_has_alpha;
- cairo_bool_t xrender_format_has_color;
-
- /* This only happens when using a non-Render server. Let's punt
- * and say there's no alpha here. */
- if (xrender_format == NULL)
- return CAIRO_CONTENT_COLOR;
-
- xrender_format_has_alpha = (xrender_format->direct.alpha_mask != 0);
- xrender_format_has_color = (xrender_format->direct.red_mask != 0 ||
- xrender_format->direct.green_mask != 0 ||
- xrender_format->direct.blue_mask != 0);
-
- if (xrender_format_has_alpha)
- if (xrender_format_has_color)
- return CAIRO_CONTENT_COLOR_ALPHA;
- else
- return CAIRO_CONTENT_ALPHA;
- else
- return CAIRO_CONTENT_COLOR;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
-{
- if (surface->have_clip_rects) {
- xcb_void_cookie_t cookie;
+ if (other->flags & CAIRO_XCB_HAS_SHM) {
+ cairo_status_t status;
- cookie = xcb_set_clip_rectangles_checked (surface->dpy,
- XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
- 0, 0,
- surface->num_clip_rects,
- surface->clip_rects);
+ status = _cairo_xcb_surface_create_similar_shm (other,
+ pixman_format,
+ width, height,
+ &image);
+ if (_cairo_status_is_error (status))
+ return _cairo_surface_create_in_error (status);
+ }
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ if (image == NULL) {
+ image = _cairo_image_surface_create_with_pixman_format (NULL,
+ pixman_format,
+ width, height,
+ 0);
}
- return CAIRO_STATUS_SUCCESS;
+ return image;
}
-static cairo_status_t
-_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
+cairo_surface_t *
+_cairo_xcb_surface_create_similar (void *abstract_other,
+ cairo_content_t content,
+ int width,
+ int height)
{
- if (surface->have_clip_rects) {
- xcb_void_cookie_t cookie;
+ cairo_xcb_surface_t *other = abstract_other;
+ cairo_xcb_surface_t *surface;
+ cairo_xcb_connection_t *connection;
+ xcb_pixmap_t pixmap;
+ cairo_status_t status;
- cookie = xcb_render_set_picture_clip_rectangles_checked (surface->dpy,
- surface->dst_picture,
- 0, 0,
- surface->num_clip_rects,
- surface->clip_rects);
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return NULL;
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
- }
+ if (width <= 0 || height <= 0)
+ return NULL;
- return CAIRO_STATUS_SUCCESS;
-}
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+ if (other->drm != NULL) {
+ cairo_surface_t *drm;
-static cairo_status_t
-_cairo_xcb_surface_set_clip_region (void *abstract_surface,
- cairo_region_t *region)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
+ drm = _cairo_drm_surface_create_similar (other->drm, content, width, height);
+ if (drm != NULL)
+ return drm;
+ }
+#endif
- if (region == surface->clip_region)
- return CAIRO_STATUS_SUCCESS;
+ if ((other->flags & CAIRO_XCB_HAS_RENDER) == 0)
+ return _cairo_xcb_surface_create_similar_image (other, content, width, height);
- cairo_region_destroy (surface->clip_region);
- region = cairo_region_reference (region);
+ connection = other->connection;
+ status = _cairo_xcb_connection_acquire (connection);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
- if (surface->clip_rects) {
- free (surface->clip_rects);
- surface->clip_rects = NULL;
+ status =_cairo_xcb_connection_take_socket (connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (connection);
+ return _cairo_surface_create_in_error (status);
}
- surface->have_clip_rects = FALSE;
- surface->num_clip_rects = 0;
-
- if (region == NULL) {
- uint32_t none[] = { XCB_NONE };
- if (surface->gc)
- xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
+ if (content == other->base.content) {
+ pixmap = _cairo_xcb_connection_create_pixmap (connection,
+ other->depth,
+ other->drawable,
+ width, height);
- if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
- xcb_render_change_picture (surface->dpy, surface->dst_picture,
- XCB_RENDER_CP_CLIP_MASK, none);
+ surface = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_internal (other->screen,
+ pixmap, TRUE,
+ other->pixman_format,
+ other->xrender_format,
+ width, height);
} else {
- xcb_rectangle_t *rects = NULL;
- int n_rects, i;
-
- n_rects = cairo_region_num_rectangles (region);
-
- if (n_rects > 0) {
- rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
- if (rects == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- } else {
- rects = NULL;
- }
-
- 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;
+ cairo_format_t format;
+ pixman_format_code_t pixman_format;
+
+ /* XXX find a compatible xrender format */
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ pixman_format = PIXMAN_a8;
+ format = CAIRO_FORMAT_A8;
+ break;
+ case CAIRO_CONTENT_COLOR:
+ pixman_format = PIXMAN_x8r8g8b8;
+ format = CAIRO_FORMAT_RGB24;
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ pixman_format = PIXMAN_a8r8g8b8;
+ format = CAIRO_FORMAT_ARGB32;
+ break;
}
- surface->have_clip_rects = TRUE;
- surface->clip_rects = rects;
- surface->num_clip_rects = n_rects;
-
- if (surface->gc)
- _cairo_xcb_surface_set_gc_clip_rects (surface);
-
- if (surface->dst_picture)
- _cairo_xcb_surface_set_picture_clip_rects (surface);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_surface_t *
-_cairo_xcb_surface_create_similar (void *abstract_src,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_xcb_surface_t *src = abstract_src;
- xcb_connection_t *dpy = src->dpy;
- xcb_pixmap_t pixmap;
- cairo_xcb_surface_t *surface;
- cairo_format_t format = _cairo_format_from_content (content);
- xcb_render_pictforminfo_t *xrender_format;
+ pixmap = _cairo_xcb_connection_create_pixmap (connection,
+ PIXMAN_FORMAT_DEPTH (pixman_format),
+ other->drawable,
+ width, height);
- /* As a good first approximation, if the display doesn't have COMPOSITE,
- * we're better off using image surfaces for all temporary operations
- */
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
- return cairo_image_surface_create (format, width, height);
+ surface = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_internal (other->screen,
+ pixmap, TRUE,
+ pixman_format,
+ connection->standard_formats[format],
+ width, height);
}
- pixmap = xcb_generate_id (dpy);
- xcb_create_pixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
- pixmap, src->drawable,
- width <= 0 ? 1 : width,
- height <= 0 ? 1 : height);
-
- xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, format);
- /* XXX: what to do if xrender_format is null? */
- surface = (cairo_xcb_surface_t *)
- cairo_xcb_surface_create_with_xrender_format (dpy, pixmap, src->screen,
- xrender_format,
- width, height);
- if (surface->base.status)
- return &surface->base;
+ if (unlikely (surface->base.status))
+ _cairo_xcb_connection_free_pixmap (connection, pixmap);
- surface->owns_pixmap = TRUE;
+ _cairo_xcb_connection_release (connection);
return &surface->base;
}
@@ -341,1826 +249,958 @@ static cairo_status_t
_cairo_xcb_surface_finish (void *abstract_surface)
{
cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
- if (surface->dst_picture != XCB_NONE)
- xcb_render_free_picture (surface->dpy, surface->dst_picture);
-
- if (surface->src_picture != XCB_NONE)
- xcb_render_free_picture (surface->dpy, surface->src_picture);
-
- if (surface->owns_pixmap)
- xcb_free_pixmap (surface->dpy, surface->drawable);
+ assert (surface->fallback == NULL);
- if (surface->gc != XCB_NONE)
- xcb_free_gc (surface->dpy, surface->gc);
+ cairo_list_del (&surface->link);
- free (surface->clip_rects);
- cairo_region_destroy (surface->clip_region);
+ if (surface->drm != NULL) {
+ cairo_surface_finish (surface->drm);
+ cairo_surface_destroy (surface->drm);
- _cairo_freepool_fini (&surface->cookie_pool);
+ xcb_dri2_destroy_drawable (surface->connection->xcb_connection,
+ surface->drawable);
+ }
- surface->dpy = NULL;
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+ if (surface->picture != XCB_NONE) {
+ _cairo_xcb_connection_render_free_picture (surface->connection,
+ surface->picture);
+ }
- return CAIRO_STATUS_SUCCESS;
-}
+ if (surface->owns_pixmap)
+ _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable);
+ }
+ _cairo_xcb_connection_release (surface->connection);
+ }
-static int
-_bits_per_pixel(xcb_connection_t *c, int depth)
-{
- xcb_format_t *fmt = xcb_setup_pixmap_formats(xcb_get_setup(c));
- xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(xcb_get_setup(c));
-
- for(; fmt != fmtend; ++fmt)
- if(fmt->depth == depth)
- return fmt->bits_per_pixel;
-
- if(depth <= 4)
- return 4;
- if(depth <= 8)
- return 8;
- if(depth <= 16)
- return 16;
- return 32;
-}
+ _cairo_xcb_connection_destroy (surface->connection);
-static int
-_bytes_per_line(xcb_connection_t *c, int width, int bpp)
-{
- int bitmap_pad = xcb_get_setup(c)->bitmap_format_scanline_pad;
- return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
+ return status;
}
-static cairo_bool_t
-_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
+static void
+_destroy_image (pixman_image_t *image, void *data)
{
- 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;
+ free (data);
}
-static cairo_status_t
-_get_image_surface (cairo_xcb_surface_t *surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect)
+static cairo_int_status_t
+_cairo_xcb_surface_create_shm_image (cairo_xcb_surface_t *target,
+ cairo_image_surface_t **image_out,
+ cairo_xcb_shm_info_t **shm_info_out)
{
cairo_image_surface_t *image;
- xcb_get_image_reply_t *imagerep;
- int bpp, bytes_per_line;
- cairo_rectangle_int_t extents;
- unsigned char *data;
- cairo_format_masks_t masks;
- cairo_format_t format;
-
- extents.x = 0;
- extents.y = 0;
- extents.width = surface->width;
- extents.height = surface->height;
-
- if (interest_rect) {
- if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
- *image_out = NULL;
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- if (image_rect)
- *image_rect = extents;
-
- /* XXX: This should try to use the XShm extension if available */
-
- if (surface->use_pixmap == 0)
- {
- xcb_generic_error_t *error;
-
- imagerep = xcb_get_image_reply (surface->dpy,
- xcb_get_image (surface->dpy,
- XCB_IMAGE_FORMAT_Z_PIXMAP,
- surface->drawable,
- extents.x, extents.y,
- extents.width, extents.height,
- AllPlanes),
- &error);
-
- /* If we get an error, the surface must have been a window,
- * so retry with the safe code path.
- */
- if (error)
- surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
- }
- else
- {
- surface->use_pixmap--;
- imagerep = NULL;
- }
-
- if (!imagerep)
- {
- /* xcb_get_image_t 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
- */
- xcb_pixmap_t pixmap;
- cairo_xcb_cookie_t *cookies[2];
- cairo_status_t status;
-
- status = _cairo_xcb_surface_ensure_gc (surface);
- if (unlikely (status))
- return status;
-
- status = _cairo_freepool_alloc_array (&surface->cookie_pool,
- ARRAY_LENGTH (cookies),
- (void **) cookies);
- if (unlikely (status))
- return status;
-
- pixmap = xcb_generate_id (surface->dpy);
- cookies[0]->xcb = xcb_create_pixmap_checked (surface->dpy,
- surface->depth,
- pixmap,
- surface->drawable,
- extents.width, extents.height);
- cairo_list_add_tail (&cookies[0]->link, &surface->to_be_checked);
-
- cookies[1]->xcb = xcb_copy_area_checked (surface->dpy,
- surface->drawable,
- pixmap, surface->gc,
- extents.x, extents.y,
- 0, 0,
- extents.width, extents.height);
- cairo_list_add_tail (&cookies[1]->link, &surface->to_be_checked);
-
- imagerep = xcb_get_image_reply (surface->dpy,
- xcb_get_image (surface->dpy,
- XCB_IMAGE_FORMAT_Z_PIXMAP,
- pixmap,
- extents.x, extents.y,
- extents.width, extents.height,
- AllPlanes),
- 0);
-
- xcb_free_pixmap (surface->dpy, pixmap);
-
- }
- if (unlikely (imagerep == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_status_t status;
+ size_t size, stride;
- bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
- bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
+ if ((target->flags & CAIRO_XCB_HAS_SHM) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- data = _cairo_malloc_ab (surface->height, bytes_per_line);
- if (data == NULL) {
- free (imagerep);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ stride = CAIRO_STRIDE_FOR_WIDTH_BPP (target->width,
+ PIXMAN_FORMAT_BPP (target->pixman_format));
+ size = stride * target->height;
+ if (size < CAIRO_XCB_SHM_SMALL_IMAGE) {
+ target->flags &= ~CAIRO_XCB_HAS_SHM;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
- memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height);
- free (imagerep);
+ status = _cairo_xcb_connection_allocate_shm_info (target->screen->connection,
+ size, &shm_info);
+ if (unlikely (status))
+ return status;
- /*
- * Compute the pixel format masks from either an xcb_visualtype_t or
- * a xcb_render_pctforminfo_t, 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 = bpp;
- 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->xrender_format.id != XCB_NONE) {
- masks.bpp = bpp;
- masks.red_mask = (unsigned long)surface->xrender_format.direct.red_mask << surface->xrender_format.direct.red_shift;
- masks.green_mask = (unsigned long)surface->xrender_format.direct.green_mask << surface->xrender_format.direct.green_shift;
- masks.blue_mask = (unsigned long)surface->xrender_format.direct.blue_mask << surface->xrender_format.direct.blue_shift;
- masks.alpha_mask = (unsigned long)surface->xrender_format.direct.alpha_mask << surface->xrender_format.direct.alpha_shift;
- } else {
- masks.bpp = bpp;
- 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_t *)
+ _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+ target->pixman_format,
+ target->width,
+ target->height,
+ stride);
+ status = image->base.status;
+ if (unlikely (status)) {
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
}
- /*
- * 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 (data,
- format,
- extents.width,
- extents.height,
- bytes_per_line);
- if (image->base.status)
- goto FAIL;
- } 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.
- */
- ASSERT_NOT_REACHED;
- goto FAIL;
+ status = _cairo_user_data_array_set_data (&image->base.user_data,
+ (const cairo_user_data_key_t *) target->connection,
+ shm_info,
+ (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
+ _cairo_xcb_shm_info_destroy (shm_info);
+ return status;
}
- /* Let the surface take ownership of the data */
- _cairo_image_surface_assume_ownership_of_data (image);
-
*image_out = image;
+ *shm_info_out = shm_info;
return CAIRO_STATUS_SUCCESS;
-
- FAIL:
- free (data);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
static cairo_status_t
-_cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t *surface)
+_get_shm_image (cairo_xcb_surface_t *surface,
+ cairo_image_surface_t **image_out)
{
- if (!surface->src_picture) {
- xcb_void_cookie_t cookie;
+ cairo_image_surface_t *image;
+ cairo_xcb_shm_info_t *shm_info;
+ cairo_status_t status;
- surface->src_picture = xcb_generate_id (surface->dpy);
- cookie = xcb_render_create_picture_checked (surface->dpy,
- surface->src_picture,
- surface->drawable,
- surface->xrender_format.id,
- 0, NULL);
+ status = _cairo_xcb_surface_create_shm_image (surface, &image, &shm_info);
+ if (unlikely (status))
+ return status;
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ if (! surface->base.is_clear) {
+ status = _cairo_xcb_connection_shm_get_image (surface->connection,
+ surface->drawable,
+ 0, 0,
+ surface->width,
+ surface->height,
+ shm_info->shm,
+ shm_info->offset);
+ if (unlikely (status))
+ return status;
+ } else {
+ memset (image->data, 0, image->stride * image->height);
}
+ *image_out = image;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t *surface)
+_get_image (cairo_xcb_surface_t *surface,
+ cairo_bool_t use_shm,
+ cairo_image_surface_t **image_out)
{
- if (!surface->dst_picture) {
- xcb_void_cookie_t cookie;
+ cairo_image_surface_t *image;
+ cairo_xcb_connection_t *connection;
+ xcb_get_image_reply_t *reply;
+ cairo_status_t status;
+
+ connection = surface->connection;
+
+ status = _cairo_xcb_connection_acquire (connection);
+ if (unlikely (status))
+ return status;
- surface->dst_picture = xcb_generate_id (surface->dpy);
- cookie = xcb_render_create_picture_checked (surface->dpy,
- surface->dst_picture,
- surface->drawable,
- surface->xrender_format.id,
- 0, NULL);
+ status = _cairo_xcb_connection_take_socket (connection);
+ if (unlikely (status))
+ goto FAIL;
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ if (use_shm) {
+ status = _get_shm_image (surface, image_out);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto FAIL;
}
- return CAIRO_STATUS_SUCCESS;
-}
+ if (surface->base.is_clear) {
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ surface->pixman_format,
+ surface->width,
+ surface->height,
+ 0);
+ status = image->base.status;
+ *image_out = image;
+ goto FAIL;
+ }
-static cairo_status_t
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
-{
- xcb_void_cookie_t cookie;
+ if (surface->use_pixmap == 0) {
+ status = _cairo_xcb_connection_get_image (connection,
+ surface->drawable,
+ 0, 0,
+ surface->width,
+ surface->height,
+ &reply);
+ if (unlikely (status))
+ goto FAIL;
+ } else {
+ surface->use_pixmap--;
+ reply = NULL;
+ }
- if (surface->gc)
- return CAIRO_STATUS_SUCCESS;
+ if (reply == NULL && ! surface->owns_pixmap) {
+ /* xcb_get_image_t 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
+ */
+ xcb_pixmap_t pixmap;
+ xcb_gcontext_t gc;
+
+ gc = _cairo_xcb_screen_get_gc (surface->screen,
+ surface->drawable,
+ surface->depth);
+ pixmap = _cairo_xcb_connection_create_pixmap (connection,
+ surface->depth,
+ surface->drawable,
+ surface->width,
+ surface->height);
+
+ /* XXX IncludeInferiors? */
+ _cairo_xcb_connection_copy_area (connection,
+ surface->drawable,
+ pixmap, gc,
+ 0, 0,
+ 0, 0,
+ surface->width,
+ surface->height);
- surface->gc = xcb_generate_id(surface->dpy);
- cookie = xcb_create_gc_checked (surface->dpy, surface->gc, surface->drawable, 0, 0);
- _cairo_xcb_surface_set_gc_clip_rects (surface);
+ _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
+ status = _cairo_xcb_connection_get_image (connection,
+ pixmap,
+ 0, 0,
+ surface->width,
+ surface->height,
+ &reply);
+ _cairo_xcb_connection_free_pixmap (connection, pixmap);
-static cairo_status_t
-_draw_image_surface (cairo_xcb_surface_t *surface,
- cairo_image_surface_t *image,
- int src_x,
- int src_y,
- int width,
- int height,
- int dst_x,
- int dst_y)
-{
- int bpp, bpl;
- uint32_t data_len;
- uint8_t *data, left_pad=0;
- xcb_void_cookie_t cookie;
-
- /* equivalent of XPutImage(..., src_x,src_y, dst_x,dst_y, width,height); */
- /* XXX: assumes image and surface formats and depths are the same */
- /* XXX: assumes depth is a multiple of 8 (not bitmap) */
-
- /* fit src_{x,y,width,height} within image->{0,0,width,height} */
- if (src_x < 0) {
- width += src_x;
- src_x = 0;
+ if (unlikely (status))
+ goto FAIL;
}
- if (src_y < 0) {
- height += src_y;
- src_y = 0;
+
+ if (unlikely (reply == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto FAIL;
}
- if (width + src_x > image->width)
- width = image->width - src_x;
- if (height + src_y > image->height)
- height = image->height - src_y;
- if (width <= 0 || height <= 0)
- return CAIRO_STATUS_SUCCESS;
- bpp = _bits_per_pixel(surface->dpy, image->depth);
- /* XXX: could use bpl = image->stride? */
- bpl = _bytes_per_line(surface->dpy, image->width, bpp);
+ /* XXX byte swap */
+ /* XXX format conversion */
+ assert (reply->depth == surface->depth);
- if (src_x == 0 && width == image->width) {
- /* can work in-place */
- data_len = height * bpl;
- data = image->data + src_y * bpl;
- } else {
- /* must copy {src_x,src_y,width,height} into new data */
- int line = 0;
- uint8_t *data_line, *image_line;
- int data_bpl = _bytes_per_line(surface->dpy, width, bpp);
- data_len = height * data_bpl;
- data_line = data = malloc(data_len);
- if (data == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- image_line = image->data + src_y * bpl + (src_x * bpp / 8);
- while (line++ < height) {
- memcpy(data_line, image_line, data_bpl);
- data_line += data_bpl;
- image_line += bpl;
- }
+ image = (cairo_image_surface_t *)
+ _cairo_image_surface_create_with_pixman_format
+ (xcb_get_image_data (reply),
+ surface->pixman_format,
+ surface->width,
+ surface->height,
+ CAIRO_STRIDE_FOR_WIDTH_BPP (surface->width,
+ PIXMAN_FORMAT_BPP (surface->pixman_format)));
+ status = image->base.status;
+ if (unlikely (status)) {
+ free (reply);
+ goto FAIL;
}
- _cairo_xcb_surface_ensure_gc (surface);
- cookie = xcb_put_image_checked (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
- surface->drawable, surface->gc,
- width, height,
- dst_x, dst_y,
- left_pad, image->depth,
- data_len, data);
-
- if (data < image->data || data >= image->data + image->height * bpl)
- free (data);
-
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
-static cairo_status_t
-_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
+ assert (xcb_get_image_data_length (reply) == image->height * image->stride);
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (status)
- return status;
+ pixman_image_set_destroy_function (image->pixman_image, _destroy_image, reply);
- *image_out = image;
- *image_extra = NULL;
+ _cairo_xcb_connection_release (connection);
+
+ /* synchronisation point */
+ surface->marked_dirty = FALSE;
+ *image_out = image;
return CAIRO_STATUS_SUCCESS;
+
+FAIL:
+ _cairo_xcb_connection_release (connection);
+ return status;
}
-static cairo_surface_t *
-_cairo_xcb_surface_snapshot (void *abstract_surface)
+static cairo_status_t
+_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
{
cairo_xcb_surface_t *surface = abstract_surface;
cairo_image_surface_t *image;
cairo_status_t status;
- status = _get_image_surface (surface, NULL, &image, NULL);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_acquire_source_image (surface->drm,
+ image_out, image_extra);
+ }
- return &image->base;
-}
+ if (surface->fallback != NULL) {
+ image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback);
+ goto DONE;
+ }
-static void
-_cairo_xcb_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
+ image = (cairo_image_surface_t *)
+ _cairo_surface_has_snapshot (&surface->base,
+ &_cairo_image_surface_backend);
+ if (image != NULL) {
+ image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
+ goto DONE;
+ }
-static cairo_status_t
-_cairo_xcb_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_status_t status;
+ status = _get_image (surface, FALSE, &image);
+ if (unlikely (status))
+ return status;
- status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
- if (status)
+ status = _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&image->base);
return status;
+ }
+DONE:
*image_out = image;
*image_extra = NULL;
-
return CAIRO_STATUS_SUCCESS;
}
static void
-_cairo_xcb_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
+_cairo_xcb_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image,
+ void *image_extra)
{
cairo_xcb_surface_t *surface = abstract_surface;
- /* ignore errors */
- _draw_image_surface (surface, image, 0, 0, image->width, image->height,
- image_rect->x, image_rect->y);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_release_source_image (surface->drm,
+ image, image_extra);
+ }
cairo_surface_destroy (&image->base);
}
-/*
- * Return whether two xcb surfaces share the same
- * screen. Both core and Render drawing require this
- * when using multiple drawables in an operation.
- */
static cairo_bool_t
-_cairo_xcb_surface_same_screen (cairo_xcb_surface_t *dst,
- cairo_xcb_surface_t *src)
-{
- return dst->dpy == src->dpy && dst->screen == src->screen;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- cairo_content_t content,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
+_cairo_xcb_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *extents)
{
cairo_xcb_surface_t *surface = abstract_surface;
- cairo_xcb_surface_t *clone;
-
- if (src->backend == surface->base.backend ) {
- cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
-
- if (_cairo_xcb_surface_same_screen(surface, xcb_src)) {
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- }
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
- cairo_content_t content = _cairo_content_from_format (image_src->format);
- cairo_status_t status;
-
- if (surface->base.status)
- return surface->base.status;
-
- clone = (cairo_xcb_surface_t *)
- _cairo_xcb_surface_create_similar (surface, content, width, height);
- if (clone == NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
- if (clone->base.status)
- return clone->base.status;
-
- status = _draw_image_surface (clone, image_src,
- src_x, src_y,
- width, height,
- 0, 0);
- if (status) {
- cairo_surface_destroy (&clone->base);
- return status;
- }
-
- *clone_offset_x = src_x;
- *clone_offset_y = src_y;
- *clone_out = &clone->base;
-
- return CAIRO_STATUS_SUCCESS;
- }
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ extents->x = extents->y = 0;
+ extents->width = surface->width;
+ extents->height = surface->height;
+ return TRUE;
}
-static cairo_status_t
-_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
- cairo_matrix_t *matrix)
+static void
+_cairo_xcb_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
{
- xcb_render_transform_t xtransform;
- xcb_void_cookie_t cookie;
-
- xtransform.matrix11 = _cairo_fixed_16_16_from_double (matrix->xx);
- xtransform.matrix12 = _cairo_fixed_16_16_from_double (matrix->xy);
- xtransform.matrix13 = _cairo_fixed_16_16_from_double (matrix->x0);
-
- xtransform.matrix21 = _cairo_fixed_16_16_from_double (matrix->yx);
- xtransform.matrix22 = _cairo_fixed_16_16_from_double (matrix->yy);
- xtransform.matrix23 = _cairo_fixed_16_16_from_double (matrix->y0);
-
- xtransform.matrix31 = 0;
- xtransform.matrix32 = 0;
- xtransform.matrix33 = 1 << 16;
-
- if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
- {
- static const xcb_render_transform_t identity = {
- 1 << 16, 0x00000, 0x00000,
- 0x00000, 1 << 16, 0x00000,
- 0x00000, 0x00000, 1 << 16
- };
-
- if (memcmp (&xtransform, &identity, sizeof (xcb_render_transform_t)) == 0)
- return CAIRO_STATUS_SUCCESS;
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- cookie = xcb_render_set_picture_transform_checked (surface->dpy,
- surface->src_picture,
- xtransform);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ /* XXX copy from xlib */
+ _cairo_font_options_init_default (options);
}
static cairo_status_t
-_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
- cairo_filter_t filter)
+_put_shm_image (cairo_xcb_surface_t *surface,
+ xcb_gcontext_t gc,
+ cairo_image_surface_t *image)
{
- const char *render_filter;
- xcb_void_cookie_t cookie;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
- {
- if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
- return CAIRO_STATUS_SUCCESS;
+ cairo_xcb_shm_info_t *shm_info;
+ shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
+ (const cairo_user_data_key_t *) surface->connection);
+ if (shm_info == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- switch (filter) {
- case CAIRO_FILTER_FAST:
- render_filter = "fast";
- break;
- case CAIRO_FILTER_GOOD:
- render_filter = "good";
- break;
- case CAIRO_FILTER_BEST:
- render_filter = "best";
- break;
- case CAIRO_FILTER_NEAREST:
- render_filter = "nearest";
- break;
- case CAIRO_FILTER_BILINEAR:
- render_filter = "bilinear";
- break;
- case CAIRO_FILTER_GAUSSIAN:
- default:
- render_filter = "best";
- break;
- }
- cookie = xcb_render_set_picture_filter_checked (surface->dpy, surface->src_picture,
- strlen(render_filter), render_filter,
- 0, NULL);
+ shm_info->seqno =
+ _cairo_xcb_connection_shm_put_image (surface->connection,
+ surface->drawable,
+ gc,
+ surface->width, surface->height,
+ 0, 0,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ shm_info->shm,
+ shm_info->offset);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, cairo_extend_t extend)
+_put_image (cairo_xcb_surface_t *surface,
+ cairo_image_surface_t *image)
{
- uint32_t mask = XCB_RENDER_CP_REPEAT;
- uint32_t pa[1];
- xcb_void_cookie_t cookie;
-
- switch (extend) {
- case CAIRO_EXTEND_NONE:
- pa[0] = XCB_RENDER_REPEAT_NONE;
- break;
-
- case CAIRO_EXTEND_REPEAT:
- pa[0] = XCB_RENDER_REPEAT_NORMAL;
- break;
-
- case CAIRO_EXTEND_REFLECT:
- if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- pa[0] = XCB_RENDER_REPEAT_REFLECT;
- break;
-
- case CAIRO_EXTEND_PAD:
- if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- pa[0] = XCB_RENDER_REPEAT_PAD;
- break;
-
- default:
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- cookie = xcb_render_change_picture_checked (surface->dpy, surface->src_picture,
- mask, pa);
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
-static cairo_int_status_t
-_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t *surface,
- cairo_surface_attributes_t *attributes)
-{
- cairo_int_status_t status;
+ /* XXX track damaged region? */
- status = _cairo_xcb_surface_ensure_src_picture (surface);
- if (status)
+ status = _cairo_xcb_connection_acquire (surface->connection);
+ if (unlikely (status))
return status;
- status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
- if (status)
+ status = _cairo_xcb_connection_take_socket (surface->connection);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (surface->connection);
return status;
+ }
- status = _cairo_xcb_surface_set_repeat (surface, attributes->extend);
- if (status)
- return status;
+ if (image->pixman_format == surface->pixman_format) {
+ xcb_gcontext_t gc;
+
+ assert (image->width == surface->width);
+ assert (image->height == surface->height);
+ assert (image->depth == surface->depth);
+ assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
+
+ gc = _cairo_xcb_screen_get_gc (surface->screen,
+ surface->drawable,
+ surface->depth);
+
+ status = _put_shm_image (surface, gc, image);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ _cairo_xcb_connection_put_image (surface->connection,
+ surface->drawable, gc,
+ image->width, image->height,
+ 0, 0,
+ image->depth,
+ image->stride,
+ image->data);
+ status = CAIRO_STATUS_SUCCESS;
+ }
- status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
- if (status)
- return status;
+ _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
- return CAIRO_STATUS_SUCCESS;
+ _cairo_xcb_connection_release (surface->connection);
+ return status;
}
-/* Checks whether we can can directly draw from src to dst with
- * the core protocol: either with CopyArea or using src as a
- * a tile in a GC.
- */
-static cairo_bool_t
-_surfaces_compatible (cairo_xcb_surface_t *dst,
- cairo_xcb_surface_t *src)
+static cairo_status_t
+_cairo_xcb_surface_flush (void *abstract_surface)
{
- /* same screen */
- if (!_cairo_xcb_surface_same_screen (dst, src))
- return FALSE;
-
- /* same depth (for core) */
- if (src->depth != dst->depth)
- return FALSE;
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
- /* if Render is supported, match picture formats */
- if (src->xrender_format.id != dst->xrender_format.id)
- return FALSE;
- else if (src->xrender_format.id != XCB_NONE)
- return TRUE;
+ if (surface->drm != NULL && ! surface->marked_dirty)
+ return surface->drm->backend->flush (surface->drm);
- /* Without Render, match visuals instead */
- if (src->visual == dst->visual)
- return TRUE;
+ if (likely (surface->fallback == NULL))
+ return CAIRO_STATUS_SUCCESS;
- return FALSE;
-}
+ if (! surface->base.finished) {
+ status = _put_image (surface,
+ (cairo_image_surface_t *) surface->fallback);
-static cairo_bool_t
-_surface_has_alpha (cairo_xcb_surface_t *surface)
-{
- if (surface->xrender_format.id != XCB_NONE) {
- if (surface->xrender_format.type == XCB_RENDER_PICT_TYPE_DIRECT &&
- surface->xrender_format.direct.alpha_mask != 0)
- return TRUE;
- else
- return FALSE;
- } else {
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_surface_status (surface->fallback);
- /* In the no-render case, we never have alpha */
- return FALSE;
+ if (status == CAIRO_STATUS_SUCCESS) {
+ status = _cairo_surface_attach_snapshot (&surface->base,
+ surface->fallback,
+ cairo_surface_finish);
+ }
}
-}
-/* Returns true if the given operator and source-alpha combination
- * requires alpha compositing to complete.
- */
-static cairo_bool_t
-_operator_needs_alpha_composite (cairo_operator_t op,
- cairo_bool_t surface_has_alpha)
-{
- if (op == CAIRO_OPERATOR_SOURCE ||
- (!surface_has_alpha &&
- (op == CAIRO_OPERATOR_OVER ||
- op == CAIRO_OPERATOR_ATOP ||
- op == CAIRO_OPERATOR_IN)))
- return FALSE;
+ cairo_surface_destroy (surface->fallback);
+ surface->fallback = NULL;
- return TRUE;
+ return status;
}
-/* There is a bug in most older X servers with compositing using a
- * untransformed repeating source pattern when the source is in off-screen
- * video memory, and another with repeated transformed images using a
- * general transform matrix. When these bugs could be triggered, we need a
- * fallback: in the common case where we have no transformation and the
- * source and destination have the same format/visual, we can do the
- * operation using the core protocol for the first bug, otherwise, we need
- * a software fallback.
- *
- * We can also often optimize a compositing operation by calling XCopyArea
- * for some common cases where there is no alpha compositing to be done.
- * We figure that out here as well.
- */
-typedef enum {
- DO_RENDER, /* use render */
- DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
- DO_XTILE, /* core protocol XSetTile optimization/fallback */
- DO_UNSUPPORTED /* software fallback */
-} composite_operation_t;
-
-/* Initial check for the render bugs; we need to recheck for the
- * offscreen-memory bug after we turn patterns into surfaces, since that
- * may introduce a repeating pattern for gradient patterns. We don't need
- * to check for the repeat+transform bug because gradient surfaces aren't
- * transformed.
- *
- * All we do here is reject cases where we *know* are going to
- * hit the bug and won't be able to use a core protocol fallback.
- */
-static composite_operation_t
-_categorize_composite_operation (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_bool_t have_mask)
-
+static cairo_status_t
+_cairo_xcb_surface_mark_dirty (void *abstract_surface,
+ int x, int y,
+ int width, int height)
{
-#if XXX_BUGGY_REPEAT
- if (!dst->buggy_repeat)
- return DO_RENDER;
-
- if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
- {
- cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
-
- if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
- src_pattern->extend == CAIRO_EXTEND_REPEAT)
- {
- /* 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_xcb (surface_pattern->surface)) {
- cairo_xcb_surface_t *src = (cairo_xcb_surface_t *)surface_pattern->surface;
-
- if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
- return DO_UNSUPPORTED;
-
- /* If these are on the same screen but otherwise incompatible,
- * make a copy as core drawing can't cross depths and doesn't
- * work rightacross visuals of the same depth
- */
- if (_cairo_xcb_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;
- }
-#endif
- return DO_RENDER;
+ cairo_xcb_surface_t *surface = abstract_surface;
+ surface->marked_dirty = TRUE;
+ return CAIRO_STATUS_SUCCESS;
}
-/* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
- * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
- * did to turn gradients into a pattern, but most of the time we can handle
- * that case with core protocol fallback.
- *
- * Also check here if we can just use XCopyArea, instead of going through
- * Render.
- */
-static composite_operation_t
-_recategorize_composite_operation (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- cairo_surface_attributes_t *src_attr,
- cairo_bool_t have_mask)
+static cairo_surface_t *
+_cairo_xcb_surface_map_to_image (cairo_xcb_surface_t *surface)
{
- cairo_bool_t is_integer_translation =
- _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
- cairo_bool_t needs_alpha_composite =
- _operator_needs_alpha_composite (op, _surface_has_alpha (src));
-
- if (!have_mask &&
- is_integer_translation &&
- src_attr->extend == CAIRO_EXTEND_NONE &&
- !needs_alpha_composite &&
- _surfaces_compatible(src, dst))
- {
- return DO_XCOPYAREA;
- }
-#if XXX_BUGGY_REPEAT
- if (!dst->buggy_repeat)
- return DO_RENDER;
-
- if (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))
- {
- return DO_XTILE;
- }
+ cairo_status_t status;
+ cairo_image_surface_t *image;
- return DO_UNSUPPORTED;
- }
-#endif
- return DO_RENDER;
-}
+ status = _get_image (surface, TRUE, &image);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
-static int
-_render_operator (cairo_operator_t op)
-{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
- return XCB_RENDER_PICT_OP_CLEAR;
- case CAIRO_OPERATOR_SOURCE:
- return XCB_RENDER_PICT_OP_SRC;
- case CAIRO_OPERATOR_DEST:
- return XCB_RENDER_PICT_OP_DST;
- case CAIRO_OPERATOR_OVER:
- return XCB_RENDER_PICT_OP_OVER;
- case CAIRO_OPERATOR_DEST_OVER:
- return XCB_RENDER_PICT_OP_OVER_REVERSE;
- case CAIRO_OPERATOR_IN:
- return XCB_RENDER_PICT_OP_IN;
- case CAIRO_OPERATOR_DEST_IN:
- return XCB_RENDER_PICT_OP_IN_REVERSE;
- case CAIRO_OPERATOR_OUT:
- return XCB_RENDER_PICT_OP_OUT;
- case CAIRO_OPERATOR_DEST_OUT:
- return XCB_RENDER_PICT_OP_OUT_REVERSE;
- case CAIRO_OPERATOR_ATOP:
- return XCB_RENDER_PICT_OP_ATOP;
- case CAIRO_OPERATOR_DEST_ATOP:
- return XCB_RENDER_PICT_OP_ATOP_REVERSE;
- case CAIRO_OPERATOR_XOR:
- return XCB_RENDER_PICT_OP_XOR;
- case CAIRO_OPERATOR_ADD:
- return XCB_RENDER_PICT_OP_ADD;
- case CAIRO_OPERATOR_SATURATE:
- return XCB_RENDER_PICT_OP_SATURATE;
- default:
- return XCB_RENDER_PICT_OP_OVER;
- }
+ return &image->base;
}
static cairo_int_status_t
-_cairo_xcb_surface_composite (cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- const cairo_pattern_t *mask_pattern,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_region_t *clip_region)
+_cairo_xcb_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
{
- cairo_surface_attributes_t src_attr, mask_attr;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_xcb_surface_t *mask;
- cairo_int_status_t status;
- composite_operation_t operation;
- int itx, ity;
- cairo_bool_t is_integer_translation;
- xcb_void_cookie_t cookie;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- operation = _categorize_composite_operation (dst, op, src_pattern,
- mask_pattern != NULL);
- if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
- &dst->base,
- src_x, src_y,
- mask_x, mask_y,
- width, height,
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
- (cairo_surface_t **) &src,
- (cairo_surface_t **) &mask,
- &src_attr, &mask_attr);
- if (status)
- return status;
-
- operation = _recategorize_composite_operation (dst, op, src, &src_attr,
- mask_pattern != NULL);
- if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
-
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
- status = _cairo_xcb_surface_set_attributes (src, &src_attr);
- if (status)
- goto BAIL;
+ if (surface->drm != NULL && ! surface->marked_dirty)
+ return _cairo_surface_paint (surface->drm, op, source, clip);
- switch (operation)
- {
- case DO_RENDER:
- status = _cairo_xcb_surface_ensure_dst_picture (dst);
- if (unlikely (status))
- goto BAIL;
-
- if (mask) {
- status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
- if (unlikely (status))
- goto BAIL;
-
- cookie = xcb_render_composite_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- mask->src_picture,
- dst->dst_picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- mask_x + mask_attr.x_offset,
- mask_y + mask_attr.y_offset,
- dst_x, dst_y,
- width, height);
- } else {
- static xcb_render_picture_t maskpict = { XCB_NONE };
-
- cookie = xcb_render_composite_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- maskpict,
- dst->dst_picture,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- 0, 0,
- dst_x, dst_y,
- width, height);
- }
- break;
-
- case DO_XCOPYAREA:
- status = _cairo_xcb_surface_ensure_gc (dst);
- if (unlikely (status))
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- cookie = xcb_copy_area_checked (dst->dpy,
- src->drawable,
- dst->drawable,
- dst->gc,
- src_x + src_attr.x_offset,
- src_y + src_attr.y_offset,
- dst_x, dst_y,
- width, height);
- break;
-
- case DO_XTILE:
- /* This case is only used for bug fallbacks, though it is theoretically
- * applicable to the case where we don't have the RENDER extension as
- * well.
- *
- * We've checked that we have a repeating unscaled source in
- * _recategorize_composite_operation.
- */
-
- status = _cairo_xcb_surface_ensure_gc (dst);
- if (unlikely (status))
+ status = _cairo_xcb_surface_render_paint (surface, op, source, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
- is_integer_translation =
- _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
- assert (is_integer_translation == TRUE);
- {
- uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE
- | XCB_GC_TILE_STIPPLE_ORIGIN_X
- | XCB_GC_TILE_STIPPLE_ORIGIN_Y;
- uint32_t values[] = {
- XCB_FILL_STYLE_TILED, src->drawable,
- - (itx + src_attr.x_offset),
- - (ity + src_attr.y_offset)
- };
- xcb_rectangle_t rect = { dst_x, dst_y, width, height };
-
- xcb_change_gc( dst->dpy, dst->gc, mask, values );
- cookie = xcb_poly_fill_rectangle_checked (dst->dpy,
- dst->drawable,
- dst->gc,
- 1, &rect);
- }
- break;
-
- case DO_UNSUPPORTED:
- default:
- ASSERT_NOT_REACHED;
- }
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
- if (unlikely (status))
- goto BAIL;
-
- if (!_cairo_operator_bounded_by_source (op)) {
- status = _cairo_surface_composite_fixup_unbounded (&dst->base,
- &src_attr, src->width, src->height,
- mask ? &mask_attr : NULL,
- mask ? mask->width : 0,
- mask ? mask->height : 0,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y, width, height,
- clip_region);
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- BAIL:
- if (mask)
- _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
-
- _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
-
- return status;
+ return _cairo_surface_paint (surface->fallback, op, source, clip);
}
static cairo_int_status_t
-_cairo_xcb_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t op,
- const cairo_color_t * color,
- cairo_rectangle_int_t *rects,
- int num_rects)
+_cairo_xcb_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
{
cairo_xcb_surface_t *surface = abstract_surface;
- xcb_render_color_t render_color;
- xcb_rectangle_t static_xrects[16];
- xcb_rectangle_t *xrects = static_xrects;
cairo_status_t status;
- xcb_void_cookie_t cookie;
- int i;
-
- if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
- render_color.red = color->red_short;
- render_color.green = color->green_short;
- render_color.blue = color->blue_short;
- render_color.alpha = color->alpha_short;
+ if (surface->drm != NULL && ! surface->marked_dirty)
+ return _cairo_surface_mask (surface->drm, op, source, mask, clip);
- status = _cairo_xcb_surface_set_clip_region (surface, NULL);
- assert (status == CAIRO_STATUS_SUCCESS);
-
- if (num_rects > ARRAY_LENGTH(static_xrects)) {
- xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
- if (xrects == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_mask (surface,
+ op, source, mask, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- for (i = 0; i < num_rects; i++) {
- xrects[i].x = rects[i].x;
- xrects[i].y = rects[i].y;
- xrects[i].width = rects[i].width;
- xrects[i].height = rects[i].height;
- }
+ status = _cairo_xcb_surface_render_mask (surface,
+ op, source, mask, clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_xcb_surface_ensure_dst_picture (surface);
- if (unlikely (status)) {
- if (xrects != static_xrects)
- free (xrects);
- return status;
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- cookie = xcb_render_fill_rectangles_checked (surface->dpy,
- _render_operator (op),
- surface->dst_picture,
- render_color, num_rects, xrects);
-
- if (xrects != static_xrects)
- free (xrects);
-
- return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+ return _cairo_surface_mask (surface->fallback,
+ op, source, mask,
+ clip);
}
-/* Creates an A8 picture of size @width x @height, initialized with @color
- */
-static cairo_status_t
-_create_a8_picture (cairo_xcb_surface_t *surface,
- xcb_render_color_t *color,
- int width,
- int height,
- cairo_bool_t repeat,
- xcb_render_picture_t *out)
-{
- uint32_t values[] = { TRUE };
- uint32_t mask = repeat ? XCB_RENDER_CP_REPEAT : 0;
-
- xcb_pixmap_t pixmap;
- xcb_render_picture_t picture;
- xcb_render_pictforminfo_t *format;
- xcb_rectangle_t rect = { 0, 0, width, height };
-
- cairo_xcb_cookie_t *cookie[3];
- cairo_status_t status;
-
- status = _cairo_freepool_alloc_array (&surface->cookie_pool,
- ARRAY_LENGTH (cookie),
- (void **) cookie);
- if (unlikely (status))
- return status;
-
- pixmap = xcb_generate_id (surface->dpy);
- picture = xcb_generate_id (surface->dpy);
-
- cookie[0]->xcb = xcb_create_pixmap_checked (surface->dpy, 8, pixmap, surface->drawable,
- width <= 0 ? 1 : width,
- height <= 0 ? 1 : height);
- cairo_list_add_tail (&cookie[0]->link, &surface->to_be_checked);
-
- format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8);
- cookie[1]->xcb = xcb_render_create_picture_checked (surface->dpy,
- picture, pixmap, format->id,
- mask, values);
- cairo_list_add_tail (&cookie[1]->link, &surface->to_be_checked);
-
- cookie[2]->xcb = xcb_render_fill_rectangles_checked (surface->dpy,
- XCB_RENDER_PICT_OP_SRC,
- picture, *color, 1, &rect);
- cairo_list_add_tail (&cookie[2]->link, &surface->to_be_checked);
-
- xcb_free_pixmap (surface->dpy, pixmap);
-
- *out = picture;
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* Creates a temporary mask for the trapezoids covering the area
- * [@dst_x, @dst_y, @width, @height] of the destination surface.
- */
-static cairo_status_t
-_create_trapezoid_mask (cairo_xcb_surface_t *dst,
- cairo_trapezoid_t *traps,
- int num_traps,
- int dst_x,
- int dst_y,
- int width,
- int height,
- xcb_render_pictforminfo_t *pict_format,
- xcb_render_picture_t *mask_picture_out)
+static cairo_int_status_t
+_cairo_xcb_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
{
- xcb_render_color_t transparent = { 0, 0, 0, 0 };
- xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff };
- xcb_render_picture_t mask_picture, solid_picture;
- xcb_render_trapezoid_t *offset_traps;
- xcb_void_cookie_t cookie;
+ cairo_xcb_surface_t *surface = abstract_surface;
cairo_status_t status;
- 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().
- */
- status = _create_a8_picture (dst, &transparent, width, height, FALSE, &mask_picture);
- if (unlikely (status))
- return status;
- status = _create_a8_picture (dst, &solid, 1, 1, TRUE, &solid_picture);
- if (unlikely (status)) {
- xcb_render_free_picture (dst->dpy, mask_picture);
- return status;
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_stroke (surface->drm,
+ op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
}
- offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t));
- if (offset_traps == NULL) {
- xcb_render_free_picture (dst->dpy, solid_picture);
- xcb_render_free_picture (dst->dpy, mask_picture);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_stroke (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
- 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;
- }
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- cookie = xcb_render_trapezoids_checked (dst->dpy, XCB_RENDER_PICT_OP_ADD,
- solid_picture, mask_picture,
- pict_format->id,
- 0, 0,
- num_traps, offset_traps);
+ status = _cairo_xcb_surface_render_stroke (surface, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
- xcb_render_free_picture (dst->dpy, solid_picture);
- free (offset_traps);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
- if (unlikely (status)) {
- xcb_render_free_picture (dst->dpy, mask_picture);
- return status;
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- *mask_picture_out = mask_picture;
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_surface_stroke (surface->fallback,
+ op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip);
}
static cairo_int_status_t
-_cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
+_cairo_xcb_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
{
- cairo_surface_attributes_t attributes;
- cairo_xcb_surface_t *dst = abstract_dst;
- cairo_xcb_surface_t *src;
- cairo_int_status_t status;
- composite_operation_t operation;
- int render_reference_x, render_reference_y;
- int render_src_x, render_src_y;
- int cairo_format;
- xcb_render_pictforminfo_t *render_format;
-
- if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- operation = _categorize_composite_operation (dst, op, pattern, TRUE);
- if (operation == DO_UNSUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_pattern_acquire_surface (pattern, &dst->base,
- src_x, src_y, width, height,
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
- (cairo_surface_t **) &src,
- &attributes);
- if (status)
- return status;
-
- operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
- if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
-
- switch (antialias) {
- case CAIRO_ANTIALIAS_NONE:
- cairo_format = CAIRO_FORMAT_A1;
- break;
- case CAIRO_ANTIALIAS_GRAY:
- case CAIRO_ANTIALIAS_SUBPIXEL:
- case CAIRO_ANTIALIAS_DEFAULT:
- default:
- cairo_format = CAIRO_FORMAT_A8;
- break;
- }
- render_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dst->dpy, cairo_format);
- /* XXX: what to do if render_format is null? */
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
- if (traps[0].left.p1.y < traps[0].left.p2.y) {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
- } else {
- render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
- render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_fill (surface->drm,
+ op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
}
- render_src_x = src_x + render_reference_x - dst_x;
- render_src_y = src_y + render_reference_y - dst_y;
-
- status = _cairo_xcb_surface_ensure_dst_picture (dst);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xcb_surface_set_attributes (src, &attributes);
- if (status)
- goto BAIL;
-
- if (!_cairo_operator_bounded_by_mask (op)) {
- xcb_void_cookie_t cookie;
-
- /* xcb_render_composite+trapezoids() 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. (xcb_render_add_traps() could be used to make creating
- * the mask somewhat cheaper.)
- */
- xcb_render_picture_t mask_picture = 0; /* silence compiler */
-
- status = _create_trapezoid_mask (dst, traps, num_traps,
- dst_x, dst_y, width, height,
- render_format,
- &mask_picture);
- if (status)
- goto BAIL;
-
- cookie = xcb_render_composite_checked (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);
- xcb_render_free_picture (dst->dpy, mask_picture);
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
- if (unlikely (status))
- goto BAIL;
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_fill (surface, op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- 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,
- clip_region);
+ status = _cairo_xcb_surface_render_fill (surface, op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- } else {
- xcb_render_trapezoid_t xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (xcb_render_trapezoid_t)];
- xcb_render_trapezoid_t *xtraps = xtraps_stack;
- xcb_void_cookie_t cookie;
- int i;
-
- if (num_traps > ARRAY_LENGTH(xtraps_stack)) {
- xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t));
- if (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);
- }
-
- cookie = xcb_render_trapezoids_checked (dst->dpy,
- _render_operator (op),
- src->src_picture, dst->dst_picture,
- render_format->id,
- render_src_x + attributes.x_offset,
- render_src_y + attributes.y_offset,
- num_traps, xtraps);
-
- if (xtraps != xtraps_stack)
- free (xtraps);
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
}
- BAIL:
- _cairo_pattern_release_surface (pattern, &src->base, &attributes);
-
- return status;
+ return _cairo_surface_fill (surface->fallback,
+ op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip);
}
-static cairo_bool_t
-_cairo_xcb_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- cairo_xcb_surface_t *surface = abstract_surface;
-
- rectangle->x = 0;
- rectangle->y = 0;
-
- rectangle->width = surface->width;
- rectangle->height = surface->height;
-
- return TRUE;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_flush (void *abstract_surface)
+static cairo_int_status_t
+_cairo_xcb_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
{
cairo_xcb_surface_t *surface = abstract_surface;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
- while (! cairo_list_is_empty (&surface->to_be_checked)) {
- cairo_xcb_cookie_t *cookie;
- xcb_generic_error_t *error;
-
- cookie = cairo_list_first_entry (&surface->to_be_checked,
- cairo_xcb_cookie_t,
- link);
+ cairo_status_t status;
- error = xcb_request_check (surface->dpy, cookie->xcb);
- if (error != NULL) {
-#if 0
- /* XXX */
- fprintf (stderr, "Delayed error detected: %d, major=%d, minor=%d, seqno=%d\n",
- error->error_code,
- error->major_code,
- error->minor_code,
- error->sequence);
-#endif
- if (status == CAIRO_STATUS_SUCCESS)
- status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); /* XXX CAIRO_STATUS_CONNECTION_ERROR */
- }
+ *num_remaining = 0;
- cairo_list_del (&cookie->link);
- _cairo_freepool_free (&surface->cookie_pool, cookie);
+ if (surface->drm != NULL && ! surface->marked_dirty) {
+ return _cairo_surface_show_text_glyphs (surface->drm,
+ op, source,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ scaled_font,
+ clip);
}
- return status;
-}
-
-/* XXX: _cairo_xcb_surface_get_font_options */
-
-static void
-_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
-
-static void
-_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font);
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_clip_t *clip,
- int *remaining_glyphs);
-
-static cairo_bool_t
-_cairo_xcb_surface_is_similar (void *surface_a,
- void *surface_b,
- cairo_content_t content)
-{
- cairo_xcb_surface_t *a = surface_a;
- cairo_xcb_surface_t *b = surface_b;
- xcb_render_pictforminfo_t *xrender_format;
-
- /* XXX: disable caching by the solid pattern cache until we implement
- * display notification to avoid issuing xcb calls from the wrong thread
- * or accessing the surface after the Display has been closed.
- */
- return FALSE;
+ if (surface->fallback == NULL) {
+ status = _cairo_xcb_surface_cairo_glyphs (surface,
+ op, source,
+ scaled_font, glyphs, num_glyphs,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- if (! _cairo_xcb_surface_same_screen (a, b))
- return FALSE;
+ status = _cairo_xcb_surface_render_glyphs (surface,
+ op, source,
+ scaled_font, glyphs, num_glyphs,
+ clip);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
- /* now check that the target is a similar format */
- xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy,
- _cairo_format_from_content (content));
+ surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+ }
- return a->xrender_format.id == xrender_format->id;
+ return _cairo_surface_show_text_glyphs (surface->fallback,
+ op, source,
+ NULL, 0,
+ glyphs, num_glyphs,
+ NULL, 0, 0,
+ scaled_font,
+ clip);
}
-/* XXX: move this to the bottom of the file, XCB and Xlib */
-
-static const cairo_surface_backend_t cairo_xcb_surface_backend = {
+const cairo_surface_backend_t _cairo_xcb_surface_backend = {
CAIRO_SURFACE_TYPE_XCB,
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_finish,
_cairo_xcb_surface_acquire_source_image,
_cairo_xcb_surface_release_source_image,
+ NULL, NULL, NULL, /* dest acquire/release/clone */
- _cairo_xcb_surface_acquire_dest_image,
- _cairo_xcb_surface_release_dest_image,
-
- _cairo_xcb_surface_clone_similar,
- _cairo_xcb_surface_composite,
- _cairo_xcb_surface_fill_rectangles,
- _cairo_xcb_surface_composite_trapezoids,
- NULL, /* create_span_renderer */
- NULL, /* check_span_renderer */
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
NULL, /* copy_page */
NULL, /* show_page */
-
_cairo_xcb_surface_get_extents,
- NULL, /* old_show_glyphs */
- NULL, /* get_font_options */
+ NULL, /* old-glyphs */
+ _cairo_xcb_surface_get_font_options,
+
_cairo_xcb_surface_flush,
- NULL, /* mark_dirty_rectangle */
+ _cairo_xcb_surface_mark_dirty,
_cairo_xcb_surface_scaled_font_fini,
_cairo_xcb_surface_scaled_glyph_fini,
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- NULL, /* fill */
- _cairo_xcb_surface_show_glyphs,
-
- _cairo_xcb_surface_snapshot,
-
- _cairo_xcb_surface_is_similar,
+ _cairo_xcb_surface_paint,
+ _cairo_xcb_surface_mask,
+ _cairo_xcb_surface_stroke,
+ _cairo_xcb_surface_fill,
+ _cairo_xcb_surface_glyphs,
};
-/**
- * _cairo_surface_is_xcb:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is a #cairo_xcb_surface_t
- *
- * Return value: True if the surface is an xcb surface
- **/
-static cairo_bool_t
-_cairo_surface_is_xcb (cairo_surface_t *surface)
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+static cairo_surface_t *
+_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection,
+ cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ pixman_format_code_t pixman_format,
+ int width, int height)
{
- return surface->backend == &cairo_xcb_surface_backend;
+ uint32_t attachments[] = { XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT };
+ xcb_dri2_get_buffers_reply_t *buffers;
+ xcb_dri2_dri2_buffer_t *buffer;
+ cairo_surface_t *surface;
+
+ if (! _cairo_drm_size_is_valid (screen->device, width, height))
+ return NULL;
+
+ xcb_dri2_create_drawable (connection->xcb_connection,
+ drawable);
+
+ buffers = xcb_dri2_get_buffers_reply (connection->xcb_connection,
+ xcb_dri2_get_buffers (connection->xcb_connection,
+ drawable, 1,
+ ARRAY_LENGTH (attachments),
+ attachments),
+ 0);
+ if (buffers == NULL) {
+ xcb_dri2_destroy_drawable (connection->xcb_connection,
+ drawable);
+ return NULL;
+ }
+
+ /* If the drawable is a window, we expect to receive an extra fake front,
+ * which would involve copying on each flush - contrary to the user
+ * expectations. But that is likely to be preferable to mixing drm/xcb
+ * operations.
+ */
+ buffer = xcb_dri2_get_buffers_buffers (buffers);
+ if (buffers->count == 1 && buffer[0].attachment == XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT) {
+ assert (buffer[0].cpp == PIXMAN_FORMAT_BPP (pixman_format) / 8);
+ surface = cairo_drm_surface_create_for_name (screen->device,
+ buffer[0].name,
+ _cairo_format_from_pixman_format (pixman_format),
+ width, height,
+ buffer[0].pitch);
+ } else {
+ xcb_dri2_destroy_drawable (connection->xcb_connection,
+ drawable);
+ surface = NULL;
+ }
+ free (buffers);
+
+ return surface;
}
+#else
+
static cairo_surface_t *
-_cairo_xcb_surface_create_internal (xcb_connection_t *dpy,
- xcb_drawable_t drawable,
- xcb_screen_t *screen,
- xcb_visualtype_t *visual,
- xcb_render_pictforminfo_t *xrender_format,
- int width,
- int height,
- int depth)
+_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection,
+ cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ pixman_format_code_t pixman_format,
+ int width, int height)
+{
+ return NULL;
+}
+
+#endif
+
+cairo_surface_t *
+_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ cairo_bool_t owns_pixmap,
+ pixman_format_code_t pixman_format,
+ xcb_render_pictformat_t xrender_format,
+ int width,
+ int height)
{
cairo_xcb_surface_t *surface;
- const xcb_query_extension_reply_t *er;
- const xcb_render_query_version_reply_t *r = NULL;
surface = malloc (sizeof (cairo_xcb_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- if (xrender_format) {
- depth = xrender_format->depth;
- } else if (visual) {
- xcb_depth_iterator_t depths;
- xcb_visualtype_iterator_t visuals;
-
- /* This is ugly, but we have to walk over all visuals
- * for the screen to find the depth.
- */
- depths = xcb_screen_allowed_depths_iterator(screen);
- for(; depths.rem; xcb_depth_next(&depths))
- {
- visuals = xcb_depth_visuals_iterator(depths.data);
- for(; visuals.rem; xcb_visualtype_next(&visuals))
- {
- if(visuals.data->visual_id == visual->visual_id)
- {
- depth = depths.data->depth;
- goto found;
- }
- }
- }
- found:
- ;
- }
-
- er = xcb_get_extension_data(dpy, &xcb_render_id);
- if(er && er->present) {
- r = xcb_render_util_query_version(dpy);
- }
- if (r) {
- surface->render_major = r->major_version;
- surface->render_minor = r->minor_version;
- } else {
- surface->render_major = -1;
- surface->render_minor = -1;
- }
-
- if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
- if (!xrender_format) {
- if (visual) {
- const xcb_render_query_pict_formats_reply_t *formats;
- xcb_render_pictvisual_t *pict_visual;
- formats = xcb_render_util_query_formats (dpy);
- pict_visual = xcb_render_util_find_visual_format (formats, visual->visual_id);
- if (pict_visual) {
- xcb_render_pictforminfo_t template;
- template.id = pict_visual->format;
- xrender_format = xcb_render_util_find_format (formats, XCB_PICT_FORMAT_ID, &template, 0);
- }
- } else if (depth == 1) {
- xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, CAIRO_FORMAT_A1);
- }
- }
- } else {
- xrender_format = NULL;
- }
-
_cairo_surface_init (&surface->base,
- &cairo_xcb_surface_backend,
- NULL, /* device */
- _xcb_render_format_to_content (xrender_format));
+ &_cairo_xcb_surface_backend,
+ &screen->connection->device,
+ _cairo_content_from_pixman_format (pixman_format));
+
+ surface->connection = _cairo_xcb_connection_reference (screen->connection);
+ surface->screen = screen;
+ cairo_list_add (&surface->link, &screen->surfaces);
- surface->dpy = dpy;
+ surface->fallback = NULL;
- surface->gc = XCB_NONE;
surface->drawable = drawable;
- surface->screen = screen;
- surface->owns_pixmap = FALSE;
+ surface->owns_pixmap = owns_pixmap;
surface->use_pixmap = 0;
- surface->width = width;
- surface->height = height;
- /* XXX: set buggy_repeat based on ServerVendor and VendorRelease */
+ surface->width = width;
+ surface->height = height;
+ surface->depth = PIXMAN_FORMAT_DEPTH (pixman_format);
- surface->dst_picture = XCB_NONE;
- surface->src_picture = XCB_NONE;
+ surface->picture = XCB_NONE;
- surface->visual = visual;
- surface->xrender_format.id = XCB_NONE;
- if (xrender_format) surface->xrender_format = *xrender_format;
- surface->depth = depth;
+ surface->pixman_format = pixman_format;
+ surface->xrender_format = xrender_format;
- surface->have_clip_rects = FALSE;
- surface->clip_rects = NULL;
- surface->num_clip_rects = 0;
- surface->clip_region = NULL;
+ surface->flags = screen->connection->flags;
- cairo_list_init (&surface->to_be_checked);
- _cairo_freepool_init (&surface->cookie_pool,
- sizeof (cairo_xcb_cookie_t));
+ surface->marked_dirty = FALSE;
+ surface->drm = NULL;
+ if (screen->device != NULL) {
+ surface->drm = _xcb_drm_create_surface_for_drawable (surface->connection,
+ surface->screen,
+ drawable,
+ pixman_format,
+ width, height);
+ }
return &surface->base;
}
static xcb_screen_t *
-_cairo_xcb_screen_from_visual (xcb_connection_t *c, xcb_visualtype_t *visual)
+_cairo_xcb_screen_from_visual (xcb_connection_t *connection,
+ xcb_visualtype_t *visual,
+ int *depth)
{
xcb_depth_iterator_t d;
- xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c));
- for (; s.rem; xcb_screen_next(&s))
- {
- if (s.data->root_visual == visual->visual_id)
+ xcb_screen_iterator_t s;
+
+ s = xcb_setup_roots_iterator (xcb_get_setup (connection));
+ for (; s.rem; xcb_screen_next (&s)) {
+ if (s.data->root_visual == visual->visual_id) {
+ *depth = s.data->root_depth;
return s.data;
+ }
d = xcb_screen_allowed_depths_iterator(s.data);
- for (; d.rem; xcb_depth_next(&d))
- {
- xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);
- for (; v.rem; xcb_visualtype_next(&v))
- {
- if (v.data->visual_id == visual->visual_id)
+ for (; d.rem; xcb_depth_next (&d)) {
+ xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
+
+ for (; v.rem; xcb_visualtype_next (&v)) {
+ if (v.data->visual_id == visual->visual_id) {
+ *depth = d.data->depth;
return s.data;
+ }
}
}
}
+
return NULL;
}
-/**
- * cairo_xcb_surface_create:
- * @c: an XCB connection
- * @drawable: an XCB drawable
- * @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 XCB 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_xcb_surface_set_size() must be called whenever the size of the
- * window changes.
- *
- * Return value: the newly created surface
- **/
cairo_surface_t *
-cairo_xcb_surface_create (xcb_connection_t *c,
- xcb_drawable_t drawable,
- xcb_visualtype_t *visual,
- int width,
- int height)
+cairo_xcb_surface_create (xcb_connection_t *xcb_connection,
+ xcb_drawable_t drawable,
+ xcb_visualtype_t *visual,
+ int width,
+ int height)
{
- xcb_screen_t *screen = _cairo_xcb_screen_from_visual (c, visual);
+ cairo_xcb_screen_t *screen;
+ xcb_screen_t *xcb_screen;
+ cairo_format_masks_t image_masks;
+ pixman_format_code_t pixman_format;
+ xcb_render_pictformat_t xrender_format;
+ int depth;
- if (screen == NULL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
+ if (xcb_connection_has_error (xcb_connection))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+ if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ xcb_screen = _cairo_xcb_screen_from_visual (xcb_connection, visual, &depth);
+ if (unlikely (xcb_screen == NULL))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_VISUAL);
+
+ image_masks.alpha_mask = 0;
+ image_masks.red_mask = visual->red_mask;
+ image_masks.green_mask = visual->green_mask;
+ image_masks.blue_mask = visual->blue_mask;
+ if (depth > 16)
+ image_masks.bpp = 32;
+ else if (depth > 8)
+ image_masks.bpp = 16;
+ else if (depth > 1)
+ image_masks.bpp = 8;
+ else
+ image_masks.bpp = 1;
- return _cairo_xcb_surface_create_internal (c, drawable, screen,
- visual, NULL,
- width, height, 0);
+ if (! _pixman_format_from_masks (&image_masks, &pixman_format))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+ screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+ if (unlikely (screen == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ xrender_format =
+ _cairo_xcb_connection_get_xrender_format_for_visual (screen->connection,
+ visual->visual_id);
+
+ return _cairo_xcb_surface_create_internal (screen, drawable, FALSE,
+ pixman_format,
+ xrender_format,
+ width, height);
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_create);
+#endif
-/**
- * cairo_xcb_surface_create_for_bitmap:
- * @c: an XCB connection
- * @bitmap: an XCB Pixmap (a depth-1 pixmap)
- * @screen: an XCB Screen
- * @width: the current width of @bitmap
- * @height: the current height of @bitmap
- *
- * Creates an XCB 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_xcb_surface_create_for_bitmap (xcb_connection_t *c,
- xcb_pixmap_t bitmap,
- xcb_screen_t *screen,
- int width,
- int height)
+cairo_xcb_surface_create_for_bitmap (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen,
+ xcb_pixmap_t bitmap,
+ int width,
+ int height)
{
- return _cairo_xcb_surface_create_internal (c, bitmap, screen,
- NULL, NULL,
- width, height, 1);
+ cairo_xcb_screen_t *screen;
+
+ if (xcb_connection_has_error (xcb_connection))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+ if (unlikely (screen == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ return _cairo_xcb_surface_create_internal (screen, bitmap, FALSE,
+ PIXMAN_a1,
+ screen->connection->standard_formats[CAIRO_FORMAT_A1],
+ width, height);
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_create_for_bitmap);
+#endif
/**
* cairo_xcb_surface_create_with_xrender_format:
- * @c: an XCB connection
+ * @connection: an XCB connection
* @drawable: an XCB drawable
* @screen: the XCB screen associated with @drawable
* @format: the picture format to use for drawing to @drawable. The
@@ -2179,18 +1219,61 @@ cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
* Return value: the newly created surface.
**/
cairo_surface_t *
-cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *c,
+cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *xcb_connection,
+ xcb_screen_t *xcb_screen,
xcb_drawable_t drawable,
- xcb_screen_t *screen,
xcb_render_pictforminfo_t *format,
int width,
int height)
{
- return _cairo_xcb_surface_create_internal (c, drawable, screen,
- NULL, format,
- width, height, 0);
+ cairo_xcb_screen_t *screen;
+ cairo_format_masks_t image_masks;
+ pixman_format_code_t pixman_format;
+
+ if (xcb_connection_has_error (xcb_connection))
+ return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+ image_masks.alpha_mask =
+ (unsigned long) format->direct.alpha_mask << format->direct.alpha_shift;
+ image_masks.red_mask =
+ (unsigned long) format->direct.red_mask << format->direct.red_shift;
+ image_masks.green_mask =
+ (unsigned long) format->direct.green_mask << format->direct.green_shift;
+ image_masks.blue_mask =
+ (unsigned long) format->direct.blue_mask << format->direct.blue_shift;
+#if 0
+ image_masks.bpp = format->depth;
+#else
+ if (format->depth > 16)
+ image_masks.bpp = 32;
+ else if (format->depth > 8)
+ image_masks.bpp = 16;
+ else if (format->depth > 1)
+ image_masks.bpp = 8;
+ else
+ image_masks.bpp = 1;
+#endif
+
+ if (! _pixman_format_from_masks (&image_masks, &pixman_format))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+ screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+ if (unlikely (screen == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ return _cairo_xcb_surface_create_internal (screen,
+ drawable,
+ FALSE,
+ pixman_format,
+ format->id,
+ width, height);
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
+#endif
/**
* cairo_xcb_surface_set_size:
@@ -2210,613 +1293,28 @@ slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
**/
void
cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
- int width,
- int height)
+ int width,
+ int height)
{
- cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) abstract_surface;
+ cairo_xcb_surface_t *surface;
cairo_status_t status_ignored;
- if (! _cairo_surface_is_xcb (abstract_surface)) {
+ if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) {
status_ignored = _cairo_surface_set_error (abstract_surface,
- CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return;
}
- surface->width = width;
- surface->height = height;
-}
-
-/*
- * Glyph rendering support
- */
-
-typedef struct _cairo_xcb_surface_font_private {
- xcb_connection_t *dpy;
- xcb_render_glyphset_t glyphset;
- cairo_format_t format;
- xcb_render_pictforminfo_t *xrender_format;
-} cairo_xcb_surface_font_private_t;
-
-static cairo_status_t
-_cairo_xcb_surface_font_init (xcb_connection_t *dpy,
- cairo_scaled_font_t *scaled_font,
- cairo_format_t format)
-{
- cairo_xcb_surface_font_private_t *font_private;
-
- font_private = malloc (sizeof (cairo_xcb_surface_font_private_t));
- if (!font_private)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- font_private->dpy = dpy;
- font_private->format = format;
- font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format);
- font_private->glyphset = xcb_generate_id(dpy);
-
- /* XXX checking, adding to CloseDisplay */
- xcb_render_create_glyph_set (dpy,
- font_private->glyphset,
- font_private->xrender_format->id);
-
- scaled_font->surface_private = font_private;
- scaled_font->surface_backend = &cairo_xcb_surface_backend;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
-
- if (font_private) {
- xcb_render_free_glyph_set (font_private->dpy, font_private->glyphset);
- free (font_private);
- }
-}
-
-static void
-_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
-
- if (font_private != NULL && scaled_glyph->surface_private != NULL) {
- xcb_render_glyph_t glyph_index = _cairo_scaled_glyph_index(scaled_glyph);
- xcb_render_free_glyphs (font_private->dpy,
- font_private->glyphset,
- 1, &glyph_index);
- }
-}
-
-static cairo_bool_t
-_native_byte_order_lsb (void)
-{
- int x = 1;
-
- return *((char *) &x) == 1;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_add_glyph (cairo_xcb_surface_t *dst,
- cairo_scaled_font_t *scaled_font,
- cairo_scaled_glyph_t *scaled_glyph)
-{
- xcb_render_glyphinfo_t glyph_info;
- xcb_render_glyph_t glyph_index;
- unsigned char *data;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_xcb_surface_font_private_t *font_private;
- cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
- xcb_void_cookie_t cookie;
-
- if (scaled_font->surface_private == NULL) {
- status = _cairo_xcb_surface_font_init (dst->dpy, scaled_font,
- glyph_surface->format);
- if (status)
- return status;
- }
- font_private = scaled_font->surface_private;
-
- /* If the glyph format does not match the font format, then we
- * create a temporary surface for the glyph image with the font's
- * format.
- */
- if (glyph_surface->format != font_private->format) {
- cairo_surface_pattern_t pattern;
- cairo_surface_t *tmp_surface;
-
- tmp_surface = cairo_image_surface_create (font_private->format,
- glyph_surface->width,
- glyph_surface->height);
- status = tmp_surface->status;
- if (unlikely (status))
- goto BAIL;
-
- tmp_surface->device_transform = glyph_surface->base.device_transform;
- tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
-
- _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;
-
- if (unlikely (status))
- goto BAIL;
- }
-
- /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
- glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
- glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
- glyph_info.width = glyph_surface->width;
- glyph_info.height = glyph_surface->height;
- glyph_info.x_off = 0;
- glyph_info.y_off = 0;
-
- data = glyph_surface->data;
-
- /* flip formats around */
- switch (scaled_glyph->surface->format) {
- case CAIRO_FORMAT_A1:
- /* local bitmaps are always stored with bit == byte */
- if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
- int c = glyph_surface->stride * glyph_surface->height;
- unsigned char *d;
- unsigned char *new, *n;
-
- new = malloc (c);
- if (!new) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- n = new;
- d = data;
- while (c--)
- {
- char b = *d++;
- b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
- b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
- b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
- *n++ = b;
- }
- data = new;
- }
- break;
- case CAIRO_FORMAT_A8:
- break;
- case CAIRO_FORMAT_ARGB32:
- if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
- unsigned int c = glyph_surface->stride * glyph_surface->height;
- unsigned char *d;
- unsigned char *new, *n;
-
- new = malloc (c);
- if (new == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
- n = new;
- d = data;
- while (c >= 4)
- {
- n[3] = d[0];
- n[2] = d[1];
- n[1] = d[2];
- n[0] = d[3];
- d += 4;
- n += 4;
- c -= 4;
- }
- data = new;
- }
- break;
- case CAIRO_FORMAT_RGB24:
- default:
- ASSERT_NOT_REACHED;
- break;
- }
- /* XXX assume X server wants pixman padding. Xft assumes this as well */
-
- glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
-
- cookie = xcb_render_add_glyphs_checked (dst->dpy, font_private->glyphset,
- 1, &glyph_index, &glyph_info,
- glyph_surface->stride * glyph_surface->height,
- data);
-
- if (data != glyph_surface->data)
- free (data);
-
- status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-
- BAIL:
- if (glyph_surface != scaled_glyph->surface)
- cairo_surface_destroy (&glyph_surface->base);
-
- return status;
-}
-
-#define N_STACK_BUF 1024
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_8 (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- int src_x_offset, int src_y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
- xcb_render_util_composite_text_stream_t *stream;
- xcb_void_cookie_t cookie;
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
- uint8_t glyph;
-
- stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
- for (i = 0; i < num_glyphs; ++i) {
- thisX = _cairo_lround (glyphs[i].x);
- thisY = _cairo_lround (glyphs[i].y);
- glyph = glyphs[i].index;
- xcb_render_util_glyphs_8 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
- lastX = thisX;
- lastY = thisY;
- }
-
- cookie = xcb_render_util_composite_text_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- dst->dst_picture,
- font_private->xrender_format->id,
- src_x_offset + _cairo_lround (glyphs[0].x),
- src_y_offset + _cairo_lround (glyphs[0].y),
- stream);
-
- xcb_render_util_composite_text_free (stream);
-
- return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- int src_x_offset, int src_y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
- xcb_render_util_composite_text_stream_t *stream;
- xcb_void_cookie_t cookie;
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
- uint16_t glyph;
-
- stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
- for (i = 0; i < num_glyphs; ++i) {
- thisX = _cairo_lround (glyphs[i].x);
- thisY = _cairo_lround (glyphs[i].y);
- glyph = glyphs[i].index;
- xcb_render_util_glyphs_16 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
- lastX = thisX;
- lastY = thisY;
- }
-
- cookie = xcb_render_util_composite_text_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- dst->dst_picture,
- font_private->xrender_format->id,
- src_x_offset + _cairo_lround (glyphs[0].x),
- src_y_offset + _cairo_lround (glyphs[0].y),
- stream);
-
- xcb_render_util_composite_text_free (stream);
-
- return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- int src_x_offset, int src_y_offset,
- const cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
- xcb_render_util_composite_text_stream_t *stream;
- xcb_void_cookie_t cookie;
- int i;
- int thisX, thisY;
- int lastX = 0, lastY = 0;
- uint32_t glyph;
-
- stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
- for (i = 0; i < num_glyphs; ++i) {
- thisX = _cairo_lround (glyphs[i].x);
- thisY = _cairo_lround (glyphs[i].y);
- glyph = glyphs[i].index;
- xcb_render_util_glyphs_32 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
- lastX = thisX;
- lastY = thisY;
- }
-
- cookie = xcb_render_util_composite_text_checked (dst->dpy,
- _render_operator (op),
- src->src_picture,
- dst->dst_picture,
- font_private->xrender_format->id,
- src_x_offset + _cairo_lround (glyphs[0].x),
- src_y_offset + _cairo_lround (glyphs[0].y),
- stream);
-
- xcb_render_util_composite_text_free (stream);
-
- return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t)
- (cairo_xcb_surface_t *, cairo_operator_t, cairo_xcb_surface_t *, int, int,
- const cairo_glyph_t *, int, cairo_scaled_font_t *);
-
-static cairo_bool_t
-_cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_xcb_surface_font_private_t *font_private;
-
- font_private = scaled_font->surface_private;
- if ((scaled_font->surface_backend != NULL &&
- scaled_font->surface_backend != &cairo_xcb_surface_backend) ||
- (font_private != NULL && font_private->dpy != dst->dpy))
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
- cairo_xcb_surface_t *src,
- cairo_surface_attributes_t *attributes,
- int *remaining_glyphs)
-{
- cairo_scaled_glyph_t *scaled_glyph;
- int i, o;
- unsigned long max_index = 0;
- cairo_status_t status;
- cairo_glyph_t *output_glyphs;
- const cairo_glyph_t *glyphs_chunk;
- int glyphs_remaining, chunk_size, max_chunk_size;
- cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
-
- /* We make a copy of the glyphs so that we can elide any size-zero
- * glyphs to workaround an X server bug, (present in at least Xorg
- * 7.1 without EXA). */
- output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
- if (output_glyphs == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- for (i = 0, o = 0; i < num_glyphs; i++) {
- if (glyphs[i].index > max_index)
- max_index = glyphs[i].index;
- status = _cairo_scaled_glyph_lookup (scaled_font,
- glyphs[i].index,
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- &scaled_glyph);
- if (status) {
- free (output_glyphs);
- return status;
- }
-
- /* Don't put any size-zero glyphs into output_glyphs to avoid
- * an X server bug which stops rendering glyphs after the
- * first size-zero glyph. */
- if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
- output_glyphs[o++] = glyphs[i];
- if (scaled_glyph->surface_private == NULL) {
- _cairo_xcb_surface_add_glyph (dst, scaled_font, scaled_glyph);
- scaled_glyph->surface_private = (void *) 1;
- }
- }
- }
- num_glyphs = o;
-
- status = _cairo_xcb_surface_ensure_dst_picture (dst);
- if (status) {
- free (output_glyphs);
- return status;
- }
-
- max_chunk_size = xcb_get_maximum_request_length (dst->dpy);
- if (max_index < 256) {
- /* XXX: these are all the same size! (28) */
- max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t);
- show_glyphs_func = _cairo_xcb_surface_show_glyphs_8;
- } else if (max_index < 65536) {
- max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t);
- show_glyphs_func = _cairo_xcb_surface_show_glyphs_16;
- } else {
- max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t);
- show_glyphs_func = _cairo_xcb_surface_show_glyphs_32;
- }
- /* XXX: I think this is wrong; this is only the header size (2 longs) */
- /* but should also include the glyph (1 long) */
- /* max_chunk_size /= sz_xGlyphElt; */
- max_chunk_size /= 3*sizeof(uint32_t);
-
- for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
- glyphs_remaining;
- glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
- {
- chunk_size = MIN (glyphs_remaining, max_chunk_size);
-
- status = show_glyphs_func (dst, op, src,
- attributes->x_offset, attributes->y_offset,
- glyphs_chunk, chunk_size, scaled_font);
- if (status) {
- free (output_glyphs);
- return status;
- }
- }
-
- /* We wouldn't want to leak memory, would we? */
- free(output_glyphs);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *src_pattern,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- cairo_clip_t *clip,
- int *remaining_glyphs)
-{
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_xcb_surface_t *dst = abstract_dst;
-
- composite_operation_t operation;
- cairo_surface_attributes_t attributes;
- cairo_xcb_surface_t *src = NULL;
-
- cairo_region_t *clip_region = NULL;
-
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* 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;
-
- /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
- * the solid source seems to be multiplied by the glyph mask, and
- * then the entire thing is copied to the destination surface,
- * 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;
-
- /* 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 (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;
-
- if (! _cairo_xcb_surface_owns_font (dst, scaled_font))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* After passing all those tests, we're now committed to rendering
- * these glyphs or to fail trying. We first upload any glyphs to
- * the X server that it doesn't have already, then we draw
- * them. We tie into the scaled_font's glyph cache and remove
- * glyphs from the X server when they are ejected from the
- * scaled_font cache.
- */
-
- /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
- * the mask (the glyphs). This code below was executed as a side effect
- * of going through the _clip_and_composite fallback code for old_show_glyphs,
- * so PictOpClear was never used with CompositeText before.
- */
- if (op == CAIRO_OPERATOR_CLEAR) {
- src_pattern = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
- status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
- 0, 0, 1, 1,
- CAIRO_PATTERN_ACQUIRE_NONE,
- (cairo_surface_t **) &src,
- &attributes);
- } else {
- cairo_rectangle_int_t glyph_extents;
-
- status = _cairo_scaled_font_glyph_device_extents (scaled_font,
- glyphs,
- num_glyphs,
- &glyph_extents,
- NULL);
- if (status)
- goto BAIL;
-
- status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
- glyph_extents.x, glyph_extents.y,
- glyph_extents.width, glyph_extents.height,
- CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
- (cairo_surface_t **) &src,
- &attributes);
- }
-
- if (status)
- goto BAIL;
-
- operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
- if (operation == DO_UNSUPPORTED) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto BAIL;
- }
-
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_xcb_surface_set_attributes (src, &attributes);
- if (status)
- goto BAIL;
-
- /* Send all unsent glyphs to the server, and count the max of the glyph indices */
- _cairo_scaled_font_freeze_cache (scaled_font);
-
- if (_cairo_xcb_surface_owns_font (dst, scaled_font)) {
- status = _cairo_xcb_surface_emit_glyphs (dst,
- glyphs, num_glyphs,
- scaled_font,
- op,
- src,
- &attributes,
- remaining_glyphs);
- } else {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
+ status_ignored = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_INVALID_SIZE);
+ return;
}
- _cairo_scaled_font_thaw_cache (scaled_font);
-
- BAIL:
- if (src)
- _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
- return status;
+ surface = (cairo_xcb_surface_t *) abstract_surface;
+ surface->width = width;
+ surface->height = height;
}
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_set_size);
+#endif
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
index 1b6d2e69f..a1e9da171 100644
--- a/src/cairo-xcb.h
+++ b/src/cairo-xcb.h
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_XCB_H
@@ -42,28 +44,49 @@
#if CAIRO_HAS_XCB_SURFACE
#include <xcb/xcb.h>
+#include <xcb/render.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
-cairo_xcb_surface_create (xcb_connection_t *c,
+cairo_xcb_surface_create (xcb_connection_t *connection,
xcb_drawable_t drawable,
- xcb_visualtype_t *visual,
- int width,
- int height);
+ xcb_visualtype_t *visual,
+ int width,
+ int height);
cairo_public cairo_surface_t *
-cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
- xcb_pixmap_t bitmap,
- xcb_screen_t *screen,
- int width,
- int height);
+cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection,
+ xcb_screen_t *screen,
+ xcb_pixmap_t bitmap,
+ int width,
+ int height);
+
+cairo_public cairo_surface_t *
+cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection,
+ xcb_screen_t *screen,
+ xcb_drawable_t drawable,
+ xcb_render_pictforminfo_t *format,
+ int width,
+ int height);
cairo_public void
cairo_xcb_surface_set_size (cairo_surface_t *surface,
int width,
int height);
+/* debug interface */
+
+cairo_public void
+cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
+ int major_version,
+ int minor_version);
+
+cairo_public void
+cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
+ int major_version,
+ int minor_version);
+
CAIRO_END_DECLS
#else /* CAIRO_HAS_XCB_SURFACE */
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
new file mode 100644
index 000000000..a8e0cde7b
--- /dev/null
+++ b/src/cairo-xlib-xcb-surface.c
@@ -0,0 +1,515 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xlib.h"
+#include "cairo-xcb.h"
+
+#include "cairo-xcb-private.h"
+#include "cairo-xlib-xrender-private.h"
+
+#include <X11/Xlib-xcb.h>
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create (void *dpy,
+ void *scr,
+ void *visual,
+ void *format,
+ cairo_surface_t *xcb);
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create_similar (void *abstract_other,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_xlib_xcb_surface_t *other = abstract_other;
+ cairo_surface_t *xcb;
+
+ xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height);
+ if (unlikely (xcb == NULL || xcb->status))
+ return xcb;
+
+ return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_finish (void *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ cairo_surface_finish (&surface->xcb->base);
+ status = surface->xcb->base.status;
+ cairo_surface_destroy (&surface->xcb->base);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface,
+ cairo_image_surface_t **image_out,
+ void **image_extra)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return _cairo_surface_acquire_source_image (&surface->xcb->base,
+ image_out, image_extra);
+}
+
+static void
+_cairo_xlib_xcb_surface_release_source_image (void *abstract_surface,
+ cairo_image_surface_t *image_out,
+ void *image_extra)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra);
+}
+
+static cairo_bool_t
+_cairo_xlib_xcb_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return _cairo_surface_get_extents (&surface->xcb->base, extents);
+}
+
+static void
+_cairo_xlib_xcb_surface_get_font_options (void *abstract_surface,
+ cairo_font_options_t *options)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ surface->xcb->base.backend->get_font_options (surface->xcb, options);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->paint (surface->xcb, op, source, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->mask (surface->xcb, op, source, mask, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->stroke (surface->xcb,
+ op, source, path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->fill (surface->xcb,
+ op, source, path,
+ fill_rule, tolerance, antialias,
+ clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ int *num_remaining)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->show_glyphs (surface->xcb, op, source,
+ glyphs, num_glyphs, scaled_font,
+ clip, num_remaining);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_flush (void *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->flush (surface->xcb);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
+ int x, int y,
+ int width, int height)
+{
+ cairo_xlib_xcb_surface_t *surface = abstract_surface;
+ return surface->xcb->base.backend->mark_dirty_rectangle (surface->xcb, x, y, width, height);
+}
+
+static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
+ CAIRO_SURFACE_TYPE_XLIB,
+ _cairo_xlib_xcb_surface_create_similar,
+ _cairo_xlib_xcb_surface_finish,
+ _cairo_xlib_xcb_surface_acquire_source_image,
+ _cairo_xlib_xcb_surface_release_source_image,
+ NULL, NULL, NULL, /* dest acquire/release/clone */
+
+ NULL, /* composite */
+ NULL, /* fill */
+ NULL, /* trapezoids */
+ NULL, /* span */
+ NULL, /* check-span */
+
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _cairo_xlib_xcb_surface_get_extents,
+ NULL, /* old-glyphs */
+ _cairo_xlib_xcb_surface_get_font_options,
+
+ _cairo_xlib_xcb_surface_flush,
+ _cairo_xlib_xcb_surface_mark_dirty,
+ NULL, NULL, /* font/glyph fini */
+
+ _cairo_xlib_xcb_surface_paint,
+ _cairo_xlib_xcb_surface_mask,
+ _cairo_xlib_xcb_surface_stroke,
+ _cairo_xlib_xcb_surface_fill,
+ _cairo_xlib_xcb_surface_glyphs,
+};
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create (void *dpy,
+ void *scr,
+ void *visual,
+ void *format,
+ cairo_surface_t *xcb)
+{
+ cairo_xlib_xcb_surface_t *surface;
+
+ if (unlikely (xcb->status))
+ return xcb;
+
+ surface = malloc (sizeof (*surface));
+ if (unlikely (surface == NULL)) {
+ cairo_surface_destroy (xcb);
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_xlib_xcb_surface_backend,
+ xcb->device,
+ xcb->content);
+
+ surface->display = dpy;
+ surface->screen = scr;
+ surface->visual = visual;
+ surface->format = format;
+ surface->xcb = (cairo_xcb_surface_t *) xcb;
+
+ return &surface->base;
+}
+
+static Screen *
+_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
+{
+ 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;
+}
+
+cairo_surface_t *
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ int width,
+ int height)
+{
+ Screen *scr;
+ xcb_visualtype_t xcb_visual;
+
+ scr = _cairo_xlib_screen_from_visual (dpy, visual);
+ if (scr == NULL)
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
+
+ xcb_visual.visual_id = visual->visualid;
+#if defined(__cplusplus) || defined(c_plusplus)
+ xcb_visual._class = visual->c_class;
+#else
+ xcb_visual._class = visual->class;
+#endif
+ xcb_visual.bits_per_rgb_value = visual->bits_per_rgb;
+ xcb_visual.colormap_entries = visual->map_entries;
+ xcb_visual.red_mask = visual->red_mask;
+ xcb_visual.green_mask = visual->green_mask;
+ xcb_visual.blue_mask = visual->blue_mask;
+
+ return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL,
+ cairo_xcb_surface_create (XGetXCBConnection (dpy),
+ drawable,
+ &xcb_visual,
+ width, height));
+}
+
+cairo_surface_t *
+cairo_xlib_surface_create_for_bitmap (Display *dpy,
+ Pixmap bitmap,
+ Screen *scr,
+ int width,
+ int height)
+{
+ return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
+ cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy),
+ (xcb_screen_t *) scr,
+ bitmap,
+ width, height));
+}
+
+#if CAIRO_HAS_XLIB_XRENDER_SURFACE
+cairo_surface_t *
+cairo_xlib_surface_create_with_xrender_format (Display *dpy,
+ Drawable drawable,
+ Screen *scr,
+ XRenderPictFormat *format,
+ int width,
+ int height)
+{
+ xcb_render_pictforminfo_t xcb_format;
+
+ xcb_format.id = format->id;
+ xcb_format.type = format->type;
+ xcb_format.depth = format->depth;
+ xcb_format.direct.red_shift = format->direct.red;
+ xcb_format.direct.red_mask = format->direct.redMask;
+ xcb_format.direct.green_shift = format->direct.green;
+ xcb_format.direct.green_mask = format->direct.greenMask;
+ xcb_format.direct.blue_shift = format->direct.blue;
+ xcb_format.direct.blue_mask = format->direct.blueMask;
+ xcb_format.direct.alpha_shift = format->direct.alpha;
+ xcb_format.direct.alpha_mask = format->direct.alphaMask;
+ xcb_format.colormap = format->colormap;
+
+ return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
+ cairo_xcb_surface_create_with_xrender_format (XGetXCBConnection (dpy),
+ (xcb_screen_t *) scr,
+ drawable,
+ &xcb_format,
+ width, height));
+}
+
+XRenderPictFormat *
+cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
+{
+ cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface;
+
+ /* Throw an error for a non-xlib surface */
+ if (surface->type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return xlib_surface->format;
+}
+#endif
+
+void
+cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
+ int width,
+ int height)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+ cairo_status_t status;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ status = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return;
+ }
+
+ cairo_xcb_surface_set_size (&surface->xcb->base, width, height);
+}
+
+void
+cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
+ Drawable drawable,
+ int width,
+ int height)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface;
+ cairo_status_t status;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ status = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return;
+ }
+
+ ASSERT_NOT_REACHED;
+}
+
+Display *
+cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return surface->display;
+}
+
+Drawable
+cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->drawable;
+}
+
+Screen *
+cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return surface->screen;
+}
+
+Visual *
+cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return NULL;
+ }
+
+ return surface->visual;
+}
+
+int
+cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->depth;
+}
+
+int
+cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->width;
+}
+
+int
+cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
+{
+ cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+ if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return 0;
+ }
+
+ return surface->xcb->height;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 0892bbbd0..acc5769e4 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2555,9 +2555,25 @@ cairo_private unsigned long
_cairo_pattern_hash (const cairo_pattern_t *pattern);
cairo_private unsigned long
+_cairo_linear_pattern_hash (unsigned long hash,
+ const cairo_linear_pattern_t *linear);
+
+cairo_private unsigned long
+_cairo_radial_pattern_hash (unsigned long hash,
+ const cairo_radial_pattern_t *radial);
+
+cairo_private cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
+ const cairo_linear_pattern_t *b);
+
+cairo_private unsigned long
_cairo_pattern_size (const cairo_pattern_t *pattern);
cairo_private cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
+ const cairo_radial_pattern_t *b);
+
+cairo_private cairo_bool_t
_cairo_pattern_equal (const cairo_pattern_t *a,
const cairo_pattern_t *b);
diff --git a/test/xcb-surface-source.c b/test/xcb-surface-source.c
index debe93e35..d359cf2cb 100644
--- a/test/xcb-surface-source.c
+++ b/test/xcb-surface-source.c
@@ -26,7 +26,6 @@
#include "cairo-test.h"
#if CAIRO_HAS_XCB_SURFACE
#include <cairo-xcb.h>
-#include <cairo-xcb-xrender.h>
#endif
#include "surface-source.c"