1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2002 University of Southern California
5
 * Copyright © 2005 Red Hat, Inc.
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it either under the terms of the GNU Lesser General Public
9
 * License version 2.1 as published by the Free Software Foundation
10
 * (the "LGPL") or, at your option, under the terms of the Mozilla
11
 * Public License Version 1.1 (the "MPL"). If you do not alter this
12
 * notice, a recipient may use your version of this file under either
13
 * the MPL or the LGPL.
14
 *
15
 * You should have received a copy of the LGPL along with this library
16
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18
 * You should have received a copy of the MPL along with this library
19
 * in the file COPYING-MPL-1.1
20
 *
21
 * The contents of this file are subject to the Mozilla Public License
22
 * Version 1.1 (the "License"); you may not use this file except in
23
 * compliance with the License. You may obtain a copy of the License at
24
 * http://www.mozilla.org/MPL/
25
 *
26
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28
 * the specific language governing rights and limitations.
29
 *
30
 * The Original Code is the cairo graphics library.
31
 *
32
 * The Initial Developer of the Original Code is University of Southern
33
 * California.
34
 *
35
 * Contributor(s):
36
 *	Carl D. Worth <cworth@cworth.org>
37
 *	Behdad Esfahbod <behdad@behdad.org>
38
 *	Chris Wilson <chris@chris-wilson.co.uk>
39
 *	Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
40
 */
41

            
42
/* Heed well the words of Owen Taylor:
43
 * "Any patch that works around a render bug, or claims to, without a
44
 * specific reference to the bug filed in bugzilla.freedesktop.org will
45
 * never pass approval."
46
 */
47

            
48
#include "cairoint.h"
49

            
50
/**
51
 * CAIRO_HAS_XLIB_XCB_FUNCTIONS:
52
 *
53
 * Defined if Cairo has support for XCB integration with Xlib.
54
 * This macro can be used to conditionally compile backend-specific code.
55
 *
56
 * Since: 1.10
57
 **/
58

            
59
#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
60

            
61
#include "cairo-xlib-private.h"
62
#include "cairo-xlib-surface-private.h"
63

            
64
#include "cairo-compositor-private.h"
65
#include "cairo-clip-private.h"
66
#include "cairo-damage-private.h"
67
#include "cairo-default-context-private.h"
68
#include "cairo-error-private.h"
69
#include "cairo-image-surface-private.h"
70
#include "cairo-list-inline.h"
71
#include "cairo-pattern-private.h"
72
#include "cairo-pixman-private.h"
73
#include "cairo-region-private.h"
74
#include "cairo-scaled-font-private.h"
75
#include "cairo-surface-snapshot-private.h"
76
#include "cairo-surface-subsurface-private.h"
77

            
78
#include <X11/Xutil.h> /* for XDestroyImage */
79

            
80
#include <X11/extensions/XShm.h>
81
#include <sys/ipc.h>
82
#include <sys/shm.h>
83

            
84
#define DEBUG 0
85

            
86
#if DEBUG
87
#define UNSUPPORTED(reason) \
88
    fprintf (stderr, \
89
	     "cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \
90
	     __FUNCTION__, __LINE__, reason), \
91
    CAIRO_INT_STATUS_UNSUPPORTED
92
#else
93
#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
94
#endif
95

            
96
#if DEBUG
97
#include <X11/Xlibint.h>
98
static void CAIRO_PRINTF_FORMAT (2, 3)
99
_x_bread_crumb (Display *dpy,
100
		const char *fmt,
101
		...)
102
{
103
    xReq *req;
104
    char buf[2048];
105
    unsigned int len, len_dwords;
106
    va_list ap;
107

            
108
    va_start (ap, fmt);
109
    len = vsnprintf (buf, sizeof (buf), fmt, ap);
110
    va_end (ap);
111

            
112
    buf[len++] = '\0';
113
    while (len & 3)
114
	buf[len++] = '\0';
115

            
116
    LockDisplay (dpy);
117
    GetEmptyReq (NoOperation, req);
118

            
119
    len_dwords = len >> 2;
120
    SetReqLen (req, len_dwords, len_dwords);
121
    Data (dpy, buf, len);
122

            
123
    UnlockDisplay (dpy);
124
    SyncHandle ();
125
}
126
#define X_DEBUG(x) _x_bread_crumb x
127
#else
128
#define X_DEBUG(x)
129
#endif
130

            
131
/**
132
 * SECTION:cairo-xlib
133
 * @Title: XLib Surfaces
134
 * @Short_Description: X Window System rendering using XLib
135
 * @See_Also: #cairo_surface_t
136
 *
137
 * The XLib surface is used to render cairo graphics to X Window System
138
 * windows and pixmaps using the XLib library.
139
 *
140
 * Note that the XLib surface automatically takes advantage of X render extension
141
 * if it is available.
142
 **/
143

            
144
/**
145
 * CAIRO_HAS_XLIB_SURFACE:
146
 *
147
 * Defined if the Xlib surface backend is available.
148
 * This macro can be used to conditionally compile backend-specific code.
149
 *
150
 * Since: 1.0
151
 **/
152

            
153
/**
154
 * SECTION:cairo-xlib-xrender
155
 * @Title: XLib-XRender Backend
156
 * @Short_Description: X Window System rendering using XLib and the X Render extension
157
 * @See_Also: #cairo_surface_t
158
 *
159
 * The XLib surface is used to render cairo graphics to X Window System
160
 * windows and pixmaps using the XLib and Xrender libraries.
161
 *
162
 * Note that the XLib surface automatically takes advantage of X Render extension
163
 * if it is available.
164
 **/
165

            
166
/**
167
 * CAIRO_HAS_XLIB_XRENDER_SURFACE:
168
 *
169
 * Defined if the XLib/XRender surface functions are available.
170
 * This macro can be used to conditionally compile backend-specific code.
171
 *
172
 * Since: 1.6
173
 **/
174

            
175
/* Xlib doesn't define a typedef, so define one ourselves */
176
typedef int (*cairo_xlib_error_func_t) (Display     *display,
177
					XErrorEvent *event);
178

            
179
static cairo_surface_t *
180
_cairo_xlib_surface_create_internal (cairo_xlib_screen_t	*screen,
181
				     Drawable		        drawable,
182
				     Visual		       *visual,
183
				     XRenderPictFormat	       *xrender_format,
184
				     int			width,
185
				     int			height,
186
				     int			depth);
187

            
188
static cairo_bool_t
189
_cairo_surface_is_xlib (cairo_surface_t *surface);
190

            
191
/*
192
 * Instead of taking two round trips for each blending request,
193
 * assume that if a particular drawable fails GetImage that it will
194
 * fail for a "while"; use temporary pixmaps to avoid the errors
195
 */
196

            
197
#define CAIRO_ASSUME_PIXMAP	20
198

            
199
static Visual *
200
4
_visual_for_xrender_format(Screen *screen,
201
			   XRenderPictFormat *xrender_format)
202
{
203
    int d, v;
204

            
205
    /* XXX Consider searching through the list of known cairo_visual_t for
206
     * the reverse mapping.
207
     */
208

            
209
24
    for (d = 0; d < screen->ndepths; d++) {
210
24
	Depth *d_info = &screen->depths[d];
211

            
212
24
	if (d_info->depth != xrender_format->depth)
213
20
	    continue;
214

            
215
4
	for (v = 0; v < d_info->nvisuals; v++) {
216
4
	    Visual *visual = &d_info->visuals[v];
217

            
218
4
	    switch (visual->class) {
219
4
	    case TrueColor:
220
4
		if (xrender_format->type != PictTypeDirect)
221
		    continue;
222
4
		break;
223

            
224
	    case DirectColor:
225
		/* Prefer TrueColor to DirectColor.
226
		 * (XRenderFindVisualFormat considers both TrueColor and DirectColor
227
		 * Visuals to match the same PictFormat.)
228
		 */
229
		continue;
230

            
231
	    case StaticGray:
232
	    case GrayScale:
233
	    case StaticColor:
234
	    case PseudoColor:
235
		if (xrender_format->type != PictTypeIndexed)
236
		    continue;
237
		break;
238
	    }
239

            
240
4
	    if (xrender_format ==
241
4
		XRenderFindVisualFormat (DisplayOfScreen(screen), visual))
242
4
		return visual;
243
	}
244
    }
245

            
246
    return NULL;
247
}
248

            
249
static cairo_content_t
250
10
_xrender_format_to_content (XRenderPictFormat *xrender_format)
251
{
252
    cairo_content_t content;
253

            
254
    /* This only happens when using a non-Render server. Let's punt
255
     * and say there's no alpha here. */
256
10
    if (xrender_format == NULL)
257
	return CAIRO_CONTENT_COLOR;
258

            
259
10
    content = 0;
260
10
    if (xrender_format->direct.alphaMask)
261
10
	    content |= CAIRO_CONTENT_ALPHA;
262
10
    if (xrender_format->direct.redMask |
263
10
	xrender_format->direct.greenMask |
264
10
	xrender_format->direct.blueMask)
265
10
	    content |= CAIRO_CONTENT_COLOR;
266

            
267
10
    return content;
268
}
269

            
270
static cairo_surface_t *
271
3
_cairo_xlib_surface_create_similar (void	       *abstract_src,
272
				    cairo_content_t	content,
273
				    int			width,
274
				    int			height)
