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

            
43
/* The original X drawing API was very restrictive in what it could handle,
44
 * pixel-aligned fill/blits are all that map into Cairo's drawing model.
45
 */
46

            
47
#include "cairoint.h"
48

            
49
#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
50

            
51
#include "cairo-xlib-private.h"
52
#include "cairo-xlib-surface-private.h"
53

            
54
#include "cairo-boxes-private.h"
55
#include "cairo-clip-inline.h"
56
#include "cairo-compositor-private.h"
57
#include "cairo-image-surface-private.h"
58
#include "cairo-pattern-private.h"
59
#include "cairo-region-private.h"
60
#include "cairo-surface-offset-private.h"
61

            
62
/* the low-level interface */
63

            
64
static cairo_int_status_t
65
acquire (void *abstract_dst)
66
{
67
    cairo_xlib_surface_t *dst = abstract_dst;
68
    return _cairo_xlib_display_acquire (dst->base.device, &dst->display);
69
}
70

            
71
static cairo_int_status_t
72
release (void *abstract_dst)
73
{
74
    cairo_xlib_surface_t *dst = abstract_dst;
75

            
76
    cairo_device_release (&dst->display->base);
77
    dst->display = NULL;
78

            
79
    return CAIRO_STATUS_SUCCESS;
80
}
81

            
82
struct _fill_box {
83
    Display *dpy;
84
    Drawable drawable;
85
    GC gc;
86
    //cairo_surface_t *dither = NULL;
87
};
88

            
89
static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
90
{
91
    struct _fill_box *data = closure;
92
    int x = _cairo_fixed_integer_part (box->p1.x);
93
    int y = _cairo_fixed_integer_part (box->p1.y);
94
    int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
95
    int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
96

            
97
    XFillRectangle (data->dpy, data->drawable, data->gc, x, y, width, height);
98
    return TRUE;
99
}
100

            
101
static void
102
_characterize_field (uint32_t mask, int *width, int *shift)
103
{
104
    *width = _cairo_popcount (mask);
105
    /* The final '& 31' is to force a 0 mask to result in 0 shift. */
106
    *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
107
}
108

            
109
static uint32_t
110
color_to_pixel (cairo_xlib_surface_t    *dst,
111
		const cairo_color_t     *color)
112
{
113
    uint32_t rgba = 0;
114
    int width, shift;
115

            
116
    _characterize_field (dst->a_mask, &width, &shift);
117
    rgba |= color->alpha_short >> (16 - width) << shift;
118

            
119
    _characterize_field (dst->r_mask, &width, &shift);
120
    rgba |= color->red_short >> (16 - width) << shift;
121

            
122
    _characterize_field (dst->g_mask, &width, &shift);
123
    rgba |= color->green_short >> (16 - width) << shift;
124

            
125
    _characterize_field (dst->b_mask, &width, &shift);
126
    rgba |= color->blue_short >> (16 - width) << shift;
127

            
128
    return rgba;
129
}
130

            
131
static cairo_int_status_t
132
_fill_box_init (struct _fill_box *fb,
133
		cairo_xlib_surface_t *dst,
134
		const cairo_color_t *color)
135
{
136
    cairo_int_status_t status;
137

            
138
    status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc);
139
    if (unlikely (status))
140
        return status;
141

            
142
    fb->dpy = dst->display->display;
143
    fb->drawable = dst->drawable;
144

            
145
    if (dst->visual && dst->visual->class != TrueColor && 0) {
146
#if 0
147
	cairo_solid_pattern_t solid;
148
	cairo_surface_attributes_t attrs;
149

            
150
	_cairo_pattern_init_solid (&solid, color);
151
	status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
152
						 0, 0,
153
						 ARRAY_LENGTH (dither_pattern[0]),
154
						 ARRAY_LENGTH (dither_pattern),
155
						 CAIRO_PATTERN_ACQUIRE_NONE,
156
						 &dither,
157
						 &attrs);
158
	if (unlikely (status)) {
159
	    _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
160
	    return status;
161
	}
162

            
163
	XSetTSOrigin (fb->dpy, fb->gc,
164
		      - (dst->base.device_transform.x0 + attrs.x_offset),
165
		      - (dst->base.device_transform.y0 + attrs.y_offset));
166
	XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable);
167
#endif
168
    } else {
169
	XGCValues gcv;
170

            
171
	gcv.foreground = color_to_pixel (dst, color);
172
	gcv.fill_style = FillSolid;
173

            
174
	XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv);
175
    }
176

            
177
    return CAIRO_INT_STATUS_SUCCESS;
