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
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
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.
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
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
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
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.
49 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
51 #include "cairo-xlib-private.h"
52 #include "cairo-xlib-surface-private.h"
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"
62 /* the low-level interface */
64 static cairo_int_status_t
65 acquire (void *abstract_dst
)
67 cairo_xlib_surface_t
*dst
= abstract_dst
;
68 return _cairo_xlib_display_acquire (dst
->base
.device
, &dst
->display
);
71 static cairo_int_status_t
72 release (void *abstract_dst
)
74 cairo_xlib_surface_t
*dst
= abstract_dst
;
76 cairo_device_release (&dst
->display
->base
);
79 return CAIRO_STATUS_SUCCESS
;
86 //cairo_surface_t *dither = NULL;
89 static cairo_bool_t
fill_box (cairo_box_t
*box
, void *closure
)
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
);
97 XFillRectangle (data
->dpy
, data
->drawable
, data
->gc
, x
, y
, width
, height
);
102 _characterize_field (uint32_t mask
, int *width
, int *shift
)
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;
110 color_to_pixel (cairo_xlib_surface_t
*dst
,
111 const cairo_color_t
*color
)
116 _characterize_field (dst
->a_mask
, &width
, &shift
);
117 rgba
|= color
->alpha_short
>> (16 - width
) << shift
;
119 _characterize_field (dst
->r_mask
, &width
, &shift
);
120 rgba
|= color
->red_short
>> (16 - width
) << shift
;
122 _characterize_field (dst
->g_mask
, &width
, &shift
);
123 rgba
|= color
->green_short
>> (16 - width
) << shift
;
125 _characterize_field (dst
->b_mask
, &width
, &shift
);
126 rgba
|= color
->blue_short
>> (16 - width
) << shift
;
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
)
136 cairo_int_status_t status
;
138 status
= _cairo_xlib_surface_get_gc (dst
->display
, dst
, &fb
->gc
);
139 if (unlikely (status
))
142 fb
->dpy
= dst
->display
->display
;
143 fb
->drawable
= dst
->drawable
;
145 if (dst
->visual
&& dst
->visual
->class != TrueColor
&& 0) {
147 cairo_solid_pattern_t solid
;
148 cairo_surface_attributes_t attrs
;
150 _cairo_pattern_init_solid (&solid
, color
);
151 status
= _cairo_pattern_acquire_surface (&solid
.base
, &dst
->base
,
153 ARRAY_LENGTH (dither_pattern
[0]),
154 ARRAY_LENGTH (dither_pattern
),
155 CAIRO_PATTERN_ACQUIRE_NONE
,
158 if (unlikely (status
)) {
159 _cairo_xlib_surface_put_gc (dst
->display
, dst
, fb
.gc
);
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
);
171 gcv
.foreground
= color_to_pixel (dst
, color
);
172 gcv
.fill_style
= FillSolid
;
174 XChangeGC (fb
->dpy
, fb
->gc
, GCFillStyle
| GCForeground
, &gcv
);
177 return CAIRO_INT_STATUS_SUCCESS
;
181 _fill_box_fini (struct _fill_box
*fb
,
182 cairo_xlib_surface_t
*dst
)
184 _cairo_xlib_surface_put_gc (dst
->display
, dst
, fb
->gc
);
185 //cairo_surface_destroy (fb->dither);
189 _cairo_xlib_core_fill_boxes (cairo_xlib_surface_t
*dst
,
190 const cairo_color_t
*color
,
191 cairo_boxes_t
*boxes
)
193 cairo_int_status_t status
;
196 status
= _fill_box_init (&fb
, dst
, color
);
197 if (unlikely (status
))
200 _cairo_boxes_for_each_box (boxes
, fill_box
, &fb
);
202 _fill_box_fini (&fb
, dst
);
203 return CAIRO_STATUS_SUCCESS
;
207 _cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t
*dst
,
208 const cairo_color_t
*color
,
210 cairo_rectangle_int_t
*rects
)
212 cairo_int_status_t status
;
216 status
= _fill_box_init (&fb
, dst
, color
);
217 if (unlikely (status
))
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
);
225 _fill_box_fini (&fb
, dst
);
226 return CAIRO_STATUS_SUCCESS
;
229 struct _fallback_box
{
230 cairo_xlib_surface_t
*dst
;
231 cairo_format_t format
;
232 const cairo_pattern_t
*pattern
;
235 static cairo_bool_t
fallback_box (cairo_box_t
*box
, void *closure
)
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
;
245 /* XXX for EXTEND_NONE and if the box is wholly outside we can just fill */
247 image
= cairo_surface_create_similar_image (&data
->dst
->base
, data
->format
,
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
,
259 cairo_surface_destroy (image
);
261 return status
== CAIRO_STATUS_SUCCESS
;
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
)
269 struct _fallback_box fb
;
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
;
282 fb
.pattern
= pattern
;
284 if (! _cairo_boxes_for_each_box (boxes
, fallback_box
, &fb
))
285 return CAIRO_INT_STATUS_UNSUPPORTED
;
287 return CAIRO_STATUS_SUCCESS
;
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
)
295 if (pattern
->filter
!= CAIRO_FILTER_NEAREST
)
296 return fallback_boxes (dst
, pattern
, boxes
);
298 switch (pattern
->extend
) {
300 case CAIRO_EXTEND_NONE
:
301 case CAIRO_EXTEND_REFLECT
:
302 case CAIRO_EXTEND_PAD
:
303 return fallback_boxes (dst
, pattern
, boxes
);
305 case CAIRO_EXTEND_REPEAT
: /* XXX Use tiling */
306 return fallback_boxes (dst
, pattern
, boxes
);
310 /* the mid-level: converts boxes into drawing operations */
314 cairo_xlib_surface_t
*dst
;
315 cairo_surface_t
*src
;
321 static cairo_bool_t
source_contains_box (cairo_box_t
*box
, void *closure
)
323 struct _box_data
*data
= closure
;
325 /* The box is pixel-aligned so the truncation is safe. */
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
;
333 static cairo_bool_t
image_upload_box (cairo_box_t
*box
, void *closure
)
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
);
341 return _cairo_xlib_surface_draw_image (iub
->dst
,
342 (cairo_image_surface_t
*)iub
->src
,
343 x
+ iub
->tx
, y
+ iub
->ty
,
345 x
, y
) == CAIRO_STATUS_SUCCESS
;
349 surface_matches_image_format (cairo_xlib_surface_t
*surface
,
350 cairo_image_surface_t
*image
)
352 cairo_format_masks_t format
;
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));
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
)
366 const cairo_surface_pattern_t
*pattern
;
367 struct _box_data iub
;
368 cairo_image_surface_t
*image
;
370 if (source
->type
!= CAIRO_PATTERN_TYPE_SURFACE
)
371 return CAIRO_INT_STATUS_UNSUPPORTED
;
373 pattern
= (const cairo_surface_pattern_t
*) source
;
374 if (pattern
->surface
->type
!= CAIRO_SURFACE_TYPE_IMAGE
)
375 return CAIRO_INT_STATUS_UNSUPPORTED
;
377 image
= (cairo_image_surface_t
*) pattern
->surface
;
378 if (image
->format
== CAIRO_FORMAT_INVALID
)
379 return CAIRO_INT_STATUS_UNSUPPORTED
;
381 if (image
->depth
!= dst
->depth
)
382 return CAIRO_INT_STATUS_UNSUPPORTED
;
384 if (! surface_matches_image_format (dst
, image
))
385 return CAIRO_INT_STATUS_UNSUPPORTED
;
389 if (! _cairo_matrix_is_integer_translation (&source
->matrix
,
391 return CAIRO_INT_STATUS_UNSUPPORTED
;
394 iub
.src
= &image
->base
;
395 iub
.width
= image
->width
;
396 iub
.height
= image
->height
;
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
;
402 if (! _cairo_boxes_for_each_box (boxes
, image_upload_box
, &iub
))
403 return CAIRO_INT_STATUS_UNSUPPORTED
;
405 return CAIRO_STATUS_SUCCESS
;
408 static cairo_bool_t
copy_box (cairo_box_t
*box
, void *closure
)
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
);
417 ((cairo_xlib_surface_t
*)cb
->src
)->drawable
,
420 x
+ cb
->tx
, y
+ cb
->ty
,
426 static cairo_status_t
427 copy_boxes (cairo_xlib_surface_t
*dst
,
428 const cairo_pattern_t
*source
,
429 cairo_boxes_t
*boxes
)
431 const cairo_surface_pattern_t
*pattern
;
433 cairo_xlib_surface_t
*src
;
434 cairo_status_t status
;
436 if (source
->type
!= CAIRO_PATTERN_TYPE_SURFACE
)
437 return CAIRO_INT_STATUS_UNSUPPORTED
;
441 pattern
= (const cairo_surface_pattern_t
*) source
;
442 if (pattern
->surface
->backend
->type
!= CAIRO_SURFACE_TYPE_XLIB
)
443 return CAIRO_INT_STATUS_UNSUPPORTED
;
445 src
= (cairo_xlib_surface_t
*) pattern
->surface
;
446 if (src
->depth
!= dst
->depth
)
447 return CAIRO_INT_STATUS_UNSUPPORTED
;
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
458 if (! src
->owns_pixmap
&& ! dst
->owns_pixmap
)
459 return CAIRO_INT_STATUS_UNSUPPORTED
;
461 if (! _cairo_xlib_surface_same_screen (dst
, src
))
462 return CAIRO_INT_STATUS_UNSUPPORTED
;
464 if (! _cairo_matrix_is_integer_translation (&source
->matrix
,
466 return CAIRO_INT_STATUS_UNSUPPORTED
;
468 cb
.dpy
= dst
->display
->display
;
471 cb
.width
= src
->width
;
472 cb
.height
= src
->height
;
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
;
478 status
= _cairo_xlib_surface_get_gc (dst
->display
, dst
, &cb
.gc
);
479 if (unlikely (status
))
482 if (! src
->owns_pixmap
) {
485 gcv
.subwindow_mode
= IncludeInferiors
;
486 XChangeGC (dst
->display
->display
, cb
.gc
, GCSubwindowMode
, &gcv
);
489 status
= CAIRO_STATUS_SUCCESS
;
490 if (! _cairo_boxes_for_each_box (boxes
, copy_box
, &cb
))
491 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
493 if (! src
->owns_pixmap
) {
496 gcv
.subwindow_mode
= ClipByChildren
;
497 XChangeGC (dst
->display
->display
, cb
.gc
, GCSubwindowMode
, &gcv
);
500 _cairo_xlib_surface_put_gc (dst
->display
, dst
, cb
.gc
);
505 static cairo_status_t
506 draw_boxes (cairo_composite_rectangles_t
*extents
,
507 cairo_boxes_t
*boxes
)
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
;
514 if (boxes
->num_boxes
== 0 && extents
->is_bounded
)
515 return CAIRO_STATUS_SUCCESS
;
517 if (! boxes
->is_pixel_aligned
)
518 return CAIRO_INT_STATUS_UNSUPPORTED
;
520 if (op
== CAIRO_OPERATOR_CLEAR
)
521 op
= CAIRO_OPERATOR_SOURCE
;
523 if (op
== CAIRO_OPERATOR_OVER
&&
524 _cairo_pattern_is_opaque (src
, &extents
->bounded
))
525 op
= CAIRO_OPERATOR_SOURCE
;
527 if (dst
->base
.is_clear
&& op
== CAIRO_OPERATOR_OVER
)
528 op
= CAIRO_OPERATOR_SOURCE
;
530 if (op
!= CAIRO_OPERATOR_SOURCE
)
531 return CAIRO_INT_STATUS_UNSUPPORTED
;
533 status
= acquire (dst
);
534 if (unlikely (status
))
537 if (src
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
538 status
= _cairo_xlib_core_fill_boxes
539 (dst
, &((cairo_solid_pattern_t
*) src
)->color
, boxes
);
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
);
553 /* high-level compositor interface */
555 static cairo_int_status_t
556 _cairo_xlib_core_compositor_paint (const cairo_compositor_t
*compositor
,
557 cairo_composite_rectangles_t
*extents
)
559 cairo_int_status_t status
;
561 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
562 if (_cairo_clip_is_region (extents
->clip
)) {
565 _cairo_clip_steal_boxes (extents
->clip
, &boxes
);
566 status
= draw_boxes (extents
, &boxes
);
567 _cairo_clip_unsteal_boxes (extents
->clip
, &boxes
);
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
,
581 cairo_antialias_t antialias
)
583 cairo_int_status_t status
;
585 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
586 if (extents
->clip
->path
== NULL
&&
587 _cairo_path_fixed_stroke_is_rectilinear (path
)) {
590 _cairo_boxes_init_with_clip (&boxes
, extents
->clip
);
591 status
= _cairo_path_fixed_stroke_rectilinear_to_boxes (path
,
596 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
597 status
= draw_boxes (extents
, &boxes
);
598 _cairo_boxes_fini (&boxes
);
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
,
610 cairo_antialias_t antialias
)
612 cairo_int_status_t status
;
614 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
615 if (extents
->clip
->path
== NULL
&&
616 _cairo_path_fixed_fill_is_rectilinear (path
)) {
619 _cairo_boxes_init_with_clip (&boxes
, extents
->clip
);
620 status
= _cairo_path_fixed_fill_rectilinear_to_boxes (path
,
624 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
625 status
= draw_boxes (extents
, &boxes
);
626 _cairo_boxes_fini (&boxes
);
632 const cairo_compositor_t
*
633 _cairo_xlib_core_compositor_get (void)
635 static cairo_compositor_t compositor
;
637 if (compositor
.delegate
== NULL
) {
638 compositor
.delegate
= _cairo_xlib_fallback_compositor_get ();
640 compositor
.paint
= _cairo_xlib_core_compositor_paint
;
641 compositor
.mask
= NULL
;
642 compositor
.fill
= _cairo_xlib_core_compositor_fill
;
643 compositor
.stroke
= _cairo_xlib_core_compositor_stroke
;
644 compositor
.glyphs
= NULL
; /* XXX PolyGlyph? */
650 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */