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-image-surface-inline.h"
49
#include "cairo-list-inline.h"
50
#include "cairo-surface-backend-private.h"
51
#include "cairo-compositor-private.h"
52

            
53
/**
54
 * SECTION:cairo-xcb
55
 * @Title: XCB Surfaces
56
 * @Short_Description: X Window System rendering using the XCB library
57
 * @See_Also: #cairo_surface_t
58
 *
59
 * The XCB surface is used to render cairo graphics to X Window System
60
 * windows and pixmaps using the XCB library.
61
 *
62
 * Note that the XCB surface automatically takes advantage of the X render
63
 * extension if it is available.
64
 **/
65

            
66
/**
67
 * CAIRO_HAS_XCB_SURFACE:
68
 *
69
 * Defined if the xcb surface backend is available.
70
 * This macro can be used to conditionally compile backend-specific code.
71
 *
72
 * Since: 1.12
73
 **/
74

            
75
cairo_surface_t *
76
3
_cairo_xcb_surface_create_similar (void			*abstract_other,
77
				   cairo_content_t	 content,
78
				   int			 width,
79
				   int			 height)
80
{
81
3
    cairo_xcb_surface_t *other = abstract_other;
82
    cairo_xcb_surface_t *surface;
83
    cairo_xcb_connection_t *connection;
84
    xcb_pixmap_t pixmap;
85
    cairo_status_t status;
86

            
87
3
    if (unlikely(width  > XLIB_COORD_MAX ||
88
		 height > XLIB_COORD_MAX ||
89
		 width  <= 0 ||
90
		 height <= 0))
91
	return cairo_image_surface_create (_cairo_format_from_content (content),
92
					   width, height);
93

            
94
3
    if ((other->connection->flags & CAIRO_XCB_HAS_RENDER) == 0)
95
	return _cairo_xcb_surface_create_similar_image (other,
96
							_cairo_format_from_content (content),
97
							width, height);
98

            
99
3
    connection = other->connection;
100
3
    status = _cairo_xcb_connection_acquire (connection);
101
3
    if (unlikely (status))
102
	return _cairo_surface_create_in_error (status);
103

            
104
3
    if (content == other->base.content) {
105
3
	pixmap = _cairo_xcb_connection_create_pixmap (connection,
106
3
						      other->depth,
107
						      other->drawable,
108
						      width, height);
109

            
110
	surface = (cairo_xcb_surface_t *)
111
3
	    _cairo_xcb_surface_create_internal (other->screen,
112
						pixmap, TRUE,
113
						other->pixman_format,
114
						other->xrender_format,
115
						width, height);
116
    } else {
117
	cairo_format_t format;
118
	pixman_format_code_t pixman_format;
119

            
120
	/* XXX find a compatible xrender format */
121
	switch (content) {
122
	case CAIRO_CONTENT_ALPHA:
123
	    pixman_format = PIXMAN_a8;
124
	    format = CAIRO_FORMAT_A8;
125
	    break;
126
	case CAIRO_CONTENT_COLOR:
127
	    pixman_format = PIXMAN_x8r8g8b8;
128
	    format = CAIRO_FORMAT_RGB24;
129
	    break;
130
	default:
131
	    ASSERT_NOT_REACHED;
132
	case CAIRO_CONTENT_COLOR_ALPHA:
133
	    pixman_format = PIXMAN_a8r8g8b8;
134
	    format = CAIRO_FORMAT_ARGB32;
135
	    break;
136
	}
137

            
138
	pixmap = _cairo_xcb_connection_create_pixmap (connection,
139
						      PIXMAN_FORMAT_DEPTH (pixman_format),
140
						      other->drawable,
141
						      width, height);
142

            
143
	surface = (cairo_xcb_surface_t *)
144
	    _cairo_xcb_surface_create_internal (other->screen,
145
						pixmap, TRUE,
146
						pixman_format,
147
						connection->standard_formats[format],
148
						width, height);
149
    }
150

            
151
3
    if (unlikely (surface->base.status))
152
	xcb_free_pixmap (connection->xcb_connection, pixmap);
153

            
154
3
    _cairo_xcb_connection_release (connection);
155

            
156
3
    return &surface->base;
157
}
158

            
159
cairo_surface_t *
160
_cairo_xcb_surface_create_similar_image (void			*abstract_other,
161
					 cairo_format_t		 format,
162
					 int			 width,
163
					 int			 height)
164
{
165
    cairo_xcb_surface_t *other = abstract_other;
166
    cairo_xcb_connection_t *connection = other->connection;
167

            
168
    cairo_xcb_shm_info_t *shm_info;
169
    cairo_image_surface_t *image;
170
    cairo_status_t status;
171
    pixman_format_code_t pixman_format;
172

            
173
    if (unlikely(width  > XLIB_COORD_MAX ||
174
		 height > XLIB_COORD_MAX ||
175
		 width  <= 0 ||
176
		 height <= 0))
177
	return NULL;
178

            
179
    pixman_format = _cairo_format_to_pixman_format_code (format);
180

            
181
    status = _cairo_xcb_shm_image_create (connection, pixman_format,
182
					  width, height, &image,
183
					  &shm_info);
184
    if (unlikely (status))
185
	return _cairo_surface_create_in_error (status);
186

            
187
    if (! image->base.is_clear) {
188
	memset (image->data, 0, image->stride * image->height);
189
	image->base.is_clear = TRUE;
190
    }
191

            
192
    return &image->base;
193
}
194

            
195
static cairo_status_t
196
7
_cairo_xcb_surface_finish (void *abstract_surface)
197
{
198
7
    cairo_xcb_surface_t *surface = abstract_surface;
199
    cairo_status_t status;
200

            
201
7
    if (surface->fallback != NULL) {
202
	cairo_surface_finish (&surface->fallback->base);
203
	cairo_surface_destroy (&surface->fallback->base);
204
    }
205
7
    _cairo_boxes_fini (&surface->fallback_damage);
206

            
207
7
    cairo_list_del (&surface->link);
208

            
209
7
    status = _cairo_xcb_connection_acquire (surface->connection);
210
7
    if (status == CAIRO_STATUS_SUCCESS) {
211
7
	if (surface->picture != XCB_NONE) {
212
6
	    _cairo_xcb_connection_render_free_picture (surface->connection,
213
						       surface->picture);
214
	}
215

            
216
7
	if (surface->owns_pixmap)
217
3
	    xcb_free_pixmap (surface->connection->xcb_connection, surface->drawable);
218
7
	_cairo_xcb_connection_release (surface->connection);
219
    }
220

            
221
7
    _cairo_xcb_connection_destroy (surface->connection);
222

            
223
7
    return status;
224
}
225

            
226
static void
227
3
_destroy_image (pixman_image_t *image, void *data)
228
{
229
3
    free (data);
230
3
}
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
3
_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
3
    assert (surface->fallback == NULL);
335
3
    assert (x >= 0);
336
3
    assert (y >= 0);
337
3
    assert (x + width <= surface->width);
338
3
    assert (y + height <= surface->height);
339

            
340
3
    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
3
    connection = surface->connection;
363

            
364
3
    status = _cairo_xcb_connection_acquire (connection);
365
3
    if (unlikely (status))
366
	return _cairo_surface_create_in_error (status);
367

            
368
3
    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
3
    reply =_cairo_xcb_connection_get_image (connection,
380
					    surface->drawable,
381
					    x, y,
382
					    width, height);
383

            
384
3
    if (reply == NULL && ! surface->owns_pixmap) {
385
	/* xcb_get_image_t from a window is dangerous because it can
386
	 * produce errors if the window is unmapped or partially
387
	 * outside the screen. We could check for errors and
388
	 * retry, but to keep things simple, we just create a
389
	 * temporary pixmap
390
	 *
391
	 * If we hit this fallback too often, we should remember so and
392
	 * skip the round-trip from the above GetImage request,
393
	 * similar to what cairo-xlib does.
394
	 */
395
	xcb_pixmap_t pixmap;
396
	xcb_gcontext_t gc;
397

            
398
	gc = _cairo_xcb_screen_get_gc (surface->screen,
399
				       surface->drawable,
400
				       surface->depth);
401
	pixmap = _cairo_xcb_connection_create_pixmap (connection,
402
						      surface->depth,
403
						      surface->drawable,
404
						      width, height);
405

            
406
	/* XXX IncludeInferiors? */
407
	_cairo_xcb_connection_copy_area (connection,
408
					 surface->drawable,
409
					 pixmap, gc,
410
					 x, y,
411
					 0, 0,
412
					 width, height);
413

            
414
	_cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
415

            
416
	reply = _cairo_xcb_connection_get_image (connection,
417
						 pixmap,
418
						 0, 0,
419
						 width, height);
420
	xcb_free_pixmap (connection->xcb_connection, pixmap);
421
    }
422

            
423
3
    if (unlikely (reply == NULL)) {
424
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
425
	goto FAIL;
426
    }
427

            
428
    /* XXX byte swap */
429
    /* XXX format conversion */
430
3
    assert (reply->depth == surface->depth);
431

            
432
3
    image = _cairo_image_surface_create_with_pixman_format
433
3
	(xcb_get_image_data (reply),
434
	 surface->pixman_format,
435
	 width, height,
436
3
	 CAIRO_STRIDE_FOR_WIDTH_BPP (width,
437
				     PIXMAN_FORMAT_BPP (surface->pixman_format)));
438
3
    status = image->status;
439
3
    if (unlikely (status)) {
440
	free (reply);
441
	goto FAIL;
442
    }
443

            
444
    /* XXX */
445
3
    pixman_image_set_destroy_function (((cairo_image_surface_t *)image)->pixman_image, _destroy_image, reply);
446

            
447
3
    _cairo_xcb_connection_release (connection);
448

            
449
3
    return image;
450

            
451
FAIL:
452
    _cairo_xcb_connection_release (connection);
453
    return _cairo_surface_create_in_error (status);
454
}
455

            
456
static cairo_surface_t *
457
3
_cairo_xcb_surface_source (void *abstract_surface,
458
			   cairo_rectangle_int_t *extents)
459
{
460
3
    cairo_xcb_surface_t *surface = abstract_surface;
461

            
462
3
    if (extents) {
463
3
	extents->x = extents->y = 0;
464
3
	extents->width  = surface->width;
465
3
	extents->height = surface->height;
466
    }
467

            
468
3
    return &surface->base;
469
}
470

            
471
static cairo_status_t
472
3
_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
473
					 cairo_image_surface_t **image_out,
474
					 void **image_extra)
475
{
476
3
    cairo_xcb_surface_t *surface = abstract_surface;
477
    cairo_surface_t *image;
478

            
479
3
    if (surface->fallback != NULL) {
480
	image = cairo_surface_reference (&surface->fallback->base);
481
	goto DONE;
482
    }
483

            
484
3
    image = _cairo_surface_has_snapshot (&surface->base,
485
					 &_cairo_image_surface_backend);
486
3
    if (image != NULL) {
487
	image = cairo_surface_reference (image);
488
	goto DONE;
489
    }
490

            
491
3
    image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height);
492
3
    if (unlikely (image->status))
493
	return image->status;
494

            
495
3
    _cairo_surface_attach_snapshot (&surface->base, image, NULL);