178
}
179

            
180
static void
181
_fill_box_fini (struct _fill_box *fb,
182
		cairo_xlib_surface_t *dst)
183
{
184
    _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc);
185
    //cairo_surface_destroy (fb->dither);
186
}
187

            
188
cairo_int_status_t
189
_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t    *dst,
190
			     const cairo_color_t     *color,
191
			     cairo_boxes_t	    *boxes)
192
{
193
    cairo_int_status_t status;
194
    struct _fill_box fb;
195

            
196
    status = _fill_box_init (&fb, dst, color);
197
    if (unlikely (status))
198
        return status;
199

            
200
    _cairo_boxes_for_each_box (boxes, fill_box, &fb);
201

            
202
    _fill_box_fini (&fb, dst);
203
    return CAIRO_STATUS_SUCCESS;
204
}
205

            
206
cairo_int_status_t
207
_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t    *dst,
208
				  const cairo_color_t     *color,
209
				  int num_rects,
210
				  cairo_rectangle_int_t *rects)
211
{
212
    cairo_int_status_t status;
213
    struct _fill_box fb;
214
    int i;
215

            
216
    status = _fill_box_init (&fb, dst, color);
217
    if (unlikely (status))
218
        return status;
219

            
220
    for (i = 0; i < num_rects; i++)
221
	XFillRectangle (fb.dpy, fb.drawable, fb.gc,
222
			rects[i].x, rects[i].y,
223
			rects[i].width, rects[i].height);
224

            
225
    _fill_box_fini (&fb, dst);
226
    return CAIRO_STATUS_SUCCESS;
227
}
228

            
229
struct _fallback_box {
230
    cairo_xlib_surface_t	*dst;
231
    cairo_format_t		 format;
232
    const cairo_pattern_t	*pattern;
233
};
234

            
235
static cairo_bool_t fallback_box (cairo_box_t *box, void *closure)
236
{
237
    struct _fallback_box *data = closure;
238
    int x = _cairo_fixed_integer_part (box->p1.x);
239
    int y = _cairo_fixed_integer_part (box->p1.y);
240
    int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
241
    int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
242
    cairo_surface_t *image;
243
    cairo_status_t status;
244

            
245
    /* XXX for EXTEND_NONE and if the box is wholly outside we can just fill */
246

            
247
    image = cairo_surface_create_similar_image (&data->dst->base, data->format,
248
						width, height);
249
    status = _cairo_surface_offset_paint (image, x, y,
250
					  CAIRO_OPERATOR_SOURCE,
251
					  data->pattern, NULL);
252
    if (status == CAIRO_STATUS_SUCCESS) {
253
	status = _cairo_xlib_surface_draw_image (data->dst,
254
						 (cairo_image_surface_t *)image,
255
						 0, 0,
256
						 width, height,
257
						 x, y);
258
    }
259
    cairo_surface_destroy (image);
260

            
261
    return status == CAIRO_STATUS_SUCCESS;
262
}
263

            
264
static cairo_int_status_t
265
fallback_boxes (cairo_xlib_surface_t	*dst,
266
		const cairo_pattern_t	*pattern,
267
		cairo_boxes_t		*boxes)
268
{
269
    struct _fallback_box fb;
270

            
271
    /* XXX create_similar_image using pixman_format? */
272
    switch (dst->depth) {
273
    case 8: fb.format = CAIRO_FORMAT_A8; break;
274
    case 16: fb.format = CAIRO_FORMAT_RGB16_565; break;
275
    case 24: fb.format = CAIRO_FORMAT_RGB24; break;
276
    case 30: fb.format = CAIRO_FORMAT_RGB30; break;
277
    case 32: fb.format = CAIRO_FORMAT_ARGB32; break;
278
    default: return CAIRO_INT_STATUS_UNSUPPORTED;
279
    }
280

            
281
    fb.dst = dst;
282
    fb.pattern = pattern;
283

            
284
    if (! _cairo_boxes_for_each_box (boxes, fallback_box, &fb))
285
	return CAIRO_INT_STATUS_UNSUPPORTED;
286

            
287
    return CAIRO_STATUS_SUCCESS;
288
}
289

            
290
static cairo_int_status_t
291
render_boxes (cairo_xlib_surface_t	*dst,
292
	      const cairo_pattern_t	*pattern,
293
	      cairo_boxes_t		*boxes)
