1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
29 * Chris Wilson <chris@chris-wilson.co.uk>
34 #include "cairo-boxes-private.h"
35 #include "cairo-xcb-private.h"
36 #include "cairo-image-surface-private.h"
37 #include "cairo-surface-backend-private.h"
41 typedef struct _cairo_xcb_pixmap {
44 cairo_xcb_connection_t *connection;
45 cairo_xcb_screen_t *screen;
47 cairo_surface_t *owner;
57 _cairo_xcb_pixmap_finish (void *abstract_surface)
59 cairo_xcb_pixmap_t *surface = abstract_surface;
60 cairo_status_t status;
62 if (surface->owner != NULL) {
63 cairo_surface_destroy (surface->owner);
65 status = _cairo_xcb_connection_acquire (surface->connection);
66 if (unlikely (status))
69 _cairo_xcb_connection_free_pixmap (surface->connection,
71 _cairo_xcb_connection_release (surface->connection);
74 return CAIRO_STATUS_SUCCESS;
77 static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = {
78 CAIRO_SURFACE_TYPE_XCB,
79 _cairo_xcb_pixmap_finish,
82 static cairo_xcb_pixmap_t *
83 _cairo_xcb_pixmap_create (cairo_xcb_surface_t *target,
84 int width, int height)
86 cairo_xcb_pixmap_t *surface;
88 surface = malloc (sizeof (cairo_xcb_pixmap_t));
89 if (unlikely (surface == NULL))
90 return (cairo_xcb_pixmap_t *)
91 _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
93 _cairo_surface_init (&surface->base,
94 &_cairo_xcb_pixmap_backend,
96 target->base.content);
98 surface->connection = target->connection;
99 surface->screen = target->screen;
100 surface->owner = NULL;
101 surface->width = width;
102 surface->height = height;
103 surface->depth = target->depth;
104 surface->x0 = surface->y0 = 0;
105 surface->repeat = FALSE;
108 _cairo_xcb_connection_create_pixmap (surface->connection,
116 static cairo_xcb_pixmap_t *
117 _cairo_xcb_pixmap_copy (cairo_xcb_surface_t *target)
119 cairo_xcb_pixmap_t *surface;
121 surface = malloc (sizeof (cairo_xcb_pixmap_t));
122 if (unlikely (surface == NULL))
123 return (cairo_xcb_pixmap_t *)
124 _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
126 _cairo_surface_init (&surface->base,
127 &_cairo_xcb_pixmap_backend,
129 target->base.content);
131 surface->connection = target->connection;
132 surface->screen = target->screen;
133 surface->pixmap = target->drawable;
134 surface->owner = cairo_surface_reference (&target->base);
135 surface->width = target->width;
136 surface->height = target->height;
137 surface->depth = target->depth;
138 surface->x0 = surface->y0 = 0;
139 surface->repeat = FALSE;
144 #if CAIRO_HAS_XCB_SHM_FUNCTIONS
145 static cairo_status_t
146 _cairo_xcb_shm_image_create_shm (cairo_xcb_connection_t *connection,
147 pixman_format_code_t pixman_format,
148 int width, int height,
149 cairo_image_surface_t **image_out,
150 cairo_xcb_shm_info_t **shm_info_out)
152 cairo_surface_t *image = NULL;
153 cairo_xcb_shm_info_t *shm_info = NULL;
154 cairo_status_t status;
157 if (! (connection->flags & CAIRO_XCB_HAS_SHM))
158 return CAIRO_INT_STATUS_UNSUPPORTED;
160 if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
161 return CAIRO_INT_STATUS_UNSUPPORTED;
163 stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
164 size = stride * height;
165 if (size <= CAIRO_XCB_SHM_SMALL_IMAGE)
166 return CAIRO_INT_STATUS_UNSUPPORTED;
168 status = _cairo_xcb_connection_allocate_shm_info (connection, size,
170 if (unlikely (status))
173 image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
177 status = image->status;
178 if (unlikely (status)) {
179 _cairo_xcb_shm_info_destroy (shm_info);
183 status = _cairo_user_data_array_set_data (&image->user_data,
184 (const cairo_user_data_key_t *) connection,
186 (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
188 if (unlikely (status)) {
189 cairo_surface_destroy (image);
190 _cairo_xcb_shm_info_destroy (shm_info);
194 *image_out = (cairo_image_surface_t *) image;
195 *shm_info_out = shm_info;
196 return CAIRO_STATUS_SUCCESS;
199 static cairo_status_t
200 _cairo_xcb_shm_image_create_shm (cairo_xcb_connection_t *connection,
201 pixman_format_code_t pixman_format,
202 int width, int height,
203 cairo_image_surface_t **image_out,
204 cairo_xcb_shm_info_t **shm_info_out)
206 return CAIRO_INT_STATUS_UNSUPPORTED;
211 _cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
212 pixman_format_code_t pixman_format,
213 int width, int height,
214 cairo_image_surface_t **image_out,
215 cairo_xcb_shm_info_t **shm_info_out)
217 cairo_surface_t *image = NULL;
218 cairo_xcb_shm_info_t *shm_info = NULL;
219 cairo_status_t status;
221 status = _cairo_xcb_shm_image_create_shm (connection,
228 if (status != CAIRO_STATUS_SUCCESS) {
229 image = _cairo_image_surface_create_with_pixman_format (NULL,
233 status = image->status;
234 if (unlikely (status))
237 *image_out = (cairo_image_surface_t *) image;
238 *shm_info_out = shm_info;
241 return CAIRO_STATUS_SUCCESS;
244 static cairo_xcb_pixmap_t *
245 _pixmap_from_image (cairo_xcb_surface_t *target,
246 xcb_render_pictformat_t format,
247 cairo_image_surface_t *image,
248 cairo_xcb_shm_info_t *shm_info)
251 cairo_xcb_pixmap_t *pixmap;
253 pixmap = _cairo_xcb_pixmap_create (target,
256 if (unlikely (pixmap->base.status))
259 gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth);
261 if (shm_info != NULL) {
262 _cairo_xcb_connection_shm_put_image (target->connection,
264 image->width, image->height,
266 image->width, image->height,
274 /* Do we need to trim the image? */
275 len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width,
276 PIXMAN_FORMAT_BPP (image->pixman_format));
277 if (len == image->stride) {
278 _cairo_xcb_connection_put_image (target->connection,
280 image->width, image->height,
286 _cairo_xcb_connection_put_subimage (target->connection,
289 image->width, image->height,
290 PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
299 _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
304 static cairo_xcb_pixmap_t *
305 _render_to_pixmap (cairo_xcb_surface_t *target,
306 const cairo_pattern_t *pattern,
307 const cairo_rectangle_int_t *extents)
309 cairo_image_surface_t *image;
310 cairo_xcb_shm_info_t *shm_info;
311 cairo_pattern_union_t copy;
312 cairo_status_t status;
313 cairo_xcb_pixmap_t *pixmap;
315 status = _cairo_xcb_shm_image_create (target->screen->connection,
316 target->pixman_format,
317 extents->width, extents->height,
319 if (unlikely (status))
320 return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
322 _cairo_pattern_init_static_copy (©.base, pattern);
323 cairo_matrix_translate (©.base.matrix, -extents->x, -extents->y);
324 status = _cairo_surface_paint (&image->base,
325 CAIRO_OPERATOR_SOURCE,
328 if (unlikely (status)) {
329 cairo_surface_destroy (&image->base);
330 return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
333 pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info);
334 cairo_surface_destroy (&image->base);
336 if (unlikely (pixmap->base.status))
339 pixmap->x0 = -extents->x;
340 pixmap->y0 = -extents->y;
344 static cairo_xcb_pixmap_t *
345 _copy_to_pixmap (cairo_xcb_surface_t *source)
347 cairo_xcb_pixmap_t *pixmap;
349 /* If the source may be a window, we need to copy it and its children
350 * via a temporary pixmap so that we can IncludeInferiors on the source
351 * and use ClipByChildren on the destination.
353 if (source->owns_pixmap) {
354 pixmap = _cairo_xcb_pixmap_copy (source);
355 if (unlikely (pixmap->base.status))
361 pixmap = _cairo_xcb_pixmap_create (source,
364 if (unlikely (pixmap->base.status))
367 gc = _cairo_xcb_screen_get_gc (source->screen,
372 _cairo_xcb_connection_change_gc (pixmap->connection, gc,
373 XCB_GC_SUBWINDOW_MODE, values);
375 _cairo_xcb_connection_copy_area (pixmap->connection,
384 _cairo_xcb_connection_change_gc (pixmap->connection, gc,
385 XCB_GC_SUBWINDOW_MODE, values);
387 _cairo_xcb_screen_put_gc (source->screen,
394 static cairo_xcb_pixmap_t *
395 _cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target,
396 const cairo_surface_pattern_t *pattern,
397 const cairo_rectangle_int_t *extents,
400 cairo_surface_t *source;
401 cairo_xcb_pixmap_t *pixmap;
403 source = pattern->surface;
404 pixmap = (cairo_xcb_pixmap_t *)
405 _cairo_surface_has_snapshot (source, &_cairo_xcb_pixmap_backend);
406 if (pixmap != NULL && pixmap->screen == target->screen)
407 return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base);
409 if (source->type == CAIRO_SURFACE_TYPE_XCB &&
410 ((cairo_xcb_surface_t *) source)->screen == target->screen)
412 cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;
414 if (xcb_source->depth == target->depth)
415 pixmap = _copy_to_pixmap (xcb_source);
417 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
418 else if (source->type == CAIRO_SURFACE_TYPE_XLIB &&
419 ((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen)
421 cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;
423 if (xcb_source->depth == target->depth)
424 pixmap = _copy_to_pixmap (xcb_source);
428 if (pixmap == NULL) {
429 cairo_rectangle_int_t rect;
431 if (! _cairo_surface_get_extents (source, &rect)) {
433 rect.width = target->width;
434 rect.height = target->height;
437 pixmap = _render_to_pixmap (target, &pattern->base, &rect);
440 if (unlikely (pixmap->base.status))
443 _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
445 if (pattern->base.extend != CAIRO_EXTEND_NONE) {
446 if (extents->x < 0 || extents->y < 0 ||
447 extents->x + extents->width > pixmap->width ||
448 extents->y + extents->height > pixmap->height)
450 pixmap->repeat = TRUE;
460 static cairo_xcb_pixmap_t *
461 _cairo_xcb_pixmap_for_pattern (cairo_xcb_surface_t *target,
462 const cairo_pattern_t *pattern,
463 const cairo_rectangle_int_t *extents)
467 switch (pattern->type) {
468 case CAIRO_PATTERN_TYPE_SURFACE:
469 /* Core can only perform a native, unscaled blit, but can handle tiles */
470 if (_cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty)) {
471 switch (pattern->extend) {
472 case CAIRO_EXTEND_NONE:
473 case CAIRO_EXTEND_REPEAT:
474 return _cairo_xcb_surface_pixmap (target,
475 (cairo_surface_pattern_t *) pattern,
479 case CAIRO_EXTEND_PAD:
480 case CAIRO_EXTEND_REFLECT:
485 case CAIRO_PATTERN_TYPE_LINEAR:
486 case CAIRO_PATTERN_TYPE_RADIAL:
487 case CAIRO_PATTERN_TYPE_MESH:
488 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
489 return _render_to_pixmap (target, pattern, extents);
492 case CAIRO_PATTERN_TYPE_SOLID:
499 _cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst,
500 const cairo_pattern_t *src_pattern,
501 const cairo_rectangle_int_t *extents,
502 const cairo_boxes_t *boxes)
504 cairo_xcb_pixmap_t *src;
505 const struct _cairo_boxes_chunk *chunk;
507 cairo_status_t status;
509 status = _cairo_xcb_connection_acquire (dst->connection);
510 if (unlikely (status))
513 src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents);
514 status = src->base.status;
515 if (unlikely (status))
516 goto CLEANUP_CONNECTION;
518 assert (src->depth == dst->depth);
520 gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth);
526 XCB_GC_TILE_STIPPLE_ORIGIN_X |
527 XCB_GC_TILE_STIPPLE_ORIGIN_Y;
528 uint32_t values[] = {
529 XCB_FILL_STYLE_TILED,
531 - src->x0, - src->y0,
533 xcb_rectangle_t *xcb_rects;
535 _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values);
537 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
540 xcb_rects = (xcb_rectangle_t *) chunk->base;
542 for (i = 0; i < chunk->count; i++) {
543 int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
544 int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
545 int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
546 int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
550 xcb_rects[i].width = x2 - x1;
551 xcb_rects[i].height = y2 - y1;
553 _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
555 gc, chunk->count, xcb_rects);
559 _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values);
561 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
564 for (i = 0; i < chunk->count; i++) {
565 int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
566 int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
567 int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
568 int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
570 _cairo_xcb_connection_copy_area (dst->connection,
581 _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc);
582 cairo_surface_destroy (&src->base);
585 _cairo_xcb_connection_release (dst->connection);
591 _cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
592 const cairo_color_t *color,
593 cairo_boxes_t *boxes)
595 struct _cairo_boxes_chunk *chunk;
597 cairo_status_t status;
599 status = _cairo_xcb_connection_acquire (dst->connection);
600 if (unlikely (status))
603 gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
608 source = _dither_source (dst, color);
609 XSetTSOrigin (surface->dpy, gc, 0, 0);
610 XSetTile (surface->dpy, gc, source);
613 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
614 xcb_rectangle_t *xcb_rects;
617 xcb_rects = (xcb_rectangle_t *) chunk->base;
618 for (i = 0; i < chunk->count; i++) {
619 int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
620 int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
621 int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
622 int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
626 xcb_rects[i].width = x2 - x1;
627 xcb_rects[i].height = y2 - y1;
630 _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
632 chunk->count, xcb_rects);
635 _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
636 _cairo_xcb_connection_release (dst->connection);
638 return CAIRO_STATUS_SUCCESS;