Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* cairo - a vector graphics library with display and print output |
2 | * |
||
3 | * Copyright © 2002 University of Southern California |
||
4 | * Copyright © 2009 Intel Corporation |
||
5 | * |
||
6 | * This library is free software; you can redistribute it and/or |
||
7 | * modify it either under the terms of the GNU Lesser General Public |
||
8 | * License version 2.1 as published by the Free Software Foundation |
||
9 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
||
10 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
||
11 | * notice, a recipient may use your version of this file under either |
||
12 | * the MPL or the LGPL. |
||
13 | * |
||
14 | * You should have received a copy of the LGPL along with this library |
||
15 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
||
16 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
||
17 | * You should have received a copy of the MPL along with this library |
||
18 | * in the file COPYING-MPL-1.1 |
||
19 | * |
||
20 | * The contents of this file are subject to the Mozilla Public License |
||
21 | * Version 1.1 (the "License"); you may not use this file except in |
||
22 | * compliance with the License. You may obtain a copy of the License at |
||
23 | * http://www.mozilla.org/MPL/ |
||
24 | * |
||
25 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
||
26 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
||
27 | * the specific language governing rights and limitations. |
||
28 | * |
||
29 | * The Original Code is the cairo graphics library. |
||
30 | * |
||
31 | * The Initial Developer of the Original Code is University of Southern |
||
32 | * California. |
||
33 | * |
||
34 | * Contributor(s): |
||
35 | * Behdad Esfahbod |
||
36 | * Carl D. Worth |
||
37 | * Chris Wilson |
||
38 | * Karl Tomlinson |
||
39 | */ |
||
40 | |||
41 | #include "cairoint.h" |
||
42 | |||
43 | #include "cairo-xcb.h" |
||
44 | #include "cairo-xcb-private.h" |
||
45 | |||
46 | #include "cairo-composite-rectangles-private.h" |
||
47 | #include "cairo-default-context-private.h" |
||
48 | #include "cairo-image-surface-inline.h" |
||
49 | #include "cairo-list-inline.h" |
||
50 | #include "cairo-surface-backend-private.h" |
||
51 | #include "cairo-compositor-private.h" |
||
52 | |||
53 | #if CAIRO_HAS_XLIB_XCB_FUNCTIONS |
||
54 | slim_hidden_proto (cairo_xcb_surface_create); |
||
55 | slim_hidden_proto (cairo_xcb_surface_create_for_bitmap); |
||
56 | slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format); |
||
57 | #endif |
||
58 | |||
59 | /** |
||
60 | * SECTION:cairo-xcb |
||
61 | * @Title: XCB Surfaces |
||
62 | * @Short_Description: X Window System rendering using the XCB library |
||
63 | * @See_Also: #cairo_surface_t |
||
64 | * |
||
65 | * The XCB surface is used to render cairo graphics to X Window System |
||
66 | * windows and pixmaps using the XCB library. |
||
67 | * |
||
68 | * Note that the XCB surface automatically takes advantage of the X render |
||
69 | * extension if it is available. |
||
70 | **/ |
||
71 | |||
72 | /** |
||
73 | * CAIRO_HAS_XCB_SURFACE: |
||
74 | * |
||
75 | * Defined if the xcb surface backend is available. |
||
76 | * This macro can be used to conditionally compile backend-specific code. |
||
77 | * |
||
78 | * Since: 1.12 |
||
79 | **/ |
||
80 | |||
81 | cairo_surface_t * |
||
82 | _cairo_xcb_surface_create_similar (void *abstract_other, |
||
83 | cairo_content_t content, |
||
84 | int width, |
||
85 | int height) |
||
86 | { |
||
87 | cairo_xcb_surface_t *other = abstract_other; |
||
88 | cairo_xcb_surface_t *surface; |
||
89 | cairo_xcb_connection_t *connection; |
||
90 | xcb_pixmap_t pixmap; |
||
91 | cairo_status_t status; |
||
92 | |||
93 | if (unlikely(width > XLIB_COORD_MAX || |
||
94 | height > XLIB_COORD_MAX || |
||
95 | width <= 0 || |
||
96 | height <= 0)) |
||
97 | return cairo_image_surface_create (_cairo_format_from_content (content), |
||
98 | width, height); |
||
99 | |||
100 | if ((other->connection->flags & CAIRO_XCB_HAS_RENDER) == 0) |
||
101 | return _cairo_xcb_surface_create_similar_image (other, |
||
102 | _cairo_format_from_content (content), |
||
103 | width, height); |
||
104 | |||
105 | connection = other->connection; |
||
106 | status = _cairo_xcb_connection_acquire (connection); |
||
107 | if (unlikely (status)) |
||
108 | return _cairo_surface_create_in_error (status); |
||
109 | |||
110 | if (content == other->base.content) { |
||
111 | pixmap = _cairo_xcb_connection_create_pixmap (connection, |
||
112 | other->depth, |
||
113 | other->drawable, |
||
114 | width, height); |
||
115 | |||
116 | surface = (cairo_xcb_surface_t *) |
||
117 | _cairo_xcb_surface_create_internal (other->screen, |
||
118 | pixmap, TRUE, |
||
119 | other->pixman_format, |
||
120 | other->xrender_format, |
||
121 | width, height); |
||
122 | } else { |
||
123 | cairo_format_t format; |
||
124 | pixman_format_code_t pixman_format; |
||
125 | |||
126 | /* XXX find a compatible xrender format */ |
||
127 | switch (content) { |
||
128 | case CAIRO_CONTENT_ALPHA: |
||
129 | pixman_format = PIXMAN_a8; |
||
130 | format = CAIRO_FORMAT_A8; |
||
131 | break; |
||
132 | case CAIRO_CONTENT_COLOR: |
||
133 | pixman_format = PIXMAN_x8r8g8b8; |
||
134 | format = CAIRO_FORMAT_RGB24; |
||
135 | break; |
||
136 | default: |
||
137 | ASSERT_NOT_REACHED; |
||
138 | case CAIRO_CONTENT_COLOR_ALPHA: |
||
139 | pixman_format = PIXMAN_a8r8g8b8; |
||
140 | format = CAIRO_FORMAT_ARGB32; |
||
141 | break; |
||
142 | } |
||
143 | |||
144 | pixmap = _cairo_xcb_connection_create_pixmap (connection, |
||
145 | PIXMAN_FORMAT_DEPTH (pixman_format), |
||
146 | other->drawable, |
||
147 | width, height); |
||
148 | |||
149 | surface = (cairo_xcb_surface_t *) |
||
150 | _cairo_xcb_surface_create_internal (other->screen, |
||
151 | pixmap, TRUE, |
||
152 | pixman_format, |
||
153 | connection->standard_formats[format], |
||
154 | width, height); |
||
155 | } |
||
156 | |||
157 | if (unlikely (surface->base.status)) |
||
158 | _cairo_xcb_connection_free_pixmap (connection, pixmap); |
||
159 | |||
160 | _cairo_xcb_connection_release (connection); |
||
161 | |||
162 | return &surface->base; |
||
163 | } |
||
164 | |||
165 | cairo_surface_t * |
||
166 | _cairo_xcb_surface_create_similar_image (void *abstract_other, |
||
167 | cairo_format_t format, |
||
168 | int width, |
||
169 | int height) |
||
170 | { |
||
171 | cairo_xcb_surface_t *other = abstract_other; |
||
172 | cairo_xcb_connection_t *connection = other->connection; |
||
173 | |||
174 | cairo_xcb_shm_info_t *shm_info; |
||
175 | cairo_image_surface_t *image; |
||
176 | cairo_status_t status; |
||
177 | pixman_format_code_t pixman_format; |
||
178 | |||
179 | if (unlikely(width > XLIB_COORD_MAX || |
||
180 | height > XLIB_COORD_MAX || |
||
181 | width <= 0 || |
||
182 | height <= 0)) |
||
183 | return NULL; |
||
184 | |||
185 | pixman_format = _cairo_format_to_pixman_format_code (format); |
||
186 | |||
187 | status = _cairo_xcb_shm_image_create (connection, pixman_format, |
||
188 | width, height, &image, |
||
189 | &shm_info); |
||
190 | if (unlikely (status)) |
||
191 | return _cairo_surface_create_in_error (status); |
||
192 | |||
193 | if (! image->base.is_clear) { |
||
194 | memset (image->data, 0, image->stride * image->height); |
||
195 | image->base.is_clear = TRUE; |
||
196 | } |
||
197 | |||
198 | return &image->base; |
||
199 | } |
||
200 | |||
201 | static cairo_status_t |
||
202 | _cairo_xcb_surface_finish (void *abstract_surface) |
||
203 | { |
||
204 | cairo_xcb_surface_t *surface = abstract_surface; |
||
205 | cairo_status_t status; |
||
206 | |||
207 | if (surface->fallback != NULL) { |
||
208 | cairo_surface_finish (&surface->fallback->base); |
||
209 | cairo_surface_destroy (&surface->fallback->base); |
||
210 | } |
||
211 | _cairo_boxes_fini (&surface->fallback_damage); |
||
212 | |||
213 | cairo_list_del (&surface->link); |
||
214 | |||
215 | status = _cairo_xcb_connection_acquire (surface->connection); |
||
216 | if (status == CAIRO_STATUS_SUCCESS) { |
||
217 | if (surface->picture != XCB_NONE) { |
||
218 | _cairo_xcb_connection_render_free_picture (surface->connection, |
||
219 | surface->picture); |
||
220 | } |
||
221 | |||
222 | if (surface->owns_pixmap) |
||
223 | _cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable); |
||
224 | _cairo_xcb_connection_release (surface->connection); |
||
225 | } |
||
226 | |||
227 | _cairo_xcb_connection_destroy (surface->connection); |
||
228 | |||
229 | return status; |
||
230 | } |
||
231 | |||
232 | static void |
||
233 | _destroy_image (pixman_image_t *image, void *data) |
||
234 | { |
||
235 | free (data); |
||
236 | } |
||
237 | |||
238 | #if CAIRO_HAS_XCB_SHM_FUNCTIONS |
||
239 | static cairo_surface_t * |
||
240 | _cairo_xcb_surface_create_shm_image (cairo_xcb_connection_t *connection, |
||
241 | pixman_format_code_t pixman_format, |
||
242 | int width, int height, |
||
243 | cairo_bool_t might_reuse, |
||
244 | cairo_xcb_shm_info_t **shm_info_out) |
||
245 | { |
||
246 | cairo_surface_t *image; |
||
247 | cairo_xcb_shm_info_t *shm_info; |
||
248 | cairo_int_status_t status; |
||
249 | size_t stride; |
||
250 | |||
251 | *shm_info_out = NULL; |
||
252 | |||
253 | stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, |
||
254 | PIXMAN_FORMAT_BPP (pixman_format)); |
||
255 | status = _cairo_xcb_connection_allocate_shm_info (connection, |
||
256 | stride * height, |
||
257 | might_reuse, |
||
258 | &shm_info); |
||
259 | if (unlikely (status)) { |
||
260 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) |
||
261 | return NULL; |
||
262 | |||
263 | return _cairo_surface_create_in_error (status); |
||
264 | } |
||
265 | |||
266 | image = _cairo_image_surface_create_with_pixman_format (shm_info->mem, |
||
267 | pixman_format, |
||
268 | width, height, |
||
269 | stride); |
||
270 | if (unlikely (image->status)) { |
||
271 | _cairo_xcb_shm_info_destroy (shm_info); |
||
272 | return image; |
||
273 | } |
||
274 | |||
275 | status = _cairo_user_data_array_set_data (&image->user_data, |
||
276 | (const cairo_user_data_key_t *) connection, |
||
277 | shm_info, |
||
278 | (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy); |
||
279 | if (unlikely (status)) { |
||
280 | cairo_surface_destroy (image); |
||
281 | _cairo_xcb_shm_info_destroy (shm_info); |
||
282 | return _cairo_surface_create_in_error (status); |
||
283 | } |
||
284 | |||
285 | *shm_info_out = shm_info; |
||
286 | return image; |
||
287 | } |
||
288 | #endif |
||
289 | |||
290 | static cairo_surface_t * |
||
291 | _get_shm_image (cairo_xcb_surface_t *surface, |
||
292 | int x, int y, |
||
293 | int width, int height) |
||
294 | { |
||
295 | #if CAIRO_HAS_XCB_SHM_FUNCTIONS |
||
296 | cairo_xcb_shm_info_t *shm_info; |
||
297 | cairo_surface_t *image; |
||
298 | cairo_status_t status; |
||
299 | |||
300 | if ((surface->connection->flags & CAIRO_XCB_HAS_SHM) == 0) |
||
301 | return NULL; |
||
302 | |||
303 | image = _cairo_xcb_surface_create_shm_image (surface->connection, |
||
304 | surface->pixman_format, |
||
305 | width, height, |
||
306 | TRUE, |
||
307 | &shm_info); |
||
308 | if (unlikely (image == NULL || image->status)) |
||
309 | goto done; |
||
310 | |||
311 | status = _cairo_xcb_connection_shm_get_image (surface->connection, |
||
312 | surface->drawable, |
||
313 | x, y, |
||
314 | width, height, |
||
315 | shm_info->shm, |
||
316 | shm_info->offset); |
||
317 | if (unlikely (status)) { |
||
318 | cairo_surface_destroy (image); |
||
319 | image = _cairo_surface_create_in_error (status); |
||
320 | } |
||
321 | |||
322 | done: |
||
323 | return image; |
||
324 | #else |
||
325 | return NULL; |
||
326 | #endif |
||
327 | } |
||
328 | |||
329 | static cairo_surface_t * |
||
330 | _get_image (cairo_xcb_surface_t *surface, |
||
331 | cairo_bool_t use_shm, |
||
332 | int x, int y, |
||
333 | int width, int height) |
||
334 | { |
||
335 | cairo_surface_t *image; |
||
336 | cairo_xcb_connection_t *connection; |
||
337 | xcb_get_image_reply_t *reply; |
||
338 | cairo_int_status_t status; |
||
339 | |||
340 | assert (surface->fallback == NULL); |
||
341 | assert (x >= 0); |
||
342 | assert (y >= 0); |
||
343 | assert (x + width <= surface->width); |
||
344 | assert (y + height <= surface->height); |
||
345 | |||
346 | if (surface->deferred_clear) { |
||
347 | image = |
||
348 | _cairo_image_surface_create_with_pixman_format (NULL, |
||
349 | surface->pixman_format, |
||
350 | width, height, |
||
351 | 0); |
||
352 | if (surface->deferred_clear_color.alpha_short > 0x00ff) { |
||
353 | cairo_solid_pattern_t solid; |
||
354 | |||
355 | _cairo_pattern_init_solid (&solid, &surface->deferred_clear_color); |
||
356 | status = _cairo_surface_paint (image, |
||
357 | CAIRO_OPERATOR_SOURCE, |
||
358 | &solid.base, |
||
359 | NULL); |
||
360 | if (unlikely (status)) { |
||
361 | cairo_surface_destroy (image); |
||
362 | image = _cairo_surface_create_in_error (status); |
||
363 | } |
||
364 | } |
||
365 | return image; |
||
366 | } |
||
367 | |||
368 | connection = surface->connection; |
||
369 | |||
370 | status = _cairo_xcb_connection_acquire (connection); |
||
371 | if (unlikely (status)) |
||
372 | return _cairo_surface_create_in_error (status); |
||
373 | |||
374 | if (use_shm) { |
||
375 | image = _get_shm_image (surface, x, y, width, height); |
||
376 | if (image) { |
||
377 | if (image->status == CAIRO_STATUS_SUCCESS) { |
||
378 | _cairo_xcb_connection_release (connection); |
||
379 | return image; |
||
380 | } |
||
381 | cairo_surface_destroy (image); |
||
382 | } |
||
383 | } |
||
384 | |||
385 | status = _cairo_xcb_connection_get_image (connection, |
||
386 | surface->drawable, |
||
387 | x, y, |
||
388 | width, height, |
||
389 | &reply); |
||
390 | if (unlikely (status)) |
||
391 | goto FAIL; |
||
392 | |||
393 | if (reply == NULL && ! surface->owns_pixmap) { |
||
394 | /* xcb_get_image_t from a window is dangerous because it can |
||
395 | * produce errors if the window is unmapped or partially |
||
396 | * outside the screen. We could check for errors and |
||
397 | * retry, but to keep things simple, we just create a |
||
398 | * temporary pixmap |
||
399 | * |
||
400 | * If we hit this fallback too often, we should remember so and |
||
401 | * skip the round-trip from the above GetImage request, |
||
402 | * similar to what cairo-xlib does. |
||
403 | */ |
||
404 | xcb_pixmap_t pixmap; |
||
405 | xcb_gcontext_t gc; |
||
406 | |||
407 | gc = _cairo_xcb_screen_get_gc (surface->screen, |
||
408 | surface->drawable, |
||
409 | surface->depth); |
||
410 | pixmap = _cairo_xcb_connection_create_pixmap (connection, |
||
411 | surface->depth, |
||
412 | surface->drawable, |
||
413 | width, height); |
||
414 | |||
415 | /* XXX IncludeInferiors? */ |
||
416 | _cairo_xcb_connection_copy_area (connection, |
||
417 | surface->drawable, |
||
418 | pixmap, gc, |
||
419 | x, y, |
||
420 | 0, 0, |
||
421 | width, height); |
||
422 | |||
423 | _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); |
||
424 | |||
425 | status = _cairo_xcb_connection_get_image (connection, |
||
426 | pixmap, |
||
427 | 0, 0, |
||
428 | width, height, |
||
429 | &reply); |
||
430 | _cairo_xcb_connection_free_pixmap (connection, pixmap); |
||
431 | |||
432 | if (unlikely (status)) |
||
433 | goto FAIL; |
||
434 | } |
||
435 | |||
436 | if (unlikely (reply == NULL)) { |
||
437 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
438 | goto FAIL; |
||
439 | } |
||
440 | |||
441 | /* XXX byte swap */ |
||
442 | /* XXX format conversion */ |
||
443 | assert (reply->depth == surface->depth); |
||
444 | |||
445 | image = _cairo_image_surface_create_with_pixman_format |
||
446 | (xcb_get_image_data (reply), |
||
447 | surface->pixman_format, |
||
448 | width, height, |
||
449 | CAIRO_STRIDE_FOR_WIDTH_BPP (width, |
||
450 | PIXMAN_FORMAT_BPP (surface->pixman_format))); |
||
451 | status = image->status; |
||
452 | if (unlikely (status)) { |
||
453 | free (reply); |
||
454 | goto FAIL; |
||
455 | } |
||
456 | |||
457 | /* XXX */ |
||
458 | pixman_image_set_destroy_function (((cairo_image_surface_t *)image)->pixman_image, _destroy_image, reply); |
||
459 | |||
460 | _cairo_xcb_connection_release (connection); |
||
461 | |||
462 | return image; |
||
463 | |||
464 | FAIL: |
||
465 | _cairo_xcb_connection_release (connection); |
||
466 | return _cairo_surface_create_in_error (status); |
||
467 | } |
||
468 | |||
469 | static cairo_surface_t * |
||
470 | _cairo_xcb_surface_source (void *abstract_surface, |
||
471 | cairo_rectangle_int_t *extents) |
||
472 | { |
||
473 | cairo_xcb_surface_t *surface = abstract_surface; |
||
474 | |||
475 | if (extents) { |
||
476 | extents->x = extents->y = 0; |
||
477 | extents->width = surface->width; |
||
478 | extents->height = surface->height; |
||
479 | } |
||
480 | |||
481 | return &surface->base; |
||
482 | } |
||
483 | |||
484 | static cairo_status_t |
||
485 | _cairo_xcb_surface_acquire_source_image (void *abstract_surface, |
||
486 | cairo_image_surface_t **image_out, |
||
487 | void **image_extra) |
||
488 | { |
||
489 | cairo_xcb_surface_t *surface = abstract_surface; |
||
490 | cairo_surface_t *image; |
||
491 | |||
492 | if (surface->fallback != NULL) { |
||
493 | image = cairo_surface_reference (&surface->fallback->base); |
||
494 | goto DONE; |
||
495 | } |
||
496 | |||
497 | image = _cairo_surface_has_snapshot (&surface->base, |
||
498 | &_cairo_image_surface_backend); |
||
499 | if (image != NULL) { |
||
500 | image = cairo_surface_reference (image); |
||
501 | goto DONE; |
||
502 | } |
||
503 | |||
504 | image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height); |
||
505 | if (unlikely (image->status)) |
||
506 | return image->status; |
||
507 | |||
508 | _cairo_surface_attach_snapshot (&surface->base, image, NULL); |
||
509 | |||
510 | DONE: |
||
511 | *image_out = (cairo_image_surface_t *) image; |
||
512 | *image_extra = NULL; |
||
513 | return CAIRO_STATUS_SUCCESS; |
||
514 | } |
||
515 | |||
516 | static void |
||
517 | _cairo_xcb_surface_release_source_image (void *abstract_surface, |
||
518 | cairo_image_surface_t *image, |
||
519 | void *image_extra) |
||
520 | { |
||
521 | cairo_surface_destroy (&image->base); |
||
522 | } |
||
523 | |||
524 | cairo_bool_t |
||
525 | _cairo_xcb_surface_get_extents (void *abstract_surface, |
||
526 | cairo_rectangle_int_t *extents) |
||
527 | { |
||
528 | cairo_xcb_surface_t *surface = abstract_surface; |
||
529 | |||
530 | extents->x = extents->y = 0; |
||
531 | extents->width = surface->width; |
||
532 | extents->height = surface->height; |
||
533 | return TRUE; |
||
534 | } |
||
535 | |||
536 | static void |
||
537 | _cairo_xcb_surface_get_font_options (void *abstract_surface, |
||
538 | cairo_font_options_t *options) |
||
539 | { |
||
540 | /* XXX copy from xlib */ |
||
541 | _cairo_font_options_init_default (options); |
||
542 | _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); |
||
543 | } |
||
544 | |||
545 | static cairo_status_t |
||
546 | _put_shm_image (cairo_xcb_surface_t *surface, |
||
547 | xcb_gcontext_t gc, |
||
548 | cairo_image_surface_t *image) |
||
549 | { |
||
550 | #if CAIRO_HAS_XCB_SHM_FUNCTIONS |
||
551 | cairo_xcb_shm_info_t *shm_info; |
||
552 | |||
553 | shm_info = _cairo_user_data_array_get_data (&image->base.user_data, |
||
554 | (const cairo_user_data_key_t *) surface->connection); |
||
555 | if (shm_info == NULL) |
||
556 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
557 | |||
558 | _cairo_xcb_connection_shm_put_image (surface->connection, |
||
559 | surface->drawable, |
||
560 | gc, |
||
561 | surface->width, surface->height, |
||
562 | 0, 0, |
||
563 | image->width, image->height, |
||
564 | image->base.device_transform_inverse.x0, |
||
565 | image->base.device_transform_inverse.y0, |
||
566 | image->depth, |
||
567 | shm_info->shm, |
||
568 | shm_info->offset); |
||
569 | |||
570 | return CAIRO_STATUS_SUCCESS; |
||
571 | #else |
||
572 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
573 | #endif |
||
574 | } |
||
575 | |||
576 | static cairo_status_t |
||
577 | _put_image (cairo_xcb_surface_t *surface, |
||
578 | cairo_image_surface_t *image) |
||
579 | { |
||
580 | cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; |
||
581 | |||
582 | /* XXX track damaged region? */ |
||
583 | |||
584 | status = _cairo_xcb_connection_acquire (surface->connection); |
||
585 | if (unlikely (status)) |
||
586 | return status; |
||
587 | |||
588 | if (image->pixman_format == surface->pixman_format) { |
||
589 | xcb_gcontext_t gc; |
||
590 | |||
591 | assert (image->depth == surface->depth); |
||
592 | assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); |
||
593 | |||
594 | gc = _cairo_xcb_screen_get_gc (surface->screen, |
||
595 | surface->drawable, |
||
596 | surface->depth); |
||
597 | |||
598 | status = _put_shm_image (surface, gc, image); |
||
599 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
600 | _cairo_xcb_connection_put_image (surface->connection, |
||
601 | surface->drawable, gc, |
||
602 | image->width, image->height, |
||
603 | image->base.device_transform_inverse.x0, |
||
604 | image->base.device_transform_inverse.y0, |
||
605 | image->depth, |
||
606 | image->stride, |
||
607 | image->data); |
||
608 | status = CAIRO_STATUS_SUCCESS; |
||
609 | } |
||
610 | |||
611 | _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); |
||
612 | } else { |
||
613 | ASSERT_NOT_REACHED; |
||
614 | } |
||
615 | |||
616 | _cairo_xcb_connection_release (surface->connection); |
||
617 | return status; |
||
618 | } |
||
619 | |||
620 | static cairo_int_status_t |
||
621 | _put_shm_image_boxes (cairo_xcb_surface_t *surface, |
||
622 | cairo_image_surface_t *image, |
||
623 | xcb_gcontext_t gc, |
||
624 | cairo_boxes_t *boxes) |
||
625 | { |
||
626 | #if CAIRO_HAS_XCB_SHM_FUNCTIONS |
||
627 | cairo_xcb_shm_info_t *shm_info; |
||
628 | |||
629 | shm_info = _cairo_user_data_array_get_data (&image->base.user_data, |
||
630 | (const cairo_user_data_key_t *) surface->connection); |
||
631 | if (shm_info != NULL) { |
||
632 | struct _cairo_boxes_chunk *chunk; |
||
633 | |||
634 | for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { |
||
635 | int i; |
||
636 | |||
637 | for (i = 0; i < chunk->count; i++) { |
||
638 | cairo_box_t *b = &chunk->base[i]; |
||
639 | int x = _cairo_fixed_integer_part (b->p1.x); |
||
640 | int y = _cairo_fixed_integer_part (b->p1.y); |
||
641 | int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x); |
||
642 | int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y); |
||
643 | |||
644 | _cairo_xcb_connection_shm_put_image (surface->connection, |
||
645 | surface->drawable, |
||
646 | gc, |
||
647 | surface->width, surface->height, |
||
648 | x, y, |
||
649 | width, height, |
||
650 | x, y, |
||
651 | image->depth, |
||
652 | shm_info->shm, |
||
653 | shm_info->offset); |
||
654 | } |
||
655 | } |
||
656 | } |
||
657 | |||
658 | return CAIRO_INT_STATUS_SUCCESS; |
||
659 | #endif |
||
660 | |||
661 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
662 | } |
||
663 | |||
664 | static cairo_status_t |
||
665 | _put_image_boxes (cairo_xcb_surface_t *surface, |
||
666 | cairo_image_surface_t *image, |
||
667 | cairo_boxes_t *boxes) |
||
668 | { |
||
669 | cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; |
||
670 | xcb_gcontext_t gc; |
||
671 | |||
672 | if (boxes->num_boxes == 0) |
||
673 | return CAIRO_STATUS_SUCCESS; |
||
674 | |||
675 | /* XXX track damaged region? */ |
||
676 | |||
677 | status = _cairo_xcb_connection_acquire (surface->connection); |
||
678 | if (unlikely (status)) |
||
679 | return status; |
||
680 | |||
681 | assert (image->pixman_format == surface->pixman_format); |
||
682 | assert (image->depth == surface->depth); |
||
683 | assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); |
||
684 | |||
685 | gc = _cairo_xcb_screen_get_gc (surface->screen, |
||
686 | surface->drawable, |
||
687 | surface->depth); |
||
688 | |||
689 | status = _put_shm_image_boxes (surface, image, gc, boxes); |
||
690 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
691 | struct _cairo_boxes_chunk *chunk; |
||
692 | |||
693 | for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { |
||
694 | int i; |
||
695 | |||
696 | for (i = 0; i < chunk->count; i++) { |
||
697 | cairo_box_t *b = &chunk->base[i]; |
||
698 | int x = _cairo_fixed_integer_part (b->p1.x); |
||
699 | int y = _cairo_fixed_integer_part (b->p1.y); |
||
700 | int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x); |
||
701 | int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y); |
||
702 | _cairo_xcb_connection_put_image (surface->connection, |
||
703 | surface->drawable, gc, |
||
704 | width, height, |
||
705 | x, y, |
||
706 | image->depth, |
||
707 | image->stride, |
||
708 | image->data + |
||
709 | x * PIXMAN_FORMAT_BPP (image->pixman_format) / 8 + |
||
710 | y * image->stride); |
||
711 | |||
712 | } |
||
713 | } |
||
714 | status = CAIRO_STATUS_SUCCESS; |
||
715 | } |
||
716 | |||
717 | _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); |
||
718 | _cairo_xcb_connection_release (surface->connection); |
||
719 | return status; |
||
720 | } |
||
721 | |||
722 | static cairo_status_t |
||
723 | _cairo_xcb_surface_flush (void *abstract_surface, |
||
724 | unsigned flags) |
||
725 | { |
||
726 | cairo_xcb_surface_t *surface = abstract_surface; |
||
727 | cairo_status_t status; |
||
728 | |||
729 | if (flags) |
||
730 | return CAIRO_STATUS_SUCCESS; |
||
731 | |||
732 | if (likely (surface->fallback == NULL)) { |
||
733 | status = CAIRO_STATUS_SUCCESS; |
||
734 | if (! surface->base.finished && surface->deferred_clear) |
||
735 | status = _cairo_xcb_surface_clear (surface); |
||
736 | |||
737 | return status; |
||
738 | } |
||
739 | |||
740 | status = surface->base.status; |
||
741 | if (status == CAIRO_STATUS_SUCCESS && |
||
742 | (! surface->base._finishing || ! surface->owns_pixmap)) { |
||
743 | status = cairo_surface_status (&surface->fallback->base); |
||
744 | |||
745 | if (status == CAIRO_STATUS_SUCCESS) |
||
746 | status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage, |
||
747 | CAIRO_FILL_RULE_WINDING, |
||
748 | &surface->fallback_damage); |
||
749 | |||
750 | if (status == CAIRO_STATUS_SUCCESS) |
||
751 | status = _put_image_boxes (surface, |
||
752 | surface->fallback, |
||
753 | &surface->fallback_damage); |
||
754 | |||
755 | if (status == CAIRO_STATUS_SUCCESS && ! surface->base._finishing) { |
||
756 | _cairo_surface_attach_snapshot (&surface->base, |
||
757 | &surface->fallback->base, |
||
758 | cairo_surface_finish); |
||
759 | } |
||
760 | } |
||
761 | |||
762 | _cairo_boxes_clear (&surface->fallback_damage); |
||
763 | cairo_surface_destroy (&surface->fallback->base); |
||
764 | surface->fallback = NULL; |
||
765 | |||
766 | return status; |
||
767 | } |
||
768 | |||
769 | static cairo_image_surface_t * |
||
770 | _cairo_xcb_surface_map_to_image (void *abstract_surface, |
||
771 | const cairo_rectangle_int_t *extents) |
||
772 | { |
||
773 | cairo_xcb_surface_t *surface = abstract_surface; |
||
774 | cairo_surface_t *image; |
||
775 | cairo_status_t status; |
||
776 | |||
777 | if (surface->fallback) |
||
778 | return _cairo_surface_map_to_image (&surface->fallback->base, extents); |
||
779 | |||
780 | image = _get_image (surface, TRUE, |
||
781 | extents->x, extents->y, |
||
782 | extents->width, extents->height); |
||
783 | status = cairo_surface_status (image); |
||
784 | if (unlikely (status)) { |
||
785 | cairo_surface_destroy(image); |
||
786 | return _cairo_image_surface_create_in_error (status); |
||
787 | } |
||
788 | |||
789 | /* Do we have a deferred clear and this image surface does NOT cover the |
||
790 | * whole xcb surface? Have to apply the clear in that case, else |
||
791 | * uploading the image will handle the problem for us. |
||
792 | */ |
||
793 | if (surface->deferred_clear && |
||
794 | ! (extents->width == surface->width && |
||
795 | extents->height == surface->height)) { |
||
796 | status = _cairo_xcb_surface_clear (surface); |
||
797 | if (unlikely (status)) { |
||
798 | cairo_surface_destroy(image); |
||
799 | return _cairo_image_surface_create_in_error (status); |
||
800 | } |
||
801 | } |
||
802 | surface->deferred_clear = FALSE; |
||
803 | |||
804 | cairo_surface_set_device_offset (image, -extents->x, -extents->y); |
||
805 | return (cairo_image_surface_t *) image; |
||
806 | } |
||
807 | |||
808 | static cairo_int_status_t |
||
809 | _cairo_xcb_surface_unmap (void *abstract_surface, |
||
810 | cairo_image_surface_t *image) |
||
811 | { |
||
812 | cairo_xcb_surface_t *surface = abstract_surface; |
||
813 | cairo_int_status_t status; |
||
814 | |||
815 | if (surface->fallback) |
||
816 | return _cairo_surface_unmap_image (&surface->fallback->base, image); |
||
817 | |||
818 | status = _put_image (abstract_surface, image); |
||
819 | |||
820 | cairo_surface_finish (&image->base); |
||
821 | cairo_surface_destroy (&image->base); |
||
822 | |||
823 | return status; |
||
824 | } |
||
825 | |||
826 | static cairo_surface_t * |
||
827 | _cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface, |
||
828 | cairo_composite_rectangles_t *composite) |
||
829 | { |
||
830 | cairo_image_surface_t *image; |
||
831 | cairo_status_t status; |
||
832 | |||
833 | status = _cairo_composite_rectangles_add_to_damage (composite, |
||
834 | &surface->fallback_damage); |
||
835 | if (unlikely (status)) |
||
836 | return _cairo_surface_create_in_error (status); |
||
837 | |||
838 | if (surface->fallback) |
||
839 | return &surface->fallback->base; |
||
840 | |||
841 | image = (cairo_image_surface_t *) |
||
842 | _get_image (surface, TRUE, 0, 0, surface->width, surface->height); |
||
843 | |||
844 | /* If there was a deferred clear, _get_image applied it */ |
||
845 | if (image->base.status == CAIRO_STATUS_SUCCESS) { |
||
846 | surface->deferred_clear = FALSE; |
||
847 | |||
848 | surface->fallback = image; |
||
849 | } |
||
850 | |||
851 | return &surface->fallback->base; |
||
852 | } |
||
853 | |||
854 | static cairo_int_status_t |
||
855 | _cairo_xcb_fallback_compositor_paint (const cairo_compositor_t *compositor, |
||
856 | cairo_composite_rectangles_t *extents) |
||
857 | { |
||
858 | cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; |
||
859 | cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); |
||
860 | |||
861 | return _cairo_surface_paint (fallback, extents->op, |
||
862 | &extents->source_pattern.base, |
||
863 | extents->clip); |
||
864 | } |
||
865 | |||
866 | static cairo_int_status_t |
||
867 | _cairo_xcb_fallback_compositor_mask (const cairo_compositor_t *compositor, |
||
868 | cairo_composite_rectangles_t *extents) |
||
869 | { |
||
870 | cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; |
||
871 | cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); |
||
872 | |||
873 | return _cairo_surface_mask (fallback, extents->op, |
||
874 | &extents->source_pattern.base, |
||
875 | &extents->mask_pattern.base, |
||
876 | extents->clip); |
||
877 | } |
||
878 | |||
879 | static cairo_int_status_t |
||
880 | _cairo_xcb_fallback_compositor_stroke (const cairo_compositor_t *compositor, |
||
881 | cairo_composite_rectangles_t *extents, |
||
882 | const cairo_path_fixed_t *path, |
||
883 | const cairo_stroke_style_t *style, |
||
884 | const cairo_matrix_t *ctm, |
||
885 | const cairo_matrix_t *ctm_inverse, |
||
886 | double tolerance, |
||
887 | cairo_antialias_t antialias) |
||
888 | { |
||
889 | cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; |
||
890 | cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); |
||
891 | |||
892 | return _cairo_surface_stroke (fallback, extents->op, |
||
893 | &extents->source_pattern.base, |
||
894 | path, style, ctm, ctm_inverse, |
||
895 | tolerance, antialias, |
||
896 | extents->clip); |
||
897 | } |
||
898 | |||
899 | static cairo_int_status_t |
||
900 | _cairo_xcb_fallback_compositor_fill (const cairo_compositor_t *compositor, |
||
901 | cairo_composite_rectangles_t *extents, |
||
902 | const cairo_path_fixed_t *path, |
||
903 | cairo_fill_rule_t fill_rule, |
||
904 | double tolerance, |
||
905 | cairo_antialias_t antialias) |
||
906 | { |
||
907 | cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; |
||
908 | cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); |
||
909 | |||
910 | return _cairo_surface_fill (fallback, extents->op, |
||
911 | &extents->source_pattern.base, |
||
912 | path, fill_rule, tolerance, |
||
913 | antialias, extents->clip); |
||
914 | } |
||
915 | |||
916 | static cairo_int_status_t |
||
917 | _cairo_xcb_fallback_compositor_glyphs (const cairo_compositor_t *compositor, |
||
918 | cairo_composite_rectangles_t *extents, |
||
919 | cairo_scaled_font_t *scaled_font, |
||
920 | cairo_glyph_t *glyphs, |
||
921 | int num_glyphs, |
||
922 | cairo_bool_t overlap) |
||
923 | { |
||
924 | cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; |
||
925 | cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); |
||
926 | |||
927 | return _cairo_surface_show_text_glyphs (fallback, extents->op, |
||
928 | &extents->source_pattern.base, |
||
929 | NULL, 0, glyphs, num_glyphs, |
||
930 | NULL, 0, 0, |
||
931 | scaled_font, extents->clip); |
||
932 | } |
||
933 | |||
934 | static const cairo_compositor_t _cairo_xcb_fallback_compositor = { |
||
935 | &__cairo_no_compositor, |
||
936 | |||
937 | _cairo_xcb_fallback_compositor_paint, |
||
938 | _cairo_xcb_fallback_compositor_mask, |
||
939 | _cairo_xcb_fallback_compositor_stroke, |
||
940 | _cairo_xcb_fallback_compositor_fill, |
||
941 | _cairo_xcb_fallback_compositor_glyphs, |
||
942 | }; |
||
943 | |||
944 | static const cairo_compositor_t _cairo_xcb_render_compositor = { |
||
945 | &_cairo_xcb_fallback_compositor, |
||
946 | |||
947 | _cairo_xcb_render_compositor_paint, |
||
948 | _cairo_xcb_render_compositor_mask, |
||
949 | _cairo_xcb_render_compositor_stroke, |
||
950 | _cairo_xcb_render_compositor_fill, |
||
951 | _cairo_xcb_render_compositor_glyphs, |
||
952 | }; |
||
953 | |||
954 | static inline const cairo_compositor_t * |
||
955 | get_compositor (cairo_surface_t **s) |
||
956 | { |
||
957 | cairo_xcb_surface_t *surface = (cairo_xcb_surface_t * )*s; |
||
958 | if (surface->fallback) { |
||
959 | *s = &surface->fallback->base; |
||
960 | return ((cairo_image_surface_t *) *s)->compositor; |
||
961 | } |
||
962 | |||
963 | return &_cairo_xcb_render_compositor; |
||
964 | } |
||
965 | |||
966 | static cairo_int_status_t |
||
967 | _cairo_xcb_surface_paint (void *abstract_surface, |
||
968 | cairo_operator_t op, |
||
969 | const cairo_pattern_t *source, |
||
970 | const cairo_clip_t *clip) |
||
971 | { |
||
972 | cairo_surface_t *surface = abstract_surface; |
||
973 | const cairo_compositor_t *compositor = get_compositor (&surface); |
||
974 | return _cairo_compositor_paint (compositor, surface, op, source, clip); |
||
975 | } |
||
976 | |||
977 | static cairo_int_status_t |
||
978 | _cairo_xcb_surface_mask (void *abstract_surface, |
||
979 | cairo_operator_t op, |
||
980 | const cairo_pattern_t *source, |
||
981 | const cairo_pattern_t *mask, |
||
982 | const cairo_clip_t *clip) |
||
983 | { |
||
984 | cairo_surface_t *surface = abstract_surface; |
||
985 | const cairo_compositor_t *compositor = get_compositor (&surface); |
||
986 | return _cairo_compositor_mask (compositor, surface, op, source, mask, clip); |
||
987 | } |
||
988 | |||
989 | static cairo_int_status_t |
||
990 | _cairo_xcb_surface_stroke (void *abstract_surface, |
||
991 | cairo_operator_t op, |
||
992 | const cairo_pattern_t *source, |
||
993 | const cairo_path_fixed_t *path, |
||
994 | const cairo_stroke_style_t *style, |
||
995 | const cairo_matrix_t *ctm, |
||
996 | const cairo_matrix_t *ctm_inverse, |
||
997 | double tolerance, |
||
998 | cairo_antialias_t antialias, |
||
999 | const cairo_clip_t *clip) |
||
1000 | { |
||
1001 | cairo_surface_t *surface = abstract_surface; |
||
1002 | const cairo_compositor_t *compositor = get_compositor (&surface); |
||
1003 | return _cairo_compositor_stroke (compositor, surface, op, source, |
||
1004 | path, style, ctm, ctm_inverse, |
||
1005 | tolerance, antialias, clip); |
||
1006 | } |
||
1007 | |||
1008 | static cairo_int_status_t |
||
1009 | _cairo_xcb_surface_fill (void *abstract_surface, |
||
1010 | cairo_operator_t op, |
||
1011 | const cairo_pattern_t *source, |
||
1012 | const cairo_path_fixed_t*path, |
||
1013 | cairo_fill_rule_t fill_rule, |
||
1014 | double tolerance, |
||
1015 | cairo_antialias_t antialias, |
||
1016 | const cairo_clip_t *clip) |
||
1017 | { |
||
1018 | cairo_surface_t *surface = abstract_surface; |
||
1019 | const cairo_compositor_t *compositor = get_compositor (&surface); |
||
1020 | return _cairo_compositor_fill (compositor, surface, op, |
||
1021 | source, path, fill_rule, |
||
1022 | tolerance, antialias, clip); |
||
1023 | } |
||
1024 | |||
1025 | static cairo_int_status_t |
||
1026 | _cairo_xcb_surface_glyphs (void *abstract_surface, |
||
1027 | cairo_operator_t op, |
||
1028 | const cairo_pattern_t *source, |
||
1029 | cairo_glyph_t *glyphs, |
||
1030 | int num_glyphs, |
||
1031 | cairo_scaled_font_t *scaled_font, |
||
1032 | const cairo_clip_t *clip) |
||
1033 | { |
||
1034 | cairo_surface_t *surface = abstract_surface; |
||
1035 | const cairo_compositor_t *compositor = get_compositor (&surface); |
||
1036 | return _cairo_compositor_glyphs (compositor, surface, op, |
||
1037 | source, glyphs, num_glyphs, |
||
1038 | scaled_font, clip); |
||
1039 | } |
||
1040 | |||
1041 | const cairo_surface_backend_t _cairo_xcb_surface_backend = { |
||
1042 | CAIRO_SURFACE_TYPE_XCB, |
||
1043 | _cairo_xcb_surface_finish, |
||
1044 | _cairo_default_context_create, |
||
1045 | |||
1046 | _cairo_xcb_surface_create_similar, |
||
1047 | _cairo_xcb_surface_create_similar_image, |
||
1048 | _cairo_xcb_surface_map_to_image, |
||
1049 | _cairo_xcb_surface_unmap, |
||
1050 | |||
1051 | _cairo_xcb_surface_source, |
||
1052 | _cairo_xcb_surface_acquire_source_image, |
||
1053 | _cairo_xcb_surface_release_source_image, |
||
1054 | NULL, /* snapshot */ |
||
1055 | |||
1056 | |||
1057 | NULL, /* copy_page */ |
||
1058 | NULL, /* show_page */ |
||
1059 | |||
1060 | _cairo_xcb_surface_get_extents, |
||
1061 | _cairo_xcb_surface_get_font_options, |
||
1062 | |||
1063 | _cairo_xcb_surface_flush, |
||
1064 | NULL, |
||
1065 | |||
1066 | _cairo_xcb_surface_paint, |
||
1067 | _cairo_xcb_surface_mask, |
||
1068 | _cairo_xcb_surface_stroke, |
||
1069 | _cairo_xcb_surface_fill, |
||
1070 | NULL, /* fill-stroke */ |
||
1071 | _cairo_xcb_surface_glyphs, |
||
1072 | }; |
||
1073 | |||
1074 | cairo_surface_t * |
||
1075 | _cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen, |
||
1076 | xcb_drawable_t drawable, |
||
1077 | cairo_bool_t owns_pixmap, |
||
1078 | pixman_format_code_t pixman_format, |
||
1079 | xcb_render_pictformat_t xrender_format, |
||
1080 | int width, |
||
1081 | int height) |
||
1082 | { |
||
1083 | cairo_xcb_surface_t *surface; |
||
1084 | |||
1085 | surface = malloc (sizeof (cairo_xcb_surface_t)); |
||
1086 | if (unlikely (surface == NULL)) |
||
1087 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
1088 | |||
1089 | _cairo_surface_init (&surface->base, |
||
1090 | &_cairo_xcb_surface_backend, |
||
1091 | &screen->connection->device, |
||
1092 | _cairo_content_from_pixman_format (pixman_format)); |
||
1093 | |||
1094 | surface->connection = _cairo_xcb_connection_reference (screen->connection); |
||
1095 | surface->screen = screen; |
||
1096 | cairo_list_add (&surface->link, &screen->surfaces); |
||
1097 | |||
1098 | surface->drawable = drawable; |
||
1099 | surface->owns_pixmap = owns_pixmap; |
||
1100 | |||
1101 | surface->deferred_clear = FALSE; |
||
1102 | surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT; |
||
1103 | |||
1104 | surface->width = width; |
||
1105 | surface->height = height; |
||
1106 | surface->depth = PIXMAN_FORMAT_DEPTH (pixman_format); |
||
1107 | |||
1108 | surface->picture = XCB_NONE; |
||
1109 | if (screen->connection->force_precision != -1) |
||
1110 | surface->precision = screen->connection->force_precision; |
||
1111 | else |
||
1112 | surface->precision = XCB_RENDER_POLY_MODE_IMPRECISE; |
||
1113 | |||
1114 | surface->pixman_format = pixman_format; |
||
1115 | surface->xrender_format = xrender_format; |
||
1116 | |||
1117 | surface->fallback = NULL; |
||
1118 | _cairo_boxes_init (&surface->fallback_damage); |
||
1119 | |||
1120 | return &surface->base; |
||
1121 | } |
||
1122 | |||
1123 | static xcb_screen_t * |
||
1124 | _cairo_xcb_screen_from_visual (xcb_connection_t *connection, |
||
1125 | xcb_visualtype_t *visual, |
||
1126 | int *depth) |
||
1127 | { |
||
1128 | xcb_depth_iterator_t d; |
||
1129 | xcb_screen_iterator_t s; |
||
1130 | |||
1131 | s = xcb_setup_roots_iterator (xcb_get_setup (connection)); |
||
1132 | for (; s.rem; xcb_screen_next (&s)) { |
||
1133 | if (s.data->root_visual == visual->visual_id) { |
||
1134 | *depth = s.data->root_depth; |
||
1135 | return s.data; |
||
1136 | } |
||
1137 | |||
1138 | d = xcb_screen_allowed_depths_iterator(s.data); |
||
1139 | for (; d.rem; xcb_depth_next (&d)) { |
||
1140 | xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data); |
||
1141 | |||
1142 | for (; v.rem; xcb_visualtype_next (&v)) { |
||
1143 | if (v.data->visual_id == visual->visual_id) { |
||
1144 | *depth = d.data->depth; |
||
1145 | return s.data; |
||
1146 | } |
||
1147 | } |
||
1148 | } |
||
1149 | } |
||
1150 | |||
1151 | return NULL; |
||
1152 | } |
||
1153 | |||
1154 | /** |
||
1155 | * cairo_xcb_surface_create: |
||
1156 | * @connection: an XCB connection |
||
1157 | * @drawable: an XCB drawable |
||
1158 | * @visual: the visual to use for drawing to @drawable. The depth |
||
1159 | * of the visual must match the depth of the drawable. |
||
1160 | * Currently, only TrueColor visuals are fully supported. |
||
1161 | * @width: the current width of @drawable |
||
1162 | * @height: the current height of @drawable |
||
1163 | * |
||
1164 | * Creates an XCB surface that draws to the given drawable. |
||
1165 | * The way that colors are represented in the drawable is specified |
||
1166 | * by the provided visual. |
||
1167 | * |
||
1168 | * Note: If @drawable is a Window, then the function |
||
1169 | * cairo_xcb_surface_set_size() must be called whenever the size of the |
||
1170 | * window changes. |
||
1171 | * |
||
1172 | * When @drawable is a Window containing child windows then drawing to |
||
1173 | * the created surface will be clipped by those child windows. When |
||
1174 | * the created surface is used as a source, the contents of the |
||
1175 | * children will be included. |
||
1176 | * |
||
1177 | * Return value: a pointer to the newly created surface. The caller |
||
1178 | * owns the surface and should call cairo_surface_destroy() when done |
||
1179 | * with it. |
||
1180 | * |
||
1181 | * This function always returns a valid pointer, but it will return a |
||
1182 | * pointer to a "nil" surface if an error such as out of memory |
||
1183 | * occurs. You can use cairo_surface_status() to check for this. |
||
1184 | * |
||
1185 | * Since: 1.12 |
||
1186 | **/ |
||
1187 | cairo_surface_t * |
||
1188 | cairo_xcb_surface_create (xcb_connection_t *connection, |
||
1189 | xcb_drawable_t drawable, |
||
1190 | xcb_visualtype_t *visual, |
||
1191 | int width, |
||
1192 | int height) |
||
1193 | { |
||
1194 | cairo_xcb_screen_t *screen; |
||
1195 | xcb_screen_t *xcb_screen; |
||
1196 | cairo_format_masks_t image_masks; |
||
1197 | pixman_format_code_t pixman_format; |
||
1198 | xcb_render_pictformat_t xrender_format; |
||
1199 | int depth; |
||
1200 | |||
1201 | if (xcb_connection_has_error (connection)) |
||
1202 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); |
||
1203 | |||
1204 | if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)) |
||
1205 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1206 | if (unlikely (width <= 0 || height <= 0)) |
||
1207 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1208 | |||
1209 | xcb_screen = _cairo_xcb_screen_from_visual (connection, visual, &depth); |
||
1210 | if (unlikely (xcb_screen == NULL)) |
||
1211 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); |
||
1212 | |||
1213 | image_masks.alpha_mask = 0; |
||
1214 | image_masks.red_mask = visual->red_mask; |
||
1215 | image_masks.green_mask = visual->green_mask; |
||
1216 | image_masks.blue_mask = visual->blue_mask; |
||
1217 | if (depth == 32) /* XXX visuals have no alpha! */ |
||
1218 | image_masks.alpha_mask = |
||
1219 | 0xffffffff & ~(visual->red_mask | visual->green_mask | visual->blue_mask); |
||
1220 | if (depth > 16) |
||
1221 | image_masks.bpp = 32; |
||
1222 | else if (depth > 8) |
||
1223 | image_masks.bpp = 16; |
||
1224 | else if (depth > 1) |
||
1225 | image_masks.bpp = 8; |
||
1226 | else |
||
1227 | image_masks.bpp = 1; |
||
1228 | |||
1229 | if (! _pixman_format_from_masks (&image_masks, &pixman_format)) |
||
1230 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); |
||
1231 | |||
1232 | screen = _cairo_xcb_screen_get (connection, xcb_screen); |
||
1233 | if (unlikely (screen == NULL)) |
||
1234 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
1235 | |||
1236 | xrender_format = |
||
1237 | _cairo_xcb_connection_get_xrender_format_for_visual (screen->connection, |
||
1238 | visual->visual_id); |
||
1239 | |||
1240 | return _cairo_xcb_surface_create_internal (screen, drawable, FALSE, |
||
1241 | pixman_format, |
||
1242 | xrender_format, |
||
1243 | width, height); |
||
1244 | } |
||
1245 | #if CAIRO_HAS_XLIB_XCB_FUNCTIONS |
||
1246 | slim_hidden_def (cairo_xcb_surface_create); |
||
1247 | #endif |
||
1248 | |||
1249 | /** |
||
1250 | * cairo_xcb_surface_create_for_bitmap: |
||
1251 | * @connection: an XCB connection |
||
1252 | * @screen: the XCB screen associated with @bitmap |
||
1253 | * @bitmap: an XCB drawable (a Pixmap with depth 1) |
||
1254 | * @width: the current width of @bitmap |
||
1255 | * @height: the current height of @bitmap |
||
1256 | * |
||
1257 | * Creates an XCB surface that draws to the given bitmap. |
||
1258 | * This will be drawn to as a %CAIRO_FORMAT_A1 object. |
||
1259 | * |
||
1260 | * Return value: a pointer to the newly created surface. The caller |
||
1261 | * owns the surface and should call cairo_surface_destroy() when done |
||
1262 | * with it. |
||
1263 | * |
||
1264 | * This function always returns a valid pointer, but it will return a |
||
1265 | * pointer to a "nil" surface if an error such as out of memory |
||
1266 | * occurs. You can use cairo_surface_status() to check for this. |
||
1267 | * |
||
1268 | * Since: 1.12 |
||
1269 | **/ |
||
1270 | cairo_surface_t * |
||
1271 | cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection, |
||
1272 | xcb_screen_t *screen, |
||
1273 | xcb_pixmap_t bitmap, |
||
1274 | int width, |
||
1275 | int height) |
||
1276 | { |
||
1277 | cairo_xcb_screen_t *cairo_xcb_screen; |
||
1278 | |||
1279 | if (xcb_connection_has_error (connection)) |
||
1280 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); |
||
1281 | |||
1282 | if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) |
||
1283 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1284 | if (unlikely (width <= 0 || height <= 0)) |
||
1285 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1286 | |||
1287 | cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen); |
||
1288 | if (unlikely (cairo_xcb_screen == NULL)) |
||
1289 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
1290 | |||
1291 | return _cairo_xcb_surface_create_internal (cairo_xcb_screen, bitmap, FALSE, |
||
1292 | PIXMAN_a1, |
||
1293 | cairo_xcb_screen->connection->standard_formats[CAIRO_FORMAT_A1], |
||
1294 | width, height); |
||
1295 | } |
||
1296 | #if CAIRO_HAS_XLIB_XCB_FUNCTIONS |
||
1297 | slim_hidden_def (cairo_xcb_surface_create_for_bitmap); |
||
1298 | #endif |
||
1299 | |||
1300 | /** |
||
1301 | * cairo_xcb_surface_create_with_xrender_format: |
||
1302 | * @connection: an XCB connection |
||
1303 | * @drawable: an XCB drawable |
||
1304 | * @screen: the XCB screen associated with @drawable |
||
1305 | * @format: the picture format to use for drawing to @drawable. The |
||
1306 | * depth of @format mush match the depth of the drawable. |
||
1307 | * @width: the current width of @drawable |
||
1308 | * @height: the current height of @drawable |
||
1309 | * |
||
1310 | * Creates an XCB surface that draws to the given drawable. |
||
1311 | * The way that colors are represented in the drawable is specified |
||
1312 | * by the provided picture format. |
||
1313 | * |
||
1314 | * Note: If @drawable is a Window, then the function |
||
1315 | * cairo_xcb_surface_set_size() must be called whenever the size of the |
||
1316 | * window changes. |
||
1317 | * |
||
1318 | * When @drawable is a Window containing child windows then drawing to |
||
1319 | * the created surface will be clipped by those child windows. When |
||
1320 | * the created surface is used as a source, the contents of the |
||
1321 | * children will be included. |
||
1322 | * |
||
1323 | * Return value: a pointer to the newly created surface. The caller |
||
1324 | * owns the surface and should call cairo_surface_destroy() when done |
||
1325 | * with it. |
||
1326 | * |
||
1327 | * This function always returns a valid pointer, but it will return a |
||
1328 | * pointer to a "nil" surface if an error such as out of memory |
||
1329 | * occurs. You can use cairo_surface_status() to check for this. |
||
1330 | * |
||
1331 | * Since: 1.12 |
||
1332 | **/ |
||
1333 | cairo_surface_t * |
||
1334 | cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection, |
||
1335 | xcb_screen_t *screen, |
||
1336 | xcb_drawable_t drawable, |
||
1337 | xcb_render_pictforminfo_t *format, |
||
1338 | int width, |
||
1339 | int height) |
||
1340 | { |
||
1341 | cairo_xcb_screen_t *cairo_xcb_screen; |
||
1342 | cairo_format_masks_t image_masks; |
||
1343 | pixman_format_code_t pixman_format; |
||
1344 | |||
1345 | if (xcb_connection_has_error (connection)) |
||
1346 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); |
||
1347 | |||
1348 | if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) |
||
1349 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1350 | if (unlikely (width <= 0 || height <= 0)) |
||
1351 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1352 | |||
1353 | image_masks.alpha_mask = |
||
1354 | (unsigned long) format->direct.alpha_mask << format->direct.alpha_shift; |
||
1355 | image_masks.red_mask = |
||
1356 | (unsigned long) format->direct.red_mask << format->direct.red_shift; |
||
1357 | image_masks.green_mask = |
||
1358 | (unsigned long) format->direct.green_mask << format->direct.green_shift; |
||
1359 | image_masks.blue_mask = |
||
1360 | (unsigned long) format->direct.blue_mask << format->direct.blue_shift; |
||
1361 | #if 0 |
||
1362 | image_masks.bpp = format->depth; |
||
1363 | #else |
||
1364 | if (format->depth > 16) |
||
1365 | image_masks.bpp = 32; |
||
1366 | else if (format->depth > 8) |
||
1367 | image_masks.bpp = 16; |
||
1368 | else if (format->depth > 1) |
||
1369 | image_masks.bpp = 8; |
||
1370 | else |
||
1371 | image_masks.bpp = 1; |
||
1372 | #endif |
||
1373 | |||
1374 | if (! _pixman_format_from_masks (&image_masks, &pixman_format)) |
||
1375 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); |
||
1376 | |||
1377 | cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen); |
||
1378 | if (unlikely (cairo_xcb_screen == NULL)) |
||
1379 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
1380 | |||
1381 | return _cairo_xcb_surface_create_internal (cairo_xcb_screen, |
||
1382 | drawable, |
||
1383 | FALSE, |
||
1384 | pixman_format, |
||
1385 | format->id, |
||
1386 | width, height); |
||
1387 | } |
||
1388 | #if CAIRO_HAS_XLIB_XCB_FUNCTIONS |
||
1389 | slim_hidden_def (cairo_xcb_surface_create_with_xrender_format); |
||
1390 | #endif |
||
1391 | |||
1392 | /* This does the necessary fixup when a surface's drawable or size changed. */ |
||
1393 | static void |
||
1394 | _drawable_changed (cairo_xcb_surface_t *surface) |
||
1395 | { |
||
1396 | _cairo_surface_set_error (&surface->base, |
||
1397 | _cairo_surface_begin_modification (&surface->base)); |
||
1398 | _cairo_boxes_clear (&surface->fallback_damage); |
||
1399 | cairo_surface_destroy (&surface->fallback->base); |
||
1400 | |||
1401 | surface->deferred_clear = FALSE; |
||
1402 | surface->fallback = NULL; |
||
1403 | } |
||
1404 | |||
1405 | /** |
||
1406 | * cairo_xcb_surface_set_size: |
||
1407 | * @surface: a #cairo_surface_t for the XCB backend |
||
1408 | * @width: the new width of the surface |
||
1409 | * @height: the new height of the surface |
||
1410 | * |
||
1411 | * Informs cairo of the new size of the XCB drawable underlying the |
||
1412 | * surface. For a surface created for a window (rather than a pixmap), |
||
1413 | * this function must be called each time the size of the window |
||
1414 | * changes. (For a subwindow, you are normally resizing the window |
||
1415 | * yourself, but for a toplevel window, it is necessary to listen for |
||
1416 | * ConfigureNotify events.) |
||
1417 | * |
||
1418 | * A pixmap can never change size, so it is never necessary to call |
||
1419 | * this function on a surface created for a pixmap. |
||
1420 | * |
||
1421 | * If cairo_surface_flush() wasn't called, some pending operations |
||
1422 | * might be discarded. |
||
1423 | * |
||
1424 | * Since: 1.12 |
||
1425 | **/ |
||
1426 | void |
||
1427 | cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface, |
||
1428 | int width, |
||
1429 | int height) |
||
1430 | { |
||
1431 | cairo_xcb_surface_t *surface; |
||
1432 | |||
1433 | if (unlikely (abstract_surface->status)) |
||
1434 | return; |
||
1435 | if (unlikely (abstract_surface->finished)) { |
||
1436 | _cairo_surface_set_error (abstract_surface, |
||
1437 | _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
||
1438 | return; |
||
1439 | } |
||
1440 | |||
1441 | |||
1442 | if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { |
||
1443 | _cairo_surface_set_error (abstract_surface, |
||
1444 | _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); |
||
1445 | return; |
||
1446 | } |
||
1447 | |||
1448 | if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) { |
||
1449 | _cairo_surface_set_error (abstract_surface, |
||
1450 | _cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1451 | return; |
||
1452 | } |
||
1453 | |||
1454 | surface = (cairo_xcb_surface_t *) abstract_surface; |
||
1455 | |||
1456 | _drawable_changed(surface); |
||
1457 | surface->width = width; |
||
1458 | surface->height = height; |
||
1459 | } |
||
1460 | #if CAIRO_HAS_XLIB_XCB_FUNCTIONS |
||
1461 | slim_hidden_def (cairo_xcb_surface_set_size); |
||
1462 | #endif |
||
1463 | |||
1464 | /** |
||
1465 | * cairo_xcb_surface_set_drawable: |
||
1466 | * @surface: a #cairo_surface_t for the XCB backend |
||
1467 | * @drawable: the new drawable of the surface |
||
1468 | * @width: the new width of the surface |
||
1469 | * @height: the new height of the surface |
||
1470 | * |
||
1471 | * Informs cairo of the new drawable and size of the XCB drawable underlying the |
||
1472 | * surface. |
||
1473 | * |
||
1474 | * If cairo_surface_flush() wasn't called, some pending operations |
||
1475 | * might be discarded. |
||
1476 | * |
||
1477 | * Since: 1.12 |
||
1478 | **/ |
||
1479 | void |
||
1480 | cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface, |
||
1481 | xcb_drawable_t drawable, |
||
1482 | int width, |
||
1483 | int height) |
||
1484 | { |
||
1485 | cairo_xcb_surface_t *surface; |
||
1486 | |||
1487 | if (unlikely (abstract_surface->status)) |
||
1488 | return; |
||
1489 | if (unlikely (abstract_surface->finished)) { |
||
1490 | _cairo_surface_set_error (abstract_surface, |
||
1491 | _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
||
1492 | return; |
||
1493 | } |
||
1494 | |||
1495 | |||
1496 | if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { |
||
1497 | _cairo_surface_set_error (abstract_surface, |
||
1498 | _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); |
||
1499 | return; |
||
1500 | } |
||
1501 | |||
1502 | if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) { |
||
1503 | _cairo_surface_set_error (abstract_surface, |
||
1504 | _cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
1505 | return; |
||
1506 | } |
||
1507 | |||
1508 | surface = (cairo_xcb_surface_t *) abstract_surface; |
||
1509 | |||
1510 | /* XXX: and what about this case? */ |
||
1511 | if (surface->owns_pixmap) |
||
1512 | return; |
||
1513 | |||
1514 | _drawable_changed (surface); |
||
1515 | |||
1516 | if (surface->drawable != drawable) { |
||
1517 | cairo_status_t status; |
||
1518 | status = _cairo_xcb_connection_acquire (surface->connection); |
||
1519 | if (unlikely (status)) |
||
1520 | return; |
||
1521 | |||
1522 | if (surface->picture != XCB_NONE) { |
||
1523 | _cairo_xcb_connection_render_free_picture (surface->connection, |
||
1524 | surface->picture); |
||
1525 | surface->picture = XCB_NONE; |
||
1526 | } |
||
1527 | |||
1528 | _cairo_xcb_connection_release (surface->connection); |
||
1529 | |||
1530 | surface->drawable = drawable; |
||
1531 | } |
||
1532 | surface->width = width; |
||
1533 | surface->height = height; |
||
1534 | } |
||
1535 | #if CAIRO_HAS_XLIB_XCB_FUNCTIONS |
||
1536 | slim_hidden_def (cairo_xcb_surface_set_drawable); |
||
1537 | #endif=>=>=>=>><>><>><>><>=>=>=>=>=>=>>>=>=>=>=>=>=> |