294
{
295
    if (pattern->filter != CAIRO_FILTER_NEAREST)
296
	return fallback_boxes (dst, pattern, boxes);
297

            
298
    switch (pattern->extend) {
299
    default:
300
    case CAIRO_EXTEND_NONE:
301
    case CAIRO_EXTEND_REFLECT:
302
    case CAIRO_EXTEND_PAD:
303
	return fallback_boxes (dst, pattern, boxes);
304

            
305
    case CAIRO_EXTEND_REPEAT: /* XXX Use tiling */
306
	return fallback_boxes (dst, pattern, boxes);
307
    }
308
}
309

            
310
/* the mid-level: converts boxes into drawing operations */
311

            
312
struct _box_data {
313
    Display *dpy;
314
    cairo_xlib_surface_t *dst;
315
    cairo_surface_t *src;
316
    GC gc;
317
    int tx, ty;
318
    int width, height;
319
};
320

            
321
static cairo_bool_t source_contains_box (cairo_box_t *box, void *closure)
322
{
323
    struct _box_data *data = closure;
324

            
325
    /* The box is pixel-aligned so the truncation is safe. */
326
    return
327
	_cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 &&
328
	_cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 &&
329
	_cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width &&
330
	_cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height;
331
}
332

            
333
static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure)
334
{
335
    const struct _box_data *iub = closure;
336
    int x = _cairo_fixed_integer_part (box->p1.x);
337
    int y = _cairo_fixed_integer_part (box->p1.y);
338
    int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
339
    int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
340

            
341
    return _cairo_xlib_surface_draw_image (iub->dst,
342
					   (cairo_image_surface_t *)iub->src,
343
					   x + iub->tx, y + iub->ty,
344
					   width, height,
345
					   x, y) == CAIRO_STATUS_SUCCESS;
346
}
347

            
348
static cairo_bool_t
349
surface_matches_image_format (cairo_xlib_surface_t *surface,
350
			      cairo_image_surface_t *image)
351
{
352
    cairo_format_masks_t format;
353

            
354
    return (_pixman_format_to_masks (image->pixman_format, &format) &&
355
	    (format.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
356
	    (format.red_mask   == surface->r_mask || surface->r_mask == 0) &&
357
	    (format.green_mask == surface->g_mask || surface->g_mask == 0) &&
358
	    (format.blue_mask  == surface->b_mask || surface->b_mask == 0));
359
}
360

            
361
static cairo_status_t
362
upload_image_inplace (cairo_xlib_surface_t *dst,
363
		      const cairo_pattern_t *source,
364
		      cairo_boxes_t *boxes)
365
{
366
    const cairo_surface_pattern_t *pattern;
367
    struct _box_data iub;
368
    cairo_image_surface_t *image;
369

            
370
    if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
371
	return CAIRO_INT_STATUS_UNSUPPORTED;
372

            
373
    pattern = (const cairo_surface_pattern_t *) source;
374
    if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
375
	return CAIRO_INT_STATUS_UNSUPPORTED;
376

            
377
    image = (cairo_image_surface_t *) pattern->surface;
378
    if (image->format == CAIRO_FORMAT_INVALID)
379
	return CAIRO_INT_STATUS_UNSUPPORTED;
380

            
381
    if (image->depth != dst->depth)
382
	return CAIRO_INT_STATUS_UNSUPPORTED;
383

            
384
    if (! surface_matches_image_format (dst, image))
385
	return CAIRO_INT_STATUS_UNSUPPORTED;
386

            
387
    /* XXX subsurface */
388

            
389
    if (! _cairo_matrix_is_integer_translation (&source->matrix,
390
						&iub.tx, &iub.ty))
391
	return CAIRO_INT_STATUS_UNSUPPORTED;
392

            
393
    iub.dst = dst;
394
    iub.src = &image->base;
395
    iub.width  = image->width;
396
    iub.height = image->height;
397

            
398
    /* First check that the data is entirely within the image */
399
    if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &iub))
400
	return CAIRO_INT_STATUS_UNSUPPORTED;
401

            
402
    if (! _cairo_boxes_for_each_box (boxes, image_upload_box, &iub))
403
	return CAIRO_INT_STATUS_UNSUPPORTED;
404

            
405
    return CAIRO_STATUS_SUCCESS;
406
}
407

            
408
static cairo_bool_t copy_box (cairo_box_t *box, void *closure)
409
{
410
    const struct _box_data *cb = closure;
411
    int x = _cairo_fixed_integer_part (box->p1.x);
412
    int y = _cairo_fixed_integer_part (box->p1.y);
413
    int width  = _cairo_fixed_integer_part (box->p2.x - box->p1.x);
414
    int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y);