275
{
276
3
    cairo_xlib_surface_t *src = abstract_src;
277
    XRenderPictFormat *xrender_format;
278
    cairo_xlib_surface_t *surface;
279
    cairo_xlib_display_t *display;
280
    Pixmap pix;
281

            
282
3
    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
283
	return NULL;
284

            
285
3
    if (width == 0 || height == 0)
286
	return NULL;
287

            
288
3
    if (_cairo_xlib_display_acquire (src->base.device, &display))
289
        return NULL;
290

            
291
    /* If we never found an XRenderFormat or if it isn't compatible
292
     * with the content being requested, then we fallback to just
293
     * constructing a cairo_format_t instead, (which will fairly
294
     * arbitrarily pick a visual/depth for the similar surface.
295
     */
296
3
    xrender_format = NULL;
297
6
    if (src->xrender_format &&
298
3
	_xrender_format_to_content (src->xrender_format) == content)
299
    {
300
3
	xrender_format = src->xrender_format;
301
    }
302
3
    if (xrender_format == NULL) {
303
	xrender_format =
304
	    _cairo_xlib_display_get_xrender_format (display,
305
						    _cairo_format_from_content (content));
306
    }
307
3
    if (xrender_format) {
308
	Visual *visual;
309

            
310
	/* We've got a compatible XRenderFormat now, which means the
311
	 * similar surface will match the existing surface as closely in
312
	 * visual/depth etc. as possible. */
313
3
	pix = XCreatePixmap (display->display, src->drawable,
314
3
			     width, height, xrender_format->depth);
315

            
316
3
	if (xrender_format == src->xrender_format)
317
3
	    visual = src->visual;
318
	else
319
	    visual = _visual_for_xrender_format(src->screen->screen,
320
					        xrender_format);
321

            
322
	surface = (cairo_xlib_surface_t *)
323
3
		  _cairo_xlib_surface_create_internal (src->screen, pix, visual,
324
						       xrender_format,
325
						       width, height,
326
						       xrender_format->depth);
327
    }
328
    else
329
    {
330
	Screen *screen = src->screen->screen;
331
	int depth;
332

            
333
	/* No compatible XRenderFormat, see if we can make an ordinary pixmap,
334
	 * so that we can still accelerate blits with XCopyArea(). */
335
	if (content != CAIRO_CONTENT_COLOR) {
336
            cairo_device_release (&display->base);
337
	    return NULL;
338
        }
339

            
340
	depth = DefaultDepthOfScreen (screen);
341

            
342
	pix = XCreatePixmap (display->display, RootWindowOfScreen (screen),
343
			     width <= 0 ? 1 : width, height <= 0 ? 1 : height,
344
			     depth);
345

            
346
	surface = (cairo_xlib_surface_t *)
347
		  _cairo_xlib_surface_create_internal (src->screen, pix,
348
						       DefaultVisualOfScreen (screen),
349
						       NULL,
350
						       width, height, depth);
351
    }
352

            
353
3
    if (likely (surface->base.status == CAIRO_STATUS_SUCCESS))
354
3
	surface->owns_pixmap = TRUE;
355
    else
356
	XFreePixmap (display->display, pix);
357

            
358
3
    cairo_device_release (&display->base);
359

            
360
3
    return &surface->base;
361
}
362

            
363
static void
364
7
_cairo_xlib_surface_discard_shm (cairo_xlib_surface_t *surface)
365
{
366
7
    if (surface->shm == NULL)
367
4
	return;
368

            
369
    /* Force the flush for an external surface */
370
3
    if (!surface->owns_pixmap)
371
	cairo_surface_flush (surface->shm);
372

            
373
3
    cairo_surface_finish (surface->shm);
374
3
    cairo_surface_destroy (surface->shm);
375
3
    surface->shm = NULL;
376

            
377
3
    _cairo_damage_destroy (surface->base.damage);
378
3
    surface->base.damage = NULL;
379

            
380
3
    surface->fallback = 0;
381
}
382

            
383
static cairo_status_t
384
7
_cairo_xlib_surface_finish (void *abstract_surface)
385
{
386
7
    cairo_xlib_surface_t *surface = abstract_surface;
387
    cairo_status_t        status;
388
    cairo_xlib_display_t *display;
389

            
390
7
    cairo_list_del (&surface->link);
391

            
392
7
    status = _cairo_xlib_display_acquire (surface->base.device, &display);
393
7
    if (unlikely (status))
394
        return status;
395

            
396
    X_DEBUG ((display->display, "finish (drawable=%x)", (unsigned int) surface->drawable));
397

            
398
7
    if (surface->embedded_source.picture)
399
	XRenderFreePicture (display->display, surface->embedded_source.picture);
400
7
    if (surface->picture)
401
6
	XRenderFreePicture (display->display, surface->picture);
402

            
403
7
    _cairo_xlib_surface_discard_shm (surface);
404

            
405
7
    if (surface->owns_pixmap)
406
3
	XFreePixmap (display->display, surface->drawable);
407

            
408
7
    cairo_device_release (&display->base);
409

            
410
7
    return status;
411
}
412

            
413
cairo_status_t
414
6
_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
415
                            cairo_xlib_surface_t *surface,
416
                            GC                   *gc)
417
{
418
6
    *gc = _cairo_xlib_screen_get_gc (display,
419
                                     surface->screen,
420
				     surface->depth,
421
				     surface->drawable);
422
6
    if (unlikely (*gc == NULL))
423
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
424

            
425
6
    return CAIRO_STATUS_SUCCESS;
426
}
427

            
428
static int
429
_noop_error_handler (Display     *display,
430
		     XErrorEvent *event)
431
{
432
    return False;		/* return value is ignored */
433
}
434

            
435
static void
436
_swap_ximage_2bytes (XImage *ximage)
437
{
438
    int i, j;
439
    char *line = ximage->data;
440

            
441
    for (j = ximage->height; j; j--) {
442
	uint16_t *p = (uint16_t *) line;
443
	for (i = ximage->width; i; i--) {
444
	    *p = bswap_16 (*p);
445
	    p++;
446
	}
447

            
448
	line += ximage->bytes_per_line;
449
    }
450
}
451

            
452
static void
453
_swap_ximage_3bytes (XImage *ximage)
454
{
455
    int i, j;
456
    char *line = ximage->data;
457

            
458
    for (j = ximage->height; j; j--) {
459
	uint8_t *p = (uint8_t *) line;
460
	for (i = ximage->width; i; i--) {
461
	    uint8_t tmp;
462
	    tmp = p[2];
463
	    p[2] = p[0];
464
	    p[0] = tmp;
465
	    p += 3;
466
	}
467

            
468
	line += ximage->bytes_per_line;
469
    }
470
}
471

            
472
static void
473
_swap_ximage_4bytes (XImage *ximage)
474
{
475
    int i, j;
476
    char *line = ximage->data;
477

            
478
    for (j = ximage->height; j; j--) {
479
	uint32_t *p = (uint32_t *) line;
480
	for (i = ximage->width; i; i--) {
481
	    *p = bswap_32 (*p);
482
	    p++;
483
	}
484

            
485
	line += ximage->bytes_per_line;
486
    }
487
}
488

            
489
static void
490
_swap_ximage_nibbles (XImage *ximage)
491
{
492
    int i, j;
493
    char *line = ximage->data;
494

            
495
    for (j = ximage->height; j; j--) {
496
	uint8_t *p = (uint8_t *) line;
497
	for (i = (ximage->width + 1) / 2; i; i--) {
498
	    *p = ((*p >> 4) & 0xf) | ((*p << 4) & ~0xf);
499
	    p++;
500
	}
501

            
502
	line += ximage->bytes_per_line;
503
    }
504
}
505

            
506
static void
507
_swap_ximage_bits (XImage *ximage)
508
{
509
    int i, j;
510
    char *line = ximage->data;
511
    int unit = ximage->bitmap_unit;
512
    int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8;
513

            
514
    for (j = ximage->height; j; j--) {
515
	char *p = line;
516

            
517
	for (i = line_bytes; i; i--) {
518
	    char b = *p;
519
	    b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
520
	    b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
521
	    b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
522
	    *p = b;
523

            
524
	    p++;
525
	}
526

            
527
	line += ximage->bytes_per_line;
528
    }
529
}
530

            
531
static void
532
_swap_ximage_to_native (XImage *ximage)
533
{
534
    int unit_bytes = 0;
535
    int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
536

            
537
    if (ximage->bits_per_pixel == 1 &&
538
	ximage->bitmap_bit_order != native_byte_order)
539
    {
540
	_swap_ximage_bits (ximage);
541
	if (ximage->bitmap_bit_order == ximage->byte_order)
542
	    return;
543
    }
544

            
545
    if (ximage->byte_order == native_byte_order)
546
	return;
547

            
548
    switch (ximage->bits_per_pixel) {
549
    case 1:
550
	unit_bytes = ximage->bitmap_unit / 8;
551
	break;
552
    case 4:
553
	_swap_ximage_nibbles (ximage);
554
	/* fall-through */
555
    case 8:
556
    case 16:
557
    case 20:
558
    case 24:
559
    case 28:
560
    case 30:
561
    case 32:
562
	unit_bytes = (ximage->bits_per_pixel + 7) / 8;
563
	break;
564
    default:
565
        /* This could be hit on some rare but possible cases. */
566
	ASSERT_NOT_REACHED;
567
    }
568

            
569
    switch (unit_bytes) {
570
    case 1:
571
	break;
572
    case 2:
573
	_swap_ximage_2bytes (ximage);
574
	break;
575
    case 3:
576
	_swap_ximage_3bytes (ximage);
577
	break;
578
    case 4:
579
	_swap_ximage_4bytes (ximage);
580
	break;
581
    default:
582
	ASSERT_NOT_REACHED;
583
    }
584
}
585

            
586

            
587
/* Given a mask, (with a single sequence of contiguous 1 bits), return
588
 * the number of 1 bits in 'width' and the number of 0 bits to its
589
 * right in 'shift'. */
