beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-xcb-surface.c
blobd4d60ad72856c8585b2f36b3b87c2c0f68594b45
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2002 University of Southern California
4 * Copyright © 2009 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is University of Southern
32 * California.
34 * Contributor(s):
35 * Behdad Esfahbod <behdad@behdad.org>
36 * Carl D. Worth <cworth@cworth.org>
37 * Chris Wilson <chris@chris-wilson.co.uk>
38 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
41 #include "cairoint.h"
43 #include "cairo-xcb.h"
44 #include "cairo-xcb-private.h"
46 #include "cairo-composite-rectangles-private.h"
47 #include "cairo-default-context-private.h"
48 #include "cairo-image-surface-inline.h"
49 #include "cairo-list-inline.h"
50 #include "cairo-surface-backend-private.h"
51 #include "cairo-compositor-private.h"
53 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
54 slim_hidden_proto (cairo_xcb_surface_create);
55 slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
56 slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
57 #endif
59 /**
60 * SECTION:cairo-xcb
61 * @Title: XCB Surfaces
62 * @Short_Description: X Window System rendering using the XCB library
63 * @See_Also: #cairo_surface_t
65 * The XCB surface is used to render cairo graphics to X Window System
66 * windows and pixmaps using the XCB library.
68 * Note that the XCB surface automatically takes advantage of the X render
69 * extension if it is available.
70 **/
72 /**
73 * CAIRO_HAS_XCB_SURFACE:
75 * Defined if the xcb surface backend is available.
76 * This macro can be used to conditionally compile backend-specific code.
78 * Since: 1.12
79 **/
81 cairo_surface_t *
82 _cairo_xcb_surface_create_similar (void *abstract_other,
83 cairo_content_t content,
84 int width,
85 int height)
87 cairo_xcb_surface_t *other = abstract_other;
88 cairo_xcb_surface_t *surface;
89 cairo_xcb_connection_t *connection;
90 xcb_pixmap_t pixmap;
91 cairo_status_t status;
93 if (unlikely(width > XLIB_COORD_MAX ||
94 height > XLIB_COORD_MAX ||
95 width <= 0 ||
96 height <= 0))
97 return cairo_image_surface_create (_cairo_format_from_content (content),
98 width, height);
100 if ((other->connection->flags & CAIRO_XCB_HAS_RENDER) == 0)
101 return _cairo_xcb_surface_create_similar_image (other,
102 _cairo_format_from_content (content),
103 width, height);
105 connection = other->connection;
106 status = _cairo_xcb_connection_acquire (connection);
107 if (unlikely (status))
108 return _cairo_surface_create_in_error (status);
110 if (content == other->base.content) {
111 pixmap = _cairo_xcb_connection_create_pixmap (connection,
112 other->depth,
113 other->drawable,
114 width, height);
116 surface = (cairo_xcb_surface_t *)
117 _cairo_xcb_surface_create_internal (other->screen,
118 pixmap, TRUE,
119 other->pixman_format,
120 other->xrender_format,
121 width, height);
122 } else {
123 cairo_format_t format;
124 pixman_format_code_t pixman_format;
126 /* XXX find a compatible xrender format */
127 switch (content) {
128 case CAIRO_CONTENT_ALPHA:
129 pixman_format = PIXMAN_a8;
130 format = CAIRO_FORMAT_A8;
131 break;
132 case CAIRO_CONTENT_COLOR:
133 pixman_format = PIXMAN_x8r8g8b8;
134 format = CAIRO_FORMAT_RGB24;
135 break;
136 default:
137 ASSERT_NOT_REACHED;
138 case CAIRO_CONTENT_COLOR_ALPHA:
139 pixman_format = PIXMAN_a8r8g8b8;
140 format = CAIRO_FORMAT_ARGB32;
141 break;
144 pixmap = _cairo_xcb_connection_create_pixmap (connection,
145 PIXMAN_FORMAT_DEPTH (pixman_format),
146 other->drawable,
147 width, height);
149 surface = (cairo_xcb_surface_t *)
150 _cairo_xcb_surface_create_internal (other->screen,
151 pixmap, TRUE,
152 pixman_format,
153 connection->standard_formats[format],
154 width, height);
157 if (unlikely (surface->base.status))
158 _cairo_xcb_connection_free_pixmap (connection, pixmap);
160 _cairo_xcb_connection_release (connection);
162 return &surface->base;
165 cairo_surface_t *
166 _cairo_xcb_surface_create_similar_image (void *abstract_other,
167 cairo_format_t format,
168 int width,
169 int height)
171 cairo_xcb_surface_t *other = abstract_other;
172 cairo_xcb_connection_t *connection = other->connection;
174 cairo_xcb_shm_info_t *shm_info;
175 cairo_image_surface_t *image;
176 cairo_status_t status;
177 pixman_format_code_t pixman_format;
179 if (unlikely(width > XLIB_COORD_MAX ||
180 height > XLIB_COORD_MAX ||
181 width <= 0 ||
182 height <= 0))
183 return NULL;
185 pixman_format = _cairo_format_to_pixman_format_code (format);
187 status = _cairo_xcb_shm_image_create (connection, pixman_format,
188 width, height, &image,
189 &shm_info);
190 if (unlikely (status))
191 return _cairo_surface_create_in_error (status);
193 if (! image->base.is_clear) {
194 memset (image->data, 0, image->stride * image->height);
195 image->base.is_clear = TRUE;
198 return &image->base;
201 static cairo_status_t
202 _cairo_xcb_surface_finish (void *abstract_surface)
204 cairo_xcb_surface_t *surface = abstract_surface;
205 cairo_status_t status;
207 if (surface->fallback != NULL) {
208 cairo_surface_finish (&surface->fallback->base);
209 cairo_surface_destroy (&surface->fallback->base);
211 _cairo_boxes_fini (&surface->fallback_damage);
213 cairo_list_del (&surface->link);
215 status = _cairo_xcb_connection_acquire (surface->connection);
216 if (status == CAIRO_STATUS_SUCCESS) {
217 if (surface->picture != XCB_NONE) {
218 _cairo_xcb_connection_render_free_picture (surface->connection,
219 surface->picture);
222 if (surface->owns_pixmap)
223 _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable);
224 _cairo_xcb_connection_release (surface->connection);
227 _cairo_xcb_connection_destroy (surface->connection);
229 return status;
232 static void
233 _destroy_image (pixman_image_t *image, void *data)
235 free (data);
238 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
239 static cairo_surface_t *
240 _cairo_xcb_surface_create_shm_image (cairo_xcb_connection_t *connection,
241 pixman_format_code_t pixman_format,
242 int width, int height,
243 cairo_bool_t might_reuse,
244 cairo_xcb_shm_info_t **shm_info_out)
246 cairo_surface_t *image;
247 cairo_xcb_shm_info_t *shm_info;
248 cairo_int_status_t status;
249 size_t stride;
251 *shm_info_out = NULL;
253 stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width,
254 PIXMAN_FORMAT_BPP (pixman_format));
255 status = _cairo_xcb_connection_allocate_shm_info (connection,
256 stride * height,
257 might_reuse,
258 &shm_info);
259 if (unlikely (status)) {
260 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
261 return NULL;
263 return _cairo_surface_create_in_error (status);
266 image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
267 pixman_format,
268 width, height,
269 stride);
270 if (unlikely (image->status)) {
271 _cairo_xcb_shm_info_destroy (shm_info);
272 return image;
275 status = _cairo_user_data_array_set_data (&image->user_data,
276 (const cairo_user_data_key_t *) connection,
277 shm_info,
278 (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
279 if (unlikely (status)) {
280 cairo_surface_destroy (image);
281 _cairo_xcb_shm_info_destroy (shm_info);
282 return _cairo_surface_create_in_error (status);
285 *shm_info_out = shm_info;
286 return image;
288 #endif
290 static cairo_surface_t *
291 _get_shm_image (cairo_xcb_surface_t *surface,
292 int x, int y,
293 int width, int height)
295 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
296 cairo_xcb_shm_info_t *shm_info;
297 cairo_surface_t *image;
298 cairo_status_t status;
300 if ((surface->connection->flags & CAIRO_XCB_HAS_SHM) == 0)
301 return NULL;
303 image = _cairo_xcb_surface_create_shm_image (surface->connection,
304 surface->pixman_format,
305 width, height,
306 TRUE,
307 &shm_info);
308 if (unlikely (image == NULL || image->status))
309 goto done;
311 status = _cairo_xcb_connection_shm_get_image (surface->connection,
312 surface->drawable,
313 x, y,
314 width, height,
315 shm_info->shm,
316 shm_info->offset);
317 if (unlikely (status)) {
318 cairo_surface_destroy (image);
319 image = _cairo_surface_create_in_error (status);
322 done:
323 return image;
324 #else
325 return NULL;
326 #endif
329 static cairo_surface_t *
330 _get_image (cairo_xcb_surface_t *surface,
331 cairo_bool_t use_shm,
332 int x, int y,
333 int width, int height)
335 cairo_surface_t *image;
336 cairo_xcb_connection_t *connection;
337 xcb_get_image_reply_t *reply;
338 cairo_int_status_t status;
340 assert (surface->fallback == NULL);
341 assert (x >= 0);
342 assert (y >= 0);
343 assert (x + width <= surface->width);
344 assert (y + height <= surface->height);
346 if (surface->deferred_clear) {
347 image =
348 _cairo_image_surface_create_with_pixman_format (NULL,
349 surface->pixman_format,
350 width, height,
352 if (surface->deferred_clear_color.alpha_short > 0x00ff) {
353 cairo_solid_pattern_t solid;
355 _cairo_pattern_init_solid (&solid, &surface->deferred_clear_color);
356 status = _cairo_surface_paint (image,
357 CAIRO_OPERATOR_SOURCE,
358 &solid.base,
359 NULL);
360 if (unlikely (status)) {
361 cairo_surface_destroy (image);
362 image = _cairo_surface_create_in_error (status);
365 return image;
368 connection = surface->connection;
370 status = _cairo_xcb_connection_acquire (connection);
371 if (unlikely (status))
372 return _cairo_surface_create_in_error (status);
374 if (use_shm) {
375 image = _get_shm_image (surface, x, y, width, height);
376 if (image) {
377 if (image->status == CAIRO_STATUS_SUCCESS) {
378 _cairo_xcb_connection_release (connection);
379 return image;
381 cairo_surface_destroy (image);
385 reply =_cairo_xcb_connection_get_image (connection,
386 surface->drawable,
387 x, y,
388 width, height);
390 if (reply == NULL && ! surface->owns_pixmap) {
391 /* xcb_get_image_t from a window is dangerous because it can
392 * produce errors if the window is unmapped or partially
393 * outside the screen. We could check for errors and
394 * retry, but to keep things simple, we just create a
395 * temporary pixmap
397 * If we hit this fallback too often, we should remember so and
398 * skip the round-trip from the above GetImage request,
399 * similar to what cairo-xlib does.
401 xcb_pixmap_t pixmap;
402 xcb_gcontext_t gc;
404 gc = _cairo_xcb_screen_get_gc (surface->screen,
405 surface->drawable,
406 surface->depth);
407 pixmap = _cairo_xcb_connection_create_pixmap (connection,
408 surface->depth,
409 surface->drawable,
410 width, height);
412 /* XXX IncludeInferiors? */
413 _cairo_xcb_connection_copy_area (connection,
414 surface->drawable,
415 pixmap, gc,
416 x, y,
417 0, 0,
418 width, height);
420 _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
422 reply = _cairo_xcb_connection_get_image (connection,
423 pixmap,
424 0, 0,
425 width, height);
426 _cairo_xcb_connection_free_pixmap (connection, pixmap);
429 if (unlikely (reply == NULL)) {
430 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
431 goto FAIL;
434 /* XXX byte swap */
435 /* XXX format conversion */
436 assert (reply->depth == surface->depth);
438 image = _cairo_image_surface_create_with_pixman_format
439 (xcb_get_image_data (reply),
440 surface->pixman_format,
441 width, height,
442 CAIRO_STRIDE_FOR_WIDTH_BPP (width,
443 PIXMAN_FORMAT_BPP (surface->pixman_format)));
444 status = image->status;
445 if (unlikely (status)) {
446 free (reply);
447 goto FAIL;
450 /* XXX */
451 pixman_image_set_destroy_function (((cairo_image_surface_t *)image)->pixman_image, _destroy_image, reply);
453 _cairo_xcb_connection_release (connection);
455 return image;
457 FAIL:
458 _cairo_xcb_connection_release (connection);
459 return _cairo_surface_create_in_error (status);
462 static cairo_surface_t *
463 _cairo_xcb_surface_source (void *abstract_surface,
464 cairo_rectangle_int_t *extents)
466 cairo_xcb_surface_t *surface = abstract_surface;
468 if (extents) {
469 extents->x = extents->y = 0;
470 extents->width = surface->width;
471 extents->height = surface->height;
474 return &surface->base;
477 static cairo_status_t
478 _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
479 cairo_image_surface_t **image_out,
480 void **image_extra)
482 cairo_xcb_surface_t *surface = abstract_surface;
483 cairo_surface_t *image;
485 if (surface->fallback != NULL) {
486 image = cairo_surface_reference (&surface->fallback->base);
487 goto DONE;
490 image = _cairo_surface_has_snapshot (&surface->base,
491 &_cairo_image_surface_backend);
492 if (image != NULL) {
493 image = cairo_surface_reference (image);
494 goto DONE;
497 image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height);
498 if (unlikely (image->status))
499 return image->status;
501 _cairo_surface_attach_snapshot (&surface->base, image, NULL);
503 DONE:
504 *image_out = (cairo_image_surface_t *) image;
505 *image_extra = NULL;
506 return CAIRO_STATUS_SUCCESS;
509 static void
510 _cairo_xcb_surface_release_source_image (void *abstract_surface,
511 cairo_image_surface_t *image,
512 void *image_extra)
514 cairo_surface_destroy (&image->base);
517 cairo_bool_t
518 _cairo_xcb_surface_get_extents (void *abstract_surface,
519 cairo_rectangle_int_t *extents)
521 cairo_xcb_surface_t *surface = abstract_surface;
523 extents->x = extents->y = 0;
524 extents->width = surface->width;
525 extents->height = surface->height;
526 return TRUE;
529 static void
530 _cairo_xcb_surface_get_font_options (void *abstract_surface,
531 cairo_font_options_t *options)
533 cairo_xcb_surface_t *surface = abstract_surface;
535 *options = *_cairo_xcb_screen_get_font_options (surface->screen);
538 static cairo_status_t
539 _put_shm_image (cairo_xcb_surface_t *surface,
540 xcb_gcontext_t gc,
541 cairo_image_surface_t *image)
543 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
544 cairo_xcb_shm_info_t *shm_info;
546 shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
547 (const cairo_user_data_key_t *) surface->connection);
548 if (shm_info == NULL)
549 return CAIRO_INT_STATUS_UNSUPPORTED;
551 _cairo_xcb_connection_shm_put_image (surface->connection,
552 surface->drawable,
554 surface->width, surface->height,
555 0, 0,
556 image->width, image->height,
557 image->base.device_transform_inverse.x0,
558 image->base.device_transform_inverse.y0,
559 image->depth,
560 shm_info->shm,
561 shm_info->offset);
563 return CAIRO_STATUS_SUCCESS;
564 #else
565 return CAIRO_INT_STATUS_UNSUPPORTED;
566 #endif
569 static cairo_status_t
570 _put_image (cairo_xcb_surface_t *surface,
571 cairo_image_surface_t *image)
573 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
575 /* XXX track damaged region? */
577 status = _cairo_xcb_connection_acquire (surface->connection);
578 if (unlikely (status))
579 return status;
581 if (image->pixman_format == surface->pixman_format) {
582 xcb_gcontext_t gc;
584 assert (image->depth == surface->depth);
585 assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
587 gc = _cairo_xcb_screen_get_gc (surface->screen,
588 surface->drawable,
589 surface->depth);
591 status = _put_shm_image (surface, gc, image);
592 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
593 _cairo_xcb_connection_put_image (surface->connection,
594 surface->drawable, gc,
595 image->width, image->height,
596 image->base.device_transform_inverse.x0,
597 image->base.device_transform_inverse.y0,
598 image->depth,
599 image->stride,
600 image->data);
601 status = CAIRO_STATUS_SUCCESS;
604 _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
605 } else {
606 ASSERT_NOT_REACHED;
609 _cairo_xcb_connection_release (surface->connection);
610 return status;
613 static cairo_int_status_t
614 _put_shm_image_boxes (cairo_xcb_surface_t *surface,
615 cairo_image_surface_t *image,
616 xcb_gcontext_t gc,
617 cairo_boxes_t *boxes)
619 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
620 cairo_xcb_shm_info_t *shm_info;
622 shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
623 (const cairo_user_data_key_t *) surface->connection);
624 if (shm_info != NULL) {
625 struct _cairo_boxes_chunk *chunk;
627 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
628 int i;
630 for (i = 0; i < chunk->count; i++) {
631 cairo_box_t *b = &chunk->base[i];
632 int x = _cairo_fixed_integer_part (b->p1.x);
633 int y = _cairo_fixed_integer_part (b->p1.y);
634 int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
635 int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
637 _cairo_xcb_connection_shm_put_image (surface->connection,
638 surface->drawable,
640 surface->width, surface->height,
641 x, y,
642 width, height,
643 x, y,
644 image->depth,
645 shm_info->shm,
646 shm_info->offset);
649 return CAIRO_INT_STATUS_SUCCESS;
651 #endif
653 return CAIRO_INT_STATUS_UNSUPPORTED;
656 static cairo_status_t
657 _put_image_boxes (cairo_xcb_surface_t *surface,
658 cairo_image_surface_t *image,
659 cairo_boxes_t *boxes)
661 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
662 xcb_gcontext_t gc;
664 if (boxes->num_boxes == 0)
665 return CAIRO_STATUS_SUCCESS;
667 /* XXX track damaged region? */
669 status = _cairo_xcb_connection_acquire (surface->connection);
670 if (unlikely (status))
671 return status;
673 assert (image->pixman_format == surface->pixman_format);
674 assert (image->depth == surface->depth);
675 assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
677 gc = _cairo_xcb_screen_get_gc (surface->screen,
678 surface->drawable,
679 surface->depth);
681 status = _put_shm_image_boxes (surface, image, gc, boxes);
682 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
683 struct _cairo_boxes_chunk *chunk;
685 for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
686 int i;
688 for (i = 0; i < chunk->count; i++) {
689 cairo_box_t *b = &chunk->base[i];
690 int x = _cairo_fixed_integer_part (b->p1.x);
691 int y = _cairo_fixed_integer_part (b->p1.y);
692 int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
693 int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
694 _cairo_xcb_connection_put_subimage (surface->connection,
695 surface->drawable, gc,
696 x, y,
697 width, height,
698 PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
699 image->stride,
700 x, y,
701 image->depth,
702 image->data);
706 status = CAIRO_STATUS_SUCCESS;
709 _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
710 _cairo_xcb_connection_release (surface->connection);
711 return status;
714 static cairo_status_t
715 _cairo_xcb_surface_flush (void *abstract_surface,
716 unsigned flags)
718 cairo_xcb_surface_t *surface = abstract_surface;
719 cairo_status_t status;
721 if (flags)
722 return CAIRO_STATUS_SUCCESS;
724 if (likely (surface->fallback == NULL)) {
725 status = CAIRO_STATUS_SUCCESS;
726 if (! surface->base.finished && surface->deferred_clear)
727 status = _cairo_xcb_surface_clear (surface);
729 return status;
732 status = surface->base.status;
733 if (status == CAIRO_STATUS_SUCCESS &&
734 (! surface->base._finishing || ! surface->owns_pixmap)) {
735 status = cairo_surface_status (&surface->fallback->base);
737 if (status == CAIRO_STATUS_SUCCESS)
738 status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage,
739 CAIRO_FILL_RULE_WINDING,
740 &surface->fallback_damage);
742 if (status == CAIRO_STATUS_SUCCESS)
743 status = _put_image_boxes (surface,
744 surface->fallback,
745 &surface->fallback_damage);
747 if (status == CAIRO_STATUS_SUCCESS && ! surface->base._finishing) {
748 _cairo_surface_attach_snapshot (&surface->base,
749 &surface->fallback->base,
750 cairo_surface_finish);
754 _cairo_boxes_clear (&surface->fallback_damage);
755 cairo_surface_destroy (&surface->fallback->base);
756 surface->fallback = NULL;
758 return status;
761 static cairo_image_surface_t *
762 _cairo_xcb_surface_map_to_image (void *abstract_surface,
763 const cairo_rectangle_int_t *extents)
765 cairo_xcb_surface_t *surface = abstract_surface;
766 cairo_surface_t *image;
767 cairo_status_t status;
769 if (surface->fallback)
770 return _cairo_surface_map_to_image (&surface->fallback->base, extents);
772 image = _get_image (surface, TRUE,
773 extents->x, extents->y,
774 extents->width, extents->height);
775 status = cairo_surface_status (image);
776 if (unlikely (status)) {
777 cairo_surface_destroy(image);
778 return _cairo_image_surface_create_in_error (status);
781 /* Do we have a deferred clear and this image surface does NOT cover the
782 * whole xcb surface? Have to apply the clear in that case, else
783 * uploading the image will handle the problem for us.
785 if (surface->deferred_clear &&
786 ! (extents->width == surface->width &&
787 extents->height == surface->height)) {
788 status = _cairo_xcb_surface_clear (surface);
789 if (unlikely (status)) {
790 cairo_surface_destroy(image);
791 return _cairo_image_surface_create_in_error (status);
794 surface->deferred_clear = FALSE;
796 cairo_surface_set_device_offset (image, -extents->x, -extents->y);
797 return (cairo_image_surface_t *) image;
800 static cairo_int_status_t
801 _cairo_xcb_surface_unmap (void *abstract_surface,
802 cairo_image_surface_t *image)
804 cairo_xcb_surface_t *surface = abstract_surface;
805 cairo_int_status_t status;
807 if (surface->fallback)
808 return _cairo_surface_unmap_image (&surface->fallback->base, image);
810 status = _put_image (abstract_surface, image);
812 cairo_surface_finish (&image->base);
813 cairo_surface_destroy (&image->base);
815 return status;
818 static cairo_surface_t *
819 _cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface,
820 cairo_composite_rectangles_t *composite)
822 cairo_image_surface_t *image;
823 cairo_status_t status;
825 status = _cairo_composite_rectangles_add_to_damage (composite,
826 &surface->fallback_damage);
827 if (unlikely (status))
828 return _cairo_surface_create_in_error (status);
830 if (surface->fallback)
831 return &surface->fallback->base;
833 image = (cairo_image_surface_t *)
834 _get_image (surface, TRUE, 0, 0, surface->width, surface->height);
836 /* If there was a deferred clear, _get_image applied it */
837 if (image->base.status == CAIRO_STATUS_SUCCESS) {
838 surface->deferred_clear = FALSE;
840 surface->fallback = image;
843 return &surface->fallback->base;
846 static cairo_int_status_t
847 _cairo_xcb_fallback_compositor_paint (const cairo_compositor_t *compositor,
848 cairo_composite_rectangles_t *extents)
850 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
851 cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
853 return _cairo_surface_paint (fallback, extents->op,
854 &extents->source_pattern.base,
855 extents->clip);
858 static cairo_int_status_t
859 _cairo_xcb_fallback_compositor_mask (const cairo_compositor_t *compositor,
860 cairo_composite_rectangles_t *extents)
862 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
863 cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
865 return _cairo_surface_mask (fallback, extents->op,
866 &extents->source_pattern.base,
867 &extents->mask_pattern.base,
868 extents->clip);
871 static cairo_int_status_t
872 _cairo_xcb_fallback_compositor_stroke (const cairo_compositor_t *compositor,
873 cairo_composite_rectangles_t *extents,
874 const cairo_path_fixed_t *path,
875 const cairo_stroke_style_t *style,
876 const cairo_matrix_t *ctm,
877 const cairo_matrix_t *ctm_inverse,
878 double tolerance,
879 cairo_antialias_t antialias)
881 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
882 cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
884 return _cairo_surface_stroke (fallback, extents->op,
885 &extents->source_pattern.base,
886 path, style, ctm, ctm_inverse,
887 tolerance, antialias,
888 extents->clip);
891 static cairo_int_status_t
892 _cairo_xcb_fallback_compositor_fill (const cairo_compositor_t *compositor,
893 cairo_composite_rectangles_t *extents,
894 const cairo_path_fixed_t *path,
895 cairo_fill_rule_t fill_rule,
896 double tolerance,
897 cairo_antialias_t antialias)
899 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
900 cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
902 return _cairo_surface_fill (fallback, extents->op,
903 &extents->source_pattern.base,
904 path, fill_rule, tolerance,
905 antialias, extents->clip);
908 static cairo_int_status_t
909 _cairo_xcb_fallback_compositor_glyphs (const cairo_compositor_t *compositor,
910 cairo_composite_rectangles_t *extents,
911 cairo_scaled_font_t *scaled_font,
912 cairo_glyph_t *glyphs,
913 int num_glyphs,
914 cairo_bool_t overlap)
916 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
917 cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
919 return _cairo_surface_show_text_glyphs (fallback, extents->op,
920 &extents->source_pattern.base,
921 NULL, 0, glyphs, num_glyphs,
922 NULL, 0, 0,
923 scaled_font, extents->clip);
926 static const cairo_compositor_t _cairo_xcb_fallback_compositor = {
927 &__cairo_no_compositor,
929 _cairo_xcb_fallback_compositor_paint,
930 _cairo_xcb_fallback_compositor_mask,
931 _cairo_xcb_fallback_compositor_stroke,
932 _cairo_xcb_fallback_compositor_fill,
933 _cairo_xcb_fallback_compositor_glyphs,
936 static const cairo_compositor_t _cairo_xcb_render_compositor = {
937 &_cairo_xcb_fallback_compositor,
939 _cairo_xcb_render_compositor_paint,
940 _cairo_xcb_render_compositor_mask,
941 _cairo_xcb_render_compositor_stroke,
942 _cairo_xcb_render_compositor_fill,
943 _cairo_xcb_render_compositor_glyphs,
946 static inline const cairo_compositor_t *
947 get_compositor (cairo_surface_t **s)
949 cairo_xcb_surface_t *surface = (cairo_xcb_surface_t * )*s;
950 if (surface->fallback) {
951 *s = &surface->fallback->base;
952 return ((cairo_image_surface_t *) *s)->compositor;
955 return &_cairo_xcb_render_compositor;
958 static cairo_int_status_t
959 _cairo_xcb_surface_paint (void *abstract_surface,
960 cairo_operator_t op,
961 const cairo_pattern_t *source,
962 const cairo_clip_t *clip)
964 cairo_surface_t *surface = abstract_surface;
965 const cairo_compositor_t *compositor = get_compositor (&surface);
966 return _cairo_compositor_paint (compositor, surface, op, source, clip);
969 static cairo_int_status_t
970 _cairo_xcb_surface_mask (void *abstract_surface,
971 cairo_operator_t op,
972 const cairo_pattern_t *source,
973 const cairo_pattern_t *mask,
974 const cairo_clip_t *clip)
976 cairo_surface_t *surface = abstract_surface;
977 const cairo_compositor_t *compositor = get_compositor (&surface);
978 return _cairo_compositor_mask (compositor, surface, op, source, mask, clip);
981 static cairo_int_status_t
982 _cairo_xcb_surface_stroke (void *abstract_surface,
983 cairo_operator_t op,
984 const cairo_pattern_t *source,
985 const cairo_path_fixed_t *path,
986 const cairo_stroke_style_t *style,
987 const cairo_matrix_t *ctm,
988 const cairo_matrix_t *ctm_inverse,
989 double tolerance,
990 cairo_antialias_t antialias,
991 const cairo_clip_t *clip)
993 cairo_surface_t *surface = abstract_surface;
994 const cairo_compositor_t *compositor = get_compositor (&surface);
995 return _cairo_compositor_stroke (compositor, surface, op, source,
996 path, style, ctm, ctm_inverse,
997 tolerance, antialias, clip);
1000 static cairo_int_status_t
1001 _cairo_xcb_surface_fill (void *abstract_surface,
1002 cairo_operator_t op,
1003 const cairo_pattern_t *source,
1004 const cairo_path_fixed_t*path,
1005 cairo_fill_rule_t fill_rule,
1006 double tolerance,
1007 cairo_antialias_t antialias,
1008 const cairo_clip_t *clip)
1010 cairo_surface_t *surface = abstract_surface;
1011 const cairo_compositor_t *compositor = get_compositor (&surface);
1012 return _cairo_compositor_fill (compositor, surface, op,
1013 source, path, fill_rule,
1014 tolerance, antialias, clip);
1017 static cairo_int_status_t
1018 _cairo_xcb_surface_glyphs (void *abstract_surface,
1019 cairo_operator_t op,
1020 const cairo_pattern_t *source,
1021 cairo_glyph_t *glyphs,
1022 int num_glyphs,
1023 cairo_scaled_font_t *scaled_font,
1024 const cairo_clip_t *clip)
1026 cairo_surface_t *surface = abstract_surface;
1027 const cairo_compositor_t *compositor = get_compositor (&surface);
1028 return _cairo_compositor_glyphs (compositor, surface, op,
1029 source, glyphs, num_glyphs,
1030 scaled_font, clip);
1033 const cairo_surface_backend_t _cairo_xcb_surface_backend = {
1034 CAIRO_SURFACE_TYPE_XCB,
1035 _cairo_xcb_surface_finish,
1036 _cairo_default_context_create,
1038 _cairo_xcb_surface_create_similar,
1039 _cairo_xcb_surface_create_similar_image,
1040 _cairo_xcb_surface_map_to_image,
1041 _cairo_xcb_surface_unmap,
1043 _cairo_xcb_surface_source,
1044 _cairo_xcb_surface_acquire_source_image,
1045 _cairo_xcb_surface_release_source_image,
1046 NULL, /* snapshot */
1049 NULL, /* copy_page */
1050 NULL, /* show_page */
1052 _cairo_xcb_surface_get_extents,
1053 _cairo_xcb_surface_get_font_options,
1055 _cairo_xcb_surface_flush,
1056 NULL,
1058 _cairo_xcb_surface_paint,
1059 _cairo_xcb_surface_mask,
1060 _cairo_xcb_surface_stroke,
1061 _cairo_xcb_surface_fill,
1062 NULL, /* fill-stroke */
1063 _cairo_xcb_surface_glyphs,
1066 cairo_surface_t *
1067 _cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen,
1068 xcb_drawable_t drawable,
1069 cairo_bool_t owns_pixmap,
1070 pixman_format_code_t pixman_format,
1071 xcb_render_pictformat_t xrender_format,
1072 int width,
1073 int height)
1075 cairo_xcb_surface_t *surface;
1077 surface = malloc (sizeof (cairo_xcb_surface_t));
1078 if (unlikely (surface == NULL))
1079 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1081 _cairo_surface_init (&surface->base,
1082 &_cairo_xcb_surface_backend,
1083 &screen->connection->device,
1084 _cairo_content_from_pixman_format (pixman_format));
1086 surface->connection = _cairo_xcb_connection_reference (screen->connection);
1087 surface->screen = screen;
1088 cairo_list_add (&surface->link, &screen->surfaces);
1090 surface->drawable = drawable;
1091 surface->owns_pixmap = owns_pixmap;
1093 surface->deferred_clear = FALSE;
1094 surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
1096 surface->width = width;
1097 surface->height = height;
1098 surface->depth = PIXMAN_FORMAT_DEPTH (pixman_format);
1100 surface->picture = XCB_NONE;
1101 if (screen->connection->force_precision != -1)
1102 surface->precision = screen->connection->force_precision;
1103 else
1104 surface->precision = XCB_RENDER_POLY_MODE_IMPRECISE;
1106 surface->pixman_format = pixman_format;
1107 surface->xrender_format = xrender_format;
1109 surface->fallback = NULL;
1110 _cairo_boxes_init (&surface->fallback_damage);
1112 return &surface->base;
1115 static xcb_screen_t *
1116 _cairo_xcb_screen_from_visual (xcb_connection_t *connection,
1117 xcb_visualtype_t *visual,
1118 int *depth)
1120 xcb_depth_iterator_t d;
1121 xcb_screen_iterator_t s;
1123 s = xcb_setup_roots_iterator (xcb_get_setup (connection));
1124 for (; s.rem; xcb_screen_next (&s)) {
1125 if (s.data->root_visual == visual->visual_id) {
1126 *depth = s.data->root_depth;
1127 return s.data;
1130 d = xcb_screen_allowed_depths_iterator(s.data);
1131 for (; d.rem; xcb_depth_next (&d)) {
1132 xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
1134 for (; v.rem; xcb_visualtype_next (&v)) {
1135 if (v.data->visual_id == visual->visual_id) {
1136 *depth = d.data->depth;
1137 return s.data;
1143 return NULL;
1147 * cairo_xcb_surface_create:
1148 * @connection: an XCB connection
1149 * @drawable: an XCB drawable
1150 * @visual: the visual to use for drawing to @drawable. The depth
1151 * of the visual must match the depth of the drawable.
1152 * Currently, only TrueColor visuals are fully supported.
1153 * @width: the current width of @drawable
1154 * @height: the current height of @drawable
1156 * Creates an XCB surface that draws to the given drawable.
1157 * The way that colors are represented in the drawable is specified
1158 * by the provided visual.
1160 * Note: If @drawable is a Window, then the function
1161 * cairo_xcb_surface_set_size() must be called whenever the size of the
1162 * window changes.
1164 * When @drawable is a Window containing child windows then drawing to
1165 * the created surface will be clipped by those child windows. When
1166 * the created surface is used as a source, the contents of the
1167 * children will be included.
1169 * Return value: a pointer to the newly created surface. The caller
1170 * owns the surface and should call cairo_surface_destroy() when done
1171 * with it.
1173 * This function always returns a valid pointer, but it will return a
1174 * pointer to a "nil" surface if an error such as out of memory
1175 * occurs. You can use cairo_surface_status() to check for this.
1177 * Since: 1.12
1179 cairo_surface_t *
1180 cairo_xcb_surface_create (xcb_connection_t *connection,
1181 xcb_drawable_t drawable,
1182 xcb_visualtype_t *visual,
1183 int width,
1184 int height)
1186 cairo_xcb_screen_t *screen;
1187 xcb_screen_t *xcb_screen;
1188 cairo_format_masks_t image_masks;
1189 pixman_format_code_t pixman_format;
1190 xcb_render_pictformat_t xrender_format;
1191 int depth;
1193 if (xcb_connection_has_error (connection))
1194 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
1196 if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
1197 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1198 if (unlikely (width <= 0 || height <= 0))
1199 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1201 xcb_screen = _cairo_xcb_screen_from_visual (connection, visual, &depth);
1202 if (unlikely (xcb_screen == NULL))
1203 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
1205 image_masks.alpha_mask = 0;
1206 image_masks.red_mask = visual->red_mask;
1207 image_masks.green_mask = visual->green_mask;
1208 image_masks.blue_mask = visual->blue_mask;
1209 if (depth == 32) /* XXX visuals have no alpha! */
1210 image_masks.alpha_mask =
1211 0xffffffff & ~(visual->red_mask | visual->green_mask | visual->blue_mask);
1212 if (depth > 16)
1213 image_masks.bpp = 32;
1214 else if (depth > 8)
1215 image_masks.bpp = 16;
1216 else if (depth > 1)
1217 image_masks.bpp = 8;
1218 else
1219 image_masks.bpp = 1;
1221 if (! _pixman_format_from_masks (&image_masks, &pixman_format))
1222 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1224 screen = _cairo_xcb_screen_get (connection, xcb_screen);
1225 if (unlikely (screen == NULL))
1226 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1228 xrender_format =
1229 _cairo_xcb_connection_get_xrender_format_for_visual (screen->connection,
1230 visual->visual_id);
1232 return _cairo_xcb_surface_create_internal (screen, drawable, FALSE,
1233 pixman_format,
1234 xrender_format,
1235 width, height);
1237 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1238 slim_hidden_def (cairo_xcb_surface_create);
1239 #endif
1242 * cairo_xcb_surface_create_for_bitmap:
1243 * @connection: an XCB connection
1244 * @screen: the XCB screen associated with @bitmap
1245 * @bitmap: an XCB drawable (a Pixmap with depth 1)
1246 * @width: the current width of @bitmap
1247 * @height: the current height of @bitmap
1249 * Creates an XCB surface that draws to the given bitmap.
1250 * This will be drawn to as a %CAIRO_FORMAT_A1 object.
1252 * Return value: a pointer to the newly created surface. The caller
1253 * owns the surface and should call cairo_surface_destroy() when done
1254 * with it.
1256 * This function always returns a valid pointer, but it will return a
1257 * pointer to a "nil" surface if an error such as out of memory
1258 * occurs. You can use cairo_surface_status() to check for this.
1260 * Since: 1.12
1262 cairo_surface_t *
1263 cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection,
1264 xcb_screen_t *screen,
1265 xcb_pixmap_t bitmap,
1266 int width,
1267 int height)
1269 cairo_xcb_screen_t *cairo_xcb_screen;
1271 if (xcb_connection_has_error (connection))
1272 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
1274 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1275 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1276 if (unlikely (width <= 0 || height <= 0))
1277 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1279 cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen);
1280 if (unlikely (cairo_xcb_screen == NULL))
1281 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1283 return _cairo_xcb_surface_create_internal (cairo_xcb_screen, bitmap, FALSE,
1284 PIXMAN_a1,
1285 cairo_xcb_screen->connection->standard_formats[CAIRO_FORMAT_A1],
1286 width, height);
1288 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1289 slim_hidden_def (cairo_xcb_surface_create_for_bitmap);
1290 #endif
1293 * cairo_xcb_surface_create_with_xrender_format:
1294 * @connection: an XCB connection
1295 * @drawable: an XCB drawable
1296 * @screen: the XCB screen associated with @drawable
1297 * @format: the picture format to use for drawing to @drawable. The
1298 * depth of @format mush match the depth of the drawable.
1299 * @width: the current width of @drawable
1300 * @height: the current height of @drawable
1302 * Creates an XCB surface that draws to the given drawable.
1303 * The way that colors are represented in the drawable is specified
1304 * by the provided picture format.
1306 * Note: If @drawable is a Window, then the function
1307 * cairo_xcb_surface_set_size() must be called whenever the size of the
1308 * window changes.
1310 * When @drawable is a Window containing child windows then drawing to
1311 * the created surface will be clipped by those child windows. When
1312 * the created surface is used as a source, the contents of the
1313 * children will be included.
1315 * Return value: a pointer to the newly created surface. The caller
1316 * owns the surface and should call cairo_surface_destroy() when done
1317 * with it.
1319 * This function always returns a valid pointer, but it will return a
1320 * pointer to a "nil" surface if an error such as out of memory
1321 * occurs. You can use cairo_surface_status() to check for this.
1323 * Since: 1.12
1325 cairo_surface_t *
1326 cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection,
1327 xcb_screen_t *screen,
1328 xcb_drawable_t drawable,
1329 xcb_render_pictforminfo_t *format,
1330 int width,
1331 int height)
1333 cairo_xcb_screen_t *cairo_xcb_screen;
1334 cairo_format_masks_t image_masks;
1335 pixman_format_code_t pixman_format;
1337 if (xcb_connection_has_error (connection))
1338 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
1340 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1341 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1342 if (unlikely (width <= 0 || height <= 0))
1343 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1345 image_masks.alpha_mask =
1346 (unsigned long) format->direct.alpha_mask << format->direct.alpha_shift;
1347 image_masks.red_mask =
1348 (unsigned long) format->direct.red_mask << format->direct.red_shift;
1349 image_masks.green_mask =
1350 (unsigned long) format->direct.green_mask << format->direct.green_shift;
1351 image_masks.blue_mask =
1352 (unsigned long) format->direct.blue_mask << format->direct.blue_shift;
1353 #if 0
1354 image_masks.bpp = format->depth;
1355 #else
1356 if (format->depth > 16)
1357 image_masks.bpp = 32;
1358 else if (format->depth > 8)
1359 image_masks.bpp = 16;
1360 else if (format->depth > 1)
1361 image_masks.bpp = 8;
1362 else
1363 image_masks.bpp = 1;
1364 #endif
1366 if (! _pixman_format_from_masks (&image_masks, &pixman_format))
1367 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1369 cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen);
1370 if (unlikely (cairo_xcb_screen == NULL))
1371 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1373 return _cairo_xcb_surface_create_internal (cairo_xcb_screen,
1374 drawable,
1375 FALSE,
1376 pixman_format,
1377 format->id,
1378 width, height);
1380 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1381 slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
1382 #endif
1384 /* This does the necessary fixup when a surface's drawable or size changed. */
1385 static void
1386 _drawable_changed (cairo_xcb_surface_t *surface)
1388 _cairo_surface_set_error (&surface->base,
1389 _cairo_surface_begin_modification (&surface->base));
1390 _cairo_boxes_clear (&surface->fallback_damage);
1391 cairo_surface_destroy (&surface->fallback->base);
1393 surface->deferred_clear = FALSE;
1394 surface->fallback = NULL;
1398 * cairo_xcb_surface_set_size:
1399 * @surface: a #cairo_surface_t for the XCB backend
1400 * @width: the new width of the surface
1401 * @height: the new height of the surface
1403 * Informs cairo of the new size of the XCB drawable underlying the
1404 * surface. For a surface created for a window (rather than a pixmap),
1405 * this function must be called each time the size of the window
1406 * changes. (For a subwindow, you are normally resizing the window
1407 * yourself, but for a toplevel window, it is necessary to listen for
1408 * ConfigureNotify events.)
1410 * A pixmap can never change size, so it is never necessary to call
1411 * this function on a surface created for a pixmap.
1413 * If cairo_surface_flush() wasn't called, some pending operations
1414 * might be discarded.
1416 * Since: 1.12
1418 void
1419 cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
1420 int width,
1421 int height)
1423 cairo_xcb_surface_t *surface;
1425 if (unlikely (abstract_surface->status))
1426 return;
1427 if (unlikely (abstract_surface->finished)) {
1428 _cairo_surface_set_error (abstract_surface,
1429 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1430 return;
1434 if ( !_cairo_surface_is_xcb(abstract_surface)) {
1435 _cairo_surface_set_error (abstract_surface,
1436 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1437 return;
1440 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
1441 _cairo_surface_set_error (abstract_surface,
1442 _cairo_error (CAIRO_STATUS_INVALID_SIZE));
1443 return;
1446 surface = (cairo_xcb_surface_t *) abstract_surface;
1448 _drawable_changed(surface);
1449 surface->width = width;
1450 surface->height = height;
1452 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1453 slim_hidden_def (cairo_xcb_surface_set_size);
1454 #endif
1457 * cairo_xcb_surface_set_drawable:
1458 * @surface: a #cairo_surface_t for the XCB backend
1459 * @drawable: the new drawable of the surface
1460 * @width: the new width of the surface
1461 * @height: the new height of the surface
1463 * Informs cairo of the new drawable and size of the XCB drawable underlying the
1464 * surface.
1466 * If cairo_surface_flush() wasn't called, some pending operations
1467 * might be discarded.
1469 * Since: 1.12
1471 void
1472 cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface,
1473 xcb_drawable_t drawable,
1474 int width,
1475 int height)
1477 cairo_xcb_surface_t *surface;
1479 if (unlikely (abstract_surface->status))
1480 return;
1481 if (unlikely (abstract_surface->finished)) {
1482 _cairo_surface_set_error (abstract_surface,
1483 _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1484 return;
1488 if ( !_cairo_surface_is_xcb(abstract_surface)) {
1489 _cairo_surface_set_error (abstract_surface,
1490 _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1491 return;
1494 if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
1495 _cairo_surface_set_error (abstract_surface,
1496 _cairo_error (CAIRO_STATUS_INVALID_SIZE));
1497 return;
1500 surface = (cairo_xcb_surface_t *) abstract_surface;
1502 /* XXX: and what about this case? */
1503 if (surface->owns_pixmap)
1504 return;
1506 _drawable_changed (surface);
1508 if (surface->drawable != drawable) {
1509 cairo_status_t status;
1510 status = _cairo_xcb_connection_acquire (surface->connection);
1511 if (unlikely (status))
1512 return;
1514 if (surface->picture != XCB_NONE) {
1515 _cairo_xcb_connection_render_free_picture (surface->connection,
1516 surface->picture);
1517 surface->picture = XCB_NONE;
1520 _cairo_xcb_connection_release (surface->connection);
1522 surface->drawable = drawable;
1524 surface->width = width;
1525 surface->height = height;
1527 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1528 slim_hidden_def (cairo_xcb_surface_set_drawable);
1529 #endif