summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 5c1e0119..8d564118 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 0ab2026f..ed173e68 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 bd314e9f..b8c40a85 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 7e49cd63..95e9386d 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 e057e2c8..c55b4efa 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 d704353f..f94d9c17 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 f6d4fe30..0f77f0ed 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 048c9211..35750579 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 b8254bb7..6d65bf1c 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 c84cebf6..aa2c8f80 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 e77f1531..aae1aa57 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 00000000..22a340df
--- /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 00000000..2ebd6b47
--- /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 00000000..2c13b1ba
--- /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 00000000..6721e923
--- /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 00000000..18a485cf
--- /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 00000000..06c07a55
--- /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 00000000..7a47f338
--- /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 00000000..c8305cf7
--- /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 00000000..6f1002a8
--- /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 09c60973..1ef49003 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 00000000..e07f575c
--- /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 666abc99..2e08c641 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 1b6d2e69..a1e9da17 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 00000000..a8e0cde7
--- /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 0892bbbd..acc5769e 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 debe93e3..d359cf2c 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"