590
static void
591
_characterize_field (uint32_t mask, int *width, int *shift)
592
{
593
    *width = _cairo_popcount (mask);
594
    /* The final '& 31' is to force a 0 mask to result in 0 shift. */
595
    *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
596
}
597

            
598
/* Convert a field of 'width' bits to 'new_width' bits with correct
599
 * rounding. */
600
static inline uint32_t
601
_resize_field (uint32_t field, int width, int new_width)
602
{
603
    if (width == 0)
604
	return 0;
605

            
606
    if (width >= new_width) {
607
	return field >> (width - new_width);
608
    } else {
609
	uint32_t result = field << (new_width - width);
610

            
611
	while (width < new_width) {
612
	    result |= result >> width;
613
	    width <<= 1;
614
	}
615
	return result;
616
    }
617
}
618

            
619
static inline uint32_t
620
_adjust_field (uint32_t field, int adjustment)
621
{
622
    return MIN (255, MAX(0, (int)field + adjustment));
623
}
624

            
625
/* Given a shifted field value, (described by 'width' and 'shift),
626
 * resize it 8-bits and return that value.
627
 *
628
 * Note that the original field value must not have any non-field bits
629
 * set.
630
 */
631
static inline uint32_t
632
_field_to_8 (uint32_t field, int width, int shift)
633
{
634
    return _resize_field (field >> shift, width, 8);
635
}
636

            
637
static inline uint32_t
638
_field_to_8_undither (uint32_t field, int width, int shift,
639
		      int dither_adjustment)
640
{
641
    return _adjust_field (_field_to_8 (field, width, shift), - dither_adjustment>>width);
642
}
643

            
644
/* Given an 8-bit value, convert it to a field of 'width', shift it up
645
 *  to 'shift, and return it. */
646
static inline uint32_t
647
_field_from_8 (uint32_t field, int width, int shift)
648
{
649
    return _resize_field (field, 8, width) << shift;
650
}
651

            
652
static inline uint32_t
653
_field_from_8_dither (uint32_t field, int width, int shift,
654
		      int8_t dither_adjustment)
655
{
656
    return _field_from_8 (_adjust_field (field, dither_adjustment>>width), width, shift);
657
}
658

            
659
static inline uint32_t
660
_pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info,
661
				 uint32_t r, uint32_t g, uint32_t b,
662
				 int8_t dither_adjustment)
663
{
664
    if (r == g && g == b) {
665
	dither_adjustment /= RAMP_SIZE;
666
	return visual_info->gray8_to_pseudocolor[_adjust_field (r, dither_adjustment)];
667
    } else {
668
	dither_adjustment = visual_info->dither8_to_cube[dither_adjustment+128];
669
	return visual_info->cube_to_pseudocolor[visual_info->field8_to_cube[_adjust_field (r, dither_adjustment)]]
670
					       [visual_info->field8_to_cube[_adjust_field (g, dither_adjustment)]]
671
					       [visual_info->field8_to_cube[_adjust_field (b, dither_adjustment)]];
672
    }
673
}
674

            
675
static inline uint32_t
676
_pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info,
677
			uint32_t pixel)
678
{
679
    uint32_t r, g, b;
680
    pixel &= 0xff;
681
    r = visual_info->colors[pixel].r;
682
    g = visual_info->colors[pixel].g;
683
    b = visual_info->colors[pixel].b;
684
    return (r << 16) |
685
	   (g <<  8) |
686
	   (b      );
687
}
688

            
689
/* should range from -128 to 127 */
690
#define X 16
691
static const int8_t dither_pattern[4][4] = {
692
    {-8*X, +0*X, -6*X, +2*X},
693
    {+4*X, -4*X, +6*X, -2*X},
694
    {-5*X, +4*X, -7*X, +1*X},
695
    {+7*X, -1*X, +5*X, -3*X}
696
};
697
#undef X
698

            
699
3
static int bits_per_pixel(cairo_xlib_surface_t *surface)
700
{
701
3
    if (surface->depth > 16)
702
3
	return 32;
703
    else if (surface->depth > 8)
704
	return 16;
705
    else if (surface->depth > 1)
706
	return 8;
707
    else
708
	return 1;
709
}
710

            
711
pixman_format_code_t
712
3
_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface)
713
{
714
    cairo_format_masks_t masks;
715
    pixman_format_code_t format;
716

            
717
3
    masks.bpp = bits_per_pixel (surface);
718
3
    masks.alpha_mask = surface->a_mask;
719
3
    masks.red_mask = surface->r_mask;
720
3
    masks.green_mask = surface->g_mask;
721
3
    masks.blue_mask = surface->b_mask;
722
3
    if (! _pixman_format_from_masks (&masks, &format))
723
	return 0;
724

            
725
3
    return format;
726
}
727

            
728
static cairo_surface_t *
729
_get_image_surface (cairo_xlib_surface_t    *surface,
730
		    const cairo_rectangle_int_t *extents,
731
		    int try_shm)
