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_surface_destroy (image);
180 _cairo_xcb_shm_info_destroy (shm_info);
184 status = _cairo_user_data_array_set_data (&image->user_data,
185 (const cairo_user_data_key_t *) connection,
187 (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
189 if (unlikely (status)) {
190 cairo_surface_destroy (image);
191 _cairo_xcb_shm_info_destroy (shm_info);
195 *image_out = (cairo_image_surface_t *) image;
196 *shm_info_out = shm_info;
197 return CAIRO_STATUS_SUCCESS;
200 static cairo_status_t
201 _cairo_xcb_shm_image_create_shm (cairo_xcb_connection_t *connection,
202 pixman_format_code_t pixman_format,
203 int width, int height,
204 cairo_image_surface_t **image_out,
205 cairo_xcb_shm_info_t **shm_info_out)
207 return CAIRO_INT_STATUS_UNSUPPORTED;
212 _cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
213 pixman_format_code_t pixman_format,
214 int width, int height,
215 cairo_image_surface_t **image_out,
216 cairo_xcb_shm_info_t **shm_info_out)
218 cairo_surface_t *image = NULL;
219 cairo_xcb_shm_info_t *shm_info = NULL;
220 cairo_status_t status;
222 status = _cairo_xcb_shm_image_create_shm (connection,
229 if (status != CAIRO_STATUS_SUCCESS) {
230 image = _cairo_image_surface_create_with_pixman_format (NULL,
234 status = image->status;
235 if (unlikely (status)) {
236 cairo_surface_destroy (image);
240 *image_out = (cairo_image_surface_t *) image;
241 *shm_info_out = shm_info;
244 return CAIRO_STATUS_SUCCESS;
247 static cairo_xcb_pixmap_t *
248 _pixmap_from_image (cairo_xcb_surface_t *target,
249 xcb_render_pictformat_t format,
250 cairo_image_surface_t *image,
251 cairo_xcb_shm_info_t *shm_info)
254 cairo_xcb_pixmap_t *pixmap;
256 pixmap = _cairo_xcb_pixmap_create (target,
259 if (unlikely (pixmap->base.status))
262 gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth);
264 if (shm_info != NULL) {
265 _cairo_xcb_connection_shm_put_image (target->connection,
267 image->width, image->height,
269 image->width, image->height,
277 /* Do we need to trim the image? */
278 len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width,
279 PIXMAN_FORMAT_BPP (image->pixman_format));
280 if (len == image->stride) {
281 _cairo_xcb_connection_put_image (target->connection,
283 image->width, image->height,
289 _cairo_xcb_connection_put_subimage (target->connection,
292 image->width, image->height,
293 PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
302 _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
307 static cairo_xcb_pixmap_t *
308 _render_to_pixmap (cairo_xcb_surface_t *target,
309 const cairo_pattern_t *pattern,
310 const cairo_rectangle_int_t *extents)
312 cairo_image_surface_t *image;
313 cairo_xcb_shm_info_t *shm_info;
314 cairo_pattern_union_t copy;
315 cairo_status_t status;
316 cairo_xcb_pixmap_t *pixmap;
318 status = _cairo_xcb_shm_image_create (target->screen->connection,
319 target->pixman_format,
320 extents->width, extents->height,
322 if (unlikely (status))
323 return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
325 _cairo_pattern_init_static_copy (©.base, pattern);
326 cairo_matrix_translate (©.base.matrix, -extents->x, -extents->y);
327 status = _cairo_surface_paint (&image->base,
328 CAIRO_OPERATOR_SOURCE,
331 if (unlikely (status)) {
332 cairo_surface_destroy (&image->base);
333 return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
336 pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info);
337 cairo_surface_destroy (&image->base);
339 if (unlikely (pixmap->base.status))
342 pixmap->x0 = -extents->x;
343 pixmap->y0 = -extents->y;
347 static cairo_xcb_pixmap_t *
348 _copy_to_pixmap (cairo_xcb_surface_t *source)
350 cairo_xcb_pixmap_t *pixmap;
352 /* If the source may be a window, we need to copy it and its children
353 * via a temporary pixmap so that we can IncludeInferiors on the source
354 * and use ClipByChildren on the destination.
356 if (source->owns_pixmap) {
357 pixmap = _cairo_xcb_pixmap_copy (source);
358 if (unlikely (pixmap->base.status))
364 pixmap = _cairo_xcb_pixmap_create (source,
367 if (unlikely (pixmap->base.status))
370 gc = _cairo_xcb_screen_get_gc (source->screen,
375 _cairo_xcb_connection_change_gc (pixmap->connection, gc,
376 XCB_GC_SUBWINDOW_MODE, values);
378 _cairo_xcb_connection_copy_area (pixmap->connection,
387 _cairo_xcb_connection_change_gc (pixmap->connection, gc,
388 XCB_GC_SUBWINDOW_MODE, values);
390 _cairo_xcb_screen_put_gc (source->screen,
397 static cairo_xcb_pixmap_t *
398 _cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target,
399 const cairo_surface_pattern_t *pattern,
400 const cairo_rectangle_int_t *extents,
403 cairo_surface_t *source;
404 cairo_xcb_pixmap_t *pixmap;
406 source = pattern->surface;
407 pixmap = (cairo_xcb_pixmap_t *)
408 _cairo_surface_has_snapshot (source, &_cairo_xcb_pixmap_backend);
409 if (pixmap != NULL && pixmap->screen == target->screen)
410 return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base);
412 if (source->type == CAIRO_SURFACE_TYPE_XCB &&
413 ((cairo_xcb_surface_t *) source)->screen == target->screen)
415 cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;
417 if (xcb_source->depth == target->depth)
418 pixmap = _copy_to_pixmap (xcb_source);
420 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
421 else if (source->type == CAIRO_SURFACE_TYPE_XLIB &&
422 ((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen)
424 cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;
426 if (xcb_source->depth == target->depth)
427 pixmap = _copy_to_pixmap (xcb_source);
431 if (pixmap == NULL) {
432 cairo_rectangle_int_t rect;
434 if (! _cairo_surface_get_extents (source, &rect)) {
436 rect.width = target->width;
437 rect.height = target->height;
440 pixmap = _render_to_pixmap (target, &pattern->base, &rect);
443 if (unlikely (pixmap->base.status))
446 _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
448 if (pattern->base.extend != CAIRO_EXTEND_NONE) {
449 if (extents->x < 0 || extents->y < 0 ||
450 extents->x + extents->width > pixmap->width ||
451 extents->y + extents->height > pixmap->height)
453 pixmap->repeat = TRUE;
463 static cairo_xcb_pixmap_t *
464 _cairo_xcb_pixmap_for_pattern (cairo_xcb_surface_t *target,
465 const cairo_pattern_t *pattern,
466 const cairo_rectangle_int_t *extents)
470 switch (pattern->type) {
471 case CAIRO_PATTERN_TYPE_SURFACE:
472 /* Core can only perform a native, unscaled blit, but can handle tiles */
473 if (_cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty)) {
474 switch (pattern->extend) {
475 case CAIRO_EXTEND_NONE:
476 case CAIRO_EXTEND_REPEAT:
477 return _cairo_xcb_surface_pixmap (target,
478 (cairo_surface_pattern_t *) pattern,
482 case CAIRO_EXTEND_PAD:
483 case CAIRO_EXTEND_REFLECT:
488 case CAIRO_PATTERN_TYPE_LINEAR:
489 case CAIRO_PATTERN_TYPE_RADIAL:
490 case CAIRO_PATTERN_TYPE_MESH:
491 case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
492 return _render_to_pixmap (target, pattern, extents);
495 case CAIRO_PATTERN_TYPE_SOLID:
502 _cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst,
503 const cairo_pattern_t *src_pattern,
504 const cairo_rectangle_int_t *extents,
505 const cairo_boxes_t *boxes)
507 cairo_xcb_pixmap_t *src;
508 const struct _cairo_boxes_chunk *chunk;
510 cairo_status_t status;
512 status = _cairo_xcb_connection_acquire (dst->connection);
513 if (unlikely (status))
516 src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents);
517 status = src->base.status;
518 if (unlikely (status))
519 goto CLEANUP_CONNECTION;
521 assert (src->depth == dst->depth);
523 gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth);
529 XCB_GC_TILE_STIPPLE_ORIGIN_X |
530 XCB_GC_TILE_STIPPLE_ORIGIN_Y;
531 uint32_t values[] = {
532 XCB_FILL_STYLE_TILED,
534 - src->x0, - src->y0,
536 xcb_rectangle_t *xcb_rects;
538 _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values);
540 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
543 xcb_rects = (xcb_rectangle_t *) chunk->base;
545 for (i = 0; i < chunk->count; i++) {
546 int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
547 int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
548 int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
549 int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
553 xcb_rects[i].width = x2 - x1;
554 xcb_rects[i].height = y2 - y1;
556 _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
558 gc, chunk->count, xcb_rects);
562 _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values);
564 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
567 for (i = 0; i < chunk->count; i++) {
568 int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
569 int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
570 int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
571 int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
573 _cairo_xcb_connection_copy_area (dst->connection,
584 _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc);
585 cairo_surface_destroy (&src->base);
588 _cairo_xcb_connection_release (dst->connection);
594 _cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
595 const cairo_color_t *color,
596 cairo_boxes_t *boxes)
598 struct _cairo_boxes_chunk *chunk;
600 cairo_status_t status;
602 status = _cairo_xcb_connection_acquire (dst->connection);
603 if (unlikely (status))
606 gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
611 source = _dither_source (dst, color);
612 XSetTSOrigin (surface->dpy, gc, 0, 0);
613 XSetTile (surface->dpy, gc, source);
616 for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
617 xcb_rectangle_t *xcb_rects;
620 xcb_rects = (xcb_rectangle_t *) chunk->base;
621 for (i = 0; i < chunk->count; i++) {
622 int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
623 int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
624 int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
625 int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
629 xcb_rects[i].width = x2 - x1;
630 xcb_rects[i].height = y2 - y1;
633 _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
635 chunk->count, xcb_rects);
638 _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
639 _cairo_xcb_connection_release (dst->connection);
641 return CAIRO_STATUS_SUCCESS;