415

            
416
    XCopyArea (cb->dpy,
417
	       ((cairo_xlib_surface_t *)cb->src)->drawable,
418
	       cb->dst->drawable,
419
	       cb->gc,
420
	       x + cb->tx, y + cb->ty,
421
	       width, height,
422
	       x, y);
423
    return TRUE;
424
}
425

            
426
static cairo_status_t
427
copy_boxes (cairo_xlib_surface_t *dst,
428
	    const cairo_pattern_t *source,
429
	    cairo_boxes_t *boxes)
430
{
431
    const cairo_surface_pattern_t *pattern;
432
    struct _box_data cb;
433
    cairo_xlib_surface_t *src;
434
    cairo_status_t status;
435

            
436
    if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
437
	return CAIRO_INT_STATUS_UNSUPPORTED;
438

            
439
    /* XXX subsurface */
440

            
441
    pattern = (const cairo_surface_pattern_t *) source;
442
    if (pattern->surface->backend->type != CAIRO_SURFACE_TYPE_XLIB)
443
	return CAIRO_INT_STATUS_UNSUPPORTED;
444

            
445
    src = (cairo_xlib_surface_t *) pattern->surface;
446
    if (src->depth != dst->depth)
447
	return CAIRO_INT_STATUS_UNSUPPORTED;
448

            
449
    /* We can only have a single control for subwindow_mode on the
450
     * GC. If we have a Window destination, we need to set ClipByChildren,
451
     * but if we have a Window source, we need IncludeInferiors. If we have
452
     * both a Window destination and source, we must fallback. There is
453
     * no convenient way to detect if a drawable is a Pixmap or Window,
454
     * therefore we can only rely on those surfaces that we created
455
     * ourselves to be Pixmaps, and treat everything else as a potential
456
     * Window.
457
     */
458
    if (! src->owns_pixmap && ! dst->owns_pixmap)
459
	return CAIRO_INT_STATUS_UNSUPPORTED;
460

            
461
    if (! _cairo_xlib_surface_same_screen (dst, src))
462
	return CAIRO_INT_STATUS_UNSUPPORTED;
463

            
464
    if (! _cairo_matrix_is_integer_translation (&source->matrix,
465
						&cb.tx, &cb.ty))
466
	return CAIRO_INT_STATUS_UNSUPPORTED;
467

            
468
    cb.dpy = dst->display->display;
469
    cb.dst = dst;
470
    cb.src = &src->base;
471
    cb.width  = src->width;
472
    cb.height = src->height;
473

            
474
    /* First check that the data is entirely within the image */
475
    if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
476
	return CAIRO_INT_STATUS_UNSUPPORTED;
477

            
478
    status = _cairo_xlib_surface_get_gc (dst->display, dst, &cb.gc);
479
    if (unlikely (status))
480
	return status;
481

            
482
    if (! src->owns_pixmap) {
483
	XGCValues gcv;
484

            
485
	gcv.subwindow_mode = IncludeInferiors;
486
	XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv);
487
    }
488

            
489
    status = CAIRO_STATUS_SUCCESS;
490
    if (! _cairo_boxes_for_each_box (boxes, copy_box, &cb))
491
	status = CAIRO_INT_STATUS_UNSUPPORTED;
492

            
493
    if (! src->owns_pixmap) {
494
	XGCValues gcv;
495

            
496
	gcv.subwindow_mode = ClipByChildren;
497
	XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv);
498
    }
499

            
500
    _cairo_xlib_surface_put_gc (dst->display, dst, cb.gc);
501

            
502
    return status;
503
}
504

            
505
static cairo_status_t
506
draw_boxes (cairo_composite_rectangles_t *extents,
507
	    cairo_boxes_t *boxes)
508
{
509
    cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface;
510
    cairo_operator_t op = extents->op;
511
    const cairo_pattern_t *src = &extents->source_pattern.base;
512
    cairo_int_status_t status;
513

            
514
    if (boxes->num_boxes == 0 && extents->is_bounded)
515
	return CAIRO_STATUS_SUCCESS;
516

            
517
    if (! boxes->is_pixel_aligned)
518
	return CAIRO_INT_STATUS_UNSUPPORTED;
519

            
520
    if (op == CAIRO_OPERATOR_CLEAR)
521
	op = CAIRO_OPERATOR_SOURCE;
522

            
523
    if (op == CAIRO_OPERATOR_OVER &&
524
	_cairo_pattern_is_opaque (src, &extents->bounded))
525
	op = CAIRO_OPERATOR_SOURCE;
526

            
527
    if (dst->base.is_clear && op == CAIRO_OPERATOR_OVER)
528
	op = CAIRO_OPERATOR_SOURCE;
529

            
530
    if (op != CAIRO_OPERATOR_SOURCE)
531
	return CAIRO_INT_STATUS_UNSUPPORTED;
532

            
533
    status = acquire (dst);
534
    if (unlikely (status))
535
	return status;
536

            
537
    if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
538
	status = _cairo_xlib_core_fill_boxes
539
	    (dst, &((cairo_solid_pattern_t *) src)->color, boxes);
540
    } else {
541
	status = upload_image_inplace (dst, src, boxes);
542
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
543
	    status = copy_boxes (dst, src, boxes);
544
	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
545
	    status = render_boxes (dst, src, boxes);
546
    }
