tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-xcb-surface-core.c
1 /* cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2009 Intel Corporation
4  *
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.
12  *
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
18  *
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/
23  *
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.
27  *
28  * Contributor(s):
29  *      Chris Wilson <chris@chris-wilson.co.uk>
30  */
31
32 #include "cairoint.h"
33
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"
38
39 /* XXX dithering */
40
41 typedef struct _cairo_xcb_pixmap {
42     cairo_surface_t base;
43
44     cairo_xcb_connection_t *connection;
45     cairo_xcb_screen_t *screen;
46
47     cairo_surface_t *owner;
48     xcb_pixmap_t pixmap;
49     int width;
50     int height;
51     int depth;
52     int x0, y0;
53     cairo_bool_t repeat;
54 } cairo_xcb_pixmap_t;
55
56 static cairo_status_t
57 _cairo_xcb_pixmap_finish (void *abstract_surface)
58 {
59     cairo_xcb_pixmap_t *surface = abstract_surface;
60     cairo_status_t status;
61
62     if (surface->owner != NULL) {
63         cairo_surface_destroy (surface->owner);
64     } else {
65         status = _cairo_xcb_connection_acquire (surface->connection);
66         if (unlikely (status))
67             return status;
68
69         _cairo_xcb_connection_free_pixmap (surface->connection,
70                                            surface->pixmap);
71         _cairo_xcb_connection_release (surface->connection);
72     }
73
74     return CAIRO_STATUS_SUCCESS;
75 }
76
77 static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = {
78     CAIRO_SURFACE_TYPE_XCB,
79     _cairo_xcb_pixmap_finish,
80 };
81
82 static cairo_xcb_pixmap_t *
83 _cairo_xcb_pixmap_create (cairo_xcb_surface_t *target,
84                           int width, int height)
85 {
86     cairo_xcb_pixmap_t *surface;
87
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));
92
93     _cairo_surface_init (&surface->base,
94                          &_cairo_xcb_pixmap_backend,
95                          NULL,
96                          target->base.content);
97
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;
106
107     surface->pixmap =
108         _cairo_xcb_connection_create_pixmap (surface->connection,
109                                              surface->depth,
110                                              target->drawable,
111                                              width, height);
112
113     return surface;
114 }
115
116 static cairo_xcb_pixmap_t *
117 _cairo_xcb_pixmap_copy (cairo_xcb_surface_t *target)
118 {
119     cairo_xcb_pixmap_t *surface;
120
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));
125
126     _cairo_surface_init (&surface->base,
127                          &_cairo_xcb_pixmap_backend,
128                          NULL,
129                          target->base.content);
130
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;
140
141     return surface;
142 }
143
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)
151 {
152     cairo_surface_t *image = NULL;
153     cairo_xcb_shm_info_t *shm_info = NULL;
154     cairo_status_t status;
155     size_t size, stride;
156
157     if (! (connection->flags & CAIRO_XCB_HAS_SHM))
158         return CAIRO_INT_STATUS_UNSUPPORTED;
159
160     if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
161         return CAIRO_INT_STATUS_UNSUPPORTED;
162
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;
167
168     status = _cairo_xcb_connection_allocate_shm_info (connection, size,
169                                                       FALSE, &shm_info);
170     if (unlikely (status))
171         return status;
172
173     image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
174                                                             pixman_format,
175                                                             width, height,
176                                                             stride);
177     status = image->status;
178     if (unlikely (status)) {
179         cairo_surface_destroy (image);
180         _cairo_xcb_shm_info_destroy (shm_info);
181         return status;
182     }
183
184     status = _cairo_user_data_array_set_data (&image->user_data,
185                                               (const cairo_user_data_key_t *) connection,
186                                               shm_info,
187                                               (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
188
189     if (unlikely (status)) {
190         cairo_surface_destroy (image);
191         _cairo_xcb_shm_info_destroy (shm_info);
192         return status;
193     }
194
195     *image_out = (cairo_image_surface_t *) image;
196     *shm_info_out = shm_info;
197     return CAIRO_STATUS_SUCCESS;
198 }
199 #else
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)
206 {
207     return CAIRO_INT_STATUS_UNSUPPORTED;
208 }
209 #endif
210
211 cairo_status_t
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)
217 {
218     cairo_surface_t *image = NULL;
219     cairo_xcb_shm_info_t *shm_info = NULL;
220     cairo_status_t status;
221
222     status = _cairo_xcb_shm_image_create_shm (connection,
223                                               pixman_format,
224                                               width,
225                                               height,
226                                               image_out,
227                                               shm_info_out);
228
229     if (status != CAIRO_STATUS_SUCCESS) {
230         image = _cairo_image_surface_create_with_pixman_format (NULL,
231                                                                 pixman_format,
232                                                                 width, height,
233                                                                 0);
234         status = image->status;
235         if (unlikely (status)) {
236             cairo_surface_destroy (image);
237             return status;
238         }
239
240         *image_out = (cairo_image_surface_t *) image;
241         *shm_info_out = shm_info;
242     }
243
244     return CAIRO_STATUS_SUCCESS;
245 }
246
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)
252 {
253     xcb_gcontext_t gc;
254     cairo_xcb_pixmap_t *pixmap;
255
256     pixmap = _cairo_xcb_pixmap_create (target,
257                                        image->width,
258                                        image->height);
259     if (unlikely (pixmap->base.status))
260         return pixmap;
261
262     gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth);
263
264     if (shm_info != NULL) {
265         _cairo_xcb_connection_shm_put_image (target->connection,
266                                              pixmap->pixmap, gc,
267                                              image->width, image->height,
268                                              0, 0,
269                                              image->width, image->height,
270                                              0, 0,
271                                              image->depth,
272                                              shm_info->shm,
273                                              shm_info->offset);
274     } else {
275         int len;
276
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,
282                                              pixmap->pixmap, gc,
283                                              image->width, image->height,
284                                              0, 0,
285                                              image->depth,
286                                              image->stride,
287                                              image->data);
288         } else {
289             _cairo_xcb_connection_put_subimage (target->connection,
290                                                 pixmap->pixmap, gc,
291                                                 0, 0,
292                                                 image->width, image->height,
293                                                 PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
294                                                 image->stride,
295                                                 0, 0,
296                                                 image->depth,
297                                                 image->data);
298
299         }
300     }
301
302     _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
303
304     return pixmap;
305 }
306
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)
311 {
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;
317
318     status = _cairo_xcb_shm_image_create (target->screen->connection,
319                                           target->pixman_format,
320                                           extents->width, extents->height,
321                                           &image, &shm_info);
322     if (unlikely (status))
323         return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
324
325     _cairo_pattern_init_static_copy (&copy.base, pattern);
326     cairo_matrix_translate (&copy.base.matrix, -extents->x, -extents->y);
327     status = _cairo_surface_paint (&image->base,
328                                    CAIRO_OPERATOR_SOURCE,
329                                    &copy.base,
330                                    NULL);
331     if (unlikely (status)) {
332         cairo_surface_destroy (&image->base);
333         return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
334     }
335
336     pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info);
337     cairo_surface_destroy (&image->base);
338
339     if (unlikely (pixmap->base.status))
340         return pixmap;
341
342     pixmap->x0 = -extents->x;
343     pixmap->y0 = -extents->y;
344     return pixmap;
345 }
346
347 static cairo_xcb_pixmap_t *
348 _copy_to_pixmap (cairo_xcb_surface_t *source)
349 {
350     cairo_xcb_pixmap_t *pixmap;
351
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.
355      */
356     if (source->owns_pixmap) {
357         pixmap = _cairo_xcb_pixmap_copy (source);
358         if (unlikely (pixmap->base.status))
359             return pixmap;
360     } else {
361         uint32_t values[1];
362         xcb_gcontext_t gc;
363
364         pixmap = _cairo_xcb_pixmap_create (source,
365                                            source->width,
366                                            source->height);
367         if (unlikely (pixmap->base.status))
368             return pixmap;
369
370         gc = _cairo_xcb_screen_get_gc (source->screen,
371                                        pixmap->pixmap,
372                                        pixmap->depth);
373
374         values[0] = TRUE;
375         _cairo_xcb_connection_change_gc (pixmap->connection, gc,
376                                          XCB_GC_SUBWINDOW_MODE, values);
377
378         _cairo_xcb_connection_copy_area (pixmap->connection,
379                                          source->drawable,
380                                          pixmap->pixmap, gc,
381                                          0, 0,
382                                          0, 0,
383                                          source->width,
384                                          source->height);
385
386         values[0] = FALSE;
387         _cairo_xcb_connection_change_gc (pixmap->connection, gc,
388                                          XCB_GC_SUBWINDOW_MODE, values);
389
390         _cairo_xcb_screen_put_gc (source->screen,
391                                   pixmap->depth,
392                                   gc);
393     }
394
395     return pixmap;
396 }
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,
401                            int tx, int ty)
402 {
403     cairo_surface_t *source;
404     cairo_xcb_pixmap_t *pixmap;
405
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);
411
412     if (source->type == CAIRO_SURFACE_TYPE_XCB &&
413         ((cairo_xcb_surface_t *) source)->screen == target->screen)
414     {
415         cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;
416
417         if (xcb_source->depth == target->depth)
418             pixmap = _copy_to_pixmap (xcb_source);
419     }
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)
423     {
424         cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;
425
426         if (xcb_source->depth == target->depth)
427             pixmap = _copy_to_pixmap (xcb_source);
428     }
429 #endif
430
431     if (pixmap == NULL) {
432         cairo_rectangle_int_t rect;
433
434         if (! _cairo_surface_get_extents (source, &rect)) {
435             rect.x = rect.y = 0;
436             rect.width  = target->width;
437             rect.height = target->height;
438         }
439
440         pixmap = _render_to_pixmap (target, &pattern->base, &rect);
441     }
442
443     if (unlikely (pixmap->base.status))
444         return pixmap;
445
446     _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
447
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)
452         {
453             pixmap->repeat = TRUE;
454         }
455     }
456
457     pixmap->x0 += tx;
458     pixmap->y0 += ty;
459
460     return pixmap;
461 }
462
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)
467 {
468     int tx, ty;
469
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,
479                                                   extents, tx, ty);
480
481             default:
482             case CAIRO_EXTEND_PAD:
483             case CAIRO_EXTEND_REFLECT:
484                 break;
485             }
486         }
487         /* fallthrough */
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);
493
494     default:
495     case CAIRO_PATTERN_TYPE_SOLID:
496         ASSERT_NOT_REACHED;
497         return NULL;
498     }
499 }
500
501 cairo_status_t
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)
506 {
507     cairo_xcb_pixmap_t *src;
508     const struct _cairo_boxes_chunk *chunk;
509     xcb_gcontext_t gc;
510     cairo_status_t status;
511
512     status = _cairo_xcb_connection_acquire (dst->connection);
513     if (unlikely (status))
514         return status;
515
516     src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents);
517     status = src->base.status;
518     if (unlikely (status))
519         goto CLEANUP_CONNECTION;
520
521     assert (src->depth == dst->depth);
522
523     gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth);
524
525     if (src->repeat) {
526         uint32_t mask =
527             XCB_GC_FILL_STYLE |
528             XCB_GC_TILE |
529             XCB_GC_TILE_STIPPLE_ORIGIN_X |
530             XCB_GC_TILE_STIPPLE_ORIGIN_Y;
531         uint32_t values[] = {
532             XCB_FILL_STYLE_TILED,
533             src->pixmap,
534             - src->x0, - src->y0,
535         };
536         xcb_rectangle_t *xcb_rects;
537
538         _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values);
539
540         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
541             int i;
542
543             xcb_rects = (xcb_rectangle_t *) chunk->base;
544
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);
550
551                 xcb_rects[i].x = x1;
552                 xcb_rects[i].y = y1;
553                 xcb_rects[i].width  = x2 - x1;
554                 xcb_rects[i].height = y2 - y1;
555             }
556             _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
557                                                        dst->drawable,
558                                                        gc, chunk->count, xcb_rects);
559         }
560
561         values[0] = 0;
562         _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values);
563     } else {
564         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
565             int i;
566
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);
572
573                 _cairo_xcb_connection_copy_area (dst->connection,
574                                                  src->pixmap,
575                                                  dst->drawable, gc,
576                                                  src->x0 + x1,
577                                                  src->y0 + y1,
578                                                  x1, y1,
579                                                  x2 - x2, y2 - x2);
580             }
581         }
582     }
583
584     _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc);
585     cairo_surface_destroy (&src->base);
586
587   CLEANUP_CONNECTION:
588     _cairo_xcb_connection_release (dst->connection);
589
590     return status;
591 }
592
593 cairo_status_t
594 _cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
595                                     const cairo_color_t *color,
596                                     cairo_boxes_t *boxes)
597 {
598     struct _cairo_boxes_chunk *chunk;
599     xcb_gcontext_t gc;
600     cairo_status_t status;
601
602     status = _cairo_xcb_connection_acquire (dst->connection);
603     if (unlikely (status))
604         return status;
605
606     gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
607
608 #if 0
609     xcb_pixmap_t source;
610
611     source = _dither_source (dst, color);
612     XSetTSOrigin (surface->dpy, gc, 0, 0);
613     XSetTile (surface->dpy, gc, source);
614 #endif
615
616     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
617         xcb_rectangle_t *xcb_rects;
618         int i;
619
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);
626
627             xcb_rects[i].x = x1;
628             xcb_rects[i].y = y1;
629             xcb_rects[i].width  = x2 - x1;
630             xcb_rects[i].height = y2 - y1;
631         }
632
633         _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
634                                                    dst->drawable, gc,
635                                                    chunk->count, xcb_rects);
636     }
637
638     _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
639     _cairo_xcb_connection_release (dst->connection);
640
641     return CAIRO_STATUS_SUCCESS;
642 }