496

            
497
3
DONE:
498
3
    *image_out = (cairo_image_surface_t *) image;
499
3
    *image_extra = NULL;
500
3
    return CAIRO_STATUS_SUCCESS;
501
}
502

            
503
static void
504
3
_cairo_xcb_surface_release_source_image (void *abstract_surface,
505
					 cairo_image_surface_t *image,
506
					 void *image_extra)
507
{
508
3
    cairo_surface_destroy (&image->base);
509
3
}
510

            
511
cairo_bool_t
512
75
_cairo_xcb_surface_get_extents (void *abstract_surface,
513
				cairo_rectangle_int_t *extents)
514
{
515
75
    cairo_xcb_surface_t *surface = abstract_surface;
516

            
517
75
    extents->x = extents->y = 0;
518
75
    extents->width  = surface->width;
519
75
    extents->height = surface->height;
520
75
    return TRUE;
521
}
522

            
523
static void
524
_cairo_xcb_surface_get_font_options (void *abstract_surface,
525
				     cairo_font_options_t *options)
526
{
527
    cairo_xcb_surface_t *surface = abstract_surface;
528

            
529
    *options = *_cairo_xcb_screen_get_font_options (surface->screen);
530
}
531

            
532
static cairo_status_t
533
_put_shm_image (cairo_xcb_surface_t    *surface,
534
		xcb_gcontext_t		gc,
535
		cairo_image_surface_t  *image)
536
{
537
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
538
    cairo_xcb_shm_info_t *shm_info;
539

            
540
    shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
541
						(const cairo_user_data_key_t *) surface->connection);
542
    if (shm_info == NULL)
543
	return CAIRO_INT_STATUS_UNSUPPORTED;
544

            
545
    _cairo_xcb_connection_shm_put_image (surface->connection,
546
					 surface->drawable,
547
					 gc,
548
					 surface->width, surface->height,
549
					 0, 0,
550
					 image->width, image->height,
551
					 image->base.device_transform_inverse.x0,
552
					 image->base.device_transform_inverse.y0,
553
					 image->depth,
554
					 shm_info->shm,
555
					 shm_info->offset);
556

            
557
    return CAIRO_STATUS_SUCCESS;
558
#else
559
    return CAIRO_INT_STATUS_UNSUPPORTED;
560
#endif
561
}
562

            
563
static cairo_status_t
564
_put_image (cairo_xcb_surface_t    *surface,
565
	    cairo_image_surface_t  *image)
566
{
567
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
568

            
569
    /* XXX track damaged region? */
570

            
571
    status = _cairo_xcb_connection_acquire (surface->connection);
572
    if (unlikely (status))
573
	return status;
574

            
575
    if (image->pixman_format == surface->pixman_format) {
576
	xcb_gcontext_t gc;
577

            
578
	assert (image->depth == surface->depth);
579
	assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
580

            
581
	gc = _cairo_xcb_screen_get_gc (surface->screen,
582
				       surface->drawable,
583
				       surface->depth);
584

            
585
	status = _put_shm_image (surface, gc, image);
586
	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
587
	    _cairo_xcb_connection_put_image (surface->connection,
588
					     surface->drawable, gc,
589
					     image->width, image->height,
590
					     image->base.device_transform_inverse.x0,
591
					     image->base.device_transform_inverse.y0,
592
					     image->depth,
593
					     image->stride,
594
					     image->data);
595
	    status = CAIRO_STATUS_SUCCESS;
596
	}
597

            
598
	_cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
599
    } else {
600
	ASSERT_NOT_REACHED;
601
    }
602

            
603
    _cairo_xcb_connection_release (surface->connection);
604
    return status;
605
}
606

            
607
static cairo_int_status_t
608
_put_shm_image_boxes (cairo_xcb_surface_t    *surface,
609
		      cairo_image_surface_t  *image,
610
		      xcb_gcontext_t gc,
611
		      cairo_boxes_t *boxes)
612
{
613
#if CAIRO_HAS_XCB_SHM_FUNCTIONS
614
    cairo_xcb_shm_info_t *shm_info;
615

            
616
    shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
617
						(const cairo_user_data_key_t *) surface->connection);
618
    if (shm_info != NULL) {
619
	struct _cairo_boxes_chunk *chunk;
620

            
621
	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
622
	    int i;
623

            
624
	    for (i = 0; i < chunk->count; i++) {
625
		cairo_box_t *b = &chunk->base[i];
626
		int x = _cairo_fixed_integer_part (b->p1.x);
627
		int y = _cairo_fixed_integer_part (b->p1.y);
628
		int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
629
		int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
630

            
631
		_cairo_xcb_connection_shm_put_image (surface->connection,
632
						     surface->drawable,
633
						     gc,
634
						     surface->width, surface->height,
635
						     x, y,
636
						     width, height,
637
						     x, y,
638
						     image->depth,
639
						     shm_info->shm,
640
						     shm_info->offset);
641
	    }
642
	}
643
	return CAIRO_INT_STATUS_SUCCESS;
644
    }
645
#endif
646

            
647
    return CAIRO_INT_STATUS_UNSUPPORTED;
648
}
649

            
650
static cairo_status_t
651
_put_image_boxes (cairo_xcb_surface_t    *surface,
652
		  cairo_image_surface_t  *image,
653
		  cairo_boxes_t *boxes)