547

            
548
    release (dst);
549

            
550
    return status;
551
}
552

            
553
/* high-level compositor interface */
554

            
555
static cairo_int_status_t
556
_cairo_xlib_core_compositor_paint (const cairo_compositor_t	*compositor,
557
				   cairo_composite_rectangles_t *extents)
558
{
559
    cairo_int_status_t status;
560

            
561
    status = CAIRO_INT_STATUS_UNSUPPORTED;
562
    if (_cairo_clip_is_region (extents->clip)) {
563
	cairo_boxes_t boxes;
564

            
565
	 _cairo_clip_steal_boxes (extents->clip, &boxes);
566
	 status = draw_boxes (extents, &boxes);
567
	 _cairo_clip_unsteal_boxes (extents->clip, &boxes);
568
    }
569

            
570
    return status;
571
}
572

            
573
static cairo_int_status_t
574
_cairo_xlib_core_compositor_stroke (const cairo_compositor_t	*compositor,
575
				    cairo_composite_rectangles_t *extents,
576
				    const cairo_path_fixed_t	*path,
577
				    const cairo_stroke_style_t	*style,
578
				    const cairo_matrix_t	*ctm,
579
				    const cairo_matrix_t	*ctm_inverse,
580
				    double			 tolerance,
581
				    cairo_antialias_t		 antialias)
582
{
583
    cairo_int_status_t status;
584

            
585
    status = CAIRO_INT_STATUS_UNSUPPORTED;
586
    if (extents->clip->path == NULL &&
587
	_cairo_path_fixed_stroke_is_rectilinear (path)) {
588
	cairo_boxes_t boxes;
589

            
590
	_cairo_boxes_init_with_clip (&boxes, extents->clip);
591
	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
592
								style,
593
								ctm,
594
								antialias,
595
								&boxes);
596
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
597
	    status = draw_boxes (extents, &boxes);
598
	_cairo_boxes_fini (&boxes);
599
    }
600

            
601
    return status;
602
}
603

            
604
static cairo_int_status_t
605
_cairo_xlib_core_compositor_fill (const cairo_compositor_t	*compositor,
606
				  cairo_composite_rectangles_t	*extents,
607
				  const cairo_path_fixed_t	*path,
608
				  cairo_fill_rule_t		 fill_rule,
609
				  double			 tolerance,
610
				  cairo_antialias_t		 antialias)
611
{
612
    cairo_int_status_t status;
613

            
614
    status = CAIRO_INT_STATUS_UNSUPPORTED;
615
    if (extents->clip->path == NULL &&
616
	_cairo_path_fixed_fill_is_rectilinear (path)) {
617
	cairo_boxes_t boxes;
618

            
619
	_cairo_boxes_init_with_clip (&boxes, extents->clip);
620
	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
621
							      fill_rule,
622
							      antialias,
623
							      &boxes);
624
	if (likely (status == CAIRO_INT_STATUS_SUCCESS))
625
	    status = draw_boxes (extents, &boxes);
626
	_cairo_boxes_fini (&boxes);
627
    }
628

            
629
    return status;
630
}
631

            
632
const cairo_compositor_t *
633
_cairo_xlib_core_compositor_get (void)
634
{
635
    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
636
    static cairo_compositor_t compositor;
637

            
638
    if (_cairo_atomic_init_once_enter(&once)) {
639
	compositor.delegate = _cairo_xlib_fallback_compositor_get ();
640

            
641
	compositor.paint = _cairo_xlib_core_compositor_paint;
642
	compositor.mask  = NULL;
643
	compositor.fill  = _cairo_xlib_core_compositor_fill;
644
	compositor.stroke = _cairo_xlib_core_compositor_stroke;
645
	compositor.glyphs = NULL; /* XXX PolyGlyph? */
646

            
647
	_cairo_atomic_init_once_leave(&once);
648
    }
649

            
650
    return &compositor;
651
}
652

            
653
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */