xcb: Refresh.

Still an experimental backend, it's now a little too late to stabilise
for 1.10, but this should represent a major step forward in its feature
set and an attempt to catch up with all the bug fixes that have been
performed on xlib. Notably not tested yet (and expected to be broken)
are mixed-endian connections and low bitdepth servers (the dithering
support has not been copied over for instance). However, it seems robust
enough for daily use...

Of particular note in this update is that the xcb surface is now capable
of subverting the xlib surface through the ./configure --enable-xlib-xcb
option. This replaces the xlib surface with a proxy that forwards all
operations to an equivalent xcb surface whilst preserving the cairo-xlib
API that is required for compatibility with the existing applications,
for instance GTK+ and Mozilla. Also you can experiment with enabling a
DRM bypass, though you need to be extremely foolhardy to do so.
This commit is contained in:
Chris Wilson 2010-01-22 21:26:26 +00:00
parent 77afe8491e
commit 1236c41072
27 changed files with 11759 additions and 2622 deletions

View file

@ -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)

View file

@ -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,33 @@ _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->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 +165,373 @@ _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,
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);
surface = cairo_boilerplate_surface_create_in_error (status);
_cairo_boilerplate_xcb_cleanup (xtc);
return cairo_boilerplate_surface_create_in_error (status);
}
return surface;
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->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;
}
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);
_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);
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)

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -109,11 +109,23 @@ 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 ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(qt, Qt, no, [
@ -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, [

View file

@ -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

View file

@ -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)

View file

@ -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 */

View file

@ -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

View file

@ -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:

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

867
src/cairo-xcb-connection.c Normal file
View file

@ -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

760
src/cairo-xcb-private.h Normal file
View file

@ -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 */

518
src/cairo-xcb-screen.c Normal file
View file

@ -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;
}

576
src/cairo-xcb-shm.c Normal file
View file

@ -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));
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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
#ifndef CAIRO_XCB_SURFACE_PRIVATE_H
#define CAIRO_XCB_SURFACE_PRIVATE_H
#include "cairo.h"
#include "cairo-xcb-private.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
#else /* CAIRO_HAS_XCB_SURFACE */
# error Cairo was not compiled with support for the xcb backend
#endif /* CAIRO_HAS_XCB_SURFACE */
#endif /* CAIRO_XCB_XRENDER_H */
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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;
}

View file

@ -2554,9 +2554,25 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
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);

View file

@ -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"