Tizen 2.0 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_xcb_shm_info_destroy (shm_info);
180         return status;
181     }
182
183     status = _cairo_user_data_array_set_data (&image->user_data,
184                                               (const cairo_user_data_key_t *) connection,
185                                               shm_info,
186                                               (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
187
188     if (unlikely (status)) {
189         cairo_surface_destroy (image);
190         _cairo_xcb_shm_info_destroy (shm_info);
191         return status;
192     }
193
194     *image_out = (cairo_image_surface_t *) image;
195     *shm_info_out = shm_info;
196     return CAIRO_STATUS_SUCCESS;
197 }
198 #else
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)
205 {
206     return CAIRO_INT_STATUS_UNSUPPORTED;
207 }
208 #endif
209
210 cairo_status_t
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)
216 {
217     cairo_surface_t *image = NULL;
218     cairo_xcb_shm_info_t *shm_info = NULL;
219     cairo_status_t status;
220
221     status = _cairo_xcb_shm_image_create_shm (connection,
222                                               pixman_format,
223                                               width,
224                                               height,
225                                               image_out,
226                                               shm_info_out);
227
228     if (status != CAIRO_STATUS_SUCCESS) {
229         image = _cairo_image_surface_create_with_pixman_format (NULL,
230                                                                 pixman_format,
231                                                                 width, height,
232                                                                 0);
233         status = image->status;
234         if (unlikely (status))
235             return status;
236
237         *image_out = (cairo_image_surface_t *) image;
238         *shm_info_out = shm_info;
239     }
240
241     return CAIRO_STATUS_SUCCESS;
242 }
243
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)
249 {
250     xcb_gcontext_t gc;
251     cairo_xcb_pixmap_t *pixmap;
252
253     pixmap = _cairo_xcb_pixmap_create (target,
254                                        image->width,
255                                        image->height);
256     if (unlikely (pixmap->base.status))
257         return pixmap;
258
259     gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth);
260
261     if (shm_info != NULL) {
262         _cairo_xcb_connection_shm_put_image (target->connection,
263                                              pixmap->pixmap, gc,
264                                              image->width, image->height,
265                                              0, 0,
266                                              image->width, image->height,
267                                              0, 0,
268                                              image->depth,
269                                              shm_info->shm,
270                                              shm_info->offset);
271     } else {
272         int len;
273
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,
279                                              pixmap->pixmap, gc,
280                                              image->width, image->height,
281                                              0, 0,
282                                              image->depth,
283                                              image->stride,
284                                              image->data);
285         } else {
286             _cairo_xcb_connection_put_subimage (target->connection,
287                                                 pixmap->pixmap, gc,
288                                                 0, 0,
289                                                 image->width, image->height,
290                                                 PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
291                                                 image->stride,
292                                                 0, 0,
293                                                 image->depth,
294                                                 image->data);
295
296         }
297     }
298
299     _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
300
301     return pixmap;
302 }
303
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)
308 {
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;
314
315     status = _cairo_xcb_shm_image_create (target->screen->connection,
316                                           target->pixman_format,
317                                           extents->width, extents->height,
318                                           &image, &shm_info);
319     if (unlikely (status))
320         return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
321
322     _cairo_pattern_init_static_copy (&copy.base, pattern);
323     cairo_matrix_translate (&copy.base.matrix, -extents->x, -extents->y);
324     status = _cairo_surface_paint (&image->base,
325                                    CAIRO_OPERATOR_SOURCE,
326                                    &copy.base,
327                                    NULL);
328     if (unlikely (status)) {
329         cairo_surface_destroy (&image->base);
330         return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
331     }
332
333     pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info);
334     cairo_surface_destroy (&image->base);
335
336     if (unlikely (pixmap->base.status))
337         return pixmap;
338
339     pixmap->x0 = -extents->x;
340     pixmap->y0 = -extents->y;
341     return pixmap;
342 }
343
344 static cairo_xcb_pixmap_t *
345 _copy_to_pixmap (cairo_xcb_surface_t *source)
346 {
347     cairo_xcb_pixmap_t *pixmap;
348
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.
352      */
353     if (source->owns_pixmap) {
354         pixmap = _cairo_xcb_pixmap_copy (source);
355         if (unlikely (pixmap->base.status))
356             return pixmap;
357     } else {
358         uint32_t values[1];
359         xcb_gcontext_t gc;
360
361         pixmap = _cairo_xcb_pixmap_create (source,
362                                            source->width,
363                                            source->height);
364         if (unlikely (pixmap->base.status))
365             return pixmap;
366
367         gc = _cairo_xcb_screen_get_gc (source->screen,
368                                        pixmap->pixmap,
369                                        pixmap->depth);
370
371         values[0] = TRUE;
372         _cairo_xcb_connection_change_gc (pixmap->connection, gc,
373                                          XCB_GC_SUBWINDOW_MODE, values);
374
375         _cairo_xcb_connection_copy_area (pixmap->connection,
376                                          source->drawable,
377                                          pixmap->pixmap, gc,
378                                          0, 0,
379                                          0, 0,
380                                          source->width,
381                                          source->height);
382
383         values[0] = FALSE;
384         _cairo_xcb_connection_change_gc (pixmap->connection, gc,
385                                          XCB_GC_SUBWINDOW_MODE, values);
386
387         _cairo_xcb_screen_put_gc (source->screen,
388                                   pixmap->depth,
389                                   gc);
390     }
391
392     return pixmap;
393 }
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,
398                            int tx, int ty)
399 {
400     cairo_surface_t *source;
401     cairo_xcb_pixmap_t *pixmap;
402
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);
408
409     if (source->type == CAIRO_SURFACE_TYPE_XCB &&
410         ((cairo_xcb_surface_t *) source)->screen == target->screen)
411     {
412         cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;
413
414         if (xcb_source->depth == target->depth)
415             pixmap = _copy_to_pixmap (xcb_source);
416     }
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)
420     {
421         cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;
422
423         if (xcb_source->depth == target->depth)
424             pixmap = _copy_to_pixmap (xcb_source);
425     }
426 #endif
427
428     if (pixmap == NULL) {
429         cairo_rectangle_int_t rect;
430
431         if (! _cairo_surface_get_extents (source, &rect)) {
432             rect.x = rect.y = 0;
433             rect.width  = target->width;
434             rect.height = target->height;
435         }
436
437         pixmap = _render_to_pixmap (target, &pattern->base, &rect);
438     }
439
440     if (unlikely (pixmap->base.status))
441         return pixmap;
442
443     _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
444
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)
449         {
450             pixmap->repeat = TRUE;
451         }
452     }
453
454     pixmap->x0 += tx;
455     pixmap->y0 += ty;
456
457     return pixmap;
458 }
459
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)
464 {
465     int tx, ty;
466
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,
476                                                   extents, tx, ty);
477
478             default:
479             case CAIRO_EXTEND_PAD:
480             case CAIRO_EXTEND_REFLECT:
481                 break;
482             }
483         }
484         /* fallthrough */
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);
490
491     default:
492     case CAIRO_PATTERN_TYPE_SOLID:
493         ASSERT_NOT_REACHED;
494         return NULL;
495     }
496 }
497
498 cairo_status_t
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)
503 {
504     cairo_xcb_pixmap_t *src;
505     const struct _cairo_boxes_chunk *chunk;
506     xcb_gcontext_t gc;
507     cairo_status_t status;
508
509     status = _cairo_xcb_connection_acquire (dst->connection);
510     if (unlikely (status))
511         return status;
512
513     src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents);
514     status = src->base.status;
515     if (unlikely (status))
516         goto CLEANUP_CONNECTION;
517
518     assert (src->depth == dst->depth);
519
520     gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth);
521
522     if (src->repeat) {
523         uint32_t mask =
524             XCB_GC_FILL_STYLE |
525             XCB_GC_TILE |
526             XCB_GC_TILE_STIPPLE_ORIGIN_X |
527             XCB_GC_TILE_STIPPLE_ORIGIN_Y;
528         uint32_t values[] = {
529             XCB_FILL_STYLE_TILED,
530             src->pixmap,
531             - src->x0, - src->y0,
532         };
533         xcb_rectangle_t *xcb_rects;
534
535         _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values);
536
537         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
538             int i;
539
540             xcb_rects = (xcb_rectangle_t *) chunk->base;
541
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);
547
548                 xcb_rects[i].x = x1;
549                 xcb_rects[i].y = y1;
550                 xcb_rects[i].width  = x2 - x1;
551                 xcb_rects[i].height = y2 - y1;
552             }
553             _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
554                                                        dst->drawable,
555                                                        gc, chunk->count, xcb_rects);
556         }
557
558         values[0] = 0;
559         _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values);
560     } else {
561         for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
562             int i;
563
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);
569
570                 _cairo_xcb_connection_copy_area (dst->connection,
571                                                  src->pixmap,
572                                                  dst->drawable, gc,
573                                                  src->x0 + x1,
574                                                  src->y0 + y1,
575                                                  x1, y1,
576                                                  x2 - x2, y2 - x2);
577             }
578         }
579     }
580
581     _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc);
582     cairo_surface_destroy (&src->base);
583
584   CLEANUP_CONNECTION:
585     _cairo_xcb_connection_release (dst->connection);
586
587     return status;
588 }
589
590 cairo_status_t
591 _cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
592                                     const cairo_color_t *color,
593                                     cairo_boxes_t *boxes)
594 {
595     struct _cairo_boxes_chunk *chunk;
596     xcb_gcontext_t gc;
597     cairo_status_t status;
598
599     status = _cairo_xcb_connection_acquire (dst->connection);
600     if (unlikely (status))
601         return status;
602
603     gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
604
605 #if 0
606     xcb_pixmap_t source;
607
608     source = _dither_source (dst, color);
609     XSetTSOrigin (surface->dpy, gc, 0, 0);
610     XSetTile (surface->dpy, gc, source);
611 #endif
612
613     for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
614         xcb_rectangle_t *xcb_rects;
615         int i;
616
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);
623
624             xcb_rects[i].x = x1;
625             xcb_rects[i].y = y1;
626             xcb_rects[i].width  = x2 - x1;
627             xcb_rects[i].height = y2 - y1;
628         }
629
630         _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
631                                                    dst->drawable, gc,
632                                                    chunk->count, xcb_rects);
633     }
634
635     _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
636     _cairo_xcb_connection_release (dst->connection);
637
638     return CAIRO_STATUS_SUCCESS;
639 }