654
{
655
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
656
    xcb_gcontext_t gc;
657

            
658
    if (boxes->num_boxes == 0)
659
	    return CAIRO_STATUS_SUCCESS;
660

            
661
    /* XXX track damaged region? */
662

            
663
    status = _cairo_xcb_connection_acquire (surface->connection);
664
    if (unlikely (status))
665
	return status;
666

            
667
    assert (image->pixman_format == surface->pixman_format);
668
    assert (image->depth == surface->depth);
669
    assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
670

            
671
    gc = _cairo_xcb_screen_get_gc (surface->screen,
672
				   surface->drawable,
673
				   surface->depth);
674

            
675
    status = _put_shm_image_boxes (surface, image, gc, boxes);
676
    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
677
	    struct _cairo_boxes_chunk *chunk;
678

            
679
	    for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
680
		    int i;
681

            
682
		    for (i = 0; i < chunk->count; i++) {
683
			    cairo_box_t *b = &chunk->base[i];
684
			    int x = _cairo_fixed_integer_part (b->p1.x);
685
			    int y = _cairo_fixed_integer_part (b->p1.y);
686
			    int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x);
687
			    int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y);
688
			    _cairo_xcb_connection_put_subimage (surface->connection,
689
								surface->drawable, gc,
690
								x, y,
691
								width, height,
692
								PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
693
								image->stride,
694
								x, y,
695
								image->depth,
696
								image->data);
697

            
698
		    }
699
	    }
700
	    status = CAIRO_STATUS_SUCCESS;
701
    }
702

            
703
    _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
704
    _cairo_xcb_connection_release (surface->connection);
705
    return status;
706
}
707

            
708
static cairo_status_t
709
46
_cairo_xcb_surface_flush (void *abstract_surface,
710
			  unsigned flags)
711
{
712
46
    cairo_xcb_surface_t *surface = abstract_surface;
713
    cairo_status_t status;
714

            
715
46
    if (flags)
716
39
	return CAIRO_STATUS_SUCCESS;
717

            
718
7
    if (likely (surface->fallback == NULL)) {
719
7
	status = CAIRO_STATUS_SUCCESS;
720
7
	if (! surface->base.finished && surface->deferred_clear)
721
	    status = _cairo_xcb_surface_clear (surface);
722

            
723
7
	return status;
724
    }
725

            
726
    status = surface->base.status;
727
    if (status == CAIRO_STATUS_SUCCESS &&
728
	(! surface->base._finishing || ! surface->owns_pixmap)) {
729
	status = cairo_surface_status (&surface->fallback->base);
730

            
731
	if (status == CAIRO_STATUS_SUCCESS)
732
		status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage,
733
								  CAIRO_FILL_RULE_WINDING,
734
								  &surface->fallback_damage);
735

            
736
	if (status == CAIRO_STATUS_SUCCESS)
737
	    status = _put_image_boxes (surface,
738
				       surface->fallback,
739
				       &surface->fallback_damage);
740

            
741
	if (status == CAIRO_STATUS_SUCCESS && ! surface->base._finishing) {
742
	    _cairo_surface_attach_snapshot (&surface->base,
743
					    &surface->fallback->base,
744
					    cairo_surface_finish);
745
	}
746
    }
747

            
748
    _cairo_boxes_clear (&surface->fallback_damage);
749
    cairo_surface_destroy (&surface->fallback->base);
750
    surface->fallback = NULL;
751

            
752
    return status;
753
}
754

            
755
static cairo_image_surface_t *
756
_cairo_xcb_surface_map_to_image (void *abstract_surface,
757
				 const cairo_rectangle_int_t *extents)
758
{
759
    cairo_xcb_surface_t *surface = abstract_surface;
760
    cairo_surface_t *image;
761
    cairo_status_t status;
762

            
763
    if (surface->fallback)
764
	return _cairo_surface_map_to_image (&surface->fallback->base, extents);
765

            
766
    image = _get_image (surface, TRUE,
767
			extents->x, extents->y,
768
			extents->width, extents->height);
769
    status = cairo_surface_status (image);
770
    if (unlikely (status)) {
771
	cairo_surface_destroy(image);
772
	return _cairo_image_surface_create_in_error (status);
773
    }
774

            
775
    /* Do we have a deferred clear and this image surface does NOT cover the
776
     * whole xcb surface? Have to apply the clear in that case, else
777
     * uploading the image will handle the problem for us.
778
     */
779
    if (surface->deferred_clear &&
780
	! (extents->width == surface->width &&
781
	   extents->height == surface->height)) {
782
	status = _cairo_xcb_surface_clear (surface);
783
	if (unlikely (status)) {
784
	    cairo_surface_destroy(image);
785
	    return _cairo_image_surface_create_in_error (status);
786
	}
787
    }
788
    surface->deferred_clear = FALSE;
789

            
790
    cairo_surface_set_device_offset (image, -extents->x, -extents->y);
791
    return (cairo_image_surface_t *) image;
792
}
793

            
794
static cairo_int_status_t
795
_cairo_xcb_surface_unmap (void *abstract_surface,
796
			  cairo_image_surface_t *image)
797
{
798
    cairo_xcb_surface_t *surface = abstract_surface;
799
    cairo_int_status_t status;
800

            
801
    if (surface->fallback)
802
	return _cairo_surface_unmap_image (&surface->fallback->base, image);
803

            
804
    status = _put_image (abstract_surface, image);
805

            
806
    cairo_surface_finish (&image->base);
807
    cairo_surface_destroy (&image->base);
808

            
809
    return status;
810
}
811

            
812
static cairo_surface_t *
813
_cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface,
814
			     cairo_composite_rectangles_t *composite)
815
{
816
    cairo_image_surface_t *image;
817
    cairo_status_t status;
818

            
819
    status = _cairo_composite_rectangles_add_to_damage (composite,
820
							&surface->fallback_damage);
821
    if (unlikely (status))
822
	    return _cairo_surface_create_in_error (status);
823

            
824
    if (surface->fallback)
825
	return &surface->fallback->base;
826

            
827
    image = (cairo_image_surface_t *)
828
	    _get_image (surface, TRUE, 0, 0, surface->width, surface->height);
829

            
830
    if (image->base.status != CAIRO_STATUS_SUCCESS)
831
	return &image->base;
832

            
833
    /* If there was a deferred clear, _get_image applied it */
834
    surface->deferred_clear = FALSE;
835

            
836
    surface->fallback = image;
837

            
838
    return &surface->fallback->base;
839
}
840

            
841
static cairo_int_status_t
842
_cairo_xcb_fallback_compositor_paint (const cairo_compositor_t     *compositor,
843
				      cairo_composite_rectangles_t *extents)
844
{
845
    cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
846
    cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
847

            
848
    return _cairo_surface_paint (fallback, extents->op,
849
				 &extents->source_pattern.base,
850
				 extents->clip);
851
}
852

            
853
static cairo_int_status_t
854
_cairo_xcb_fallback_compositor_mask (const cairo_compositor_t     *compositor,
855
				     cairo_composite_rectangles_t *extents)
856
{
857
    cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
858
    cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
859

            
860
    return _cairo_surface_mask (fallback, extents->op,
861
				 &extents->source_pattern.base,
862
				 &extents->mask_pattern.base,
863
				 extents->clip);
864
}
865

            
866
static cairo_int_status_t
867
_cairo_xcb_fallback_compositor_stroke (const cairo_compositor_t     *compositor,
868
				       cairo_composite_rectangles_t *extents,
869
				       const cairo_path_fixed_t     *path,
870
				       const cairo_stroke_style_t   *style,
871
				       const cairo_matrix_t         *ctm,
872
				       const cairo_matrix_t         *ctm_inverse,
873
				       double                        tolerance,
874
				       cairo_antialias_t             antialias)
875
{
876
    cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
877
    cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
878

            
879
    return _cairo_surface_stroke (fallback, extents->op,
880
				  &extents->source_pattern.base,
881
				  path, style, ctm, ctm_inverse,
882
				  tolerance, antialias,
883
				  extents->clip);
884
}
885

            
886
static cairo_int_status_t
887
_cairo_xcb_fallback_compositor_fill (const cairo_compositor_t     *compositor,
888
				     cairo_composite_rectangles_t *extents,
889
				     const cairo_path_fixed_t     *path,
890
				     cairo_fill_rule_t             fill_rule,
891
				     double                        tolerance,
892
				     cairo_antialias_t             antialias)
893
{
894
    cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
895
    cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
896

            
897
    return _cairo_surface_fill (fallback, extents->op,
898
				&extents->source_pattern.base,
899
				path, fill_rule, tolerance,
900
				antialias, extents->clip);
901
}
902

            
903
static cairo_int_status_t
904
_cairo_xcb_fallback_compositor_glyphs (const cairo_compositor_t     *compositor,
905
				       cairo_composite_rectangles_t *extents,
906
				       cairo_scaled_font_t          *scaled_font,
907
				       cairo_glyph_t                *glyphs,
908
				       int                           num_glyphs,
909
				       cairo_bool_t                  overlap)
910
{
911
    cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface;
912
    cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents);
913

            
914
    return _cairo_surface_show_text_glyphs (fallback, extents->op,
915
					    &extents->source_pattern.base,
916
					    NULL, 0, glyphs, num_glyphs,
917
					    NULL, 0, 0,
918
					    scaled_font, extents->clip);
919
}
920

            
921
static const cairo_compositor_t _cairo_xcb_fallback_compositor = {
922
    &__cairo_no_compositor,
923

            
924
    _cairo_xcb_fallback_compositor_paint,
925
    _cairo_xcb_fallback_compositor_mask,
926
    _cairo_xcb_fallback_compositor_stroke,
927
    _cairo_xcb_fallback_compositor_fill,
928
    _cairo_xcb_fallback_compositor_glyphs,
929
};
930

            
931
static const cairo_compositor_t _cairo_xcb_render_compositor = {
932
    &_cairo_xcb_fallback_compositor,
933

            
934
    _cairo_xcb_render_compositor_paint,
935
    _cairo_xcb_render_compositor_mask,
936
    _cairo_xcb_render_compositor_stroke,
937
    _cairo_xcb_render_compositor_fill,
938
    _cairo_xcb_render_compositor_glyphs,
939
};
940

            
941
static inline const cairo_compositor_t *
942
33
get_compositor (cairo_surface_t **s)
943
{
944
33
    cairo_xcb_surface_t *surface = (cairo_xcb_surface_t * )*s;
945
33
    if (surface->fallback) {
946
	*s = &surface->fallback->base;
947
	return ((cairo_image_surface_t *) *s)->compositor;
948
    }
949

            
950
33
    return &_cairo_xcb_render_compositor;
951
}
952

            
953
static cairo_int_status_t
954
9
_cairo_xcb_surface_paint (void			*abstract_surface,
955
			  cairo_operator_t	 op,
956
			  const cairo_pattern_t	*source,
957
			  const cairo_clip_t	*clip)
958
{
959
9
    cairo_surface_t *surface = abstract_surface;
960
9
    const cairo_compositor_t *compositor = get_compositor (&surface);
961
9
    return _cairo_compositor_paint (compositor, surface, op, source, clip);
962
}
963

            
964
static cairo_int_status_t
965
_cairo_xcb_surface_mask (void			*abstract_surface,
966
			 cairo_operator_t	 op,
967
			 const cairo_pattern_t	*source,
968
			 const cairo_pattern_t	*mask,
969
			 const cairo_clip_t	*clip)
970
{
971
    cairo_surface_t *surface = abstract_surface;
972
    const cairo_compositor_t *compositor = get_compositor (&surface);
973
    return _cairo_compositor_mask (compositor, surface, op, source, mask, clip);
974
}
975

            
976
static cairo_int_status_t
977
_cairo_xcb_surface_stroke (void				*abstract_surface,
978
			   cairo_operator_t		 op,
979
			   const cairo_pattern_t	*source,
980
			   const cairo_path_fixed_t	*path,
981
			   const cairo_stroke_style_t	*style,
982
			   const cairo_matrix_t		*ctm,
983
			   const cairo_matrix_t		*ctm_inverse,
984
			   double			 tolerance,
985
			   cairo_antialias_t		 antialias,
986
			   const cairo_clip_t		*clip)
987
{
988
    cairo_surface_t *surface = abstract_surface;
989
    const cairo_compositor_t *compositor = get_compositor (&surface);
990
    return _cairo_compositor_stroke (compositor, surface, op, source,
991
				     path, style, ctm, ctm_inverse,
992
				     tolerance, antialias, clip);
993
}
994

            
995
static cairo_int_status_t
996
24
_cairo_xcb_surface_fill (void			*abstract_surface,
997
			 cairo_operator_t	 op,
998
			 const cairo_pattern_t	*source,
999
			 const cairo_path_fixed_t*path,
			 cairo_fill_rule_t	 fill_rule,
			 double			 tolerance,
			 cairo_antialias_t	 antialias,
			 const cairo_clip_t	*clip)
{
24
    cairo_surface_t *surface = abstract_surface;
24
    const cairo_compositor_t *compositor = get_compositor (&surface);
24
    return _cairo_compositor_fill (compositor, surface, op,
				   source, path, fill_rule,
				   tolerance, antialias, clip);
}
static cairo_int_status_t
_cairo_xcb_surface_glyphs (void				*abstract_surface,
			   cairo_operator_t		 op,
			   const cairo_pattern_t	*source,
			   cairo_glyph_t		*glyphs,
			   int				 num_glyphs,
			   cairo_scaled_font_t		*scaled_font,
			   const cairo_clip_t		*clip)
{
    cairo_surface_t *surface = abstract_surface;
    const cairo_compositor_t *compositor = get_compositor (&surface);
    return _cairo_compositor_glyphs (compositor, surface, op,
				     source, glyphs, num_glyphs,
				     scaled_font, clip);
}
const cairo_surface_backend_t _cairo_xcb_surface_backend = {
    CAIRO_SURFACE_TYPE_XCB,
    _cairo_xcb_surface_finish,
    _cairo_default_context_create,
    _cairo_xcb_surface_create_similar,
    _cairo_xcb_surface_create_similar_image,
    _cairo_xcb_surface_map_to_image,
    _cairo_xcb_surface_unmap,
    _cairo_xcb_surface_source,
    _cairo_xcb_surface_acquire_source_image,
    _cairo_xcb_surface_release_source_image,
    NULL, /* snapshot */
    NULL, /* copy_page */
    NULL, /* show_page */
    _cairo_xcb_surface_get_extents,
    _cairo_xcb_surface_get_font_options,
    _cairo_xcb_surface_flush,
    NULL,
    _cairo_xcb_surface_paint,
    _cairo_xcb_surface_mask,
    _cairo_xcb_surface_stroke,
    _cairo_xcb_surface_fill,
    NULL, /* fill-stroke */
    _cairo_xcb_surface_glyphs,
};
cairo_surface_t *
7
_cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
				    xcb_drawable_t		 drawable,
				    cairo_bool_t		 owns_pixmap,
				    pixman_format_code_t	 pixman_format,
				    xcb_render_pictformat_t	 xrender_format,
				    int				 width,
				    int				 height)
{
    cairo_xcb_surface_t *surface;
7
    surface = _cairo_calloc (sizeof (cairo_xcb_surface_t));
7
    if (unlikely (surface == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
7
    _cairo_surface_init (&surface->base,
			 &_cairo_xcb_surface_backend,
7
			 &screen->connection->device,
			 _cairo_content_from_pixman_format (pixman_format),
			 FALSE); /* is_vector */
7
    surface->connection = _cairo_xcb_connection_reference (screen->connection);
7
    surface->screen = screen;
7
    cairo_list_add (&surface->link, &screen->surfaces);
7
    surface->drawable = drawable;
7
    surface->owns_pixmap = owns_pixmap;
7
    surface->deferred_clear = FALSE;
7
    surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
7
    surface->width  = width;
7
    surface->height = height;
7
    surface->depth  = PIXMAN_FORMAT_DEPTH (pixman_format);
7
    surface->picture = XCB_NONE;
7
    if (screen->connection->force_precision != -1)
	surface->precision = screen->connection->force_precision;
    else
7
	surface->precision = XCB_RENDER_POLY_MODE_IMPRECISE;
7
    surface->pixman_format = pixman_format;
7
    surface->xrender_format = xrender_format;
7
    surface->fallback = NULL;
7
    _cairo_boxes_init (&surface->fallback_damage);
7
    return &surface->base;
}
static xcb_screen_t *
_cairo_xcb_screen_from_visual (xcb_connection_t *connection,
			       xcb_visualtype_t *visual,
			       int *depth)
{
    xcb_depth_iterator_t d;
    xcb_screen_iterator_t s;
    s = xcb_setup_roots_iterator (xcb_get_setup (connection));
    for (; s.rem; xcb_screen_next (&s)) {
	if (s.data->root_visual == visual->visual_id) {
	    *depth = s.data->root_depth;
	    return s.data;
	}
	d = xcb_screen_allowed_depths_iterator(s.data);
	for (; d.rem; xcb_depth_next (&d)) {
	    xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
	    for (; v.rem; xcb_visualtype_next (&v)) {
		if (v.data->visual_id == visual->visual_id) {
		    *depth = d.data->depth;
		    return s.data;
		}
	    }
	}
    }
    return NULL;
}
/**
 * cairo_xcb_surface_create:
 * @connection: an XCB connection
 * @drawable: an XCB drawable
 * @visual: the visual to use for drawing to @drawable. The depth
 *          of the visual must match the depth of the drawable.
 *          Currently, only TrueColor visuals are fully supported.
 * @width: the current width of @drawable
 * @height: the current height of @drawable
 *
 * Creates an XCB surface that draws to the given drawable.
 * The way that colors are represented in the drawable is specified
 * by the provided visual.
 *
 * Note: If @drawable is a Window, then the function
 * cairo_xcb_surface_set_size() must be called whenever the size of the
 * window changes.
 *
 * When @drawable is a Window containing child windows then drawing to
 * the created surface will be clipped by those child windows.  When
 * the created surface is used as a source, the contents of the
 * children will be included.
 *
 * Return value: a pointer to the newly created surface. The caller
 * owns the surface and should call cairo_surface_destroy() when done
 * with it.
 *
 * This function always returns a valid pointer, but it will return a
 * pointer to a "nil" surface if an error such as out of memory
 * occurs. You can use cairo_surface_status() to check for this.
 *
 * Since: 1.12
 **/
cairo_surface_t *
cairo_xcb_surface_create (xcb_connection_t  *connection,
			  xcb_drawable_t     drawable,
			  xcb_visualtype_t  *visual,
			  int		     width,
			  int		     height)
{
    cairo_xcb_screen_t *screen;
    xcb_screen_t *xcb_screen;
    cairo_format_masks_t image_masks;
    pixman_format_code_t pixman_format;
    xcb_render_pictformat_t xrender_format;
    int depth;
    if (xcb_connection_has_error (connection))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
    if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
    if (unlikely (width <= 0 || height <= 0))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
    xcb_screen = _cairo_xcb_screen_from_visual (connection, visual, &depth);
    if (unlikely (xcb_screen == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
    image_masks.alpha_mask = 0;
    image_masks.red_mask   = visual->red_mask;
    image_masks.green_mask = visual->green_mask;
    image_masks.blue_mask  = visual->blue_mask;
    if (depth == 32) /* XXX visuals have no alpha! */
	image_masks.alpha_mask =
	    0xffffffff & ~(visual->red_mask | visual->green_mask | visual->blue_mask);
    if (depth > 16)
	image_masks.bpp = 32;
    else if (depth > 8)
	image_masks.bpp = 16;
    else if (depth > 1)
	image_masks.bpp = 8;
    else
	image_masks.bpp = 1;
    if (! _pixman_format_from_masks (&image_masks, &pixman_format))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
    screen = _cairo_xcb_screen_get (connection, xcb_screen);
    if (unlikely (screen == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    xrender_format =
	_cairo_xcb_connection_get_xrender_format_for_visual (screen->connection,
							     visual->visual_id);
    return _cairo_xcb_surface_create_internal (screen, drawable, FALSE,
					       pixman_format,
					       xrender_format,
					       width, height);
}
/**
 * cairo_xcb_surface_create_for_bitmap:
 * @connection: an XCB connection
 * @screen: the XCB screen associated with @bitmap
 * @bitmap: an XCB drawable (a Pixmap with depth 1)
 * @width: the current width of @bitmap
 * @height: the current height of @bitmap
 *
 * Creates an XCB surface that draws to the given bitmap.
 * This will be drawn to as a %CAIRO_FORMAT_A1 object.
 *
 * Return value: a pointer to the newly created surface. The caller
 * owns the surface and should call cairo_surface_destroy() when done
 * with it.
 *
 * This function always returns a valid pointer, but it will return a
 * pointer to a "nil" surface if an error such as out of memory
 * occurs. You can use cairo_surface_status() to check for this.
 *
 * Since: 1.12
 **/
cairo_surface_t *
cairo_xcb_surface_create_for_bitmap (xcb_connection_t	*connection,
				     xcb_screen_t	*screen,
				     xcb_pixmap_t	 bitmap,
				     int		 width,
				     int		 height)
{
    cairo_xcb_screen_t *cairo_xcb_screen;
    if (xcb_connection_has_error (connection))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
    if (unlikely (width <= 0 || height <= 0))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
    cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen);
    if (unlikely (cairo_xcb_screen == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
    return _cairo_xcb_surface_create_internal (cairo_xcb_screen, bitmap, FALSE,
					       PIXMAN_a1,
					       cairo_xcb_screen->connection->standard_formats[CAIRO_FORMAT_A1],
					       width, height);
}
/**
 * cairo_xcb_surface_create_with_xrender_format:
 * @connection: an XCB connection
 * @drawable: an XCB drawable
 * @screen: the XCB screen associated with @drawable
 * @format: the picture format to use for drawing to @drawable. The
 *          depth of @format mush match the depth of the drawable.
 * @width: the current width of @drawable
 * @height: the current height of @drawable
 *
 * Creates an XCB surface that draws to the given drawable.
 * The way that colors are represented in the drawable is specified
 * by the provided picture format.
 *
 * Note: If @drawable is a Window, then the function
 * cairo_xcb_surface_set_size() must be called whenever the size of the
 * window changes.
 *
 * When @drawable is a Window containing child windows then drawing to
 * the created surface will be clipped by those child windows.  When
 * the created surface is used as a source, the contents of the
 * children will be included.
 *
 * Return value: a pointer to the newly created surface. The caller
 * owns the surface and should call cairo_surface_destroy() when done
 * with it.
 *
 * This function always returns a valid pointer, but it will return a
 * pointer to a "nil" surface if an error such as out of memory
 * occurs. You can use cairo_surface_status() to check for this.
 *
 * Since: 1.12
 **/
cairo_surface_t *
4
cairo_xcb_surface_create_with_xrender_format (xcb_connection_t	    *connection,
					      xcb_screen_t	    *screen,
					      xcb_drawable_t	     drawable,
					      xcb_render_pictforminfo_t *format,
					      int		     width,
					      int		     height)
{
    cairo_xcb_screen_t *cairo_xcb_screen;
    cairo_format_masks_t image_masks;
    pixman_format_code_t pixman_format;
4
    if (xcb_connection_has_error (connection))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR));
4
    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
4
    if (unlikely (width <= 0 || height <= 0))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
4
    image_masks.alpha_mask =
4
	(unsigned long) format->direct.alpha_mask << format->direct.alpha_shift;
4
    image_masks.red_mask =
4
	(unsigned long) format->direct.red_mask << format->direct.red_shift;
4
    image_masks.green_mask =
4
	(unsigned long) format->direct.green_mask << format->direct.green_shift;
4
    image_masks.blue_mask =
4
	(unsigned long) format->direct.blue_mask << format->direct.blue_shift;
#if 0
    image_masks.bpp = format->depth;
#else
4
    if (format->depth > 16)
4
	image_masks.bpp = 32;
    else if (format->depth > 8)
	image_masks.bpp = 16;
    else if (format->depth > 1)
	image_masks.bpp = 8;
    else
	image_masks.bpp = 1;
#endif
4
    if (! _pixman_format_from_masks (&image_masks, &pixman_format))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
4
    cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen);
4
    if (unlikely (cairo_xcb_screen == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
4
    return _cairo_xcb_surface_create_internal (cairo_xcb_screen,
					       drawable,
					       FALSE,
					       pixman_format,
					       format->id,
					       width, height);
}
/* This does the necessary fixup when a surface's drawable or size changed. */
static void
_drawable_changed (cairo_xcb_surface_t *surface)
{
    _cairo_surface_set_error (&surface->base,
	    _cairo_surface_begin_modification (&surface->base));
    _cairo_boxes_clear (&surface->fallback_damage);
    cairo_surface_destroy (&surface->fallback->base);
    surface->deferred_clear = FALSE;
    surface->fallback = NULL;
}
/**
 * cairo_xcb_surface_set_size:
 * @surface: a #cairo_surface_t for the XCB backend
 * @width: the new width of the surface
 * @height: the new height of the surface
 *
 * Informs cairo of the new size of the XCB drawable underlying the
 * surface. For a surface created for a window (rather than a pixmap),
 * this function must be called each time the size of the window
 * changes. (For a subwindow, you are normally resizing the window
 * yourself, but for a toplevel window, it is necessary to listen for
 * ConfigureNotify events.)
 *
 * A pixmap can never change size, so it is never necessary to call
 * this function on a surface created for a pixmap.
 *
 * If cairo_surface_flush() wasn't called, some pending operations
 * might be discarded.
 *
 * Since: 1.12
 **/
void
8
cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
			    int              width,
			    int              height)
{
    cairo_xcb_surface_t *surface;
8
    if (unlikely (abstract_surface->status))
2
	return;
6
    if (unlikely (abstract_surface->finished)) {
3
	_cairo_surface_set_error (abstract_surface,
3
				  _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
3
	return;
    }
3
    if ( !_cairo_surface_is_xcb(abstract_surface)) {
3
	_cairo_surface_set_error (abstract_surface,
3
				  _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
3
	return;
    }
    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
	_cairo_surface_set_error (abstract_surface,
				  _cairo_error (CAIRO_STATUS_INVALID_SIZE));
	return;
    }
    surface = (cairo_xcb_surface_t *) abstract_surface;
    _drawable_changed(surface);
    surface->width  = width;
    surface->height = height;
}
/**
 * cairo_xcb_surface_set_drawable:
 * @surface: a #cairo_surface_t for the XCB backend
 * @drawable: the new drawable of the surface
 * @width: the new width of the surface
 * @height: the new height of the surface
 *
 * Informs cairo of the new drawable and size of the XCB drawable underlying the
 * surface.
 *
 * If cairo_surface_flush() wasn't called, some pending operations
 * might be discarded.
 *
 * Since: 1.12
 **/
void
7
cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface,
				xcb_drawable_t  drawable,
				int             width,
				int             height)
{
    cairo_xcb_surface_t *surface;
7
    if (unlikely (abstract_surface->status))
1
	return;
6
    if (unlikely (abstract_surface->finished)) {
3
	_cairo_surface_set_error (abstract_surface,
3
				  _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
3
	return;
    }
3
    if ( !_cairo_surface_is_xcb(abstract_surface)) {
3
	_cairo_surface_set_error (abstract_surface,
3
				  _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
3
	return;
    }
    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) {
	_cairo_surface_set_error (abstract_surface,
				  _cairo_error (CAIRO_STATUS_INVALID_SIZE));
	return;
    }
    surface = (cairo_xcb_surface_t *) abstract_surface;
    /* XXX: and what about this case? */
    if (surface->owns_pixmap)
	    return;
    _drawable_changed (surface);
    if (surface->drawable != drawable) {
	    cairo_status_t status;
	    status = _cairo_xcb_connection_acquire (surface->connection);
	    if (unlikely (status))
		    return;
	    if (surface->picture != XCB_NONE) {
		    _cairo_xcb_connection_render_free_picture (surface->connection,
							       surface->picture);
		    surface->picture = XCB_NONE;
	    }
	    _cairo_xcb_connection_release (surface->connection);
	    surface->drawable = drawable;
    }
    surface->width  = width;
    surface->height = height;
}