732
{
733
    cairo_int_status_t status;
734
    cairo_image_surface_t *image = NULL;
735
    XImage *ximage;
736
    pixman_format_code_t pixman_format;
737
    cairo_xlib_display_t *display;
738

            
739
    assert (extents->x >= 0);
740
    assert (extents->y >= 0);
741
    assert (extents->x + extents->width <= surface->width);
742
    assert (extents->y + extents->height <= surface->height);
743

            
744
    if (surface->base.is_clear ||
745
	(surface->base.serial == 0 && surface->owns_pixmap))
746
    {
747
	pixman_format = _pixman_format_for_xlib_surface (surface);
748
	if (pixman_format)
749
	{
750
	    return _cairo_image_surface_create_with_pixman_format (NULL,
751
								   pixman_format,
752
								   extents->width,
753
								   extents->height,
754
								   0);
755
	}
756
    }
757

            
758
    if (surface->shm) {
759
	cairo_image_surface_t *src = (cairo_image_surface_t *) surface->shm;
760
	cairo_surface_t *dst;
761
	cairo_surface_pattern_t pattern;
762

            
763
	dst = cairo_image_surface_create (src->format,
764
					  extents->width, extents->height);
765
	if (unlikely (dst->status))
766
	    return dst;
767

            
768
	_cairo_pattern_init_for_surface (&pattern, &src->base);
769
	cairo_matrix_init_translate (&pattern.base.matrix,
770
				     extents->x, extents->y);
771
	status = _cairo_surface_paint (dst, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
772
	_cairo_pattern_fini (&pattern.base);
773
	if (unlikely (status)) {
774
	    cairo_surface_destroy (dst);
775
	    dst = _cairo_surface_create_in_error (status);
776
	}
777

            
778
	return dst;
779
    }
780

            
781
    status = _cairo_xlib_display_acquire (surface->base.device, &display);
782
    if (status)
783
        return _cairo_surface_create_in_error (status);
784

            
785
    pixman_format = _pixman_format_for_xlib_surface (surface);
786
    if (try_shm && pixman_format) {
787
	image = (cairo_image_surface_t *)
788
	    _cairo_xlib_surface_create_shm__image (surface, pixman_format,
789
						   extents->width, extents->height);
790
	if (image && image->base.status == CAIRO_STATUS_SUCCESS) {
791
	    cairo_xlib_error_func_t old_handler;
792
	    XImage shm_image;
793
	    Bool success;
794

            
795
	    _cairo_xlib_shm_surface_get_ximage (&image->base, &shm_image);
796

            
797
	    XSync (display->display, False);
798
	    old_handler = XSetErrorHandler (_noop_error_handler);
799
	    success = XShmGetImage (display->display,
800
				    surface->drawable,
801
				    &shm_image,
802
				    extents->x, extents->y,
803
				    AllPlanes);
804
	    XSetErrorHandler (old_handler);
805

            
806
	    if (success) {
807
		cairo_device_release (&display->base);
808
		return &image->base;
809
	    }
810

            
811
	    cairo_surface_destroy (&image->base);
812
	    image = NULL;
813
	}
814
    }
815

            
816
    if (surface->use_pixmap == 0) {
817
	cairo_xlib_error_func_t old_handler;
818

            
819
	XSync (display->display, False);
820
	old_handler = XSetErrorHandler (_noop_error_handler);
821

            
822
	ximage = XGetImage (display->display,
823
			    surface->drawable,
824
			    extents->x, extents->y,
825
			    extents->width, extents->height,
826
			    AllPlanes, ZPixmap);
827

            
828
	XSetErrorHandler (old_handler);
829

            
830
	/* If we get an error, the surface must have been a window,
831
	 * so retry with the safe code path.
832
	 */
833
	if (!ximage)
834
	    surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
835
    } else {
836
	surface->use_pixmap--;
837
	ximage = NULL;
838
    }
839

            
840
    if (ximage == NULL) {
841
	/* XGetImage from a window is dangerous because it can
842
	 * produce errors if the window is unmapped or partially
843
	 * outside the screen. We could check for errors and
844
	 * retry, but to keep things simple, we just create a
845
	 * temporary pixmap
846
	 */
847
	Pixmap pixmap;
848
	GC gc;
849

            
850
	status = _cairo_xlib_surface_get_gc (display, surface, &gc);
851
	if (unlikely (status))
852
            goto BAIL;
853

            
854
	pixmap = XCreatePixmap (display->display,
855
				surface->drawable,
856
				extents->width, extents->height,
857
				surface->depth);
858
	if (pixmap) {
859
	    XGCValues gcv;
860

            
861
	    gcv.subwindow_mode = IncludeInferiors;
862
	    XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
863

            
864
	    XCopyArea (display->display, surface->drawable, pixmap, gc,
865
		       extents->x, extents->y,
866
		       extents->width, extents->height,
867
		       0, 0);
868

            
869
	    gcv.subwindow_mode = ClipByChildren;
870
	    XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
871

            
872
	    ximage = XGetImage (display->display,
873
				pixmap,
874
				0, 0,
875
				extents->width, extents->height,
876
				AllPlanes, ZPixmap);
877

            
878
	    XFreePixmap (display->display, pixmap);
879
	}
880

            
881
	_cairo_xlib_surface_put_gc (display, surface, gc);
882

            
883
	if (ximage == NULL) {
884
	    status =  _cairo_error (CAIRO_STATUS_NO_MEMORY);
885
            goto BAIL;
886
        }
887
    }
888

            
889
    _swap_ximage_to_native (ximage);
890

            
891
    /* We can't use pixman to simply write to image if:
892
     *   (a) the pixels are not appropriately aligned,
893
     *   (b) pixman does not the pixel format, or
894
     *   (c) if the image is palettized and we need to convert.
895
     */
896
    if (pixman_format &&
897
	ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
898
	(surface->visual == NULL || surface->visual->class == TrueColor))
899
    {
900
	image = (cairo_image_surface_t*)
901
	    _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
902
							    pixman_format,
903
							    ximage->width,
904
							    ximage->height,
905
							    ximage->bytes_per_line);
906
	status = image->base.status;
907
	if (unlikely (status))
908
	    goto BAIL;
909

            
910
	/* Let the surface take ownership of the data */
911
	_cairo_image_surface_assume_ownership_of_data (image);
912
	ximage->data = NULL;
913
    } else {
914
	/* The visual we are dealing with is not supported by the
915
	 * standard pixman formats. So we must first convert the data
916
	 * to a supported format. */
917

            
918
	cairo_format_t format;
919
	unsigned char *data;
920
	uint32_t *row;
921
	uint32_t in_pixel, out_pixel;
922
	unsigned int rowstride;
923
	uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0;
924
	int a_width=0, r_width=0, g_width=0, b_width=0;
925
	int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
926
	int x, y, x0, y0, x_off, y_off;
927
	cairo_xlib_visual_info_t *visual_info = NULL;
928

            
929
	if (surface->visual == NULL || surface->visual->class == TrueColor) {
930
	    cairo_bool_t has_alpha;
931
	    cairo_bool_t has_color;
932

            
933
	    has_alpha =  surface->a_mask;
934
	    has_color = (surface->r_mask ||
935
			 surface->g_mask ||
936
			 surface->b_mask);
937

            
938
	    if (has_color) {
939
		if (has_alpha) {
940
		    format = CAIRO_FORMAT_ARGB32;
941
		} else {
942
		    format = CAIRO_FORMAT_RGB24;
943
		}
944
	    } else {
945
		/* XXX: Using CAIRO_FORMAT_A8 here would be more
946
		 * efficient, but would require slightly different code in
947
		 * the image conversion to put the alpha channel values
948
		 * into the right place. */
949
		format = CAIRO_FORMAT_ARGB32;
950
	    }
951

            
952
	    a_mask = surface->a_mask;
953
	    r_mask = surface->r_mask;
954
	    g_mask = surface->g_mask;
955
	    b_mask = surface->b_mask;
956

            
957
	    _characterize_field (a_mask, &a_width, &a_shift);
958
	    _characterize_field (r_mask, &r_width, &r_shift);
959
	    _characterize_field (g_mask, &g_width, &g_shift);
960
	    _characterize_field (b_mask, &b_width, &b_shift);
961

            
962
	} else {
963
	    format = CAIRO_FORMAT_RGB24;
964

            
965
	    status = _cairo_xlib_screen_get_visual_info (display,
966
                                                         surface->screen,
967
							 surface->visual,
968
							 &visual_info);
969
	    if (unlikely (status))
970
		goto BAIL;
971
	}
972

            
973
	image = (cairo_image_surface_t *) cairo_image_surface_create
974
	    (format, ximage->width, ximage->height);
975
	status = image->base.status;
976
	if (unlikely (status))
977
	    goto BAIL;
978

            
979
	data = cairo_image_surface_get_data (&image->base);
980
	rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
981
	row = (uint32_t *) data;
982
	x0 = extents->x + surface->base.device_transform.x0;
983
	y0 = extents->y + surface->base.device_transform.y0;
984
	for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
985
	     y < ximage->height;
986
	     y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
987
	    const int8_t *dither_row = dither_pattern[y_off];
988
	    for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
989
		 x < ximage->width;
990
		 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) {
991
		int dither_adjustment = dither_row[x_off];
992

            
993
		in_pixel = XGetPixel (ximage, x, y);
994
		if (visual_info == NULL) {
995
		    out_pixel = (
996
			(uint32_t)_field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
997
			_field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
998
			_field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 |
999
			_field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment));
		} else {
		    /* Undithering pseudocolor does not look better */
		    out_pixel = _pseudocolor_to_rgb888 (visual_info, in_pixel);
		}
		row[x] = out_pixel;
	    }
	    row += rowstride;
	}
	cairo_surface_mark_dirty (&image->base);
    }
 BAIL:
    if (ximage)
        XDestroyImage (ximage);
    cairo_device_release (&display->base);
    if (unlikely (status)) {
	if (image)
	    cairo_surface_destroy (&image->base);
	return _cairo_surface_create_in_error (status);
    }
    return &image->base;
}
void
_cairo_xlib_surface_set_precision (cairo_xlib_surface_t	*surface,
				   cairo_antialias_t	 antialias)
{
    cairo_xlib_display_t	*display = surface->display;
    int precision;
    if (display->force_precision != -1)
	    precision = display->force_precision;
    else switch (antialias) {
    default:
    case CAIRO_ANTIALIAS_DEFAULT:
    case CAIRO_ANTIALIAS_GRAY:
    case CAIRO_ANTIALIAS_NONE:
    case CAIRO_ANTIALIAS_FAST:
    case CAIRO_ANTIALIAS_GOOD:
	precision = PolyModeImprecise;
	break;
    case CAIRO_ANTIALIAS_BEST:
    case CAIRO_ANTIALIAS_SUBPIXEL:
	precision = PolyModePrecise;
	break;
    }
    if (surface->precision != precision) {
	XRenderPictureAttributes pa;
	pa.poly_mode = precision;
	XRenderChangePicture (display->display, surface->picture,
			      CPPolyMode, &pa);
	surface->precision = precision;
    }
}
void
30
_cairo_xlib_surface_ensure_picture (cairo_xlib_surface_t    *surface)
{
30
    cairo_xlib_display_t *display = surface->display;
    XRenderPictureAttributes pa;
30
    int mask = 0;
30
    if (surface->picture)
24
	return;
6
    if (display->force_precision != -1)
	pa.poly_mode = display->force_precision;
    else
6
	pa.poly_mode = PolyModeImprecise;
6
    if (pa.poly_mode)
6
	    mask |= CPPolyMode;
6
    surface->precision = pa.poly_mode;
6
    surface->picture = XRenderCreatePicture (display->display,
					     surface->drawable,
6
					     surface->xrender_format,
					     mask, &pa);
}
cairo_status_t
_cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
				cairo_image_surface_t  *image,
				int                    src_x,
				int                    src_y,
				int                    width,
				int                    height,
				int                    dst_x,
				int                    dst_y)
{
    cairo_xlib_display_t *display;
    XImage ximage;
    cairo_format_masks_t image_masks;
    int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
    cairo_surface_t *shm_image = NULL;
    pixman_image_t *pixman_image = NULL;
    cairo_status_t status;
    cairo_bool_t own_data = FALSE;
    cairo_bool_t is_rgb_image;
    GC gc;
    ximage.width = image->width;
    ximage.height = image->height;
    ximage.format = ZPixmap;
    ximage.byte_order = native_byte_order;
    ximage.bitmap_unit = 32;	/* always for libpixman */
    ximage.bitmap_bit_order = native_byte_order;
    ximage.bitmap_pad = 32;	/* always for libpixman */
    ximage.depth = surface->depth;
    ximage.red_mask = surface->r_mask;
    ximage.green_mask = surface->g_mask;
    ximage.blue_mask = surface->b_mask;
    ximage.xoffset = 0;
    ximage.obdata = NULL;
    status = _cairo_xlib_display_acquire (surface->base.device, &display);
    if (unlikely (status))
        return status;
    is_rgb_image = _pixman_format_to_masks (image->pixman_format, &image_masks);
    if (is_rgb_image &&
	(image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
	(image_masks.red_mask   == surface->r_mask || surface->r_mask == 0) &&
	(image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
	(image_masks.blue_mask  == surface->b_mask || surface->b_mask == 0))
    {
	int ret;
	ximage.bits_per_pixel = image_masks.bpp;
	ximage.bytes_per_line = image->stride;
	ximage.data = (char *)image->data;
	if (image->base.device != surface->base.device) {
	    /* If PutImage will break the image up into chunks, prefer to
	     * send it all in one pass with ShmPutImage.  For larger images,
	     * it is further advantageous to reduce the number of copies,
	     * albeit at the expense of more SHM bookkeeping.
	     */
	    int max_request_size = XExtendedMaxRequestSize (display->display);
	    if (max_request_size == 0)
		max_request_size = XMaxRequestSize (display->display);
	    if (max_request_size > 8192)
		max_request_size = 8192;
	    if (width * height * 4 > max_request_size) {
		shm_image = _cairo_xlib_surface_create_shm__image (surface,
								   image->pixman_format,
								   width, height);
		if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
		    cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
		    pixman_image_composite32 (PIXMAN_OP_SRC,
					      image->pixman_image, NULL, clone->pixman_image,
					      src_x, src_y,
					      0, 0,
					      0, 0,
					      width, height);
		    ximage.obdata = _cairo_xlib_shm_surface_get_obdata (shm_image);
		    ximage.data = (char *)clone->data;
		    ximage.bytes_per_line = clone->stride;
		    ximage.width = width;
		    ximage.height = height;
		    src_x = src_y = 0;
		}
	    }
	} else
	    ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base);
	ret = XInitImage (&ximage);
	assert (ret != 0);
    }
    else if (surface->visual == NULL || surface->visual->class == TrueColor)
    {
        pixman_format_code_t intermediate_format;
        int ret;
        image_masks.alpha_mask = surface->a_mask;
        image_masks.red_mask   = surface->r_mask;
        image_masks.green_mask = surface->g_mask;
        image_masks.blue_mask  = surface->b_mask;
        image_masks.bpp        = bits_per_pixel (surface);
        ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
        assert (ret);
	shm_image = _cairo_xlib_surface_create_shm__image (surface,
							   intermediate_format,
							   width, height);
	if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
	    cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
	    pixman_image_composite32 (PIXMAN_OP_SRC,
				      image->pixman_image,
				      NULL,
				      clone->pixman_image,
				      src_x, src_y,
				      0, 0,
				      0, 0,
				      width, height);
	    ximage.data = (char *) clone->data;
	    ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&clone->base);
	    ximage.bytes_per_line = clone->stride;
	} else {
	    pixman_image = pixman_image_create_bits (intermediate_format,
						     width, height, NULL, 0);
	    if (pixman_image == NULL) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto BAIL;
	    }
	    pixman_image_composite32 (PIXMAN_OP_SRC,
				      image->pixman_image,
				      NULL,
				      pixman_image,
				      src_x, src_y,
				      0, 0,
				      0, 0,
				      width, height);
	    ximage.data = (char *) pixman_image_get_data (pixman_image);
	    ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
	}
	ximage.width = width;
	ximage.height = height;
	ximage.bits_per_pixel = image_masks.bpp;
	ret = XInitImage (&ximage);
	assert (ret != 0);
	src_x = src_y = 0;
    }
    else
    {
	unsigned int stride, rowstride;
	int x, y, x0, y0, x_off, y_off;
	uint32_t in_pixel, out_pixel, *row;
	int i_a_width=0, i_r_width=0, i_g_width=0, i_b_width=0;
	int i_a_shift=0, i_r_shift=0, i_g_shift=0, i_b_shift=0;
	int o_a_width=0, o_r_width=0, o_g_width=0, o_b_width=0;
	int o_a_shift=0, o_r_shift=0, o_g_shift=0, o_b_shift=0;
	cairo_xlib_visual_info_t *visual_info = NULL;
	cairo_bool_t true_color;
	int ret;
	ximage.bits_per_pixel = bits_per_pixel(surface);
	stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width,
					     ximage.bits_per_pixel);
	ximage.bytes_per_line = stride;
	ximage.data = _cairo_malloc_ab (stride, ximage.height);
	if (unlikely (ximage.data == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
            goto BAIL;
        }
	own_data = TRUE;
	ret = XInitImage (&ximage);
	assert (ret != 0);
	_characterize_field (image_masks.alpha_mask, &i_a_width, &i_a_shift);
	_characterize_field (image_masks.red_mask  , &i_r_width, &i_r_shift);
	_characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift);
	_characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift);
	true_color = surface->visual == NULL ||
	             surface->visual->class == TrueColor;
	if (true_color) {
	    _characterize_field (surface->a_mask, &o_a_width, &o_a_shift);
	    _characterize_field (surface->r_mask, &o_r_width, &o_r_shift);
	    _characterize_field (surface->g_mask, &o_g_width, &o_g_shift);
	    _characterize_field (surface->b_mask, &o_b_width, &o_b_shift);
	} else {
	    status = _cairo_xlib_screen_get_visual_info (display,
                                                         surface->screen,
							 surface->visual,
							 &visual_info);
	    if (unlikely (status))
		goto BAIL;
	}
	rowstride = image->stride >> 2;
	row = (uint32_t *) image->data;
	x0 = dst_x + surface->base.device_transform.x0;
	y0 = dst_y + surface->base.device_transform.y0;
	for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
	     y < ximage.height;
	     y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern))
	{
	    const int8_t *dither_row = dither_pattern[y_off];
	    for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
		 x < ximage.width;
		 x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0]))
	    {
		int dither_adjustment = dither_row[x_off];
		int a, r, g, b;
		if (image_masks.bpp == 1)
		    in_pixel = !! (((uint8_t*)row)[x/8] & (1 << (x & 7)));
		else if (image_masks.bpp <= 8)
		    in_pixel = ((uint8_t*)row)[x];
		else if (image_masks.bpp <= 16)
		    in_pixel = ((uint16_t*)row)[x];
		else if (image_masks.bpp <= 24)
#ifdef WORDS_BIGENDIAN
		    in_pixel = ((uint8_t*)row)[3 * x]     << 16 |
			       ((uint8_t*)row)[3 * x + 1] << 8  |
			       ((uint8_t*)row)[3 * x + 2];
#else
		    in_pixel = ((uint8_t*)row)[3 * x]           |
			       ((uint8_t*)row)[3 * x + 1] << 8  |
			       ((uint8_t*)row)[3 * x + 2] << 16;
#endif
		else
		    in_pixel = row[x];
		/* If the incoming image has no alpha channel, then the input
		 * is opaque and the output should have the maximum alpha value.
		 * For all other channels, their absence implies 0.
		 */
		if (image_masks.alpha_mask == 0x0)
		    a = 0xff;
		else
		    a = _field_to_8 (in_pixel & image_masks.alpha_mask, i_a_width, i_a_shift);
		r = _field_to_8 (in_pixel & image_masks.red_mask  , i_r_width, i_r_shift);
		g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift);
		b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift);
		if (true_color) {
		    out_pixel = _field_from_8        (a, o_a_width, o_a_shift) |
				_field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) |
				_field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) |
				_field_from_8_dither (b, o_b_width, o_b_shift, dither_adjustment);
		} else {
		    out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment);
		}
		XPutPixel (&ximage, x, y, out_pixel);
	    }
	    row += rowstride;
	}
    }
    status = _cairo_xlib_surface_get_gc (display, surface, &gc);
    if (unlikely (status))
	goto BAIL;
    if (ximage.obdata)
	XShmPutImage (display->display, surface->drawable, gc, &ximage,
		      src_x, src_y, dst_x, dst_y, width, height, True);
    else
	XPutImage (display->display, surface->drawable, gc, &ximage,
		   src_x, src_y, dst_x, dst_y, width, height);
    _cairo_xlib_surface_put_gc (display, surface, gc);
  BAIL:
    cairo_device_release (&display->base);
    if (own_data)
	free (ximage.data);
    if (shm_image)
	cairo_surface_destroy (shm_image);
    if (pixman_image)
        pixman_image_unref (pixman_image);
    return CAIRO_STATUS_SUCCESS;
}
static cairo_surface_t *
6
_cairo_xlib_surface_source(void                    *abstract_surface,
			   cairo_rectangle_int_t *extents)
{
6
    cairo_xlib_surface_t *surface = abstract_surface;
6
    if (extents) {
6
	extents->x = extents->y = 0;
6
	extents->width  = surface->width;
6
	extents->height = surface->height;
    }
6
    return &surface->base;
}
static cairo_status_t
3
_cairo_xlib_surface_acquire_source_image (void                    *abstract_surface,
					  cairo_image_surface_t  **image_out,
					  void                   **image_extra)
{
3
    cairo_xlib_surface_t *surface = abstract_surface;
    cairo_rectangle_int_t extents;
3
    *image_extra = NULL;
3
    *image_out = (cairo_image_surface_t *)
3
	_cairo_xlib_surface_get_shm (abstract_surface, FALSE);
3
    if (*image_out) 
3
	    return (*image_out)->base.status;
    extents.x = extents.y = 0;
    extents.width = surface->width;
    extents.height = surface->height;
    *image_out = (cairo_image_surface_t*)
	_get_image_surface (surface, &extents, TRUE);
    return (*image_out)->base.status;
}
static cairo_surface_t *
_cairo_xlib_surface_snapshot (void *abstract_surface)
{
    cairo_xlib_surface_t *surface = abstract_surface;
    cairo_rectangle_int_t extents;
    extents.x = extents.y = 0;
    extents.width = surface->width;
    extents.height = surface->height;
    return _get_image_surface (surface, &extents, FALSE);
}
static void
3
_cairo_xlib_surface_release_source_image (void                   *abstract_surface,
					  cairo_image_surface_t  *image,
					  void                   *image_extra)
{
3
    cairo_xlib_surface_t *surface = abstract_surface;
3
    if (&image->base == surface->shm)
3
	return;
    cairo_surface_destroy (&image->base);
}
static cairo_image_surface_t *
_cairo_xlib_surface_map_to_image (void                    *abstract_surface,
				  const cairo_rectangle_int_t   *extents)
{
    cairo_xlib_surface_t *surface = abstract_surface;
    cairo_surface_t *image;
    image = _cairo_xlib_surface_get_shm (abstract_surface, FALSE);
    if (image) {
	assert (surface->base.damage);
	surface->fallback++;
	return _cairo_image_surface_map_to_image (image, extents);
    }
    image = _get_image_surface (abstract_surface, extents, TRUE);
    cairo_surface_set_device_offset (image, -extents->x, -extents->y);
    return (cairo_image_surface_t *) image;
}
static cairo_int_status_t
_cairo_xlib_surface_unmap_image (void *abstract_surface,
				 cairo_image_surface_t *image)
{
    cairo_xlib_surface_t *surface = abstract_surface;
    cairo_int_status_t status;
    if (surface->shm) {
	cairo_rectangle_int_t r;
	assert (surface->fallback);
	assert (surface->base.damage);
	r.x = image->base.device_transform_inverse.x0;
	r.y = image->base.device_transform_inverse.y0;
	r.width  = image->width;
	r.height = image->height;
	TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n",
		__FUNCTION__, r.x, r.y, r.width, r.height));
	surface->shm->damage =
	    _cairo_damage_add_rectangle (surface->shm->damage, &r);
	return _cairo_image_surface_unmap_image (surface->shm, image);
    }
    status = _cairo_xlib_surface_draw_image (abstract_surface, image,
					     0, 0,
					     image->width, image->height,
					     image->base.device_transform_inverse.x0,
					     image->base.device_transform_inverse.y0);
    cairo_surface_finish (&image->base);
    cairo_surface_destroy (&image->base);
    return status;
}
static cairo_status_t
46
_cairo_xlib_surface_flush (void *abstract_surface,
			   unsigned flags)
{
46
    cairo_xlib_surface_t *surface = abstract_surface;
    cairo_int_status_t status;
46
    if (flags)
39
	return CAIRO_STATUS_SUCCESS;
7
    status = _cairo_xlib_surface_put_shm (surface);
7
    if (unlikely (status))
	return status;
7
    surface->fallback >>= 1;
7
    if (surface->shm && _cairo_xlib_shm_surface_is_idle (surface->shm))
	_cairo_xlib_surface_discard_shm (surface);
7
    return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
75
_cairo_xlib_surface_get_extents (void		         *abstract_surface,
				 cairo_rectangle_int_t   *rectangle)
{
75
    cairo_xlib_surface_t *surface = abstract_surface;
75
    rectangle->x = 0;
75
    rectangle->y = 0;
75
    rectangle->width  = surface->width;
75
    rectangle->height = surface->height;
75
    return TRUE;
}
static void
_cairo_xlib_surface_get_font_options (void                  *abstract_surface,
				      cairo_font_options_t  *options)
{
    cairo_xlib_surface_t *surface = abstract_surface;
    *options = *_cairo_xlib_screen_get_font_options (surface->screen);
}
static inline cairo_int_status_t
33
get_compositor (cairo_xlib_surface_t **surface,
		const cairo_compositor_t **compositor)
{
33
    cairo_xlib_surface_t *s = *surface;
33
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;;
33
    if (s->fallback) {
	assert (s->base.damage != NULL);
	assert (s->shm != NULL);
	assert (s->shm->damage != NULL);
	if (! _cairo_xlib_shm_surface_is_active (s->shm)) {
	    *surface = (cairo_xlib_surface_t *) s->shm;
	    *compositor = ((cairo_image_surface_t *) s->shm)->compositor;
	    s->fallback++;
	} else {
	    status = _cairo_xlib_surface_put_shm (s);
	    s->fallback = 0;
	    *compositor = s->compositor;
	}
    } else
33
	*compositor = s->compositor;
33
    return status;
}
static cairo_int_status_t
9
_cairo_xlib_surface_paint (void				*_surface,
			   cairo_operator_t		 op,
			   const cairo_pattern_t	*source,
			   const cairo_clip_t		*clip)
{
9
    cairo_xlib_surface_t *surface = _surface;
    const cairo_compositor_t *compositor;
    cairo_int_status_t status;
9
    status = get_compositor (&surface, &compositor);
9
    if (unlikely (status))
	return status;
9
    return _cairo_compositor_paint (compositor, &surface->base,
				    op, source,
				    clip);
}
static cairo_int_status_t
_cairo_xlib_surface_mask (void			*_surface,
			  cairo_operator_t	 op,
			  const cairo_pattern_t	*source,
			  const cairo_pattern_t	*mask,
			  const cairo_clip_t	*clip)
{
    cairo_xlib_surface_t *surface = _surface;
    const cairo_compositor_t *compositor;
    cairo_int_status_t status;
    status = get_compositor (&surface, &compositor);
    if (unlikely (status))
	return status;
    return _cairo_compositor_mask (compositor, &surface->base,
				   op, source, mask,
				   clip);
}
static cairo_int_status_t
_cairo_xlib_surface_stroke (void			*_surface,
			    cairo_operator_t		 op,
			    const cairo_pattern_t	*source,
			    const cairo_path_fixed_t	*path,
			    const cairo_stroke_style_t	*style,
			    const cairo_matrix_t	*ctm,
			    const cairo_matrix_t	*ctm_inverse,
			    double			 tolerance,
			    cairo_antialias_t		 antialias,
			    const cairo_clip_t		*clip)
{
    cairo_xlib_surface_t *surface = _surface;
    const cairo_compositor_t *compositor;
    cairo_int_status_t status;
    status = get_compositor (&surface, &compositor);
    if (unlikely (status))
	return status;
    return _cairo_compositor_stroke (compositor, &surface->base,
				     op, source,
				     path, style, ctm, ctm_inverse,
				     tolerance, antialias,
				     clip);
}
static cairo_int_status_t
24
_cairo_xlib_surface_fill (void				*_surface,
			  cairo_operator_t		 op,
			  const cairo_pattern_t		*source,
			  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_xlib_surface_t *surface = _surface;
    const cairo_compositor_t *compositor;
    cairo_int_status_t status;
24
    status = get_compositor (&surface, &compositor);
24
    if (unlikely (status))
	return status;
24
    return _cairo_compositor_fill (compositor, &surface->base,
				   op, source,
				   path, fill_rule, tolerance, antialias,
				   clip);
}
static cairo_int_status_t
_cairo_xlib_surface_glyphs (void			*_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_xlib_surface_t *surface = _surface;
    const cairo_compositor_t *compositor;
    cairo_int_status_t status;
    status = get_compositor (&surface, &compositor);
    if (unlikely (status))
	return status;
    return _cairo_compositor_glyphs (compositor, &surface->base,
				     op, source,
				     glyphs, num_glyphs, scaled_font,
				     clip);
}
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
    CAIRO_SURFACE_TYPE_XLIB,
    _cairo_xlib_surface_finish,
    _cairo_default_context_create,
    _cairo_xlib_surface_create_similar,
    _cairo_xlib_surface_create_similar_shm,
    _cairo_xlib_surface_map_to_image,
    _cairo_xlib_surface_unmap_image,
    _cairo_xlib_surface_source,
    _cairo_xlib_surface_acquire_source_image,
    _cairo_xlib_surface_release_source_image,
    _cairo_xlib_surface_snapshot,
    NULL, /* copy_page */
    NULL, /* show_page */
    _cairo_xlib_surface_get_extents,
    _cairo_xlib_surface_get_font_options,
    _cairo_xlib_surface_flush,
    NULL, /* mark_dirty_rectangle */
    _cairo_xlib_surface_paint,
    _cairo_xlib_surface_mask,
    _cairo_xlib_surface_stroke,
    _cairo_xlib_surface_fill,
    NULL, /* fill-stroke */
    _cairo_xlib_surface_glyphs,
};
/**
 * _cairo_surface_is_xlib:
 * @surface: a #cairo_surface_t
 *
 * Checks if a surface is a #cairo_xlib_surface_t
 *
 * Return value: True if the surface is an xlib surface
 **/
static cairo_bool_t
55
_cairo_surface_is_xlib (cairo_surface_t *surface)
{
55
    return surface->backend == &cairo_xlib_surface_backend;
}
static cairo_surface_t *
7
_cairo_xlib_surface_create_internal (cairo_xlib_screen_t	*screen,
				     Drawable			 drawable,
				     Visual			*visual,
				     XRenderPictFormat		*xrender_format,
				     int			 width,
				     int			 height,
				     int			 depth)
{
    cairo_xlib_surface_t *surface;
    cairo_xlib_display_t *display;
    cairo_status_t status;
7
    if (depth == 0) {
4
	if (xrender_format) {
4
	    depth = xrender_format->depth;
	    /* XXX find matching visual for core/dithering fallbacks? */
	} else if (visual) {
	    Screen *scr = screen->screen;
	    if (visual == DefaultVisualOfScreen (scr)) {
		depth = DefaultDepthOfScreen (scr);
	    } else  {
		int j, k;
		/* This is ugly, but we have to walk over all visuals
		 * for the display to find the correct depth.
		 */
		depth = 0;
		for (j = 0; j < scr->ndepths; j++) {
		    Depth *d = &scr->depths[j];
		    for (k = 0; k < d->nvisuals; k++) {
			if (&d->visuals[k] == visual) {
			    depth = d->depth;
			    goto found;
			}
		    }
		}
	    }
	}
4
	if (depth == 0)
	    return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
4
found:
	;
    }
7
    surface = _cairo_calloc (sizeof (cairo_xlib_surface_t));
7
    if (unlikely (surface == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
7
    status = _cairo_xlib_display_acquire (screen->device, &display);
7
    if (unlikely (status)) {
        free (surface);
        return _cairo_surface_create_in_error (_cairo_error (status));
    }
7
    surface->display = display;
7
    if (CAIRO_RENDER_HAS_CREATE_PICTURE (display)) {
7
	if (!xrender_format) {
	    if (visual) {
		xrender_format = XRenderFindVisualFormat (display->display, visual);
	    } else if (depth == 1) {
		xrender_format =
		    _cairo_xlib_display_get_xrender_format (display,
							    CAIRO_FORMAT_A1);
	    }
	}
    }
7
    cairo_device_release (&display->base);
7
    _cairo_surface_init (&surface->base,
			 &cairo_xlib_surface_backend,
			 screen->device,
			 _xrender_format_to_content (xrender_format),
			 FALSE); /* is_vector */
7
    surface->screen = screen;
7
    surface->compositor = display->compositor;
7
    surface->shm = NULL;
7
    surface->fallback = 0;
7
    surface->drawable = drawable;
7
    surface->owns_pixmap = FALSE;
7
    surface->use_pixmap = 0;
7
    surface->width = width;
7
    surface->height = height;
7
    surface->picture = None;
7
    surface->precision = PolyModePrecise;
7
    surface->embedded_source.picture = None;
7
    surface->visual = visual;
7
    surface->xrender_format = xrender_format;
7
    surface->depth = depth;
    /*
     * Compute the pixel format masks from either a XrenderFormat or
     * else from a visual; failing that we assume the drawable is an
     * alpha-only pixmap as it could only have been created that way
     * through the cairo_xlib_surface_create_for_bitmap function.
     */
7
    if (xrender_format) {
7
	surface->a_mask = (unsigned long)
7
	    surface->xrender_format->direct.alphaMask
7
	    << surface->xrender_format->direct.alpha;
7
	surface->r_mask = (unsigned long)
7
	    surface->xrender_format->direct.redMask
7
	    << surface->xrender_format->direct.red;
7
	surface->g_mask = (unsigned long)
7
	    surface->xrender_format->direct.greenMask
7
	    << surface->xrender_format->direct.green;
7
	surface->b_mask = (unsigned long)
7
	    surface->xrender_format->direct.blueMask
7
	    << surface->xrender_format->direct.blue;
    } else if (visual) {
	surface->a_mask = 0;
	surface->r_mask = visual->red_mask;
	surface->g_mask = visual->green_mask;
	surface->b_mask = visual->blue_mask;
    } else {
	if (depth < 32)
	    surface->a_mask = (1 << depth) - 1;
	else
	    surface->a_mask = 0xffffffff;
	surface->r_mask = 0;
	surface->g_mask = 0;
	surface->b_mask = 0;
    }
7
    cairo_list_add (&surface->link, &screen->surfaces);
7
    return &surface->base;
}
static Screen *
_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
{
    int s, d, v;
    for (s = 0; s < ScreenCount (dpy); s++) {
	Screen *screen;
	screen = ScreenOfDisplay (dpy, s);
	if (visual == DefaultVisualOfScreen (screen))
	    return screen;
	for (d = 0; d < screen->ndepths; d++) {
	    Depth  *depth;
	    depth = &screen->depths[d];
	    for (v = 0; v < depth->nvisuals; v++)
		if (visual == &depth->visuals[v])
		    return screen;
	}
    }
    return NULL;
}
4
static cairo_bool_t valid_size (int width, int height)
{
    /* Note: the minimum surface size allowed in the X protocol is 1x1.
     * However, as we historically did not check the minimum size we
     * allowed applications to lie and set the correct size later (one hopes).
     * To preserve compatibility we must allow applications to use
     * 0x0 surfaces.
     */
4
    return (width  >= 0 && width  <= XLIB_COORD_MAX &&
8
	    height >= 0 && height <= XLIB_COORD_MAX);
}
/**
 * cairo_xlib_surface_create:
 * @dpy: an X Display
 * @drawable: an X Drawable, (a Pixmap or a Window)
 * @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 Xlib 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_xlib_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: the newly created surface
 *
 * Since: 1.0
 **/
cairo_surface_t *
cairo_xlib_surface_create (Display     *dpy,
			   Drawable	drawable,
			   Visual      *visual,
			   int		width,
			   int		height)
{
    Screen *scr;
    cairo_xlib_screen_t *screen;
    cairo_status_t status;
    if (! valid_size (width, height)) {
	/* you're lying, and you know it! */
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
    }
    scr = _cairo_xlib_screen_from_visual (dpy, visual);
    if (scr == NULL)
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
    status = _cairo_xlib_screen_get (dpy, scr, &screen);
    if (unlikely (status))
	return _cairo_surface_create_in_error (status);
    X_DEBUG ((dpy, "create (drawable=%x)", (unsigned int) drawable));
    return _cairo_xlib_surface_create_internal (screen, drawable,
                                                visual, NULL,
                                                width, height, 0);
}
/**
 * cairo_xlib_surface_create_for_bitmap:
 * @dpy: an X Display
 * @bitmap: an X Drawable, (a depth-1 Pixmap)
 * @screen: the X Screen associated with @bitmap
 * @width: the current width of @bitmap.
 * @height: the current height of @bitmap.
 *
 * Creates an Xlib surface that draws to the given bitmap.
 * This will be drawn to as a %CAIRO_FORMAT_A1 object.
 *
 * Return value: the newly created surface
 *
 * Since: 1.0
 **/
cairo_surface_t *
cairo_xlib_surface_create_for_bitmap (Display  *dpy,
				      Pixmap	bitmap,
				      Screen   *scr,
				      int	width,
				      int	height)
{
    cairo_xlib_screen_t *screen;
    cairo_status_t status;
    if (! valid_size (width, height))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
    status = _cairo_xlib_screen_get (dpy, scr, &screen);
    if (unlikely (status))
	return _cairo_surface_create_in_error (status);
    X_DEBUG ((dpy, "create_for_bitmap (drawable=%x)", (unsigned int) bitmap));
    return _cairo_xlib_surface_create_internal (screen, bitmap,
                                                NULL, NULL,
                                                width, height, 1);
}
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
/**
 * cairo_xlib_surface_create_with_xrender_format:
 * @dpy: an X Display
 * @drawable: an X Drawable, (a Pixmap or a Window)
 * @screen: the X Screen associated with @drawable
 * @format: the picture format to use for drawing to @drawable. The depth
 *          of @format must match the depth of the drawable.
 * @width: the current width of @drawable.
 * @height: the current height of @drawable.
 *
 * Creates an Xlib 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_xlib_surface_set_size() must be called whenever the size of the
 * window changes.
 *
 * Return value: the newly created surface
 *
 * Since: 1.0
 **/
cairo_surface_t *
4
cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
					       Drawable		    drawable,
					       Screen		    *scr,
					       XRenderPictFormat    *format,
					       int		    width,
					       int		    height)
{
    cairo_xlib_screen_t *screen;
    cairo_status_t status;
4
    if (! valid_size (width, height))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
4
    status = _cairo_xlib_screen_get (dpy, scr, &screen);
4
    if (unlikely (status))
	return _cairo_surface_create_in_error (status);
    X_DEBUG ((dpy, "create_with_xrender_format (drawable=%x)", (unsigned int) drawable));
4
    return _cairo_xlib_surface_create_internal (screen, drawable,
						_visual_for_xrender_format (scr, format),
                                                format, width, height, 0);
}
/**
 * cairo_xlib_surface_get_xrender_format:
 * @surface: an xlib surface
 *
 * Gets the X Render picture format that @surface uses for rendering with the
 * X Render extension. If the surface was created by
 * cairo_xlib_surface_create_with_xrender_format() originally, the return
 * value is the format passed to that constructor.
 *
 * Return value: the XRenderPictFormat* associated with @surface,
 * or %NULL if the surface is not an xlib surface
 * or if the X Render extension is not available.
 *
 * Since: 1.6
 **/
XRenderPictFormat *
cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
{
    cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
    /* Throw an error for a non-xlib surface */
    if (! _cairo_surface_is_xlib (surface)) {
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
	return NULL;
    }
    return xlib_surface->xrender_format;
}
#endif
/**
 * cairo_xlib_surface_set_size:
 * @surface: a #cairo_surface_t for the XLib backend
 * @width: the new width of the surface
 * @height: the new height of the surface
 *
 * Informs cairo of the new size of the X 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.
 *
 * Since: 1.0
 **/
void
8
cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
			     int              width,
			     int              height)
{
8
    cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
    cairo_status_t status;
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_xlib (abstract_surface)) {
3
	_cairo_surface_set_error (abstract_surface,
3
				  _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
3
	return;
    }
    if (surface->width == width && surface->height == height)
	return;
    if (! valid_size (width, height)) {
	_cairo_surface_set_error (abstract_surface,
				  _cairo_error (CAIRO_STATUS_INVALID_SIZE));
	return;
    }
    status = _cairo_surface_flush (abstract_surface, 0);
    if (unlikely (status)) {
	_cairo_surface_set_error (abstract_surface, status);
	return;
    }
    _cairo_xlib_surface_discard_shm (surface);
    surface->width = width;
    surface->height = height;
}
/**
 * cairo_xlib_surface_set_drawable:
 * @surface: a #cairo_surface_t for the XLib backend
 * @drawable: the new drawable for the surface
 * @width: the width of the new drawable
 * @height: the height of the new drawable
 *
 * Informs cairo of a new X Drawable underlying the
 * surface. The drawable must match the display, screen
 * and format of the existing drawable or the application
 * will get X protocol errors and will probably terminate.
 * No checks are done by this function to ensure this
 * compatibility.
 *
 * Since: 1.0
 **/
void
8
cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
				 Drawable	    drawable,
				 int		    width,
				 int		    height)
{
8
    cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface;
    cairo_status_t status;
8
    if (unlikely (abstract_surface->status))
2
	return;
6
    if (unlikely (abstract_surface->finished)) {
3
	status = _cairo_surface_set_error (abstract_surface,
3
		                           _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
3
	return;
    }
3
    if (! _cairo_surface_is_xlib (abstract_surface)) {
3
	status = _cairo_surface_set_error (abstract_surface,
3
		                           _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
3
	return;
    }
    if (! valid_size (width, height)) {
	status = _cairo_surface_set_error (abstract_surface,
		                           _cairo_error (CAIRO_STATUS_INVALID_SIZE));
	return;
    }
    /* XXX: and what about this case? */
    if (surface->owns_pixmap)
	return;
    status = _cairo_surface_flush (abstract_surface, 0);
    if (unlikely (status)) {
	_cairo_surface_set_error (abstract_surface, status);
	return;
    }
    if (surface->drawable != drawable) {
        cairo_xlib_display_t *display;
        status = _cairo_xlib_display_acquire (surface->base.device, &display);
        if (unlikely (status))
            return;
	X_DEBUG ((display->display, "set_drawable (drawable=%x)", (unsigned int) drawable));
	if (surface->picture != None) {
	    XRenderFreePicture (display->display, surface->picture);
	    if (unlikely (status)) {
		status = _cairo_surface_set_error (&surface->base, status);
		return;
	    }
	    surface->picture = None;
	}
        cairo_device_release (&display->base);
	surface->drawable = drawable;
    }
    if (surface->width != width || surface->height != height) {
	_cairo_xlib_surface_discard_shm (surface);
	surface->width = width;
	surface->height = height;
    }
}
/**
 * cairo_xlib_surface_get_display:
 * @surface: a #cairo_xlib_surface_t
 *
 * Get the X Display for the underlying X Drawable.
 *
 * Return value: the display.
 *
 * Since: 1.2
 **/
Display *
7
cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
{
7
    if (! _cairo_surface_is_xlib (abstract_surface)) {
7
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
7
	return NULL;
    }
    return ((cairo_xlib_display_t *) abstract_surface->device)->display;
}
/**
 * cairo_xlib_surface_get_drawable:
 * @surface: a #cairo_xlib_surface_t
 *
 * Get the underlying X Drawable used for the surface.
 *
 * Return value: the drawable.
 *
 * Since: 1.2
 **/
Drawable
7
cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
{
7
    cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
7
    if (! _cairo_surface_is_xlib (abstract_surface)) {
7
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
7
	return 0;
    }
    return surface->drawable;
}
/**
 * cairo_xlib_surface_get_screen:
 * @surface: a #cairo_xlib_surface_t
 *
 * Get the X Screen for the underlying X Drawable.
 *
 * Return value: the screen.
 *
 * Since: 1.2
 **/
Screen *
7
cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
{
7
    cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
7
    if (! _cairo_surface_is_xlib (abstract_surface)) {
7
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
7
	return NULL;
    }
    return surface->screen->screen;
}
/**
 * cairo_xlib_surface_get_visual:
 * @surface: a #cairo_xlib_surface_t
 *
 * Gets the X Visual associated with @surface, suitable for use with the
 * underlying X Drawable.  If @surface was created by
 * cairo_xlib_surface_create(), the return value is the Visual passed to that
 * constructor.
 *
 * Return value: the Visual or %NULL if there is no appropriate Visual for
 * @surface.
 *
 * Since: 1.2
 **/
Visual *
7
cairo_xlib_surface_get_visual (cairo_surface_t *surface)
{
7
    cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
7
    if (! _cairo_surface_is_xlib (surface)) {
7
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
7
	return NULL;
    }
    return xlib_surface->visual;
}
/**
 * cairo_xlib_surface_get_depth:
 * @surface: a #cairo_xlib_surface_t
 *
 * Get the number of bits used to represent each pixel value.
 *
 * Return value: the depth of the surface in bits.
 *
 * Since: 1.2
 **/
int
7
cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
{
7
    cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
7
    if (! _cairo_surface_is_xlib (abstract_surface)) {
7
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
7
	return 0;
    }
    return surface->depth;
}
/**
 * cairo_xlib_surface_get_width:
 * @surface: a #cairo_xlib_surface_t
 *
 * Get the width of the X Drawable underlying the surface in pixels.
 *
 * Return value: the width of the surface in pixels.
 *
 * Since: 1.2
 **/
int
7
cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
{
7
    cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
7
    if (! _cairo_surface_is_xlib (abstract_surface)) {
7
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
7
	return 0;
    }
    return surface->width;
}
/**
 * cairo_xlib_surface_get_height:
 * @surface: a #cairo_xlib_surface_t
 *
 * Get the height of the X Drawable underlying the surface in pixels.
 *
 * Return value: the height of the surface in pixels.
 *
 * Since: 1.2
 **/
int
7
cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
{
7
    cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
7
    if (! _cairo_surface_is_xlib (abstract_surface)) {
7
	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
7
	return 0;
    }
    return surface->height;
}
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */