c6a1d29451e691fa41c72e91f0a14e1f65e9c2ff
[framework/graphics/cairo.git] / src / cairo-xcb-surface.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2002 University of Southern California
4  * Copyright © 2009 Intel Corporation
5  *
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.
13  *
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
19  *
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/
24  *
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.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is University of Southern
32  * California.
33  *
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
39  */
40
41 #include "cairoint.h"
42
43 #include "cairo-xcb.h"
44 #include "cairo-xcb-private.h"
45
46 #include "cairo-composite-rectangles-private.h"
47 #include "cairo-default-context-private.h"
48 #include "cairo-list-inline.h"
49 #include "cairo-image-surface-private.h"
50 #include "cairo-surface-backend-private.h"
51
52 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
53 slim_hidden_proto (cairo_xcb_surface_create);
54 slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
55 slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
56 #endif
57
58 /**
59  * SECTION:cairo-xcb
60  * @Title: XCB Surfaces
61  * @Short_Description: X Window System rendering using the XCB library
62  * @See_Also: #cairo_surface_t
63  *
64  * The XCB surface is used to render cairo graphics to X Window System
65  * windows and pixmaps using the XCB library.
66  *
67  * Note that the XCB surface automatically takes advantage of the X render
68  * extension if it is available.
69  **/
70
71 /**
72  * CAIRO_HAS_XCB_SURFACE:
73  *
74  * Defined if the xcb surface backend is available.
75  * This macro can be used to conditionally compile backend-specific code.
76  *
77  * Since: 1.12
78  **/
79
80 cairo_surface_t *
81 _cairo_xcb_surface_create_similar (void                 *abstract_other,
82                                    cairo_content_t       content,
83                                    int                   width,
84                                    int                   height)
85 {
86     cairo_xcb_surface_t *other = abstract_other;
87     cairo_xcb_surface_t *surface;
88     cairo_xcb_connection_t *connection;
89     xcb_pixmap_t pixmap;
90     cairo_status_t status;
91
92     if (unlikely(width  > XLIB_COORD_MAX ||
93                  height > XLIB_COORD_MAX ||
94                  width  <= 0 ||
95                  height <= 0))
96         return cairo_image_surface_create (_cairo_format_from_content (content),
97                                            width, height);
98
99     if ((other->connection->flags & CAIRO_XCB_HAS_RENDER) == 0)
100         return _cairo_xcb_surface_create_similar_image (other,
101                                                         _cairo_format_from_content (content),
102                                                         width, height);
103
104     connection = other->connection;
105     status = _cairo_xcb_connection_acquire (connection);
106     if (unlikely (status))
107         return _cairo_surface_create_in_error (status);
108
109     if (content == other->base.content) {
110         pixmap = _cairo_xcb_connection_create_pixmap (connection,
111                                                       other->depth,
112                                                       other->drawable,
113                                                       width, height);
114
115         surface = (cairo_xcb_surface_t *)
116             _cairo_xcb_surface_create_internal (other->screen,
117                                                 pixmap, TRUE,
118                                                 other->pixman_format,
119                                                 other->xrender_format,
120                                                 width, height);
121     } else {
122         cairo_format_t format;
123         pixman_format_code_t pixman_format;
124
125         /* XXX find a compatible xrender format */
126         switch (content) {
127         case CAIRO_CONTENT_ALPHA:
128             pixman_format = PIXMAN_a8;
129             format = CAIRO_FORMAT_A8;
130             break;
131         case CAIRO_CONTENT_COLOR:
132             pixman_format = PIXMAN_x8r8g8b8;
133             format = CAIRO_FORMAT_RGB24;
134             break;
135         default:
136             ASSERT_NOT_REACHED;
137         case CAIRO_CONTENT_COLOR_ALPHA:
138             pixman_format = PIXMAN_a8r8g8b8;
139             format = CAIRO_FORMAT_ARGB32;
140             break;
141         }
142
143         pixmap = _cairo_xcb_connection_create_pixmap (connection,
144                                                       PIXMAN_FORMAT_DEPTH (pixman_format),
145                                                       other->drawable,
146                                                       width, height);
147
148         surface = (cairo_xcb_surface_t *)
149             _cairo_xcb_surface_create_internal (other->screen,
150                                                 pixmap, TRUE,
151                                                 pixman_format,
152                                                 connection->standard_formats[format],
153                                                 width, height);
154     }
155
156     if (unlikely (surface->base.status))
157         _cairo_xcb_connection_free_pixmap (connection, pixmap);
158
159     _cairo_xcb_connection_release (connection);
160
161     return &surface->base;
162 }
163
164 cairo_surface_t *
165 _cairo_xcb_surface_create_similar_image (void                   *abstract_other,
166                                          cairo_format_t          format,
167                                          int                     width,
168                                          int                     height)
169 {
170     cairo_xcb_surface_t *other = abstract_other;
171     cairo_xcb_connection_t *connection = other->connection;
172
173     cairo_xcb_shm_info_t *shm_info;
174     cairo_image_surface_t *image;
175     cairo_status_t status;
176     pixman_format_code_t pixman_format;
177
178     if (unlikely(width  > XLIB_COORD_MAX ||
179                  height > XLIB_COORD_MAX ||
180                  width  <= 0 ||
181                  height <= 0))
182         return NULL;
183
184     pixman_format = _cairo_format_to_pixman_format_code (format);
185
186     status = _cairo_xcb_shm_image_create (connection, pixman_format,
187                                           width, height, &image,
188                                           &shm_info);
189     if (unlikely (status))
190         return _cairo_surface_create_in_error (status);
191
192     return &image->base;
193 }
194
195 static cairo_status_t
196 _cairo_xcb_surface_finish (void *abstract_surface)
197 {
198     cairo_xcb_surface_t *surface = abstract_surface;
199     cairo_status_t status;
200
201     if (surface->fallback != NULL) {
202         cairo_surface_finish (&surface->fallback->base);
203         cairo_surface_destroy (&surface->fallback->base);
204     }
205     _cairo_boxes_fini (&surface->fallback_damage);
206
207     cairo_list_del (&surface->link);
208
209     status = _cairo_xcb_connection_acquire (surface->connection);
210     if (status == CAIRO_STATUS_SUCCESS) {
211         if (surface->picture != XCB_NONE) {
212             _cairo_xcb_connection_render_free_picture (surface->connection,
213                                                        surface->picture);
214         }
215
216         if (surface->owns_pixmap)
217             _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable);
218         _cairo_xcb_connection_release (surface->connection);
219     }
220
221     _cairo_xcb_connection_destroy (surface->connection);
222
223     return status;
224 }
225
226 static void
227 _destroy_image (pixman_image_t *image, void *data)
228 {
229     free (data);
230 }
231
232 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
233 static cairo_surface_t *
234 _cairo_xcb_surface_create_shm_image (cairo_xcb_connection_t *connection,
235                                      pixman_format_code_t pixman_format,
236                                      int width, int height,
237                                      cairo_bool_t might_reuse,
238                                      cairo_xcb_shm_info_t **shm_info_out)
239 {
240     cairo_surface_t *image;
241     cairo_xcb_shm_info_t *shm_info;
242     cairo_int_status_t status;
243     size_t stride;
244
245     *shm_info_out = NULL;
246
247     stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width,
248                                          PIXMAN_FORMAT_BPP (pixman_format));
249     status = _cairo_xcb_connection_allocate_shm_info (connection,
250                                                       stride * height,
251                                                       might_reuse,
252                                                       &shm_info);
253     if (unlikely (status)) {
254         if (status == CAIRO_INT_STATUS_UNSUPPORTED)
255             return NULL;
256
257         return _cairo_surface_create_in_error (status);
258     }
259
260     image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
261                                                             pixman_format,
262                                                             width, height,
263                                                             stride);
264     if (unlikely (image->status)) {
265         _cairo_xcb_shm_info_destroy (shm_info);
266         return image;
267     }
268
269     status = _cairo_user_data_array_set_data (&image->user_data,
270                                               (const cairo_user_data_key_t *) connection,
271                                               shm_info,
272                                               (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
273     if (unlikely (status)) {
274         cairo_surface_destroy (image);
275         _cairo_xcb_shm_info_destroy (shm_info);
276         return _cairo_surface_create_in_error (status);
277     }
278
279     *shm_info_out = shm_info;
280     return image;
281 }
282 #endif
283
284 static cairo_surface_t *
285 _get_shm_image (cairo_xcb_surface_t *surface,
286                 int x, int y,
287                 int width, int height)
288 {
289 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
290     cairo_xcb_shm_info_t *shm_info;
291     cairo_surface_t *image;
292     cairo_status_t status;
293
294     if ((surface->connection->flags & CAIRO_XCB_HAS_SHM) == 0)
295         return NULL;
296
297     image = _cairo_xcb_surface_create_shm_image (surface->connection,
298                                                  surface->pixman_format,
299                                                  width, height,
300                                                  TRUE,
301                                                  &shm_info);
302     if (unlikely (image == NULL || image->status))
303         goto done;
304
305     status = _cairo_xcb_connection_shm_get_image (surface->connection,
306                                                   surface->drawable,
307                                                   x, y,
308                                                   width, height,
309                                                   shm_info->shm,
310                                                   shm_info->offset);
311     if (unlikely (status)) {
312         cairo_surface_destroy (image);
313         image = _cairo_surface_create_in_error (status);
314     }
315
316 done:
317     return image;
318 #else
319     return NULL;
320 #endif
321 }
322
323 static cairo_surface_t *
324 _get_image (cairo_xcb_surface_t          *surface,
325             cairo_bool_t                  use_shm,
326             int x, int y,
327             int width, int height)
328 {
329     cairo_surface_t *image;
330     cairo_xcb_connection_t *connection;
331     xcb_get_image_reply_t *reply;
332     cairo_int_status_t status;
333
334     assert (surface->fallback == NULL);
335     assert (x >= 0);
336     assert (y >= 0);
337     assert (x + width <= surface->width);
338     assert (y + height <= surface->height);
339
340     if (surface->deferred_clear) {
341         image =
342             _cairo_image_surface_create_with_pixman_format (NULL,
343                                                             surface->pixman_format,
344                                                             width, height,
345                                                             0);
346         if (surface->deferred_clear_color.alpha_short > 0x00ff) {
347             cairo_solid_pattern_t solid;
348
349             _cairo_pattern_init_solid (&solid, &surface->deferred_clear_color);
350             status = _cairo_surface_paint (image,
351                                            CAIRO_OPERATOR_SOURCE,
352                                            &solid.base,
353                                            NULL);
354             if (unlikely (status)) {
355                 cairo_surface_destroy (image);
356                 image = _cairo_surface_create_in_error (status);
357             }
358         }
359         return image;
360     }
361
362     connection = surface->connection;
363
364     status = _cairo_xcb_connection_acquire (connection);
365     if (unlikely (status))
366         return _cairo_surface_create_in_error (status);
367
368     if (use_shm) {
369         image = _get_shm_image (surface, x, y, width, height);
370         if (image) {
371             if (image->status == CAIRO_STATUS_SUCCESS) {
372                 _cairo_xcb_connection_release (connection);
373                 return image;
374             }
375             cairo_surface_destroy (image);
376         }
377     }
378
379     status = _cairo_xcb_connection_get_image (connection,
380                                               surface->drawable,
381                                               x, y,
382                                               width, height,
383                                               &reply);
384     if (unlikely (status))
385         goto FAIL;
386
387     if (reply == NULL && ! surface->owns_pixmap) {
388         /* xcb_get_image_t from a window is dangerous because it can
389          * produce errors if the window is unmapped or partially
390          * outside the screen. We could check for errors and
391          * retry, but to keep things simple, we just create a
392          * temporary pixmap
393          *
394          * If we hit this fallback too often, we should remember so and
395          * skip the round-trip from the above GetImage request,
396          * similar to what cairo-xlib does.
397          */
398         xcb_pixmap_t pixmap;
399         xcb_gcontext_t gc;
400
401         gc = _cairo_xcb_screen_get_gc (surface->screen,
402                                        surface->drawable,
403                                        surface->depth);
404         pixmap = _cairo_xcb_connection_create_pixmap (connection,
405                                                       surface->depth,
406                                                       surface->drawable,
407                                                       width, height);
408
409         /* XXX IncludeInferiors? */
410         _cairo_xcb_connection_copy_area (connection,
411                                          surface->drawable,
412                                          pixmap, gc,
413                                          x, y,
414                                          0, 0,
415                                          width, height);
416
417         _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
418
419         status = _cairo_xcb_connection_get_image (connection,
420                                                   pixmap,
421                                                   0, 0,
422                                                   width, height,
423                                                   &reply);
424         _cairo_xcb_connection_free_pixmap (connection, pixmap);
425
426         if (unlikely (status))
427             goto FAIL;
428     }
429
430     if (unlikely (reply == NULL)) {
431         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
432         goto FAIL;
433     }
434
435     /* XXX byte swap */
436     /* XXX format conversion */
437     assert (reply->depth == surface->depth);
438
439     image = _cairo_image_surface_create_with_pixman_format
440         (xcb_get_image_data (reply),
441          surface->pixman_format,
442          width, height,
443          CAIRO_STRIDE_FOR_WIDTH_BPP (width,
444                                      PIXMAN_FORMAT_BPP (surface->pixman_format)));
445     status = image->status;
446     if (unlikely (status)) {
447         free (reply);
448         goto FAIL;
449     }
450
451     /* XXX */
452     pixman_image_set_destroy_function (((cairo_image_surface_t *)image)->pixman_image, _destroy_image, reply);
453
454     _cairo_xcb_connection_release (connection);
455
456     return image;
457
458 FAIL:
459     _cairo_xcb_connection_release (connection);
460     return _cairo_surface_create_in_error (status);
461 }
462
463 static cairo_surface_t *
464 _cairo_xcb_surface_source (void *abstract_surface,
465                            cairo_rectangle_int_t *extents)
466 {
467     cairo_xcb_surface_t *surface = abstract_surface;
468
469     if (extents) {
470         extents->x = extents->y = 0;
471         extents->width  = surface->width;
472         extents->height = surface->height;
473     }
474
475     return &surface->base;
476 }
477
478 static cairo_status_t
479 _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
480                                          cairo_image_surface_t **image_out,
481                                          void **image_extra)
482 {
483     cairo_xcb_surface_t *surface = abstract_surface;
484     cairo_surface_t *image;
485
486     if (surface->fallback != NULL) {
487         image = cairo_surface_reference (&surface->fallback->base);
488         goto DONE;
489     }
490
491     image = _cairo_surface_has_snapshot (&surface->base,
492                                          &_cairo_image_surface_backend);
493     if (image != NULL) {
494         image = cairo_surface_reference (image);
495         goto DONE;
496     }
497
498     image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height);
499     if (unlikely (image->status))
500         return image->status;
501
502     _cairo_surface_attach_snapshot (&surface->base, image, NULL);
503
504 DONE:
505     *image_out = (cairo_image_surface_t *) image;
506     *image_extra = NULL;
507     return CAIRO_STATUS_SUCCESS;
508 }
509
510 static void
511 _cairo_xcb_surface_release_source_image (void *abstract_surface,
512                                          cairo_image_surface_t *image,
513                                          void *image_extra)
514 {
515     cairo_surface_destroy (&image->base);
516 }
517
518 cairo_bool_t
519 _cairo_xcb_surface_get_extents (void *abstract_surface,
520                                 cairo_rectangle_int_t *extents)
521 {
522     cairo_xcb_surface_t *surface = abstract_surface;
523
524     extents->x = extents->y = 0;
525     extents->width  = surface->width;
526     extents->height = surface->height;
527     return TRUE;
528 }
529
530 static void
531 _cairo_xcb_surface_get_font_options (void *abstract_surface,
532                                      cairo_font_options_t *options)
533 {
534     /* XXX  copy from xlib */
535     _cairo_font_options_init_default (options);
536     _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON);
537 }
538
539 static cairo_status_t
540 _put_shm_image (cairo_xcb_surface_t    *surface,
541                 xcb_gcontext_t          gc,
542                 cairo_image_surface_t  *image)
543 {
544 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
545     cairo_xcb_shm_info_t *shm_info;
546
547     shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
548                                                 (const cairo_user_data_key_t *) surface->connection);
549     if (shm_info == NULL)
550         return CAIRO_INT_STATUS_UNSUPPORTED;
551
552     _cairo_xcb_connection_shm_put_image (surface->connection,
553                                          surface->drawable,
554                                          gc,
555                                          surface->width, surface->height,
556                                          0, 0,
557                                          image->width, image->height,
558                                          image->base.device_transform_inverse.x0,
559                                          image->base.device_transform_inverse.y0,
560                                          image->depth,
561                                          shm_info->shm,
562                                          shm_info->offset);
563
564     return CAIRO_STATUS_SUCCESS;
565 #else
566     return CAIRO_INT_STATUS_UNSUPPORTED;
567 #endif
568 }
569
570 static cairo_status_t
571 _put_image (cairo_xcb_surface_t    *surface,
572             cairo_image_surface_t  *image)
573 {
574     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
575
576     /* XXX track damaged region? */
577
578     status = _cairo_xcb_connection_acquire (surface->connection);
579     if (unlikely (status))
580         return status;
581
582     if (image->pixman_format == surface->pixman_format) {
583         xcb_gcontext_t gc;
584
585         assert (image->depth == surface->depth);
586         assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
587
588         gc = _cairo_xcb_screen_get_gc (surface->screen,
589                                        surface->drawable,
590                                        surface->depth);
591
592         status = _put_shm_image (surface, gc, image);
593         if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
594             _cairo_xcb_connection_put_image (surface->connection,
595                                              surface->drawable, gc,
596                                              image->width, image->height,
597                                              image->base.device_transform_inverse.x0,
598                                              image->base.device_transform_inverse.y0,
599                                              image->depth,
600                                              image->stride,
601                                              image->data);
602             status = CAIRO_STATUS_SUCCESS;
603         }
604
605         _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
606     } else {
607         ASSERT_NOT_REACHED;
608     }
609
610     _cairo_xcb_connection_release (surface->connection);
611     return status;
612 }
613
614 static cairo_int_status_t
615 _put_shm_image_boxes (cairo_xcb_surface_t    *surface,
616                       cairo_image_surface_t  *image,
617                       xcb_gcontext_t gc,
618                       cairo_boxes_t *boxes)
619 {
620 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
621     cairo_xcb_shm_info_t *shm_info;
622
623     shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
624                                                 (const cairo_user_data_key_t *) surface->connection);
625     if (shm_info != NULL) {
626         struct _cairo_boxes_chunk *chunk;
627
628         for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
629             int i;
630
631             for (i = 0; i < chunk->count; i++) {
632                 cairo_box_t *b = &chunk->base[i];
633                 int x = _cairo_fixed_integer_part (b->p1.x);
634                 int y = _cairo_fixed_integer_part (b->p1.y);
635                 int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
636                 int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
637
638                 _cairo_xcb_connection_shm_put_image (surface->connection,
639                                                      surface->drawable,
640                                                      gc,
641                                                      surface->width, surface->height,
642                                                      x, y,
643                                                      width, height,
644                                                      x, y,
645                                                      image->depth,
646                                                      shm_info->shm,
647                                                      shm_info->offset);
648             }
649         }
650     }
651
652     return CAIRO_INT_STATUS_SUCCESS;
653 #endif
654
655     return CAIRO_INT_STATUS_UNSUPPORTED;
656 }
657
658 static cairo_status_t
659 _put_image_boxes (cairo_xcb_surface_t    *surface,
660                   cairo_image_surface_t  *image,
661                   cairo_boxes_t *boxes)
662 {
663     cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
664     xcb_gcontext_t gc;
665
666     if (boxes->num_boxes == 0)
667             return CAIRO_STATUS_SUCCESS;
668
669     /* XXX track damaged region? */
670
671     status = _cairo_xcb_connection_acquire (surface->connection);
672     if (unlikely (status))
673         return status;
674
675     assert (image->pixman_format == surface->pixman_format);
676     assert (image->depth == surface->depth);
677     assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
678
679     gc = _cairo_xcb_screen_get_gc (surface->screen,
680                                    surface->drawable,
681                                    surface->depth);
682
683     status = _put_shm_image_boxes (surface, image, gc, boxes);
684     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
685             struct _cairo_boxes_chunk *chunk;
686
687             for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
688                     int i;
689
690                     for (i = 0; i < chunk->count; i++) {
691                             cairo_box_t *b = &chunk->base[i];
692                             int x = _cairo_fixed_integer_part (b->p1.x);
693                             int y = _cairo_fixed_integer_part (b->p1.y);
694                             int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
695                             int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
696                             _cairo_xcb_connection_put_image (surface->connection,
697                                                              surface->drawable, gc,
698                                                              width, height,
699                                                              x, y,
700                                                              image->depth,
701                                                              image->stride,
702                                                              image->data +
703                                                              x * PIXMAN_FORMAT_BPP (image->pixman_format) / 8 +
704                                                              y * image->stride);
705
706                     }
707             }
708             status = CAIRO_STATUS_SUCCESS;
709     }
710
711     _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
712     _cairo_xcb_connection_release (surface->connection);
713     return status;
714 }
715
716 static cairo_status_t
717 _cairo_xcb_surface_flush (void *abstract_surface)
718 {
719     cairo_xcb_surface_t *surface = abstract_surface;
720     cairo_status_t status;
721
722     if (likely (surface->fallback == NULL)) {
723         status = CAIRO_STATUS_SUCCESS;
724         if (! surface->base.finished && surface->deferred_clear)
725             status = _cairo_xcb_surface_clear (surface);
726
727         return status;
728     }
729
730     status = surface->base.status;
731     if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) {
732         status = cairo_surface_status (&surface->fallback->base);
733
734         if (status == CAIRO_STATUS_SUCCESS)
735                 status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage,
736                                                                   CAIRO_FILL_RULE_WINDING,
737                                                                   &surface->fallback_damage);
738
739         if (status == CAIRO_STATUS_SUCCESS)
740             status = _put_image_boxes (surface,
741                                        surface->fallback,
742                                        &surface->fallback_damage);
743
744         if (status == CAIRO_STATUS_SUCCESS) {
745             _cairo_surface_attach_snapshot (&surface->base,
746                                             &surface->fallback->base,
747                                             cairo_surface_finish);
748         }
749     }
750
751     _cairo_boxes_clear (&surface->fallback_damage);
752     cairo_surface_destroy (&surface->fallback->base);
753     surface->fallback = NULL;
754
755     return status;
756 }
757
758 static cairo_surface_t *
759 _cairo_xcb_surface_map_to_image (void *abstract_surface,
760                                  const cairo_rectangle_int_t *extents)
761 {
762     cairo_xcb_surface_t *surface = abstract_surface;
763     cairo_surface_t *image;
764
765     if (surface->fallback)
766         return surface->fallback->base.backend->map_to_image (&surface->fallback->base, extents);
767
768     image = _get_image (surface, TRUE,
769                         extents->x, extents->y,
770                         extents->width, extents->height);
771     if (unlikely (image->status))
772         return image;
773
774     /* Do we have a deferred clear and this image surface does NOT cover the
775      * whole xcb surface? Have to apply the clear in that case, else
776      * uploading the image will handle the problem for us.
777      */
778     if (surface->deferred_clear &&
779         ! (extents->width == surface->width &&
780            extents->height == surface->height)) {
781         cairo_status_t status = _cairo_xcb_surface_clear (surface);
782         if (unlikely (status)) {
783             cairo_surface_destroy(image);
784             return _cairo_surface_create_in_error (status);
785         }
786     }
787     surface->deferred_clear = FALSE;
788
789     cairo_surface_set_device_offset (image, -extents->x, -extents->y);
790     return image;
791 }
792
793 static cairo_int_status_t
794 _cairo_xcb_surface_unmap (void *abstract_surface,
795                           cairo_image_surface_t *image)
796 {
797     cairo_xcb_surface_t *surface = abstract_surface;
798
799     if (surface->fallback)
800         return surface->fallback->base.backend->unmap_image (&surface->fallback->base, image);
801     return _put_image (abstract_surface, image);
802 }
803
804 static cairo_surface_t *
805 _cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface,
806                              cairo_composite_rectangles_t *composite)
807 {
808     cairo_image_surface_t *image;
809     cairo_status_t status;
810
811     status = _cairo_composite_rectangles_add_to_damage (composite,
812                                                         &surface->fallback_damage);
813     if (unlikely (status))
814             return _cairo_surface_create_in_error (status);
815
816     if (surface->fallback)
817         return &surface->fallback->base;
818
819     image = (cairo_image_surface_t *)
820             _get_image (surface, TRUE, 0, 0, surface->width, surface->height);
821
822     /* If there was a deferred clear, _get_image applied it */
823     if (image->base.status == CAIRO_STATUS_SUCCESS) {
824         surface->deferred_clear = FALSE;
825
826         surface->fallback = image;
827     }
828
829     return &surface->fallback->base;
830 }
831
832 static cairo_int_status_t
833 _cairo_xcb_surface_paint (void                  *abstract_surface,
834                           cairo_operator_t       op,
835                           const cairo_pattern_t *source,
836                           const cairo_clip_t    *clip)
837 {
838     cairo_xcb_surface_t *surface = abstract_surface;
839     cairo_composite_rectangles_t composite;
840     cairo_int_status_t status;
841
842     status = _cairo_composite_rectangles_init_for_paint (&composite,
843                                                          &surface->base,
844                                                          op, source,
845                                                          clip);
846     if (unlikely (status))
847         return status;
848
849     if (surface->fallback == NULL) {
850         status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip);
851         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
852             goto done;
853
854         status = _cairo_xcb_surface_render_paint (surface, op, source,
855                                                   &composite);
856         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
857             goto done;
858     }
859
860     status = _cairo_surface_paint (_cairo_xcb_surface_fallback (surface,
861                                                                 &composite),
862                                    op, source, clip);
863
864 done:
865     _cairo_composite_rectangles_fini (&composite);
866     return status;
867 }
868
869 static cairo_int_status_t
870 _cairo_xcb_surface_mask (void                   *abstract_surface,
871                          cairo_operator_t        op,
872                          const cairo_pattern_t  *source,
873                          const cairo_pattern_t  *mask,
874                          const cairo_clip_t     *clip)
875 {
876     cairo_xcb_surface_t *surface = abstract_surface;
877     cairo_composite_rectangles_t composite;
878     cairo_int_status_t status;
879
880     status = _cairo_composite_rectangles_init_for_mask (&composite,
881                                                         &surface->base,
882                                                         op, source, mask, clip);
883     if (unlikely (status))
884         return status;
885
886     if (surface->fallback == NULL) {
887         status =  _cairo_xcb_surface_cairo_mask (surface,
888                                                  op, source, mask, clip);
889         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
890             goto done;
891
892         status =  _cairo_xcb_surface_render_mask (surface,
893                                                   op, source, mask, &composite);
894         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
895             goto done;
896     }
897
898     status = _cairo_surface_mask (_cairo_xcb_surface_fallback (surface,
899                                                                &composite),
900                                   op, source, mask,
901                                   clip);
902 done:
903     _cairo_composite_rectangles_fini (&composite);
904     return status;
905 }
906
907 static cairo_int_status_t
908 _cairo_xcb_surface_stroke (void                         *abstract_surface,
909                            cairo_operator_t              op,
910                            const cairo_pattern_t        *source,
911                            const cairo_path_fixed_t     *path,
912                            const cairo_stroke_style_t   *style,
913                            const cairo_matrix_t         *ctm,
914                            const cairo_matrix_t         *ctm_inverse,
915                            double                        tolerance,
916                            cairo_antialias_t             antialias,
917                            const cairo_clip_t           *clip)
918 {
919     cairo_xcb_surface_t *surface = abstract_surface;
920     cairo_composite_rectangles_t composite;
921     cairo_int_status_t status;
922
923     status = _cairo_composite_rectangles_init_for_stroke (&composite,
924                                                           &surface->base,
925                                                           op, source,
926                                                           path, style, ctm,
927                                                           clip);
928     if (unlikely (status))
929         return status;
930
931     if (surface->fallback == NULL) {
932         status = _cairo_xcb_surface_cairo_stroke (surface, op, source,
933                                                   path, style,
934                                                   ctm, ctm_inverse,
935                                                   tolerance, antialias,
936                                                   clip);
937
938         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
939             goto done;
940
941         status = _cairo_xcb_surface_render_stroke (surface, op, source,
942                                                    path, style,
943                                                    ctm, ctm_inverse,
944                                                    tolerance, antialias,
945                                                    &composite);
946
947         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
948             goto done;
949     }
950
951     status = _cairo_surface_stroke (_cairo_xcb_surface_fallback (surface,
952                                                                  &composite),
953                                     op, source,
954                                     path, style,
955                                     ctm, ctm_inverse,
956                                     tolerance, antialias,
957                                     clip);
958 done:
959     _cairo_composite_rectangles_fini (&composite);
960     return status;
961 }
962
963 static cairo_int_status_t
964 _cairo_xcb_surface_fill (void                   *abstract_surface,
965                          cairo_operator_t        op,
966                          const cairo_pattern_t  *source,
967                          const cairo_path_fixed_t*path,
968                          cairo_fill_rule_t       fill_rule,
969                          double                  tolerance,
970                          cairo_antialias_t       antialias,
971                          const cairo_clip_t     *clip)
972 {
973     cairo_xcb_surface_t *surface = abstract_surface;
974     cairo_composite_rectangles_t composite;
975     cairo_int_status_t status;
976
977     status = _cairo_composite_rectangles_init_for_fill (&composite,
978                                                         &surface->base,
979                                                         op, source, path,
980                                                         clip);
981     if (unlikely (status))
982         return status;
983
984     if (surface->fallback == NULL) {
985         status = _cairo_xcb_surface_cairo_fill (surface, op, source,
986                                                 path, fill_rule,
987                                                 tolerance, antialias,
988                                                 clip);
989         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
990             goto done;
991
992         status = _cairo_xcb_surface_render_fill (surface, op, source,
993                                                  path, fill_rule,
994                                                  tolerance, antialias,
995                                                  &composite);
996         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
997             goto done;
998     }
999
1000     status = _cairo_surface_fill (_cairo_xcb_surface_fallback (surface,
1001                                                                &composite),
1002                                   op, source,
1003                                   path, fill_rule,
1004                                   tolerance, antialias,
1005                                   clip);
1006 done:
1007     _cairo_composite_rectangles_fini (&composite);
1008     return status;
1009 }
1010
1011 static cairo_int_status_t
1012 _cairo_xcb_surface_glyphs (void                         *abstract_surface,
1013                            cairo_operator_t              op,
1014                            const cairo_pattern_t        *source,
1015                            cairo_glyph_t                *glyphs,
1016                            int                           num_glyphs,
1017                            cairo_scaled_font_t          *scaled_font,
1018                            const cairo_clip_t           *clip)
1019 {
1020     cairo_xcb_surface_t *surface = abstract_surface;
1021     cairo_composite_rectangles_t composite;
1022     cairo_int_status_t status;
1023     cairo_bool_t overlap;
1024
1025     status = _cairo_composite_rectangles_init_for_glyphs (&composite,
1026                                                           &surface->base,
1027                                                           op, source,
1028                                                           scaled_font,
1029                                                           glyphs, num_glyphs,
1030                                                           clip, &overlap);
1031     if (unlikely (status))
1032         return status;
1033
1034     if (surface->fallback == NULL) {
1035         status = _cairo_xcb_surface_cairo_glyphs (surface,
1036                                                   op, source,
1037                                                   scaled_font, glyphs, num_glyphs,
1038                                                   clip);
1039         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1040             goto done;
1041
1042         status = _cairo_xcb_surface_render_glyphs (surface,
1043                                                    op, source,
1044                                                    scaled_font, glyphs, num_glyphs,
1045                                                    &composite, overlap);
1046         if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1047             goto done;
1048     }
1049
1050     status =  _cairo_surface_show_text_glyphs (_cairo_xcb_surface_fallback (surface,
1051                                                                             &composite),
1052                                                op, source,
1053                                                NULL, 0,
1054                                                glyphs, num_glyphs,
1055                                                NULL, 0, 0,
1056                                                scaled_font,
1057                                                clip);
1058 done:
1059     _cairo_composite_rectangles_fini (&composite);
1060     return status;
1061 }
1062
1063 const cairo_surface_backend_t _cairo_xcb_surface_backend = {
1064     CAIRO_SURFACE_TYPE_XCB,
1065     _cairo_xcb_surface_finish,
1066     _cairo_default_context_create,
1067
1068     _cairo_xcb_surface_create_similar,
1069     _cairo_xcb_surface_create_similar_image,
1070     _cairo_xcb_surface_map_to_image,
1071     _cairo_xcb_surface_unmap,
1072
1073     _cairo_xcb_surface_source,
1074     _cairo_xcb_surface_acquire_source_image,
1075     _cairo_xcb_surface_release_source_image,
1076     NULL, /* snapshot */
1077
1078
1079     NULL, /* copy_page */
1080     NULL, /* show_page */
1081
1082     _cairo_xcb_surface_get_extents,
1083     _cairo_xcb_surface_get_font_options,
1084
1085     _cairo_xcb_surface_flush,
1086     NULL,
1087
1088     _cairo_xcb_surface_paint,
1089     _cairo_xcb_surface_mask,
1090     _cairo_xcb_surface_stroke,
1091     _cairo_xcb_surface_fill,
1092     NULL, /* fill-stroke */
1093     _cairo_xcb_surface_glyphs,
1094 };
1095
1096 cairo_surface_t *
1097 _cairo_xcb_surface_create_internal (cairo_xcb_screen_t          *screen,
1098                                     xcb_drawable_t               drawable,
1099                                     cairo_bool_t                 owns_pixmap,
1100                                     pixman_format_code_t         pixman_format,
1101                                     xcb_render_pictformat_t      xrender_format,
1102                                     int                          width,
1103                                     int                          height)
1104 {
1105     cairo_xcb_surface_t *surface;
1106
1107     surface = malloc (sizeof (cairo_xcb_surface_t));
1108     if (unlikely (surface == NULL))
1109         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1110
1111     _cairo_surface_init (&surface->base,
1112                          &_cairo_xcb_surface_backend,
1113                          &screen->connection->device,
1114                          _cairo_content_from_pixman_format (pixman_format));
1115
1116     surface->connection = _cairo_xcb_connection_reference (screen->connection);
1117     surface->screen = screen;
1118     cairo_list_add (&surface->link, &screen->surfaces);
1119
1120     surface->drawable = drawable;
1121     surface->owns_pixmap = owns_pixmap;
1122
1123     surface->deferred_clear = FALSE;
1124     surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
1125
1126     surface->width  = width;
1127     surface->height = height;
1128     surface->depth  = PIXMAN_FORMAT_DEPTH (pixman_format);
1129
1130     surface->picture = XCB_NONE;
1131     if (screen->connection->force_precision != -1)
1132         surface->precision = screen->connection->force_precision;
1133     else
1134         surface->precision = XCB_RENDER_POLY_MODE_IMPRECISE;
1135
1136     surface->pixman_format = pixman_format;
1137     surface->xrender_format = xrender_format;
1138
1139     surface->fallback = NULL;
1140     _cairo_boxes_init (&surface->fallback_damage);
1141
1142     return &surface->base;
1143 }
1144
1145 static xcb_screen_t *
1146 _cairo_xcb_screen_from_visual (xcb_connection_t *connection,
1147                                xcb_visualtype_t *visual,
1148                                int *depth)
1149 {
1150     xcb_depth_iterator_t d;
1151     xcb_screen_iterator_t s;
1152
1153     s = xcb_setup_roots_iterator (xcb_get_setup (connection));
1154     for (; s.rem; xcb_screen_next (&s)) {
1155         if (s.data->root_visual == visual->visual_id) {
1156             *depth = s.data->root_depth;
1157             return s.data;
1158         }
1159
1160         d = xcb_screen_allowed_depths_iterator(s.data);
1161         for (; d.rem; xcb_depth_next (&d)) {
1162             xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
1163
1164             for (; v.rem; xcb_visualtype_next (&v)) {
1165                 if (v.data->visual_id == visual->visual_id) {
1166                     *depth = d.data->depth;
1167                     return s.data;
1168                 }
1169             }
1170         }
1171     }
1172
1173     return NULL;
1174 }
1175
1176 /**
1177  * cairo_xcb_surface_create:
1178  * @connection: an XCB connection
1179  * @drawable: an XCB drawable
1180  * @visual: the visual to use for drawing to @drawable. The depth
1181  *          of the visual must match the depth of the drawable.
1182  *          Currently, only TrueColor visuals are fully supported.
1183  * @width: the current width of @drawable
1184  * @height: the current height of @drawable
1185  *
1186  * Creates an XCB surface that draws to the given drawable.
1187  * The way that colors are represented in the drawable is specified
1188  * by the provided visual.
1189  *
1190  * Note: If @drawable is a Window, then the function
1191  * cairo_xcb_surface_set_size() must be called whenever the size of the
1192  * window changes.
1193  *
1194  * When @drawable is a Window containing child windows then drawing to
1195  * the created surface will be clipped by those child windows.  When
1196  * the created surface is used as a source, the contents of the
1197  * children will be included.
1198  *
1199  * Return value: a pointer to the newly created surface. The caller
1200  * owns the surface and should call cairo_surface_destroy() when done
1201  * with it.
1202  *
1203  * This function always returns a valid pointer, but it will return a
1204  * pointer to a "nil" surface if an error such as out of memory
1205  * occurs. You can use cairo_surface_status() to check for this.
1206  *
1207  * Since: 1.12
1208  **/
1209 cairo_surface_t *
1210 cairo_xcb_surface_create (xcb_connection_t  *connection,
1211                           xcb_drawable_t     drawable,
1212                           xcb_visualtype_t  *visual,
1213                           int                width,
1214                           int                height)
1215 {
1216     cairo_xcb_screen_t *screen;
1217     xcb_screen_t *xcb_screen;
1218     cairo_format_masks_t image_masks;
1219     pixman_format_code_t pixman_format;
1220     xcb_render_pictformat_t xrender_format;
1221     int depth;
1222
1223     if (xcb_connection_has_error (connection))
1224         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
1225
1226     if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
1227         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1228     if (unlikely (width <= 0 || height <= 0))
1229         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1230
1231     xcb_screen = _cairo_xcb_screen_from_visual (connection, visual, &depth);
1232     if (unlikely (xcb_screen == NULL))
1233         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
1234
1235     image_masks.alpha_mask = 0;
1236     image_masks.red_mask   = visual->red_mask;
1237     image_masks.green_mask = visual->green_mask;
1238     image_masks.blue_mask  = visual->blue_mask;
1239     if (depth == 32) /* XXX visuals have no alpha! */
1240         image_masks.alpha_mask =
1241             0xffffffff & ~(visual->red_mask | visual->green_mask | visual->blue_mask);
1242     if (depth > 16)
1243         image_masks.bpp = 32;
1244     else if (depth > 8)
1245         image_masks.bpp = 16;
1246     else if (depth > 1)
1247         image_masks.bpp = 8;
1248     else
1249         image_masks.bpp = 1;
1250
1251     if (! _pixman_format_from_masks (&image_masks, &pixman_format))
1252         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1253
1254     screen = _cairo_xcb_screen_get (connection, xcb_screen);
1255     if (unlikely (screen == NULL))
1256         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1257
1258     xrender_format =
1259         _cairo_xcb_connection_get_xrender_format_for_visual (screen->connection,
1260                                                              visual->visual_id);
1261
1262     return _cairo_xcb_surface_create_internal (screen, drawable, FALSE,
1263                                                pixman_format,
1264                                                xrender_format,
1265                                                width, height);
1266 }
1267 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1268 slim_hidden_def (cairo_xcb_surface_create);
1269 #endif
1270
1271 /**
1272  * cairo_xcb_surface_create_for_bitmap:
1273  * @connection: an XCB connection
1274  * @screen: the XCB screen associated with @bitmap
1275  * @bitmap: an XCB drawable (a Pixmap with depth 1)
1276  * @width: the current width of @bitmap
1277  * @height: the current height of @bitmap
1278  *
1279  * Creates an XCB surface that draws to the given bitmap.
1280  * This will be drawn to as a %CAIRO_FORMAT_A1 object.
1281  *
1282  * Return value: a pointer to the newly created surface. The caller
1283  * owns the surface and should call cairo_surface_destroy() when done
1284  * with it.
1285  *
1286  * This function always returns a valid pointer, but it will return a
1287  * pointer to a "nil" surface if an error such as out of memory
1288  * occurs. You can use cairo_surface_status() to check for this.
1289  *
1290  * Since: 1.12
1291  **/
1292 cairo_surface_t *
1293 cairo_xcb_surface_create_for_bitmap (xcb_connection_t   *connection,
1294                                      xcb_screen_t       *screen,
1295                                      xcb_pixmap_t        bitmap,
1296                                      int                 width,
1297                                      int                 height)
1298 {
1299     cairo_xcb_screen_t *cairo_xcb_screen;
1300
1301     if (xcb_connection_has_error (connection))
1302         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
1303
1304     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1305         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1306     if (unlikely (width <= 0 || height <= 0))
1307         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1308
1309     cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen);
1310     if (unlikely (cairo_xcb_screen == NULL))
1311         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1312
1313     return _cairo_xcb_surface_create_internal (cairo_xcb_screen, bitmap, FALSE,
1314                                                PIXMAN_a1,
1315                                                cairo_xcb_screen->connection->standard_formats[CAIRO_FORMAT_A1],
1316                                                width, height);
1317 }
1318 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1319 slim_hidden_def (cairo_xcb_surface_create_for_bitmap);
1320 #endif
1321
1322 /**
1323  * cairo_xcb_surface_create_with_xrender_format:
1324  * @connection: an XCB connection
1325  * @drawable: an XCB drawable
1326  * @screen: the XCB screen associated with @drawable
1327  * @format: the picture format to use for drawing to @drawable. The
1328  *          depth of @format mush match the depth of the drawable.
1329  * @width: the current width of @drawable
1330  * @height: the current height of @drawable
1331  *
1332  * Creates an XCB surface that draws to the given drawable.
1333  * The way that colors are represented in the drawable is specified
1334  * by the provided picture format.
1335  *
1336  * Note: If @drawable is a Window, then the function
1337  * cairo_xcb_surface_set_size() must be called whenever the size of the
1338  * window changes.
1339  *
1340  * When @drawable is a Window containing child windows then drawing to
1341  * the created surface will be clipped by those child windows.  When
1342  * the created surface is used as a source, the contents of the
1343  * children will be included.
1344  *
1345  * Return value: a pointer to the newly created surface. The caller
1346  * owns the surface and should call cairo_surface_destroy() when done
1347  * with it.
1348  *
1349  * This function always returns a valid pointer, but it will return a
1350  * pointer to a "nil" surface if an error such as out of memory
1351  * occurs. You can use cairo_surface_status() to check for this.
1352  *
1353  * Since: 1.12
1354  **/
1355 cairo_surface_t *
1356 cairo_xcb_surface_create_with_xrender_format (xcb_connection_t      *connection,
1357                                               xcb_screen_t          *screen,
1358                                               xcb_drawable_t         drawable,
1359                                               xcb_render_pictforminfo_t *format,
1360                                               int                    width,
1361                                               int                    height)
1362 {
1363     cairo_xcb_screen_t *cairo_xcb_screen;
1364     cairo_format_masks_t image_masks;
1365     pixman_format_code_t pixman_format;
1366
1367     if (xcb_connection_has_error (connection))
1368         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
1369
1370     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1371         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1372     if (unlikely (width <= 0 || height <= 0))
1373         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
1374
1375     image_masks.alpha_mask =
1376         (unsigned long) format->direct.alpha_mask << format->direct.alpha_shift;
1377     image_masks.red_mask =
1378         (unsigned long) format->direct.red_mask << format->direct.red_shift;
1379     image_masks.green_mask =
1380         (unsigned long) format->direct.green_mask << format->direct.green_shift;
1381     image_masks.blue_mask =
1382         (unsigned long) format->direct.blue_mask << format->direct.blue_shift;
1383 #if 0
1384     image_masks.bpp = format->depth;
1385 #else
1386     if (format->depth > 16)
1387         image_masks.bpp = 32;
1388     else if (format->depth > 8)
1389         image_masks.bpp = 16;
1390     else if (format->depth > 1)
1391         image_masks.bpp = 8;
1392     else
1393         image_masks.bpp = 1;
1394 #endif
1395
1396     if (! _pixman_format_from_masks (&image_masks, &pixman_format))
1397         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1398
1399     cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen);
1400     if (unlikely (cairo_xcb_screen == NULL))
1401         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1402
1403     return _cairo_xcb_surface_create_internal (cairo_xcb_screen,
1404                                                drawable,
1405                                                FALSE,
1406                                                pixman_format,
1407                                                format->id,
1408                                                width, height);
1409 }
1410 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1411 slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
1412 #endif
1413
1414 /* This does the necessary fixup when a surface's drawable or size changed. */
1415 static void
1416 _drawable_changed (cairo_xcb_surface_t *surface)
1417 {
1418     _cairo_surface_begin_modification (&surface->base);
1419     _cairo_boxes_clear (&surface->fallback_damage);
1420     cairo_surface_destroy (&surface->fallback->base);
1421
1422     surface->deferred_clear = FALSE;
1423     surface->fallback = NULL;
1424 }
1425
1426 /**
1427  * cairo_xcb_surface_set_size:
1428  * @surface: a #cairo_surface_t for the XCB backend
1429  * @width: the new width of the surface
1430  * @height: the new height of the surface
1431  *
1432  * Informs cairo of the new size of the XCB drawable underlying the
1433  * surface. For a surface created for a window (rather than a pixmap),
1434  * this function must be called each time the size of the window
1435  * changes. (For a subwindow, you are normally resizing the window
1436  * yourself, but for a toplevel window, it is necessary to listen for
1437  * ConfigureNotify events.)
1438  *
1439  * A pixmap can never change size, so it is never necessary to call
1440  * this function on a surface created for a pixmap.
1441  *
1442  * If cairo_surface_flush() wasn't called, some pending operations
1443  * might be discarded.
1444  *
1445  * Since: 1.12
1446  **/
1447 void
1448 cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
1449                             int              width,
1450                             int              height)
1451 {
1452     cairo_xcb_surface_t *surface;
1453
1454     if (unlikely (abstract_surface->status))
1455         return;
1456     if (unlikely (abstract_surface->finished)) {
1457         _cairo_surface_set_error (abstract_surface,
1458                                   _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1459         return;
1460     }
1461
1462
1463     if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) {
1464         _cairo_surface_set_error (abstract_surface,
1465                                   _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1466         return;
1467     }
1468
1469     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
1470         _cairo_surface_set_error (abstract_surface,
1471                                   _cairo_error (CAIRO_STATUS_INVALID_SIZE));
1472         return;
1473     }
1474
1475     surface = (cairo_xcb_surface_t *) abstract_surface;
1476
1477     _drawable_changed(surface);
1478     surface->width  = width;
1479     surface->height = height;
1480 }
1481 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1482 slim_hidden_def (cairo_xcb_surface_set_size);
1483 #endif
1484
1485 /**
1486  * cairo_xcb_surface_set_drawable:
1487  * @surface: a #cairo_surface_t for the XCB backend
1488  * @drawable: the new drawable of the surface
1489  * @width: the new width of the surface
1490  * @height: the new height of the surface
1491  *
1492  * Informs cairo of the new drawable and size of the XCB drawable underlying the
1493  * surface.
1494  *
1495  * If cairo_surface_flush() wasn't called, some pending operations
1496  * might be discarded.
1497  *
1498  * Since: 1.12
1499  **/
1500 void
1501 cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface,
1502                                 xcb_drawable_t  drawable,
1503                                 int             width,
1504                                 int             height)
1505 {
1506     cairo_xcb_surface_t *surface;
1507
1508     if (unlikely (abstract_surface->status))
1509         return;
1510     if (unlikely (abstract_surface->finished)) {
1511         _cairo_surface_set_error (abstract_surface,
1512                                   _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
1513         return;
1514     }
1515
1516
1517     if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) {
1518         _cairo_surface_set_error (abstract_surface,
1519                                   _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
1520         return;
1521     }
1522
1523     if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
1524         _cairo_surface_set_error (abstract_surface,
1525                                   _cairo_error (CAIRO_STATUS_INVALID_SIZE));
1526         return;
1527     }
1528
1529     surface = (cairo_xcb_surface_t *) abstract_surface;
1530
1531     /* XXX: and what about this case? */
1532     if (surface->owns_pixmap)
1533             return;
1534
1535     _drawable_changed (surface);
1536
1537     if (surface->drawable != drawable) {
1538             cairo_status_t status;
1539             status = _cairo_xcb_connection_acquire (surface->connection);
1540             if (unlikely (status))
1541                     return;
1542
1543             if (surface->picture != XCB_NONE) {
1544                     _cairo_xcb_connection_render_free_picture (surface->connection,
1545                                                                surface->picture);
1546                     surface->picture = XCB_NONE;
1547             }
1548
1549             _cairo_xcb_connection_release (surface->connection);
1550
1551             surface->drawable = drawable;
1552     }
1553     surface->width  = width;
1554     surface->height = height;
1555 }
1556 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
1557 slim_hidden_def (cairo_xcb_surface_set_drawable);
1558 #endif