Line data Source code
1 : /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 : /* cairo - a vector graphics library with display and print output
3 : *
4 : * Copyright © 2002 University of Southern California
5 : * Copyright © 2005 Red Hat, Inc.
6 : *
7 : * This library is free software; you can redistribute it and/or
8 : * modify it either under the terms of the GNU Lesser General Public
9 : * License version 2.1 as published by the Free Software Foundation
10 : * (the "LGPL") or, at your option, under the terms of the Mozilla
11 : * Public License Version 1.1 (the "MPL"). If you do not alter this
12 : * notice, a recipient may use your version of this file under either
13 : * the MPL or the LGPL.
14 : *
15 : * You should have received a copy of the LGPL along with this library
16 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 : * You should have received a copy of the MPL along with this library
19 : * in the file COPYING-MPL-1.1
20 : *
21 : * The contents of this file are subject to the Mozilla Public License
22 : * Version 1.1 (the "License"); you may not use this file except in
23 : * compliance with the License. You may obtain a copy of the License at
24 : * http://www.mozilla.org/MPL/
25 : *
26 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 : * the specific language governing rights and limitations.
29 : *
30 : * The Original Code is the cairo graphics library.
31 : *
32 : * The Initial Developer of the Original Code is University of Southern
33 : * California.
34 : *
35 : * Contributor(s):
36 : * Carl D. Worth <cworth@cworth.org>
37 : * Behdad Esfahbod <behdad@behdad.org>
38 : * Chris Wilson <chris@chris-wilson.co.uk>
39 : * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
40 : */
41 :
42 : /* Heed well the words of Owen Taylor:
43 : * "Any patch that works around a render bug, or claims to, without a
44 : * specific reference to the bug filed in bugzilla.freedesktop.org will
45 : * never pass approval."
46 : */
47 :
48 : #include "cairoint.h"
49 :
50 : #include "cairo-xlib-private.h"
51 : #include "cairo-xlib-surface-private.h"
52 : #include "cairo-clip-private.h"
53 : #include "cairo-error-private.h"
54 : #include "cairo-scaled-font-private.h"
55 : #include "cairo-surface-snapshot-private.h"
56 : #include "cairo-surface-subsurface-private.h"
57 : #include "cairo-region-private.h"
58 : #include "cairo-xlib-xrender-private.h"
59 :
60 : #include <X11/Xutil.h> /* for XDestroyImage */
61 : #include <X11/Xlibint.h> /* for access to XDisplay's innards */
62 :
63 : #define XLIB_COORD_MAX 32767
64 :
65 : #define DEBUG 0
66 :
67 : #if DEBUG
68 : #define UNSUPPORTED(reason) \
69 : fprintf (stderr, \
70 : "cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \
71 : __FUNCTION__, __LINE__, reason), \
72 : CAIRO_INT_STATUS_UNSUPPORTED
73 : #else
74 : #define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
75 : #endif
76 :
77 : #if DEBUG
78 : static void CAIRO_PRINTF_FORMAT (2, 3)
79 : _x_bread_crumb (Display *dpy,
80 : const char *fmt,
81 : ...)
82 : {
83 : xReq *req;
84 : char buf[2048];
85 : unsigned int len, len_dwords;
86 : va_list ap;
87 :
88 : va_start (ap, fmt);
89 : len = vsnprintf (buf, sizeof (buf), fmt, ap);
90 : va_end (ap);
91 :
92 : buf[len++] = '\0';
93 : while (len & 3)
94 : buf[len++] = '\0';
95 :
96 : LockDisplay (dpy);
97 : GetEmptyReq (NoOperation, req);
98 :
99 : len_dwords = len >> 2;
100 : SetReqLen (req, len_dwords, len_dwords);
101 : Data (dpy, buf, len);
102 :
103 : UnlockDisplay (dpy);
104 : SyncHandle ();
105 : }
106 : #define X_DEBUG(x) _x_bread_crumb x
107 : #else
108 : #define X_DEBUG(x)
109 : #endif
110 :
111 : /**
112 : * SECTION:cairo-xlib
113 : * @Title: XLib Surfaces
114 : * @Short_Description: X Window System rendering using XLib
115 : * @See_Also: #cairo_surface_t
116 : *
117 : * The XLib surface is used to render cairo graphics to X Window System
118 : * windows and pixmaps using the XLib library.
119 : *
120 : * Note that the XLib surface automatically takes advantage of X render extension
121 : * if it is available.
122 : */
123 :
124 : /**
125 : * CAIRO_HAS_XLIB_SURFACE:
126 : *
127 : * Defined if the Xlib surface backend is available.
128 : * This macro can be used to conditionally compile backend-specific code.
129 : */
130 :
131 : /**
132 : * SECTION:cairo-xlib-xrender
133 : * @Title: XLib/XRender Backend
134 : * @Short_Description: X Window System rendering using XLib and the X Render extension
135 : * @See_Also: #cairo_surface_t
136 : *
137 : * The XLib surface is used to render cairo graphics to X Window System
138 : * windows and pixmaps using the XLib and Xrender libraries.
139 : *
140 : * Note that the XLib surface automatically takes advantage of X Render extension
141 : * if it is available.
142 : */
143 :
144 : /**
145 : * CAIRO_HAS_XLIB_XRENDER_SURFACE:
146 : *
147 : * Defined if the XLib/XRender surface functions are available.
148 : * This macro can be used to conditionally compile backend-specific code.
149 : */
150 :
151 : /* Xlib doesn't define a typedef, so define one ourselves */
152 : typedef int (*cairo_xlib_error_func_t) (Display *display,
153 : XErrorEvent *event);
154 :
155 : static cairo_surface_t *
156 : _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen,
157 : Drawable drawable,
158 : Visual *visual,
159 : XRenderPictFormat *xrender_format,
160 : int width,
161 : int height,
162 : int depth);
163 :
164 : static cairo_bool_t
165 : _cairo_surface_is_xlib (cairo_surface_t *surface);
166 :
167 : static cairo_bool_t
168 : _native_byte_order_lsb (void);
169 :
170 : static cairo_int_status_t
171 : _cairo_xlib_surface_show_glyphs (void *abstract_dst,
172 : cairo_operator_t op,
173 : const cairo_pattern_t *src_pattern,
174 : cairo_glyph_t *glyphs,
175 : int num_glyphs,
176 : cairo_scaled_font_t *scaled_font,
177 : cairo_clip_t *clip,
178 : int *remaining_glyphs);
179 :
180 : /*
181 : * Instead of taking two round trips for each blending request,
182 : * assume that if a particular drawable fails GetImage that it will
183 : * fail for a "while"; use temporary pixmaps to avoid the errors
184 : */
185 :
186 : #define CAIRO_ASSUME_PIXMAP 20
187 :
188 : static const XTransform identity = { {
189 : { 1 << 16, 0x00000, 0x00000 },
190 : { 0x00000, 1 << 16, 0x00000 },
191 : { 0x00000, 0x00000, 1 << 16 },
192 : } };
193 :
194 : #define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
195 : (((surface)->render_major > major) || \
196 : (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
197 :
198 : #define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
199 : #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
200 : #define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
201 :
202 : #define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
203 :
204 : #define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
205 : #define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
206 :
207 : #define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
208 : #define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
209 : #define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
210 : #define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
211 :
212 : #define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
213 : #define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
214 :
215 : #define CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
216 : #define CAIRO_SURFACE_RENDER_HAS_GRADIENTS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
217 :
218 : #define CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 11)
219 :
220 : #define CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR(surface, op) \
221 : ((op) <= CAIRO_OPERATOR_SATURATE || \
222 : (CAIRO_SURFACE_RENDER_HAS_PDF_OPERATORS(surface) && \
223 : (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY))
224 :
225 : static Visual *
226 0 : _visual_for_xrender_format(Screen *screen,
227 : XRenderPictFormat *xrender_format)
228 : {
229 : int d, v;
230 :
231 : /* XXX Consider searching through the list of known cairo_visual_t for
232 : * the reverse mapping.
233 : */
234 :
235 0 : for (d = 0; d < screen->ndepths; d++) {
236 0 : Depth *d_info = &screen->depths[d];
237 :
238 0 : if (d_info->depth != xrender_format->depth)
239 0 : continue;
240 :
241 0 : for (v = 0; v < d_info->nvisuals; v++) {
242 0 : Visual *visual = &d_info->visuals[v];
243 :
244 0 : switch (visual->class) {
245 : case TrueColor:
246 0 : if (xrender_format->type != PictTypeDirect)
247 0 : continue;
248 0 : break;
249 :
250 : case DirectColor:
251 : /* Prefer TrueColor to DirectColor.
252 : * (XRenderFindVisualFormat considers both TrueColor and DirectColor
253 : * Visuals to match the same PictFormat.)
254 : */
255 0 : continue;
256 :
257 : case StaticGray:
258 : case GrayScale:
259 : case StaticColor:
260 : case PseudoColor:
261 0 : if (xrender_format->type != PictTypeIndexed)
262 0 : continue;
263 0 : break;
264 : }
265 :
266 0 : if (xrender_format ==
267 0 : XRenderFindVisualFormat (DisplayOfScreen(screen), visual))
268 0 : return visual;
269 : }
270 : }
271 :
272 0 : return NULL;
273 : }
274 :
275 : static cairo_status_t
276 0 : _cairo_xlib_surface_set_clip_region (cairo_xlib_surface_t *surface,
277 : cairo_region_t *region)
278 : {
279 0 : cairo_bool_t had_clip_rects = surface->clip_region != NULL;
280 :
281 0 : if (had_clip_rects == FALSE && region == NULL)
282 0 : return CAIRO_STATUS_SUCCESS;
283 :
284 0 : if (surface->clip_region == region)
285 0 : return CAIRO_STATUS_SUCCESS;
286 :
287 0 : if (cairo_region_equal (surface->clip_region, region))
288 0 : return CAIRO_STATUS_SUCCESS;
289 :
290 0 : cairo_region_destroy (surface->clip_region);
291 0 : surface->clip_region = cairo_region_reference (region);
292 :
293 0 : if (surface->clip_rects != surface->embedded_clip_rects) {
294 0 : free (surface->clip_rects);
295 0 : surface->clip_rects = surface->embedded_clip_rects;
296 : }
297 0 : surface->num_clip_rects = 0;
298 :
299 0 : if (region != NULL) {
300 0 : XRectangle *rects = NULL;
301 : int n_rects, i;
302 :
303 0 : n_rects = cairo_region_num_rectangles (region);
304 0 : if (n_rects > ARRAY_LENGTH (surface->embedded_clip_rects)) {
305 0 : rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
306 0 : if (unlikely (rects == NULL))
307 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
308 : } else {
309 0 : rects = surface->embedded_clip_rects;
310 : }
311 :
312 0 : for (i = 0; i < n_rects; i++) {
313 : cairo_rectangle_int_t rect;
314 :
315 0 : cairo_region_get_rectangle (region, i, &rect);
316 :
317 0 : rects[i].x = rect.x;
318 0 : rects[i].y = rect.y;
319 0 : rects[i].width = rect.width;
320 0 : rects[i].height = rect.height;
321 : }
322 :
323 0 : surface->clip_rects = rects;
324 0 : surface->num_clip_rects = n_rects;
325 : }
326 :
327 0 : surface->clip_dirty = CAIRO_XLIB_SURFACE_CLIP_DIRTY_ALL;
328 0 : return CAIRO_STATUS_SUCCESS;
329 : }
330 :
331 : static cairo_content_t
332 0 : _xrender_format_to_content (XRenderPictFormat *xrender_format)
333 : {
334 : cairo_bool_t xrender_format_has_alpha;
335 : cairo_bool_t xrender_format_has_color;
336 :
337 : /* This only happens when using a non-Render server. Let's punt
338 : * and say there's no alpha here. */
339 0 : if (xrender_format == NULL)
340 0 : return CAIRO_CONTENT_COLOR;
341 :
342 0 : xrender_format_has_alpha = (xrender_format->direct.alphaMask != 0);
343 0 : xrender_format_has_color = (xrender_format->direct.redMask != 0 ||
344 0 : xrender_format->direct.greenMask != 0 ||
345 0 : xrender_format->direct.blueMask != 0);
346 :
347 0 : if (xrender_format_has_alpha)
348 0 : if (xrender_format_has_color)
349 0 : return CAIRO_CONTENT_COLOR_ALPHA;
350 : else
351 0 : return CAIRO_CONTENT_ALPHA;
352 : else
353 0 : return CAIRO_CONTENT_COLOR;
354 : }
355 :
356 : static cairo_surface_t *
357 0 : _cairo_xlib_surface_create_similar (void *abstract_src,
358 : cairo_content_t content,
359 : int width,
360 : int height)
361 : {
362 0 : cairo_xlib_surface_t *src = abstract_src;
363 : XRenderPictFormat *xrender_format;
364 : cairo_xlib_surface_t *surface;
365 : cairo_xlib_display_t *display;
366 : Pixmap pix;
367 :
368 0 : if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
369 0 : return NULL;
370 :
371 0 : if (! CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (src))
372 0 : return NULL;
373 :
374 0 : if (_cairo_xlib_display_acquire (src->base.device, &display))
375 0 : return NULL;
376 :
377 : /* If we never found an XRenderFormat or if it isn't compatible
378 : * with the content being requested, then we fallback to just
379 : * constructing a cairo_format_t instead, (which will fairly
380 : * arbitrarily pick a visual/depth for the similar surface.
381 : */
382 0 : xrender_format = src->xrender_format;
383 0 : if ((xrender_format != NULL &&
384 0 : _xrender_format_to_content (xrender_format) == content) ||
385 : (xrender_format =
386 0 : _cairo_xlib_display_get_xrender_format (display,
387 : _cairo_format_from_content (content))))
388 0 : {
389 : Visual *visual;
390 :
391 : /* We've got a compatible XRenderFormat now, which means the
392 : * similar surface will match the existing surface as closely in
393 : * visual/depth etc. as possible. */
394 0 : pix = XCreatePixmap (display->display, src->drawable,
395 0 : width <= 0 ? 1 : width, height <= 0 ? 1 : height,
396 0 : xrender_format->depth);
397 :
398 0 : if (xrender_format == src->xrender_format)
399 0 : visual = src->visual;
400 : else
401 0 : visual = _visual_for_xrender_format(src->screen->screen,
402 : xrender_format);
403 :
404 0 : surface = (cairo_xlib_surface_t *)
405 0 : _cairo_xlib_surface_create_internal (src->screen, pix,
406 : visual,
407 : xrender_format,
408 : width, height,
409 : xrender_format->depth);
410 : }
411 : else
412 : {
413 : #ifdef DEBUG_FORCE_FALLBACKS
414 : Screen *screen = src->screen->screen;
415 : int depth;
416 :
417 : /* No compatabile XRenderFormat, see if we can make an ordinary pixmap,
418 : * so that we can still accelerate blits with XCopyArea(). */
419 : if (content != CAIRO_CONTENT_COLOR) {
420 : cairo_device_release (&display->base);
421 : return NULL;
422 : }
423 :
424 : depth = DefaultDepthOfScreen (screen);
425 :
426 : pix = XCreatePixmap (display->display, RootWindowOfScreen (screen),
427 : width <= 0 ? 1 : width, height <= 0 ? 1 : height,
428 : depth);
429 :
430 : surface = (cairo_xlib_surface_t *)
431 : _cairo_xlib_surface_create_internal (src->screen, pix,
432 : DefaultVisualOfScreen (screen),
433 : NULL,
434 : width, height, depth);
435 : #else
436 : /* No compatabile XRenderFormat, just say no. */
437 0 : cairo_device_release (&display->base);
438 0 : return NULL;
439 : #endif
440 : }
441 :
442 0 : if (unlikely (surface->base.status)) {
443 0 : XFreePixmap (display->display, pix);
444 0 : cairo_device_release (&display->base);
445 0 : return &surface->base;
446 : }
447 :
448 0 : surface->owns_pixmap = TRUE;
449 :
450 0 : cairo_device_release (&display->base);
451 :
452 0 : return &surface->base;
453 : }
454 :
455 : static cairo_status_t
456 0 : _cairo_xlib_surface_finish (void *abstract_surface)
457 : {
458 0 : cairo_xlib_surface_t *surface = abstract_surface;
459 : cairo_status_t status;
460 : cairo_xlib_display_t *display;
461 :
462 : X_DEBUG ((display->display, "finish (drawable=%x)", (unsigned int) surface->drawable));
463 :
464 0 : status = _cairo_xlib_display_acquire (surface->base.device, &display);
465 0 : if (unlikely (status))
466 0 : return status;
467 :
468 0 : if (surface->owns_pixmap) {
469 : cairo_status_t status2;
470 :
471 0 : if (surface->dst_picture != None) {
472 0 : status2 = _cairo_xlib_display_queue_resource (display,
473 : XRenderFreePicture,
474 : surface->dst_picture);
475 0 : if (status == CAIRO_STATUS_SUCCESS)
476 0 : status = status2;
477 : }
478 :
479 0 : if (surface->src_picture != None) {
480 0 : status2 = _cairo_xlib_display_queue_resource (display,
481 : XRenderFreePicture,
482 : surface->src_picture);
483 0 : if (status == CAIRO_STATUS_SUCCESS)
484 0 : status = status2;
485 : }
486 :
487 0 : status2 = _cairo_xlib_display_queue_resource (display,
488 : (cairo_xlib_notify_resource_func) XFreePixmap,
489 : surface->drawable);
490 0 : if (status == CAIRO_STATUS_SUCCESS)
491 0 : status = status2;
492 : } else {
493 0 : if (surface->dst_picture != None)
494 0 : XRenderFreePicture (display->display, surface->dst_picture);
495 :
496 0 : if (surface->src_picture != None)
497 0 : XRenderFreePicture (display->display, surface->src_picture);
498 : }
499 :
500 0 : if (surface->clip_rects != surface->embedded_clip_rects)
501 0 : free (surface->clip_rects);
502 :
503 0 : if (display->display != NULL)
504 0 : _cairo_xlib_remove_close_display_hook (display,
505 : &surface->close_display_hook);
506 :
507 0 : cairo_device_release (&display->base);
508 :
509 0 : cairo_region_destroy (surface->clip_region);
510 :
511 0 : return status;
512 : }
513 :
514 : static cairo_status_t
515 0 : _cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
516 : cairo_xlib_surface_t *surface,
517 : GC *gc)
518 : {
519 0 : *gc = _cairo_xlib_screen_get_gc (display,
520 : surface->screen,
521 : surface->depth,
522 : surface->drawable);
523 0 : if (unlikely (*gc == NULL))
524 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
525 :
526 0 : return CAIRO_STATUS_SUCCESS;
527 : }
528 :
529 : static void
530 0 : _cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
531 : cairo_xlib_surface_t *surface,
532 : GC gc)
533 : {
534 0 : _cairo_xlib_screen_put_gc (display,
535 : surface->screen,
536 : surface->depth,
537 : gc);
538 0 : }
539 :
540 : static int
541 0 : _noop_error_handler (Display *display,
542 : XErrorEvent *event)
543 : {
544 0 : return False; /* return value is ignored */
545 : }
546 :
547 : static void
548 0 : _swap_ximage_2bytes (XImage *ximage)
549 : {
550 : int i, j;
551 0 : char *line = ximage->data;
552 :
553 0 : for (j = ximage->height; j; j--) {
554 0 : uint16_t *p = (uint16_t *) line;
555 0 : for (i = ximage->width; i; i--) {
556 0 : *p = bswap_16 (*p);
557 0 : p++;
558 : }
559 :
560 0 : line += ximage->bytes_per_line;
561 : }
562 0 : }
563 :
564 : static void
565 0 : _swap_ximage_3bytes (XImage *ximage)
566 : {
567 : int i, j;
568 0 : char *line = ximage->data;
569 :
570 0 : for (j = ximage->height; j; j--) {
571 0 : uint8_t *p = (uint8_t *) line;
572 0 : for (i = ximage->width; i; i--) {
573 : uint8_t tmp;
574 0 : tmp = p[2];
575 0 : p[2] = p[0];
576 0 : p[0] = tmp;
577 0 : p += 3;
578 : }
579 :
580 0 : line += ximage->bytes_per_line;
581 : }
582 0 : }
583 :
584 : static void
585 0 : _swap_ximage_4bytes (XImage *ximage)
586 : {
587 : int i, j;
588 0 : char *line = ximage->data;
589 :
590 0 : for (j = ximage->height; j; j--) {
591 0 : uint32_t *p = (uint32_t *) line;
592 0 : for (i = ximage->width; i; i--) {
593 0 : *p = bswap_32 (*p);
594 0 : p++;
595 : }
596 :
597 0 : line += ximage->bytes_per_line;
598 : }
599 0 : }
600 :
601 : static void
602 0 : _swap_ximage_nibbles (XImage *ximage)
603 : {
604 : int i, j;
605 0 : char *line = ximage->data;
606 :
607 0 : for (j = ximage->height; j; j--) {
608 0 : uint8_t *p = (uint8_t *) line;
609 0 : for (i = (ximage->width + 1) / 2; i; i--) {
610 0 : *p = ((*p >> 4) & 0xf) | ((*p << 4) & ~0xf);
611 0 : p++;
612 : }
613 :
614 0 : line += ximage->bytes_per_line;
615 : }
616 0 : }
617 :
618 : static void
619 0 : _swap_ximage_bits (XImage *ximage)
620 : {
621 : int i, j;
622 0 : char *line = ximage->data;
623 0 : int unit = ximage->bitmap_unit;
624 0 : int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8;
625 :
626 0 : for (j = ximage->height; j; j--) {
627 0 : char *p = line;
628 :
629 0 : for (i = line_bytes; i; i--) {
630 0 : char b = *p;
631 0 : b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
632 0 : b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
633 0 : b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
634 0 : *p = b;
635 :
636 0 : p++;
637 : }
638 :
639 0 : line += ximage->bytes_per_line;
640 : }
641 0 : }
642 :
643 : static void
644 0 : _swap_ximage_to_native (XImage *ximage)
645 : {
646 0 : int unit_bytes = 0;
647 0 : int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
648 :
649 0 : if (ximage->bits_per_pixel == 1 &&
650 0 : ximage->bitmap_bit_order != native_byte_order)
651 : {
652 0 : _swap_ximage_bits (ximage);
653 0 : if (ximage->bitmap_bit_order == ximage->byte_order)
654 0 : return;
655 : }
656 :
657 0 : if (ximage->byte_order == native_byte_order)
658 0 : return;
659 :
660 0 : switch (ximage->bits_per_pixel) {
661 : case 1:
662 0 : unit_bytes = ximage->bitmap_unit / 8;
663 0 : break;
664 : case 4:
665 0 : _swap_ximage_nibbles (ximage);
666 : /* fall-through */
667 : case 8:
668 : case 16:
669 : case 20:
670 : case 24:
671 : case 28:
672 : case 30:
673 : case 32:
674 0 : unit_bytes = (ximage->bits_per_pixel + 7) / 8;
675 0 : break;
676 : default:
677 : /* This could be hit on some rare but possible cases. */
678 0 : ASSERT_NOT_REACHED;
679 : }
680 :
681 0 : switch (unit_bytes) {
682 : case 1:
683 0 : break;
684 : case 2:
685 0 : _swap_ximage_2bytes (ximage);
686 0 : break;
687 : case 3:
688 0 : _swap_ximage_3bytes (ximage);
689 0 : break;
690 : case 4:
691 0 : _swap_ximage_4bytes (ximage);
692 0 : break;
693 : default:
694 0 : ASSERT_NOT_REACHED;
695 : }
696 : }
697 :
698 :
699 : /* Given a mask, (with a single sequence of contiguous 1 bits), return
700 : * the number of 1 bits in 'width' and the number of 0 bits to its
701 : * right in 'shift'. */
702 : static void
703 0 : _characterize_field (uint32_t mask, int *width, int *shift)
704 : {
705 0 : *width = _cairo_popcount (mask);
706 : /* The final '& 31' is to force a 0 mask to result in 0 shift. */
707 0 : *shift = _cairo_popcount ((mask - 1) & ~mask) & 31;
708 0 : }
709 :
710 :
711 : /* Convert a field of 'width' bits to 'new_width' bits with correct
712 : * rounding. */
713 : static inline uint32_t
714 0 : _resize_field (uint32_t field, int width, int new_width)
715 : {
716 0 : if (width == 0)
717 0 : return 0;
718 :
719 0 : if (width >= new_width) {
720 0 : return field >> (width - new_width);
721 : } else {
722 0 : uint32_t result = field << (new_width - width);
723 :
724 0 : while (width < new_width) {
725 0 : result |= result >> width;
726 0 : width <<= 1;
727 : }
728 0 : return result;
729 : }
730 : }
731 :
732 : static inline uint32_t
733 0 : _adjust_field (uint32_t field, int adjustment)
734 : {
735 0 : return MIN (255, MAX(0, (int)field + adjustment));
736 : }
737 :
738 : /* Given a shifted field value, (described by 'width' and 'shift),
739 : * resize it 8-bits and return that value.
740 : *
741 : * Note that the original field value must not have any non-field bits
742 : * set.
743 : */
744 : static inline uint32_t
745 0 : _field_to_8 (uint32_t field, int width, int shift)
746 : {
747 0 : return _resize_field (field >> shift, width, 8);
748 : }
749 :
750 : static inline uint32_t
751 0 : _field_to_8_undither (uint32_t field, int width, int shift,
752 : int dither_adjustment)
753 : {
754 0 : return _adjust_field (_field_to_8 (field, width, shift), - dither_adjustment>>width);
755 : }
756 :
757 : /* Given an 8-bit value, convert it to a field of 'width', shift it up
758 : * to 'shift, and return it. */
759 : static inline uint32_t
760 0 : _field_from_8 (uint32_t field, int width, int shift)
761 : {
762 0 : return _resize_field (field, 8, width) << shift;
763 : }
764 :
765 : static inline uint32_t
766 0 : _field_from_8_dither (uint32_t field, int width, int shift,
767 : int8_t dither_adjustment)
768 : {
769 0 : return _field_from_8 (_adjust_field (field, dither_adjustment>>width), width, shift);
770 : }
771 :
772 : static inline uint32_t
773 0 : _pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info,
774 : uint32_t r, uint32_t g, uint32_t b,
775 : int8_t dither_adjustment)
776 : {
777 0 : if (r == g && g == b) {
778 0 : dither_adjustment /= RAMP_SIZE;
779 0 : return visual_info->gray8_to_pseudocolor[_adjust_field (r, dither_adjustment)];
780 : } else {
781 0 : dither_adjustment = visual_info->dither8_to_cube[dither_adjustment+128];
782 0 : return visual_info->cube_to_pseudocolor[visual_info->field8_to_cube[_adjust_field (r, dither_adjustment)]]
783 0 : [visual_info->field8_to_cube[_adjust_field (g, dither_adjustment)]]
784 0 : [visual_info->field8_to_cube[_adjust_field (b, dither_adjustment)]];
785 : }
786 : }
787 :
788 : static inline uint32_t
789 0 : _pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info,
790 : uint32_t pixel)
791 : {
792 : uint32_t r, g, b;
793 0 : pixel &= 0xff;
794 0 : r = visual_info->colors[pixel].r;
795 0 : g = visual_info->colors[pixel].g;
796 0 : b = visual_info->colors[pixel].b;
797 0 : return (r << 16) |
798 0 : (g << 8) |
799 : (b );
800 : }
801 :
802 :
803 : /* should range from -128 to 127 */
804 : #define X 16
805 : static const int8_t dither_pattern[4][4] = {
806 : {-8*X, +0*X, -6*X, +2*X},
807 : {+4*X, -4*X, +6*X, -2*X},
808 : {-5*X, +4*X, -7*X, +1*X},
809 : {+7*X, -1*X, +5*X, -3*X}
810 : };
811 : #undef X
812 :
813 :
814 : static cairo_status_t
815 0 : _get_image_surface (cairo_xlib_surface_t *surface,
816 : cairo_rectangle_int_t *interest_rect,
817 : cairo_image_surface_t **image_out,
818 : cairo_rectangle_int_t *image_rect)
819 : {
820 : cairo_int_status_t status;
821 0 : cairo_image_surface_t *image = NULL;
822 : XImage *ximage;
823 : cairo_rectangle_int_t extents;
824 : pixman_format_code_t pixman_format;
825 : cairo_format_masks_t xlib_masks;
826 : cairo_xlib_display_t *display;
827 :
828 0 : extents.x = 0;
829 0 : extents.y = 0;
830 0 : extents.width = surface->width;
831 0 : extents.height = surface->height;
832 :
833 0 : if (interest_rect) {
834 0 : if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
835 0 : *image_out = NULL;
836 0 : return CAIRO_STATUS_SUCCESS;
837 : }
838 : }
839 :
840 0 : status = _cairo_xlib_display_acquire (surface->base.device, &display);
841 0 : if (status)
842 0 : return status;
843 :
844 0 : if (image_rect)
845 0 : *image_rect = extents;
846 :
847 : /* XXX: This should try to use the XShm extension if available */
848 :
849 0 : if (surface->use_pixmap == 0)
850 : {
851 : cairo_xlib_error_func_t old_handler;
852 :
853 0 : old_handler = XSetErrorHandler (_noop_error_handler);
854 :
855 0 : ximage = XGetImage (display->display,
856 : surface->drawable,
857 : extents.x, extents.y,
858 0 : extents.width, extents.height,
859 : AllPlanes, ZPixmap);
860 :
861 0 : XSetErrorHandler (old_handler);
862 :
863 : /* If we get an error, the surface must have been a window,
864 : * so retry with the safe code path.
865 : */
866 0 : if (!ximage)
867 0 : surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
868 : }
869 : else
870 : {
871 0 : surface->use_pixmap--;
872 0 : ximage = NULL;
873 : }
874 :
875 0 : if (ximage == NULL) {
876 : /* XGetImage from a window is dangerous because it can
877 : * produce errors if the window is unmapped or partially
878 : * outside the screen. We could check for errors and
879 : * retry, but to keep things simple, we just create a
880 : * temporary pixmap
881 : */
882 : Pixmap pixmap;
883 : GC gc;
884 :
885 0 : status = _cairo_xlib_surface_get_gc (display, surface, &gc);
886 0 : if (unlikely (status))
887 0 : goto BAIL;
888 :
889 0 : pixmap = XCreatePixmap (display->display,
890 : surface->drawable,
891 0 : extents.width <= 0 ? 1 : extents.width,
892 0 : extents.height <= 0 ? 1 : extents.height,
893 0 : surface->depth);
894 0 : if (pixmap) {
895 0 : XCopyArea (display->display, surface->drawable, pixmap, gc,
896 : extents.x, extents.y,
897 0 : extents.width, extents.height,
898 : 0, 0);
899 :
900 0 : ximage = XGetImage (display->display,
901 : pixmap,
902 : 0, 0,
903 0 : extents.width <= 0 ? 1 : extents.width,
904 0 : extents.height <= 0 ? 1 : extents.height,
905 : AllPlanes, ZPixmap);
906 :
907 0 : XFreePixmap (display->display, pixmap);
908 : }
909 :
910 0 : _cairo_xlib_surface_put_gc (display, surface, gc);
911 :
912 0 : if (ximage == NULL) {
913 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
914 0 : goto BAIL;
915 : }
916 : }
917 :
918 0 : _swap_ximage_to_native (ximage);
919 :
920 0 : xlib_masks.bpp = ximage->bits_per_pixel;
921 0 : xlib_masks.alpha_mask = surface->a_mask;
922 0 : xlib_masks.red_mask = surface->r_mask;
923 0 : xlib_masks.green_mask = surface->g_mask;
924 0 : xlib_masks.blue_mask = surface->b_mask;
925 :
926 : /* We can't use pixman to simply write to image if:
927 : * (a) the pixels are not appropriately aligned,
928 : * (b) pixman does not the pixel format, or
929 : * (c) if the image is palettized and we need to convert.
930 : */
931 0 : if (ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
932 0 : _pixman_format_from_masks (&xlib_masks, &pixman_format) &&
933 0 : (surface->visual == NULL || surface->visual->class == TrueColor))
934 : {
935 0 : image = (cairo_image_surface_t*)
936 0 : _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data,
937 : pixman_format,
938 : ximage->width,
939 : ximage->height,
940 : ximage->bytes_per_line);
941 0 : status = image->base.status;
942 0 : if (unlikely (status))
943 0 : goto BAIL;
944 :
945 : /* Let the surface take ownership of the data */
946 0 : _cairo_image_surface_assume_ownership_of_data (image);
947 0 : ximage->data = NULL;
948 : } else {
949 : /* The visual we are dealing with is not supported by the
950 : * standard pixman formats. So we must first convert the data
951 : * to a supported format. */
952 :
953 : cairo_format_t format;
954 : unsigned char *data;
955 : uint32_t *row;
956 : uint32_t in_pixel, out_pixel;
957 : unsigned int rowstride;
958 0 : uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0;
959 0 : int a_width=0, r_width=0, g_width=0, b_width=0;
960 0 : int a_shift=0, r_shift=0, g_shift=0, b_shift=0;
961 : int x, y, x0, y0, x_off, y_off;
962 0 : cairo_xlib_visual_info_t *visual_info = NULL;
963 :
964 0 : if (surface->visual == NULL || surface->visual->class == TrueColor) {
965 : cairo_bool_t has_alpha;
966 : cairo_bool_t has_color;
967 :
968 0 : has_alpha = surface->a_mask;
969 0 : has_color = (surface->r_mask ||
970 0 : surface->g_mask ||
971 0 : surface->b_mask);
972 :
973 0 : if (has_color) {
974 0 : if (has_alpha) {
975 0 : format = CAIRO_FORMAT_ARGB32;
976 : } else {
977 0 : format = CAIRO_FORMAT_RGB24;
978 : }
979 : } else {
980 : /* XXX: Using CAIRO_FORMAT_A8 here would be more
981 : * efficient, but would require slightly different code in
982 : * the image conversion to put the alpha channel values
983 : * into the right place. */
984 0 : format = CAIRO_FORMAT_ARGB32;
985 : }
986 :
987 0 : a_mask = surface->a_mask;
988 0 : r_mask = surface->r_mask;
989 0 : g_mask = surface->g_mask;
990 0 : b_mask = surface->b_mask;
991 :
992 0 : _characterize_field (a_mask, &a_width, &a_shift);
993 0 : _characterize_field (r_mask, &r_width, &r_shift);
994 0 : _characterize_field (g_mask, &g_width, &g_shift);
995 0 : _characterize_field (b_mask, &b_width, &b_shift);
996 :
997 : } else {
998 0 : format = CAIRO_FORMAT_RGB24;
999 :
1000 0 : status = _cairo_xlib_screen_get_visual_info (display,
1001 : surface->screen,
1002 : surface->visual,
1003 : &visual_info);
1004 0 : if (unlikely (status))
1005 0 : goto BAIL;
1006 : }
1007 :
1008 0 : image = (cairo_image_surface_t *) cairo_image_surface_create
1009 : (format, ximage->width, ximage->height);
1010 0 : status = image->base.status;
1011 0 : if (unlikely (status))
1012 0 : goto BAIL;
1013 :
1014 0 : data = cairo_image_surface_get_data (&image->base);
1015 0 : rowstride = cairo_image_surface_get_stride (&image->base) >> 2;
1016 0 : row = (uint32_t *) data;
1017 0 : x0 = extents.x + surface->base.device_transform.x0;
1018 0 : y0 = extents.y + surface->base.device_transform.y0;
1019 0 : for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
1020 0 : y < ximage->height;
1021 0 : y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) {
1022 0 : const int8_t *dither_row = dither_pattern[y_off];
1023 0 : for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
1024 0 : x < ximage->width;
1025 0 : x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) {
1026 0 : int dither_adjustment = dither_row[x_off];
1027 :
1028 0 : in_pixel = XGetPixel (ximage, x, y);
1029 0 : if (visual_info == NULL) {
1030 0 : out_pixel = (
1031 0 : _field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 |
1032 0 : _field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 |
1033 0 : _field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 |
1034 0 : _field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment));
1035 : } else {
1036 : /* Undithering pseudocolor does not look better */
1037 0 : out_pixel = _pseudocolor_to_rgb888 (visual_info, in_pixel);
1038 : }
1039 0 : row[x] = out_pixel;
1040 : }
1041 0 : row += rowstride;
1042 : }
1043 0 : cairo_surface_mark_dirty (&image->base);
1044 : }
1045 :
1046 : BAIL:
1047 0 : if (ximage)
1048 0 : XDestroyImage (ximage);
1049 :
1050 0 : cairo_device_release (&display->base);
1051 :
1052 0 : if (unlikely (status)) {
1053 0 : if (image) {
1054 0 : cairo_surface_destroy (&image->base);
1055 0 : image = NULL;
1056 : }
1057 : }
1058 0 : *image_out = image;
1059 0 : return status;
1060 : }
1061 :
1062 : static void
1063 0 : _cairo_xlib_surface_ensure_src_picture (cairo_xlib_display_t *display,
1064 : cairo_xlib_surface_t *surface)
1065 : {
1066 0 : if (!surface->src_picture) {
1067 : XRenderPictureAttributes pa;
1068 0 : int mask = 0;
1069 :
1070 0 : pa.subwindow_mode = IncludeInferiors;
1071 0 : mask |= CPSubwindowMode;
1072 :
1073 0 : surface->src_picture = XRenderCreatePicture (display->display,
1074 : surface->drawable,
1075 0 : surface->xrender_format,
1076 : mask, &pa);
1077 : }
1078 0 : }
1079 :
1080 : static void
1081 0 : _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_display_t *display,
1082 : cairo_xlib_surface_t *surface)
1083 : {
1084 0 : if (surface->clip_region != NULL) {
1085 0 : XRenderSetPictureClipRectangles (display->display, surface->dst_picture,
1086 : 0, 0,
1087 0 : surface->clip_rects,
1088 : surface->num_clip_rects);
1089 : } else {
1090 : XRenderPictureAttributes pa;
1091 0 : pa.clip_mask = None;
1092 0 : XRenderChangePicture (display->display, surface->dst_picture,
1093 : CPClipMask, &pa);
1094 : }
1095 :
1096 0 : surface->clip_dirty &= ~CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE;
1097 0 : }
1098 :
1099 : static void
1100 0 : _cairo_xlib_surface_set_precision (cairo_xlib_display_t *display,
1101 : cairo_xlib_surface_t *surface,
1102 : cairo_antialias_t antialias)
1103 : {
1104 : int precision;
1105 :
1106 0 : switch (antialias) {
1107 : case CAIRO_ANTIALIAS_DEFAULT:
1108 : case CAIRO_ANTIALIAS_GRAY:
1109 0 : precision = PolyModeImprecise;
1110 0 : break;
1111 : case CAIRO_ANTIALIAS_NONE:
1112 : case CAIRO_ANTIALIAS_SUBPIXEL:
1113 0 : precision = PolyModePrecise;
1114 0 : break;
1115 : }
1116 :
1117 : /* NVidia's driver version 190.42 is much slower when using PolyModeInprecise */
1118 0 : precision = PolyModePrecise;
1119 :
1120 0 : if (surface->precision != precision) {
1121 : XRenderPictureAttributes pa;
1122 :
1123 0 : pa.poly_mode = precision;
1124 0 : XRenderChangePicture (display->display, surface->dst_picture,
1125 : CPPolyMode, &pa);
1126 :
1127 0 : surface->precision = precision;
1128 : }
1129 0 : }
1130 :
1131 : static void
1132 0 : _cairo_xlib_surface_ensure_dst_picture (cairo_xlib_display_t *display,
1133 : cairo_xlib_surface_t *surface)
1134 : {
1135 0 : if (!surface->dst_picture) {
1136 0 : surface->dst_picture = XRenderCreatePicture (display->display,
1137 : surface->drawable,
1138 0 : surface->xrender_format,
1139 : 0, NULL);
1140 : }
1141 :
1142 0 : if (surface->clip_dirty & CAIRO_XLIB_SURFACE_CLIP_DIRTY_PICTURE)
1143 0 : _cairo_xlib_surface_set_picture_clip_rects (display, surface);
1144 0 : }
1145 :
1146 : static cairo_status_t
1147 0 : _draw_image_surface (cairo_xlib_surface_t *surface,
1148 : cairo_image_surface_t *image,
1149 : int src_x,
1150 : int src_y,
1151 : int width,
1152 : int height,
1153 : int dst_x,
1154 : int dst_y)
1155 : {
1156 : cairo_xlib_display_t *display;
1157 : XImage ximage;
1158 : cairo_format_masks_t image_masks;
1159 0 : int native_byte_order = _native_byte_order_lsb () ? LSBFirst : MSBFirst;
1160 0 : pixman_image_t *pixman_image = NULL;
1161 : cairo_status_t status;
1162 : cairo_bool_t own_data;
1163 : GC gc;
1164 :
1165 0 : ximage.width = image->width;
1166 0 : ximage.height = image->height;
1167 0 : ximage.format = ZPixmap;
1168 0 : ximage.byte_order = native_byte_order;
1169 0 : ximage.bitmap_unit = 32; /* always for libpixman */
1170 0 : ximage.bitmap_bit_order = native_byte_order;
1171 0 : ximage.bitmap_pad = 32; /* always for libpixman */
1172 0 : ximage.depth = surface->depth;
1173 0 : ximage.red_mask = surface->r_mask;
1174 0 : ximage.green_mask = surface->g_mask;
1175 0 : ximage.blue_mask = surface->b_mask;
1176 0 : ximage.xoffset = 0;
1177 :
1178 0 : status = _cairo_xlib_display_acquire (surface->base.device, &display);
1179 0 : if (unlikely (status))
1180 0 : return status;
1181 :
1182 0 : if (!_pixman_format_to_masks (image->pixman_format, &image_masks))
1183 : {
1184 : pixman_format_code_t intermediate_format;
1185 : int ret;
1186 :
1187 0 : image_masks.alpha_mask = surface->a_mask;
1188 0 : image_masks.red_mask = surface->r_mask;
1189 0 : image_masks.green_mask = surface->g_mask;
1190 0 : image_masks.blue_mask = surface->b_mask;
1191 0 : image_masks.bpp = surface->depth;
1192 0 : ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
1193 0 : assert (ret);
1194 :
1195 0 : own_data = FALSE;
1196 :
1197 0 : pixman_image = pixman_image_create_bits (intermediate_format,
1198 : image->width,
1199 : image->height,
1200 : NULL,
1201 : 0);
1202 0 : if (pixman_image == NULL) {
1203 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1204 0 : goto BAIL;
1205 : }
1206 :
1207 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
1208 : image->pixman_image,
1209 : NULL,
1210 : pixman_image,
1211 : 0, 0,
1212 : 0, 0,
1213 : 0, 0,
1214 : image->width, image->height);
1215 :
1216 0 : ximage.bits_per_pixel = image_masks.bpp;
1217 0 : ximage.data = (char *) pixman_image_get_data (pixman_image);
1218 0 : ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
1219 :
1220 0 : ret = XInitImage (&ximage);
1221 0 : assert (ret != 0);
1222 : }
1223 0 : else if ((image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) &&
1224 0 : (image_masks.red_mask == surface->r_mask || surface->r_mask == 0) &&
1225 0 : (image_masks.green_mask == surface->g_mask || surface->g_mask == 0) &&
1226 0 : (image_masks.blue_mask == surface->b_mask || surface->b_mask == 0))
1227 0 : {
1228 : int ret;
1229 :
1230 0 : ximage.bits_per_pixel = image_masks.bpp;
1231 0 : ximage.bytes_per_line = image->stride;
1232 0 : ximage.data = (char *)image->data;
1233 0 : own_data = FALSE;
1234 :
1235 0 : ret = XInitImage (&ximage);
1236 0 : assert (ret != 0);
1237 : }
1238 : else
1239 : {
1240 : unsigned int stride, rowstride;
1241 : int x, y, x0, y0, x_off, y_off;
1242 : uint32_t in_pixel, out_pixel, *row;
1243 0 : int i_a_width=0, i_r_width=0, i_g_width=0, i_b_width=0;
1244 0 : int i_a_shift=0, i_r_shift=0, i_g_shift=0, i_b_shift=0;
1245 0 : int o_a_width=0, o_r_width=0, o_g_width=0, o_b_width=0;
1246 0 : int o_a_shift=0, o_r_shift=0, o_g_shift=0, o_b_shift=0;
1247 0 : cairo_xlib_visual_info_t *visual_info = NULL;
1248 : cairo_bool_t true_color;
1249 : int ret;
1250 :
1251 0 : if (surface->depth > 16)
1252 0 : ximage.bits_per_pixel = 32;
1253 0 : else if (surface->depth > 8)
1254 0 : ximage.bits_per_pixel = 16;
1255 0 : else if (surface->depth > 1)
1256 0 : ximage.bits_per_pixel = 8;
1257 : else
1258 0 : ximage.bits_per_pixel = 1;
1259 0 : stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width,
1260 : ximage.bits_per_pixel);
1261 0 : ximage.bytes_per_line = stride;
1262 0 : ximage.data = _cairo_malloc_ab (stride, ximage.height);
1263 0 : if (unlikely (ximage.data == NULL)) {
1264 0 : own_data = FALSE;
1265 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1266 0 : goto BAIL;
1267 : }
1268 :
1269 0 : own_data = TRUE;
1270 :
1271 0 : ret = XInitImage (&ximage);
1272 0 : assert (ret != 0);
1273 :
1274 0 : _characterize_field (image_masks.alpha_mask, &i_a_width, &i_a_shift);
1275 0 : _characterize_field (image_masks.red_mask , &i_r_width, &i_r_shift);
1276 0 : _characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift);
1277 0 : _characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift);
1278 :
1279 0 : true_color = surface->visual == NULL ||
1280 0 : surface->visual->class == TrueColor;
1281 0 : if (true_color) {
1282 0 : _characterize_field (surface->a_mask, &o_a_width, &o_a_shift);
1283 0 : _characterize_field (surface->r_mask, &o_r_width, &o_r_shift);
1284 0 : _characterize_field (surface->g_mask, &o_g_width, &o_g_shift);
1285 0 : _characterize_field (surface->b_mask, &o_b_width, &o_b_shift);
1286 : } else {
1287 0 : status = _cairo_xlib_screen_get_visual_info (display,
1288 : surface->screen,
1289 : surface->visual,
1290 : &visual_info);
1291 0 : if (unlikely (status))
1292 0 : goto BAIL;
1293 : }
1294 :
1295 0 : rowstride = image->stride >> 2;
1296 0 : row = (uint32_t *) image->data;
1297 0 : x0 = dst_x + surface->base.device_transform.x0;
1298 0 : y0 = dst_y + surface->base.device_transform.y0;
1299 0 : for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern);
1300 0 : y < ximage.height;
1301 0 : y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern))
1302 : {
1303 0 : const int8_t *dither_row = dither_pattern[y_off];
1304 :
1305 0 : for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]);
1306 0 : x < ximage.width;
1307 0 : x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0]))
1308 : {
1309 0 : int dither_adjustment = dither_row[x_off];
1310 : int a, r, g, b;
1311 :
1312 0 : if (image_masks.bpp == 1)
1313 0 : in_pixel = !! (((uint8_t*)row)[x/8] & (1 << (x & 7)));
1314 0 : else if (image_masks.bpp <= 8)
1315 0 : in_pixel = ((uint8_t*)row)[x];
1316 0 : else if (image_masks.bpp <= 16)
1317 0 : in_pixel = ((uint16_t*)row)[x];
1318 0 : else if (image_masks.bpp <= 24)
1319 : #ifdef WORDS_BIGENDIAN
1320 : in_pixel = ((uint8_t*)row)[3 * x] << 16 |
1321 : ((uint8_t*)row)[3 * x + 1] << 8 |
1322 : ((uint8_t*)row)[3 * x + 2];
1323 : #else
1324 0 : in_pixel = ((uint8_t*)row)[3 * x] |
1325 0 : ((uint8_t*)row)[3 * x + 1] << 8 |
1326 0 : ((uint8_t*)row)[3 * x + 2] << 16;
1327 : #endif
1328 : else
1329 0 : in_pixel = row[x];
1330 :
1331 : /* If the incoming image has no alpha channel, then the input
1332 : * is opaque and the output should have the maximum alpha value.
1333 : * For all other channels, their absence implies 0.
1334 : */
1335 0 : if (image_masks.alpha_mask == 0x0)
1336 0 : a = 0xff;
1337 : else
1338 0 : a = _field_to_8 (in_pixel & image_masks.alpha_mask, i_a_width, i_a_shift);
1339 0 : r = _field_to_8 (in_pixel & image_masks.red_mask , i_r_width, i_r_shift);
1340 0 : g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift);
1341 0 : b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift);
1342 :
1343 0 : if (true_color) {
1344 0 : out_pixel = _field_from_8 (a, o_a_width, o_a_shift) |
1345 0 : _field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) |
1346 0 : _field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) |
1347 0 : _field_from_8_dither (b, o_b_width, o_b_shift, dither_adjustment);
1348 : } else {
1349 0 : out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment);
1350 : }
1351 :
1352 0 : XPutPixel (&ximage, x, y, out_pixel);
1353 : }
1354 :
1355 0 : row += rowstride;
1356 : }
1357 : }
1358 :
1359 0 : status = _cairo_xlib_surface_get_gc (display, surface, &gc);
1360 0 : if (unlikely (status))
1361 0 : goto BAIL;
1362 :
1363 0 : XPutImage (display->display, surface->drawable, gc,
1364 : &ximage, src_x, src_y, dst_x, dst_y,
1365 : width, height);
1366 :
1367 0 : _cairo_xlib_surface_put_gc (display, surface, gc);
1368 :
1369 : BAIL:
1370 :
1371 0 : cairo_device_release (&display->base);
1372 :
1373 0 : if (own_data)
1374 0 : free (ximage.data);
1375 0 : if (pixman_image)
1376 0 : pixman_image_unref (pixman_image);
1377 :
1378 0 : return CAIRO_STATUS_SUCCESS;
1379 : }
1380 :
1381 : static cairo_status_t
1382 0 : _cairo_xlib_surface_acquire_source_image (void *abstract_surface,
1383 : cairo_image_surface_t **image_out,
1384 : void **image_extra)
1385 : {
1386 0 : cairo_xlib_surface_t *surface = abstract_surface;
1387 : cairo_image_surface_t *image;
1388 : cairo_status_t status;
1389 :
1390 0 : status = _get_image_surface (surface, NULL, &image, NULL);
1391 0 : if (unlikely (status))
1392 0 : return status;
1393 :
1394 0 : *image_out = image;
1395 0 : *image_extra = NULL;
1396 :
1397 0 : return CAIRO_STATUS_SUCCESS;
1398 : }
1399 :
1400 : static cairo_surface_t *
1401 0 : _cairo_xlib_surface_snapshot (void *abstract_surface)
1402 : {
1403 0 : cairo_xlib_surface_t *surface = abstract_surface;
1404 : cairo_image_surface_t *image;
1405 : cairo_status_t status;
1406 :
1407 0 : status = _get_image_surface (surface, NULL, &image, NULL);
1408 0 : if (unlikely (status))
1409 0 : return _cairo_surface_create_in_error (status);
1410 :
1411 0 : return &image->base;
1412 : }
1413 :
1414 : static void
1415 0 : _cairo_xlib_surface_release_source_image (void *abstract_surface,
1416 : cairo_image_surface_t *image,
1417 : void *image_extra)
1418 : {
1419 0 : cairo_surface_destroy (&image->base);
1420 0 : }
1421 :
1422 : static cairo_status_t
1423 0 : _cairo_xlib_surface_acquire_dest_image (void *abstract_surface,
1424 : cairo_rectangle_int_t *interest_rect,
1425 : cairo_image_surface_t **image_out,
1426 : cairo_rectangle_int_t *image_rect_out,
1427 : void **image_extra)
1428 : {
1429 0 : cairo_xlib_surface_t *surface = abstract_surface;
1430 : cairo_image_surface_t *image;
1431 : cairo_status_t status;
1432 :
1433 0 : status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
1434 0 : if (unlikely (status))
1435 0 : return status;
1436 :
1437 0 : *image_out = image;
1438 0 : *image_extra = NULL;
1439 :
1440 0 : return CAIRO_STATUS_SUCCESS;
1441 : }
1442 :
1443 : static void
1444 0 : _cairo_xlib_surface_release_dest_image (void *abstract_surface,
1445 : cairo_rectangle_int_t *interest_rect,
1446 : cairo_image_surface_t *image,
1447 : cairo_rectangle_int_t *image_rect,
1448 : void *image_extra)
1449 : {
1450 0 : cairo_xlib_surface_t *surface = abstract_surface;
1451 : cairo_status_t status;
1452 :
1453 0 : status = _draw_image_surface (surface, image,
1454 : 0, 0, image->width, image->height,
1455 : image_rect->x, image_rect->y);
1456 0 : status = _cairo_surface_set_error (&surface->base, status);
1457 :
1458 0 : cairo_surface_destroy (&image->base);
1459 0 : }
1460 :
1461 : /*
1462 : * Return whether two xlib surfaces share the same
1463 : * screen. Both core and Render drawing require this
1464 : * when using multiple drawables in an operation.
1465 : */
1466 : static inline cairo_bool_t
1467 0 : _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
1468 : cairo_xlib_surface_t *src)
1469 : {
1470 0 : return dst->screen == src->screen;
1471 : }
1472 :
1473 : static cairo_status_t
1474 0 : _cairo_xlib_surface_clone_similar (void *abstract_surface,
1475 : cairo_surface_t *src,
1476 : int src_x,
1477 : int src_y,
1478 : int width,
1479 : int height,
1480 : int *clone_offset_x,
1481 : int *clone_offset_y,
1482 : cairo_surface_t **clone_out)
1483 : {
1484 0 : cairo_xlib_surface_t *surface = abstract_surface;
1485 : cairo_xlib_surface_t *clone;
1486 : cairo_status_t status;
1487 :
1488 0 : if (src->backend == surface->base.backend ) {
1489 0 : cairo_xlib_surface_t *xlib_src = (cairo_xlib_surface_t *)src;
1490 :
1491 0 : if (_cairo_xlib_surface_same_screen (surface, xlib_src)) {
1492 0 : *clone_offset_x = 0;
1493 0 : *clone_offset_y = 0;
1494 0 : *clone_out = cairo_surface_reference (src);
1495 :
1496 0 : return CAIRO_STATUS_SUCCESS;
1497 : }
1498 0 : } else if (_cairo_surface_is_image (src)) {
1499 0 : cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
1500 :
1501 0 : if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
1502 0 : return UNSUPPORTED ("roi too large for xlib");
1503 :
1504 0 : clone = (cairo_xlib_surface_t *)
1505 0 : _cairo_xlib_surface_create_similar (surface,
1506 : image_src->base.content,
1507 : width, height);
1508 0 : if (clone == NULL)
1509 0 : return UNSUPPORTED ("unhandled image format, no similar surface");
1510 :
1511 0 : if (unlikely (clone->base.status))
1512 0 : return clone->base.status;
1513 :
1514 0 : status = _draw_image_surface (clone, image_src,
1515 : src_x, src_y,
1516 : width, height,
1517 : 0, 0);
1518 0 : if (unlikely (status)) {
1519 0 : cairo_surface_destroy (&clone->base);
1520 0 : return status;
1521 : }
1522 :
1523 0 : *clone_offset_x = src_x;
1524 0 : *clone_offset_y = src_y;
1525 0 : *clone_out = &clone->base;
1526 :
1527 0 : return CAIRO_STATUS_SUCCESS;
1528 : }
1529 :
1530 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1531 : }
1532 :
1533 : static cairo_surface_t *
1534 0 : _cairo_xlib_surface_create_solid_pattern_surface (void *abstract_surface,
1535 : const cairo_solid_pattern_t *solid_pattern)
1536 : {
1537 : /* This function's only responsibility is to create a proper surface
1538 : * for when XRender is not available. The proper surface is a xlib
1539 : * surface (as opposed to image surface which is what create_similar
1540 : * returns in those cases) and the size of the dithering pattern, not
1541 : * 1x1. This surface can then be used in
1542 : * _cairo_xlib_surface_solid_fill_rectangles() to do dithered "solid"
1543 : * fills using core protocol */
1544 :
1545 0 : cairo_xlib_surface_t *other = abstract_surface;
1546 : cairo_image_surface_t *image;
1547 0 : cairo_xlib_surface_t *surface = NULL;
1548 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
1549 : cairo_xlib_display_t *display;
1550 :
1551 0 : int width = ARRAY_LENGTH (dither_pattern[0]);
1552 0 : int height = ARRAY_LENGTH (dither_pattern);
1553 :
1554 0 : Pixmap pixmap = None;
1555 :
1556 0 : if (CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other))
1557 0 : return NULL;
1558 :
1559 0 : image = (cairo_image_surface_t *)
1560 0 : _cairo_image_surface_create_with_content (_cairo_color_get_content (&solid_pattern->color),
1561 : width, height);
1562 0 : status = image->base.status;
1563 0 : if (unlikely (status))
1564 0 : goto BAIL;
1565 :
1566 0 : status = _cairo_xlib_display_acquire (other->base.device, &display);
1567 0 : if (unlikely (status))
1568 0 : goto BAIL;
1569 :
1570 0 : pixmap = XCreatePixmap (display->display,
1571 : other->drawable,
1572 : width, height,
1573 0 : other->depth);
1574 0 : cairo_device_release (&display->base);
1575 :
1576 0 : surface = (cairo_xlib_surface_t *)
1577 0 : _cairo_xlib_surface_create_internal (other->screen,
1578 : pixmap,
1579 : other->visual,
1580 : other->xrender_format,
1581 : width, height,
1582 : other->depth);
1583 0 : status = surface->base.status;
1584 0 : if (unlikely (status))
1585 0 : goto BAIL;
1586 :
1587 0 : status = _cairo_surface_paint (&image->base,
1588 : CAIRO_OPERATOR_SOURCE,
1589 : &solid_pattern->base,
1590 : NULL);
1591 0 : if (unlikely (status))
1592 0 : goto BAIL;
1593 :
1594 0 : status = _draw_image_surface (surface, image,
1595 : 0, 0,
1596 : width, height,
1597 : 0, 0);
1598 0 : if (unlikely (status))
1599 0 : goto BAIL;
1600 :
1601 : BAIL:
1602 0 : cairo_surface_destroy (&image->base);
1603 :
1604 0 : if (status) {
1605 0 : if (pixmap != None) {
1606 0 : if (!_cairo_xlib_display_acquire (other->base.device, &display)) {
1607 0 : XFreePixmap (display->display, pixmap);
1608 0 : cairo_device_release (&display->base);
1609 : }
1610 : }
1611 0 : cairo_surface_destroy (&surface->base);
1612 :
1613 0 : return _cairo_surface_create_in_error (status);
1614 : }
1615 :
1616 0 : surface->owns_pixmap = TRUE;
1617 0 : return &surface->base;
1618 : }
1619 :
1620 : static cairo_bool_t
1621 0 : _cairo_xlib_surface_can_repaint_solid_pattern_surface (void *abstract_surface,
1622 : const cairo_solid_pattern_t *solid_pattern)
1623 : {
1624 0 : cairo_xlib_surface_t *other = abstract_surface;
1625 0 : return CAIRO_SURFACE_RENDER_HAS_COMPOSITE (other);
1626 : }
1627 :
1628 : static cairo_status_t
1629 0 : _cairo_xlib_surface_set_matrix (cairo_xlib_display_t *display,
1630 : cairo_xlib_surface_t *surface,
1631 : const cairo_matrix_t *matrix,
1632 : double xc,
1633 : double yc)
1634 : {
1635 : XTransform xtransform;
1636 :
1637 : /* Casting between pixman_transform_t and XTransform is safe because
1638 : * they happen to be the exact same type.
1639 : */
1640 0 : _cairo_matrix_to_pixman_matrix (matrix,
1641 : (pixman_transform_t *) &xtransform,
1642 : xc, yc);
1643 :
1644 0 : if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
1645 0 : return CAIRO_STATUS_SUCCESS;
1646 :
1647 0 : if (! CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
1648 0 : return UNSUPPORTED ("XRender does not support picture transforms");
1649 :
1650 0 : XRenderSetPictureTransform (display->display, surface->src_picture, &xtransform);
1651 0 : surface->xtransform = xtransform;
1652 :
1653 0 : return CAIRO_STATUS_SUCCESS;
1654 : }
1655 :
1656 : static cairo_status_t
1657 0 : _cairo_xlib_surface_set_filter (cairo_xlib_display_t *display,
1658 : cairo_xlib_surface_t *surface,
1659 : cairo_filter_t filter)
1660 : {
1661 : const char *render_filter;
1662 :
1663 0 : if (surface->filter == filter)
1664 0 : return CAIRO_STATUS_SUCCESS;
1665 :
1666 0 : if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface)) {
1667 0 : if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
1668 0 : return CAIRO_STATUS_SUCCESS;
1669 :
1670 0 : return UNSUPPORTED ("XRender does not support filter");
1671 : }
1672 :
1673 0 : switch (filter) {
1674 : case CAIRO_FILTER_FAST:
1675 0 : render_filter = FilterFast;
1676 0 : break;
1677 : case CAIRO_FILTER_GOOD:
1678 0 : render_filter = FilterGood;
1679 0 : break;
1680 : case CAIRO_FILTER_BEST:
1681 0 : render_filter = FilterBest;
1682 0 : break;
1683 : case CAIRO_FILTER_NEAREST:
1684 0 : render_filter = FilterNearest;
1685 0 : break;
1686 : case CAIRO_FILTER_BILINEAR:
1687 0 : render_filter = FilterBilinear;
1688 0 : break;
1689 : case CAIRO_FILTER_GAUSSIAN:
1690 : /* XXX: The GAUSSIAN value has no implementation in cairo
1691 : * whatsoever, so it was really a mistake to have it in the
1692 : * API. We could fix this by officially deprecating it, or
1693 : * else inventing semantics and providing an actual
1694 : * implementation for it. */
1695 : default:
1696 0 : render_filter = FilterBest;
1697 0 : break;
1698 : }
1699 :
1700 0 : XRenderSetPictureFilter (display->display, surface->src_picture,
1701 : (char *) render_filter, NULL, 0);
1702 0 : surface->filter = filter;
1703 :
1704 0 : return CAIRO_STATUS_SUCCESS;
1705 : }
1706 :
1707 : static cairo_status_t
1708 0 : _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface,
1709 : cairo_extend_t extend,
1710 : unsigned long *mask,
1711 : XRenderPictureAttributes *pa)
1712 : {
1713 : int repeat;
1714 :
1715 0 : if (surface->extend == extend)
1716 0 : return CAIRO_STATUS_SUCCESS;
1717 :
1718 0 : switch (extend) {
1719 : case CAIRO_EXTEND_NONE:
1720 0 : repeat = RepeatNone;
1721 0 : break;
1722 : case CAIRO_EXTEND_REPEAT:
1723 0 : repeat = RepeatNormal;
1724 0 : break;
1725 : case CAIRO_EXTEND_REFLECT:
1726 0 : if (surface->buggy_pad_reflect)
1727 0 : return UNSUPPORTED ("buggy reflect");
1728 :
1729 0 : repeat = RepeatReflect;
1730 0 : break;
1731 : case CAIRO_EXTEND_PAD:
1732 0 : if (surface->buggy_pad_reflect)
1733 0 : return UNSUPPORTED ("buggy pad");
1734 :
1735 0 : repeat = RepeatPad;
1736 0 : break;
1737 : default:
1738 0 : ASSERT_NOT_REACHED;
1739 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1740 : }
1741 :
1742 0 : *mask |= CPRepeat;
1743 0 : pa->repeat = repeat;
1744 :
1745 0 : surface->extend = extend;
1746 0 : return CAIRO_STATUS_SUCCESS;
1747 : }
1748 :
1749 : static cairo_status_t
1750 0 : _cairo_xlib_surface_set_component_alpha (cairo_xlib_surface_t *surface,
1751 : cairo_bool_t ca,
1752 : unsigned long *mask,
1753 : XRenderPictureAttributes *pa)
1754 : {
1755 0 : if (surface->has_component_alpha == ca)
1756 0 : return CAIRO_STATUS_SUCCESS;
1757 :
1758 0 : *mask |= CPComponentAlpha;
1759 0 : pa->component_alpha = ca;
1760 :
1761 0 : surface->has_component_alpha = ca;
1762 0 : return CAIRO_STATUS_SUCCESS;
1763 : }
1764 :
1765 : static cairo_int_status_t
1766 0 : _cairo_xlib_surface_set_attributes (cairo_xlib_display_t *display,
1767 : cairo_xlib_surface_t *surface,
1768 : const cairo_surface_attributes_t *attributes,
1769 : double xc,
1770 : double yc)
1771 : {
1772 : cairo_int_status_t status;
1773 : XRenderPictureAttributes pa;
1774 0 : unsigned long mask = 0;
1775 :
1776 0 : _cairo_xlib_surface_ensure_src_picture (display, surface);
1777 :
1778 0 : status = _cairo_xlib_surface_set_matrix (display, surface,
1779 : &attributes->matrix, xc, yc);
1780 0 : if (unlikely (status))
1781 0 : return status;
1782 :
1783 0 : status = _cairo_xlib_surface_set_repeat (surface, attributes->extend,
1784 : &mask, &pa);
1785 0 : if (unlikely (status))
1786 0 : return status;
1787 :
1788 0 : status = _cairo_xlib_surface_set_component_alpha (surface,
1789 : attributes->has_component_alpha,
1790 : &mask, &pa);
1791 0 : if (unlikely (status))
1792 0 : return status;
1793 :
1794 0 : status = _cairo_xlib_surface_set_filter (display, surface, attributes->filter);
1795 0 : if (unlikely (status))
1796 0 : return status;
1797 :
1798 0 : if (mask)
1799 0 : XRenderChangePicture (display->display, surface->src_picture, mask, &pa);
1800 :
1801 0 : return CAIRO_STATUS_SUCCESS;
1802 : }
1803 :
1804 : /* Checks whether we can can directly draw from src to dst with
1805 : * the core protocol: either with CopyArea or using src as a
1806 : * a tile in a GC.
1807 : */
1808 : static cairo_bool_t
1809 0 : _surfaces_compatible (cairo_xlib_surface_t *dst,
1810 : cairo_xlib_surface_t *src)
1811 : {
1812 : /* same screen */
1813 0 : if (! _cairo_xlib_surface_same_screen (dst, src))
1814 0 : return FALSE;
1815 :
1816 : /* same depth (for core) */
1817 0 : if (src->depth != dst->depth)
1818 0 : return FALSE;
1819 :
1820 : /* if Render is supported, match picture formats */
1821 0 : if (src->xrender_format != dst->xrender_format)
1822 0 : return FALSE;
1823 0 : else if (src->xrender_format != NULL)
1824 0 : return TRUE;
1825 :
1826 : /* Without Render, match visuals instead */
1827 0 : if (src->visual == dst->visual)
1828 0 : return TRUE;
1829 :
1830 0 : return FALSE;
1831 : }
1832 :
1833 : static cairo_bool_t
1834 0 : _surface_has_alpha (cairo_xlib_surface_t *surface)
1835 : {
1836 0 : if (surface->xrender_format) {
1837 0 : if (surface->xrender_format->type == PictTypeDirect &&
1838 0 : surface->xrender_format->direct.alphaMask != 0)
1839 0 : return TRUE;
1840 : else
1841 0 : return FALSE;
1842 : } else {
1843 : /* In the no-render case, we never have alpha */
1844 0 : return FALSE;
1845 : }
1846 : }
1847 :
1848 : /* Returns true if the given operator and alpha combination requires alpha
1849 : * compositing to complete on source and destination surfaces with the same
1850 : * format. i.e. if a simple bitwise copy is not appropriate.
1851 : */
1852 : static cairo_bool_t
1853 0 : _operator_needs_alpha_composite (cairo_operator_t op,
1854 : cairo_bool_t surfaces_have_alpha)
1855 : {
1856 0 : if (op == CAIRO_OPERATOR_SOURCE)
1857 0 : return FALSE;
1858 :
1859 0 : if (op == CAIRO_OPERATOR_OVER ||
1860 0 : op == CAIRO_OPERATOR_IN ||
1861 : op == CAIRO_OPERATOR_ATOP)
1862 0 : return surfaces_have_alpha;
1863 :
1864 0 : return TRUE;
1865 : }
1866 :
1867 : /* There is a bug in most older X servers with compositing using a
1868 : * untransformed repeating source pattern when the source is in off-screen
1869 : * video memory, and another with repeated transformed images using a
1870 : * general transform matrix. When these bugs could be triggered, we need a
1871 : * fallback: in the common case where we have no transformation and the
1872 : * source and destination have the same format/visual, we can do the
1873 : * operation using the core protocol for the first bug, otherwise, we need
1874 : * a software fallback.
1875 : *
1876 : * We can also often optimize a compositing operation by calling XCopyArea
1877 : * for some common cases where there is no alpha compositing to be done.
1878 : * We figure that out here as well.
1879 : */
1880 : typedef enum {
1881 : DO_RENDER, /* use render */
1882 : DO_XCOPYAREA, /* core protocol XCopyArea optimization/fallback */
1883 : DO_XTILE, /* core protocol XSetTile optimization/fallback */
1884 : DO_UNSUPPORTED /* software fallback */
1885 : } composite_operation_t;
1886 :
1887 : /* Initial check for the render bugs; we need to recheck for the
1888 : * offscreen-memory bug after we turn patterns into surfaces, since that
1889 : * may introduce a repeating pattern for gradient patterns. We don't need
1890 : * to check for the repeat+transform bug because gradient surfaces aren't
1891 : * transformed.
1892 : *
1893 : * All we do here is reject cases where we *know* are going to
1894 : * hit the bug and won't be able to use a core protocol fallback.
1895 : */
1896 : static composite_operation_t
1897 0 : _categorize_composite_operation (cairo_xlib_surface_t *dst,
1898 : cairo_operator_t op,
1899 : const cairo_pattern_t *src_pattern,
1900 : cairo_bool_t have_mask)
1901 :
1902 : {
1903 0 : if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (dst, op))
1904 0 : return DO_UNSUPPORTED;
1905 :
1906 0 : if (! dst->buggy_repeat)
1907 0 : return DO_RENDER;
1908 :
1909 0 : if (src_pattern->type != CAIRO_PATTERN_TYPE_SOLID &&
1910 0 : src_pattern->extend == CAIRO_EXTEND_REPEAT)
1911 : {
1912 : /* Check for the bug with repeat patterns nad general transforms. */
1913 0 : if (! _cairo_matrix_is_integer_translation (&src_pattern->matrix,
1914 : NULL, NULL))
1915 : {
1916 0 : return DO_UNSUPPORTED;
1917 : }
1918 :
1919 0 : if (have_mask ||
1920 0 : !(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
1921 : {
1922 0 : return DO_UNSUPPORTED;
1923 : }
1924 :
1925 0 : if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1926 0 : cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) src_pattern;
1927 :
1928 : /* This is the case where we have the bug involving
1929 : * untransformed repeating source patterns with off-screen
1930 : * video memory; reject some cases where a core protocol
1931 : * fallback is impossible.
1932 : */
1933 0 : if (_cairo_surface_is_xlib (surface_pattern->surface)) {
1934 0 : cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) surface_pattern->surface;
1935 :
1936 0 : if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
1937 0 : return DO_UNSUPPORTED;
1938 :
1939 : /* If these are on the same screen but otherwise incompatible,
1940 : * make a copy as core drawing can't cross depths and doesn't
1941 : * work right across visuals of the same depth
1942 : */
1943 0 : if (_cairo_xlib_surface_same_screen (dst, src) &&
1944 0 : !_surfaces_compatible (dst, src))
1945 : {
1946 0 : return DO_UNSUPPORTED;
1947 : }
1948 : }
1949 : }
1950 : }
1951 :
1952 0 : return DO_RENDER;
1953 : }
1954 :
1955 : /* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
1956 : * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
1957 : * did to turn gradients into a pattern, but most of the time we can handle
1958 : * that case with core protocol fallback.
1959 : *
1960 : * Also check here if we can just use XCopyArea, instead of going through
1961 : * Render.
1962 : */
1963 : static composite_operation_t
1964 0 : _recategorize_composite_operation (cairo_xlib_surface_t *dst,
1965 : cairo_operator_t op,
1966 : cairo_xlib_surface_t *src,
1967 : cairo_surface_attributes_t *src_attr,
1968 : cairo_bool_t have_mask)
1969 : {
1970 : /* Can we use the core protocol? */
1971 0 : if (! have_mask &&
1972 0 : _surfaces_compatible (src, dst) &&
1973 0 : _cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) &&
1974 0 : ! _operator_needs_alpha_composite (op, _surface_has_alpha (dst)))
1975 : {
1976 0 : if (src_attr->extend == CAIRO_EXTEND_NONE)
1977 0 : return DO_XCOPYAREA;
1978 :
1979 0 : if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT)
1980 0 : return DO_XTILE;
1981 : }
1982 :
1983 0 : if (dst->buggy_repeat && src_attr->extend == CAIRO_EXTEND_REPEAT &&
1984 0 : (src->width != 1 || src->height != 1))
1985 0 : return DO_UNSUPPORTED;
1986 :
1987 0 : if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
1988 0 : return DO_UNSUPPORTED;
1989 :
1990 0 : if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
1991 0 : return DO_UNSUPPORTED;
1992 :
1993 0 : return DO_RENDER;
1994 : }
1995 :
1996 : static int
1997 0 : _render_operator (cairo_operator_t op)
1998 : {
1999 0 : switch (op) {
2000 : case CAIRO_OPERATOR_CLEAR:
2001 0 : return PictOpClear;
2002 :
2003 : case CAIRO_OPERATOR_SOURCE:
2004 0 : return PictOpSrc;
2005 : case CAIRO_OPERATOR_OVER:
2006 0 : return PictOpOver;
2007 : case CAIRO_OPERATOR_IN:
2008 0 : return PictOpIn;
2009 : case CAIRO_OPERATOR_OUT:
2010 0 : return PictOpOut;
2011 : case CAIRO_OPERATOR_ATOP:
2012 0 : return PictOpAtop;
2013 :
2014 : case CAIRO_OPERATOR_DEST:
2015 0 : return PictOpDst;
2016 : case CAIRO_OPERATOR_DEST_OVER:
2017 0 : return PictOpOverReverse;
2018 : case CAIRO_OPERATOR_DEST_IN:
2019 0 : return PictOpInReverse;
2020 : case CAIRO_OPERATOR_DEST_OUT:
2021 0 : return PictOpOutReverse;
2022 : case CAIRO_OPERATOR_DEST_ATOP:
2023 0 : return PictOpAtopReverse;
2024 :
2025 : case CAIRO_OPERATOR_XOR:
2026 0 : return PictOpXor;
2027 : case CAIRO_OPERATOR_ADD:
2028 0 : return PictOpAdd;
2029 : case CAIRO_OPERATOR_SATURATE:
2030 0 : return PictOpSaturate;
2031 :
2032 : case CAIRO_OPERATOR_MULTIPLY:
2033 0 : return PictOpMultiply;
2034 : case CAIRO_OPERATOR_SCREEN:
2035 0 : return PictOpScreen;
2036 : case CAIRO_OPERATOR_OVERLAY:
2037 0 : return PictOpOverlay;
2038 : case CAIRO_OPERATOR_DARKEN:
2039 0 : return PictOpDarken;
2040 : case CAIRO_OPERATOR_LIGHTEN:
2041 0 : return PictOpLighten;
2042 : case CAIRO_OPERATOR_COLOR_DODGE:
2043 0 : return PictOpColorDodge;
2044 : case CAIRO_OPERATOR_COLOR_BURN:
2045 0 : return PictOpColorBurn;
2046 : case CAIRO_OPERATOR_HARD_LIGHT:
2047 0 : return PictOpHardLight;
2048 : case CAIRO_OPERATOR_SOFT_LIGHT:
2049 0 : return PictOpSoftLight;
2050 : case CAIRO_OPERATOR_DIFFERENCE:
2051 0 : return PictOpDifference;
2052 : case CAIRO_OPERATOR_EXCLUSION:
2053 0 : return PictOpExclusion;
2054 : case CAIRO_OPERATOR_HSL_HUE:
2055 0 : return PictOpHSLHue;
2056 : case CAIRO_OPERATOR_HSL_SATURATION:
2057 0 : return PictOpHSLSaturation;
2058 : case CAIRO_OPERATOR_HSL_COLOR:
2059 0 : return PictOpHSLColor;
2060 : case CAIRO_OPERATOR_HSL_LUMINOSITY:
2061 0 : return PictOpHSLLuminosity;
2062 :
2063 : default:
2064 0 : ASSERT_NOT_REACHED;
2065 0 : return PictOpOver;
2066 : }
2067 : }
2068 :
2069 : static cairo_int_status_t
2070 0 : _cairo_xlib_surface_acquire_pattern_surface (cairo_xlib_display_t *display,
2071 : cairo_xlib_surface_t *dst,
2072 : const cairo_pattern_t *pattern,
2073 : int x, int y,
2074 : int width, int height,
2075 : cairo_xlib_surface_t **surface_out,
2076 : cairo_surface_attributes_t *attributes)
2077 : {
2078 0 : switch (pattern->type) {
2079 : case CAIRO_PATTERN_TYPE_LINEAR:
2080 : case CAIRO_PATTERN_TYPE_RADIAL:
2081 : {
2082 0 : cairo_gradient_pattern_t *gradient =
2083 : (cairo_gradient_pattern_t *) pattern;
2084 0 : cairo_matrix_t matrix = pattern->matrix;
2085 : cairo_xlib_surface_t *surface;
2086 : char buf[CAIRO_STACK_BUFFER_SIZE];
2087 : XFixed *stops;
2088 : XRenderColor *colors;
2089 : XRenderPictFormat *format;
2090 : Picture picture;
2091 : unsigned int i;
2092 :
2093 0 : if (dst->buggy_gradients)
2094 0 : break;
2095 :
2096 0 : if (gradient->n_stops < 2) /* becomes a solid */
2097 0 : break;
2098 :
2099 0 : if (gradient->n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor)))
2100 : {
2101 0 : stops = (XFixed *) buf;
2102 : }
2103 : else
2104 : {
2105 0 : stops =
2106 0 : _cairo_malloc_ab (gradient->n_stops,
2107 : sizeof (XFixed) + sizeof (XRenderColor));
2108 0 : if (unlikely (stops == NULL))
2109 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2110 : }
2111 :
2112 0 : colors = (XRenderColor *) (stops + gradient->n_stops);
2113 0 : for (i = 0; i < gradient->n_stops; i++) {
2114 0 : stops[i] =
2115 0 : _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
2116 :
2117 0 : colors[i].red = gradient->stops[i].color.red_short;
2118 0 : colors[i].green = gradient->stops[i].color.green_short;
2119 0 : colors[i].blue = gradient->stops[i].color.blue_short;
2120 0 : colors[i].alpha = gradient->stops[i].color.alpha_short;
2121 : }
2122 :
2123 : #if 0
2124 : /* For some weird reason the X server is sometimes getting
2125 : * CreateGradient requests with bad length. So far I've only seen
2126 : * XRenderCreateLinearGradient request with 4 stops sometime end up
2127 : * with length field matching 0 stops at the server side. I've
2128 : * looked at the libXrender code and I can't see anything that
2129 : * could cause this behavior. However, for some reason having a
2130 : * XSync call here seems to avoid the issue so I'll keep it here
2131 : * until it's solved.
2132 : */
2133 : XSync (display->display, False);
2134 : #endif
2135 :
2136 0 : if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
2137 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
2138 : XLinearGradient grad;
2139 :
2140 : cairo_fixed_t xdim, ydim;
2141 :
2142 0 : xdim = linear->p2.x - linear->p1.x;
2143 0 : ydim = linear->p2.y - linear->p1.y;
2144 :
2145 : /*
2146 : * Transform the matrix to avoid overflow when converting between
2147 : * cairo_fixed_t and pixman_fixed_t (without incurring performance
2148 : * loss when the transformation is unnecessary).
2149 : *
2150 : * XXX: Consider converting out-of-range co-ordinates and transforms.
2151 : * Having a function to compute the required transformation to
2152 : * "normalize" a given bounding box would be generally useful -
2153 : * cf linear patterns, gradient patterns, surface patterns...
2154 : */
2155 : #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
2156 0 : if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
2157 0 : _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
2158 0 : {
2159 : double sf;
2160 :
2161 0 : if (xdim > ydim)
2162 0 : sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
2163 : else
2164 0 : sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
2165 :
2166 0 : grad.p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
2167 0 : grad.p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
2168 0 : grad.p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
2169 0 : grad.p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
2170 :
2171 0 : cairo_matrix_scale (&matrix, sf, sf);
2172 : }
2173 : else
2174 : {
2175 0 : grad.p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
2176 0 : grad.p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
2177 0 : grad.p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
2178 0 : grad.p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
2179 : }
2180 :
2181 0 : picture = XRenderCreateLinearGradient (display->display, &grad,
2182 : stops, colors,
2183 0 : gradient->n_stops);
2184 : } else {
2185 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
2186 : XRadialGradient grad;
2187 :
2188 0 : grad.inner.x = _cairo_fixed_to_16_16 (radial->c1.x);
2189 0 : grad.inner.y = _cairo_fixed_to_16_16 (radial->c1.y);
2190 0 : grad.inner.radius = _cairo_fixed_to_16_16 (radial->r1);
2191 :
2192 0 : grad.outer.x = _cairo_fixed_to_16_16 (radial->c2.x);
2193 0 : grad.outer.y = _cairo_fixed_to_16_16 (radial->c2.y);
2194 0 : grad.outer.radius = _cairo_fixed_to_16_16 (radial->r2);
2195 :
2196 0 : picture = XRenderCreateRadialGradient (display->display, &grad,
2197 : stops, colors,
2198 0 : gradient->n_stops);
2199 :
2200 : }
2201 :
2202 0 : if (stops != (XFixed *) buf)
2203 0 : free (stops);
2204 :
2205 0 : if (unlikely (picture == None))
2206 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2207 :
2208 : /* Wrap the remote Picture in an xlib surface. */
2209 0 : format = _cairo_xlib_display_get_xrender_format (display,
2210 : CAIRO_FORMAT_ARGB32);
2211 :
2212 0 : surface = (cairo_xlib_surface_t *)
2213 0 : _cairo_xlib_surface_create_internal (dst->screen, None,
2214 : NULL, format,
2215 : /* what could possibly go wrong? */
2216 : XLIB_COORD_MAX, XLIB_COORD_MAX, 32);
2217 0 : if (unlikely (surface->base.status)) {
2218 0 : XRenderFreePicture (display->display, picture);
2219 0 : return surface->base.status;
2220 : }
2221 :
2222 0 : surface->src_picture = picture;
2223 :
2224 0 : attributes->matrix = matrix;
2225 0 : attributes->extend = pattern->extend;
2226 0 : attributes->filter = CAIRO_FILTER_NEAREST;
2227 0 : attributes->x_offset = 0;
2228 0 : attributes->y_offset = 0;
2229 0 : attributes->has_component_alpha = FALSE;
2230 :
2231 0 : *surface_out = surface;
2232 0 : return CAIRO_STATUS_SUCCESS;
2233 : }
2234 : default:
2235 0 : ASSERT_NOT_REACHED;
2236 : case CAIRO_PATTERN_TYPE_SOLID:
2237 : case CAIRO_PATTERN_TYPE_SURFACE:
2238 0 : break;
2239 : }
2240 :
2241 0 : return _cairo_pattern_acquire_surface (pattern, &dst->base,
2242 : x, y, width, height,
2243 0 : dst->buggy_pad_reflect ?
2244 : CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
2245 : CAIRO_PATTERN_ACQUIRE_NONE,
2246 : (cairo_surface_t **) surface_out,
2247 : attributes);
2248 : }
2249 :
2250 : static cairo_int_status_t
2251 0 : _cairo_xlib_surface_acquire_pattern_surfaces (cairo_xlib_display_t *display,
2252 : cairo_xlib_surface_t *dst,
2253 : const cairo_pattern_t *src,
2254 : const cairo_pattern_t *mask,
2255 : int src_x,
2256 : int src_y,
2257 : int mask_x,
2258 : int mask_y,
2259 : unsigned int width,
2260 : unsigned int height,
2261 : cairo_xlib_surface_t **src_out,
2262 : cairo_xlib_surface_t **mask_out,
2263 : cairo_surface_attributes_t *src_attr,
2264 : cairo_surface_attributes_t *mask_attr)
2265 : {
2266 0 : if (! dst->buggy_gradients &&
2267 0 : (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
2268 0 : src->type == CAIRO_PATTERN_TYPE_RADIAL ||
2269 0 : (mask && (mask->type == CAIRO_PATTERN_TYPE_LINEAR ||
2270 0 : mask->type == CAIRO_PATTERN_TYPE_RADIAL))))
2271 : {
2272 : cairo_int_status_t status;
2273 :
2274 0 : status = _cairo_xlib_surface_acquire_pattern_surface (display,
2275 : dst, src,
2276 : src_x, src_y,
2277 : width, height,
2278 : src_out,
2279 : src_attr);
2280 0 : if (unlikely (status))
2281 0 : return status;
2282 :
2283 0 : if (mask) {
2284 0 : status = _cairo_xlib_surface_acquire_pattern_surface (display,
2285 : dst, mask,
2286 : mask_x,
2287 : mask_y,
2288 : width,
2289 : height,
2290 : mask_out,
2291 : mask_attr);
2292 0 : if (unlikely (status)) {
2293 0 : _cairo_pattern_release_surface (src, &(*src_out)->base,
2294 : src_attr);
2295 0 : return status;
2296 : }
2297 : } else {
2298 0 : *mask_out = NULL;
2299 : }
2300 :
2301 0 : return CAIRO_STATUS_SUCCESS;
2302 : }
2303 :
2304 0 : return _cairo_pattern_acquire_surfaces (src, mask,
2305 : &dst->base,
2306 : src_x, src_y,
2307 : mask_x, mask_y,
2308 : width, height,
2309 0 : dst->buggy_pad_reflect ?
2310 : CAIRO_PATTERN_ACQUIRE_NO_REFLECT :
2311 : CAIRO_PATTERN_ACQUIRE_NONE,
2312 : (cairo_surface_t **) src_out,
2313 : (cairo_surface_t **) mask_out,
2314 : src_attr, mask_attr);
2315 : }
2316 :
2317 : static cairo_int_status_t
2318 0 : _cairo_xlib_surface_upload(cairo_xlib_surface_t *surface,
2319 : cairo_operator_t op,
2320 : const cairo_pattern_t *pattern,
2321 : int src_x, int src_y,
2322 : int dst_x, int dst_y,
2323 : unsigned int width,
2324 : unsigned int height,
2325 : cairo_region_t *clip_region)
2326 : {
2327 : cairo_image_surface_t *image;
2328 : cairo_rectangle_int_t extents;
2329 : cairo_status_t status;
2330 : int tx, ty;
2331 :
2332 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
2333 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2334 :
2335 0 : image = (cairo_image_surface_t *) ((cairo_surface_pattern_t *) pattern)->surface;
2336 0 : if (image->base.type != CAIRO_SURFACE_TYPE_IMAGE)
2337 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2338 :
2339 0 : if (! (op == CAIRO_OPERATOR_SOURCE ||
2340 0 : (op == CAIRO_OPERATOR_OVER &&
2341 0 : (image->base.content & CAIRO_CONTENT_ALPHA) == 0)))
2342 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2343 :
2344 0 : if (image->base.backend->type != CAIRO_SURFACE_TYPE_IMAGE) {
2345 0 : if (image->base.backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
2346 0 : image = (cairo_image_surface_t *) ((cairo_surface_snapshot_t *) image)->target;
2347 0 : extents.x = extents.y = 0;
2348 0 : extents.width = image->width;
2349 0 : extents.height = image->height;
2350 0 : } else if (image->base.backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
2351 0 : cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) image;
2352 0 : image = (cairo_image_surface_t *) sub->target;
2353 0 : src_x += sub->extents.x;
2354 0 : src_y += sub->extents.y;
2355 0 : extents = sub->extents;
2356 : } else {
2357 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2358 : }
2359 : } else {
2360 0 : extents.x = extents.y = 0;
2361 0 : extents.width = image->width;
2362 0 : extents.height = image->height;
2363 : }
2364 :
2365 0 : if (image->format == CAIRO_FORMAT_INVALID)
2366 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2367 0 : if (image->depth != surface->depth)
2368 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2369 :
2370 0 : if (! _cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty))
2371 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2372 :
2373 0 : src_x += tx;
2374 0 : src_y += ty;
2375 :
2376 : /* XXX for EXTEND_NONE perform unbounded fixups? */
2377 0 : if (src_x < extents.x ||
2378 0 : src_y < extents.y ||
2379 0 : src_x + width > (unsigned) extents.width ||
2380 0 : src_y + height > (unsigned) extents.height)
2381 : {
2382 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2383 : }
2384 :
2385 0 : status = cairo_device_acquire (surface->base.device);
2386 0 : if (unlikely (status))
2387 0 : return status;
2388 :
2389 0 : if (clip_region != NULL) {
2390 : int n, num_rect;
2391 :
2392 0 : src_x -= dst_x;
2393 0 : src_y -= dst_y;
2394 :
2395 0 : num_rect = cairo_region_num_rectangles (clip_region);
2396 0 : for (n = 0; n < num_rect; n++) {
2397 : cairo_rectangle_int_t rect;
2398 :
2399 0 : cairo_region_get_rectangle (clip_region, n, &rect);
2400 0 : status = _draw_image_surface (surface, image,
2401 0 : rect.x + src_x, rect.y + src_y,
2402 : rect.width, rect.height,
2403 : rect.x, rect.y);
2404 0 : if (unlikely (status))
2405 0 : break;
2406 : }
2407 : } else {
2408 0 : status = _draw_image_surface (surface, image,
2409 : src_x, src_y,
2410 : width, height,
2411 : dst_x, dst_y);
2412 : }
2413 :
2414 0 : cairo_device_release (surface->base.device);
2415 :
2416 0 : return status;
2417 : }
2418 :
2419 : static cairo_int_status_t
2420 0 : _cairo_xlib_surface_composite (cairo_operator_t op,
2421 : const cairo_pattern_t *src_pattern,
2422 : const cairo_pattern_t *mask_pattern,
2423 : void *abstract_dst,
2424 : int src_x,
2425 : int src_y,
2426 : int mask_x,
2427 : int mask_y,
2428 : int dst_x,
2429 : int dst_y,
2430 : unsigned int width,
2431 : unsigned int height,
2432 : cairo_region_t *clip_region)
2433 : {
2434 : cairo_surface_attributes_t src_attr, mask_attr;
2435 0 : cairo_xlib_surface_t *dst = abstract_dst;
2436 : cairo_xlib_surface_t *src;
2437 : cairo_xlib_surface_t *mask;
2438 : cairo_xlib_display_t *display;
2439 : cairo_int_status_t status;
2440 : composite_operation_t operation;
2441 : int itx, ity;
2442 : cairo_bool_t is_integer_translation;
2443 : GC gc;
2444 :
2445 0 : if (mask_pattern != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
2446 0 : return UNSUPPORTED ("no support for masks");
2447 :
2448 0 : operation = _categorize_composite_operation (dst, op, src_pattern,
2449 : mask_pattern != NULL);
2450 0 : if (operation == DO_UNSUPPORTED)
2451 0 : return UNSUPPORTED ("unsupported operation");
2452 :
2453 : X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable));
2454 :
2455 0 : if (mask_pattern == NULL) {
2456 : /* Can we do a simple upload in-place? */
2457 0 : status = _cairo_xlib_surface_upload(dst, op, src_pattern,
2458 : src_x, src_y,
2459 : dst_x, dst_y,
2460 : width, height,
2461 : clip_region);
2462 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2463 0 : return status;
2464 : }
2465 :
2466 0 : status = _cairo_xlib_display_acquire (dst-> base.device, &display);
2467 0 : if (unlikely (status))
2468 0 : return status;
2469 :
2470 0 : status =
2471 0 : _cairo_xlib_surface_acquire_pattern_surfaces (display, dst,
2472 : src_pattern, mask_pattern,
2473 : src_x, src_y,
2474 : mask_x, mask_y,
2475 : width, height,
2476 : &src, &mask,
2477 : &src_attr, &mask_attr);
2478 0 : if (unlikely (status))
2479 0 : goto BAIL0;
2480 :
2481 : /* check for fallback surfaces that we cannot handle ... */
2482 0 : assert (_cairo_surface_is_xlib (&src->base));
2483 0 : assert (mask == NULL || _cairo_surface_is_xlib (&mask->base));
2484 :
2485 0 : if (mask != NULL && ! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (mask)) {
2486 0 : status = UNSUPPORTED ("unsupported mask");
2487 0 : goto BAIL;
2488 : }
2489 :
2490 0 : operation = _recategorize_composite_operation (dst, op, src, &src_attr,
2491 : mask_pattern != NULL);
2492 0 : if (operation == DO_UNSUPPORTED) {
2493 0 : status = UNSUPPORTED ("unsupported operation");
2494 0 : goto BAIL;
2495 : }
2496 :
2497 0 : switch (operation)
2498 : {
2499 : case DO_RENDER:
2500 0 : status = _cairo_xlib_surface_set_attributes (display,
2501 : src, &src_attr,
2502 0 : dst_x + width / 2.,
2503 0 : dst_y + height / 2.);
2504 0 : if (unlikely (status))
2505 0 : goto BAIL;
2506 :
2507 0 : status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
2508 0 : if (unlikely (status))
2509 0 : goto BAIL;
2510 :
2511 0 : _cairo_xlib_surface_ensure_dst_picture (display, dst);
2512 0 : if (mask) {
2513 0 : status = _cairo_xlib_surface_set_attributes (display,
2514 : mask, &mask_attr,
2515 0 : dst_x + width / 2.,
2516 0 : dst_y + height/ 2.);
2517 0 : if (unlikely (status))
2518 0 : goto BAIL;
2519 :
2520 0 : XRenderComposite (display->display,
2521 : _render_operator (op),
2522 0 : src->src_picture,
2523 0 : mask->src_picture,
2524 : dst->dst_picture,
2525 0 : src_x + src_attr.x_offset,
2526 0 : src_y + src_attr.y_offset,
2527 0 : mask_x + mask_attr.x_offset,
2528 0 : mask_y + mask_attr.y_offset,
2529 : dst_x, dst_y,
2530 : width, height);
2531 : } else {
2532 0 : XRenderComposite (display->display,
2533 : _render_operator (op),
2534 0 : src->src_picture,
2535 : 0,
2536 : dst->dst_picture,
2537 0 : src_x + src_attr.x_offset,
2538 0 : src_y + src_attr.y_offset,
2539 : 0, 0,
2540 : dst_x, dst_y,
2541 : width, height);
2542 : }
2543 :
2544 0 : break;
2545 :
2546 : case DO_XCOPYAREA:
2547 0 : status = _cairo_xlib_surface_get_gc (display, dst, &gc);
2548 0 : if (unlikely (status))
2549 0 : goto BAIL;
2550 :
2551 0 : is_integer_translation =
2552 : _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
2553 : /* This is a pre-condition for DO_XCOPYAREA. */
2554 0 : assert (is_integer_translation);
2555 :
2556 0 : if (clip_region == NULL) {
2557 0 : XCopyArea (display->display, src->drawable, dst->drawable, gc,
2558 0 : src_x + src_attr.x_offset + itx,
2559 0 : src_y + src_attr.y_offset + ity,
2560 : width, height,
2561 : dst_x, dst_y);
2562 : } else {
2563 : int n, num_rects, x, y;
2564 :
2565 0 : x = src_x + src_attr.x_offset + itx - dst_x;
2566 0 : y = src_y + src_attr.y_offset + ity - dst_y;
2567 :
2568 0 : num_rects = cairo_region_num_rectangles (clip_region);
2569 0 : for (n = 0; n < num_rects; n++) {
2570 : cairo_rectangle_int_t rect;
2571 :
2572 0 : cairo_region_get_rectangle (clip_region, n, &rect);
2573 0 : XCopyArea (display->display, src->drawable, dst->drawable, gc,
2574 0 : rect.x + x, rect.y + y,
2575 0 : rect.width, rect.height,
2576 : rect.x, rect.y);
2577 : }
2578 : }
2579 :
2580 0 : _cairo_xlib_surface_put_gc (display, dst, gc);
2581 0 : break;
2582 :
2583 : case DO_XTILE:
2584 : /* This case is only used for bug fallbacks, though we also use it for
2585 : * the case where we don't have the RENDER extension, by forcing
2586 : * buggy_repeat to TRUE.
2587 : *
2588 : * We've checked that we have a repeating unscaled source in
2589 : * _recategorize_composite_operation.
2590 : */
2591 :
2592 0 : status = _cairo_xlib_surface_get_gc (display, dst, &gc);
2593 0 : if (unlikely (status))
2594 0 : goto BAIL;
2595 :
2596 0 : is_integer_translation =
2597 : _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
2598 : /* This is a pre-condition for DO_XTILE. */
2599 0 : assert (is_integer_translation);
2600 :
2601 0 : XSetTSOrigin (display->display, gc,
2602 0 : - (itx + src_attr.x_offset), - (ity + src_attr.y_offset));
2603 0 : XSetTile (display->display, gc, src->drawable);
2604 :
2605 0 : if (clip_region == NULL) {
2606 0 : XFillRectangle (display->display, dst->drawable, gc,
2607 : dst_x, dst_y, width, height);
2608 : } else {
2609 : int n, num_rects;
2610 :
2611 0 : num_rects = cairo_region_num_rectangles (clip_region);
2612 0 : for (n = 0; n < num_rects; n++) {
2613 : cairo_rectangle_int_t rect;
2614 :
2615 0 : cairo_region_get_rectangle (clip_region, n, &rect);
2616 0 : XFillRectangle (display->display, dst->drawable, gc,
2617 0 : rect.x, rect.y, rect.width, rect.height);
2618 : }
2619 : }
2620 :
2621 0 : _cairo_xlib_surface_put_gc (display, dst, gc);
2622 0 : break;
2623 :
2624 : case DO_UNSUPPORTED:
2625 : default:
2626 0 : ASSERT_NOT_REACHED;
2627 : }
2628 :
2629 0 : if (!_cairo_operator_bounded_by_source (op))
2630 0 : status = _cairo_surface_composite_fixup_unbounded (&dst->base,
2631 0 : &src_attr, src->width, src->height,
2632 0 : mask ? &mask_attr : NULL,
2633 0 : mask ? mask->width : 0,
2634 0 : mask ? mask->height : 0,
2635 : src_x, src_y,
2636 : mask_x, mask_y,
2637 : dst_x, dst_y, width, height,
2638 : clip_region);
2639 :
2640 : BAIL:
2641 0 : if (mask)
2642 0 : _cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
2643 :
2644 0 : _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
2645 :
2646 : BAIL0:
2647 0 : cairo_device_release (&display->base);
2648 :
2649 0 : return status;
2650 : }
2651 :
2652 : /* XXX move this out of core and into acquire_pattern_surface() above. */
2653 : static cairo_int_status_t
2654 0 : _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
2655 : const cairo_color_t *color,
2656 : cairo_rectangle_int_t *rects,
2657 : int num_rects)
2658 : {
2659 : cairo_status_t status;
2660 : cairo_solid_pattern_t solid;
2661 0 : cairo_surface_t *solid_surface = NULL;
2662 : cairo_surface_attributes_t attrs;
2663 : cairo_xlib_display_t *display;
2664 : GC gc;
2665 : int i;
2666 :
2667 0 : _cairo_pattern_init_solid (&solid, color);
2668 :
2669 0 : status = _cairo_xlib_display_acquire (surface->base.device, &display);
2670 0 : if (unlikely (status))
2671 0 : return status;
2672 :
2673 0 : status = _cairo_xlib_surface_get_gc (display, surface, &gc);
2674 0 : if (unlikely (status))
2675 0 : return status;
2676 :
2677 : X_DEBUG ((display->display, "solid_fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
2678 :
2679 0 : status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
2680 : 0, 0,
2681 : ARRAY_LENGTH (dither_pattern[0]),
2682 : ARRAY_LENGTH (dither_pattern),
2683 : CAIRO_PATTERN_ACQUIRE_NONE,
2684 : &solid_surface,
2685 : &attrs);
2686 0 : if (unlikely (status)) {
2687 0 : _cairo_xlib_surface_put_gc (display, surface, gc);
2688 0 : cairo_device_release (&display->base);
2689 0 : return status;
2690 : }
2691 :
2692 0 : assert (_cairo_surface_is_xlib (solid_surface));
2693 :
2694 0 : XSetTSOrigin (display->display, gc,
2695 0 : - (surface->base.device_transform.x0 + attrs.x_offset),
2696 0 : - (surface->base.device_transform.y0 + attrs.y_offset));
2697 0 : XSetTile (display->display, gc,
2698 0 : ((cairo_xlib_surface_t *) solid_surface)->drawable);
2699 :
2700 0 : for (i = 0; i < num_rects; i++) {
2701 0 : XFillRectangle (display->display, surface->drawable, gc,
2702 0 : rects[i].x, rects[i].y,
2703 0 : rects[i].width, rects[i].height);
2704 : }
2705 :
2706 0 : _cairo_xlib_surface_put_gc (display, surface, gc);
2707 :
2708 0 : _cairo_pattern_release_surface (&solid.base, solid_surface, &attrs);
2709 :
2710 0 : cairo_device_release (&display->base);
2711 :
2712 0 : return CAIRO_STATUS_SUCCESS;
2713 : }
2714 :
2715 : static cairo_int_status_t
2716 0 : _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
2717 : cairo_operator_t op,
2718 : const cairo_color_t *color,
2719 : cairo_rectangle_int_t *rects,
2720 : int num_rects)
2721 : {
2722 0 : cairo_xlib_surface_t *surface = abstract_surface;
2723 : cairo_xlib_display_t *display;
2724 : XRenderColor render_color;
2725 : cairo_status_t status;
2726 : int i;
2727 :
2728 0 : if (!CAIRO_SURFACE_RENDER_SUPPORTS_OPERATOR (surface, op))
2729 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2730 :
2731 0 : if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
2732 0 : if (op == CAIRO_OPERATOR_CLEAR ||
2733 0 : ((op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER) &&
2734 0 : CAIRO_COLOR_IS_OPAQUE (color)))
2735 : {
2736 0 : return _cairo_xlib_surface_solid_fill_rectangles (surface, color,
2737 : rects, num_rects);
2738 : }
2739 :
2740 0 : return UNSUPPORTED ("no support for FillRectangles with this op");
2741 : }
2742 :
2743 0 : status = _cairo_xlib_display_acquire (surface->base.device, &display);
2744 0 : if (unlikely (status))
2745 0 : return status;
2746 :
2747 : X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
2748 :
2749 0 : render_color.red = color->red_short;
2750 0 : render_color.green = color->green_short;
2751 0 : render_color.blue = color->blue_short;
2752 0 : render_color.alpha = color->alpha_short;
2753 :
2754 0 : status = _cairo_xlib_surface_set_clip_region (surface, NULL);
2755 0 : assert (status == CAIRO_STATUS_SUCCESS);
2756 :
2757 0 : _cairo_xlib_surface_ensure_dst_picture (display, surface);
2758 0 : if (num_rects == 1) {
2759 : /* Take advantage of the protocol compaction that libXrender performs
2760 : * to amalgamate sequences of XRenderFillRectangle().
2761 : */
2762 0 : XRenderFillRectangle (display->display,
2763 : _render_operator (op),
2764 : surface->dst_picture,
2765 : &render_color,
2766 : rects->x,
2767 : rects->y,
2768 0 : rects->width,
2769 0 : rects->height);
2770 : } else {
2771 : XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
2772 0 : XRectangle *xrects = static_xrects;
2773 :
2774 0 : if (num_rects > ARRAY_LENGTH (static_xrects)) {
2775 0 : xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
2776 0 : if (unlikely (xrects == NULL)) {
2777 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2778 0 : goto BAIL;
2779 : }
2780 : }
2781 :
2782 0 : for (i = 0; i < num_rects; i++) {
2783 0 : xrects[i].x = rects[i].x;
2784 0 : xrects[i].y = rects[i].y;
2785 0 : xrects[i].width = rects[i].width;
2786 0 : xrects[i].height = rects[i].height;
2787 : }
2788 :
2789 0 : XRenderFillRectangles (display->display,
2790 : _render_operator (op),
2791 : surface->dst_picture,
2792 : &render_color, xrects, num_rects);
2793 :
2794 0 : if (xrects != static_xrects)
2795 0 : free (xrects);
2796 : }
2797 :
2798 : BAIL:
2799 0 : cairo_device_release (&display->base);
2800 0 : return status;
2801 : }
2802 :
2803 : #define CAIRO_FIXED_16_16_MIN -32768
2804 : #define CAIRO_FIXED_16_16_MAX 32767
2805 :
2806 : static cairo_bool_t
2807 0 : _line_exceeds_16_16 (const cairo_line_t *line)
2808 : {
2809 : return
2810 0 : line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
2811 0 : line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
2812 0 : line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
2813 0 : line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
2814 0 : line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
2815 0 : line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) ||
2816 0 : line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) ||
2817 0 : line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX);
2818 : }
2819 :
2820 : static void
2821 0 : _project_line_x_onto_16_16 (const cairo_line_t *line,
2822 : cairo_fixed_t top,
2823 : cairo_fixed_t bottom,
2824 : XLineFixed *out)
2825 : {
2826 : cairo_point_double_t p1, p2;
2827 : double m;
2828 :
2829 0 : p1.x = _cairo_fixed_to_double (line->p1.x);
2830 0 : p1.y = _cairo_fixed_to_double (line->p1.y);
2831 :
2832 0 : p2.x = _cairo_fixed_to_double (line->p2.x);
2833 0 : p2.y = _cairo_fixed_to_double (line->p2.y);
2834 :
2835 0 : m = (p2.x - p1.x) / (p2.y - p1.y);
2836 0 : out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
2837 0 : out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
2838 0 : }
2839 :
2840 : static cairo_int_status_t
2841 0 : _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
2842 : const cairo_pattern_t *pattern,
2843 : void *abstract_dst,
2844 : cairo_antialias_t antialias,
2845 : int src_x,
2846 : int src_y,
2847 : int dst_x,
2848 : int dst_y,
2849 : unsigned int width,
2850 : unsigned int height,
2851 : cairo_trapezoid_t *traps,
2852 : int num_traps,
2853 : cairo_region_t *clip_region)
2854 : {
2855 : cairo_surface_attributes_t attributes;
2856 0 : cairo_xlib_surface_t *dst = abstract_dst;
2857 : cairo_xlib_surface_t *src;
2858 : cairo_xlib_display_t *display;
2859 : cairo_int_status_t status;
2860 : composite_operation_t operation;
2861 : int render_reference_x, render_reference_y;
2862 : int render_src_x, render_src_y;
2863 : XRenderPictFormat *pict_format;
2864 : XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)];
2865 0 : XTrapezoid *xtraps = xtraps_stack;
2866 : int i;
2867 :
2868 0 : if (! CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
2869 0 : return UNSUPPORTED ("XRender does not support CompositeTrapezoids");
2870 :
2871 0 : operation = _categorize_composite_operation (dst, op, pattern, TRUE);
2872 0 : if (operation == DO_UNSUPPORTED)
2873 0 : return UNSUPPORTED ("unsupported operation");
2874 :
2875 0 : status = _cairo_xlib_display_acquire (dst->base.device, &display);
2876 0 : if (unlikely (status))
2877 0 : return status;
2878 :
2879 : X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable));
2880 :
2881 0 : status = _cairo_xlib_surface_acquire_pattern_surface (display,
2882 : dst,
2883 : pattern,
2884 : src_x, src_y,
2885 : width, height,
2886 : &src, &attributes);
2887 0 : if (unlikely (status))
2888 0 : goto BAIL0;
2889 :
2890 0 : operation = _recategorize_composite_operation (dst, op, src,
2891 : &attributes, TRUE);
2892 0 : if (operation == DO_UNSUPPORTED) {
2893 0 : status = UNSUPPORTED ("unsupported operation");
2894 0 : goto BAIL;
2895 : }
2896 :
2897 0 : switch (antialias) {
2898 : case CAIRO_ANTIALIAS_NONE:
2899 0 : pict_format =
2900 0 : _cairo_xlib_display_get_xrender_format (display,
2901 : CAIRO_FORMAT_A1);
2902 0 : break;
2903 : case CAIRO_ANTIALIAS_GRAY:
2904 : case CAIRO_ANTIALIAS_SUBPIXEL:
2905 : case CAIRO_ANTIALIAS_DEFAULT:
2906 : default:
2907 0 : pict_format =
2908 0 : _cairo_xlib_display_get_xrender_format (display,
2909 : CAIRO_FORMAT_A8);
2910 0 : break;
2911 : }
2912 :
2913 0 : status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
2914 0 : if (unlikely (status))
2915 0 : goto BAIL;
2916 :
2917 0 : _cairo_xlib_surface_ensure_dst_picture (display, dst);
2918 0 : _cairo_xlib_surface_set_precision (display, dst, antialias);
2919 :
2920 0 : status = _cairo_xlib_surface_set_attributes (display,
2921 : src, &attributes,
2922 0 : dst_x + width / 2.,
2923 0 : dst_y + height / 2.);
2924 0 : if (unlikely (status))
2925 0 : goto BAIL;
2926 :
2927 0 : if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
2928 0 : xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
2929 0 : if (unlikely (xtraps == NULL)) {
2930 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2931 0 : goto BAIL;
2932 : }
2933 : }
2934 :
2935 0 : for (i = 0; i < num_traps; i++) {
2936 : /* top/bottom will be clamped to surface bounds */
2937 0 : xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
2938 0 : xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
2939 :
2940 : /* However, all the other coordinates will have been left untouched so
2941 : * as not to introduce numerical error. Recompute them if they
2942 : * exceed the 16.16 limits.
2943 : */
2944 0 : if (unlikely (_line_exceeds_16_16 (&traps[i].left))) {
2945 0 : _project_line_x_onto_16_16 (&traps[i].left,
2946 0 : traps[i].top,
2947 0 : traps[i].bottom,
2948 0 : &xtraps[i].left);
2949 0 : xtraps[i].left.p1.y = xtraps[i].top;
2950 0 : xtraps[i].left.p2.y = xtraps[i].bottom;
2951 : } else {
2952 0 : xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
2953 0 : xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
2954 0 : xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
2955 0 : xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
2956 : }
2957 :
2958 0 : if (unlikely (_line_exceeds_16_16 (&traps[i].right))) {
2959 0 : _project_line_x_onto_16_16 (&traps[i].right,
2960 0 : traps[i].top,
2961 0 : traps[i].bottom,
2962 0 : &xtraps[i].right);
2963 0 : xtraps[i].right.p1.y = xtraps[i].top;
2964 0 : xtraps[i].right.p2.y = xtraps[i].bottom;
2965 : } else {
2966 0 : xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
2967 0 : xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
2968 0 : xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
2969 0 : xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
2970 : }
2971 : }
2972 :
2973 0 : if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
2974 0 : render_reference_x = _cairo_fixed_16_16_floor (xtraps[0].left.p1.x);
2975 0 : render_reference_y = _cairo_fixed_16_16_floor (xtraps[0].left.p1.y);
2976 : } else {
2977 0 : render_reference_x = _cairo_fixed_16_16_floor (xtraps[0].left.p2.x);
2978 0 : render_reference_y = _cairo_fixed_16_16_floor (xtraps[0].left.p2.y);
2979 : }
2980 :
2981 0 : render_src_x = src_x + render_reference_x - dst_x;
2982 0 : render_src_y = src_y + render_reference_y - dst_y;
2983 :
2984 0 : XRenderCompositeTrapezoids (display->display,
2985 : _render_operator (op),
2986 0 : src->src_picture, dst->dst_picture,
2987 : pict_format,
2988 0 : render_src_x + attributes.x_offset,
2989 0 : render_src_y + attributes.y_offset,
2990 : xtraps, num_traps);
2991 :
2992 0 : if (xtraps != xtraps_stack)
2993 0 : free (xtraps);
2994 :
2995 0 : if (! _cairo_operator_bounded_by_mask (op)) {
2996 : cairo_traps_t _traps;
2997 : cairo_box_t box;
2998 : cairo_rectangle_int_t extents;
2999 :
3000 : /* XRenderCompositeTrapezoids() creates a mask only large enough for the
3001 : * trapezoids themselves, but if the operator is unbounded, then we need
3002 : * to actually composite all the way out to the bounds.
3003 : */
3004 : /* XXX: update the interface to pass composite rects */
3005 0 : _traps.traps = traps;
3006 0 : _traps.num_traps = num_traps;
3007 0 : _cairo_traps_extents (&_traps, &box);
3008 0 : _cairo_box_round_to_rectangle (&box, &extents);
3009 :
3010 0 : status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
3011 : &attributes,
3012 0 : src->width, src->height,
3013 : extents.width, extents.height,
3014 : src_x, src_y,
3015 0 : -extents.x + dst_x, -extents.y + dst_y,
3016 : dst_x, dst_y,
3017 : width, height,
3018 : clip_region);
3019 : }
3020 :
3021 : BAIL:
3022 0 : _cairo_pattern_release_surface (pattern, &src->base, &attributes);
3023 : BAIL0:
3024 0 : cairo_device_release (&display->base);
3025 :
3026 0 : return status;
3027 : }
3028 :
3029 : static cairo_bool_t
3030 0 : _cairo_xlib_surface_get_extents (void *abstract_surface,
3031 : cairo_rectangle_int_t *rectangle)
3032 : {
3033 0 : cairo_xlib_surface_t *surface = abstract_surface;
3034 :
3035 0 : rectangle->x = 0;
3036 0 : rectangle->y = 0;
3037 :
3038 0 : rectangle->width = surface->width;
3039 0 : rectangle->height = surface->height;
3040 :
3041 0 : return TRUE;
3042 : }
3043 :
3044 : static void
3045 0 : _cairo_xlib_surface_get_font_options (void *abstract_surface,
3046 : cairo_font_options_t *options)
3047 : {
3048 0 : cairo_xlib_surface_t *surface = abstract_surface;
3049 :
3050 0 : *options = *_cairo_xlib_screen_get_font_options (surface->screen);
3051 0 : }
3052 :
3053 : static void
3054 : _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
3055 :
3056 : static void
3057 : _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
3058 : cairo_scaled_font_t *scaled_font);
3059 :
3060 : static cairo_bool_t
3061 0 : _cairo_xlib_surface_is_similar (void *surface_a,
3062 : void *surface_b)
3063 : {
3064 0 : return _cairo_xlib_surface_same_screen (surface_a, surface_b);
3065 : }
3066 :
3067 : static const cairo_surface_backend_t cairo_xlib_surface_backend = {
3068 : CAIRO_SURFACE_TYPE_XLIB,
3069 : _cairo_xlib_surface_create_similar,
3070 : _cairo_xlib_surface_finish,
3071 : _cairo_xlib_surface_acquire_source_image,
3072 : _cairo_xlib_surface_release_source_image,
3073 : _cairo_xlib_surface_acquire_dest_image,
3074 : _cairo_xlib_surface_release_dest_image,
3075 : _cairo_xlib_surface_clone_similar,
3076 : _cairo_xlib_surface_composite,
3077 : _cairo_xlib_surface_fill_rectangles,
3078 : _cairo_xlib_surface_composite_trapezoids,
3079 : NULL, /* create_span_renderer */
3080 : NULL, /* check_span_renderer */
3081 : NULL, /* copy_page */
3082 : NULL, /* show_page */
3083 : _cairo_xlib_surface_get_extents,
3084 : NULL, /* old_show_glyphs */
3085 : _cairo_xlib_surface_get_font_options,
3086 : NULL, /* flush */
3087 : NULL, /* mark_dirty_rectangle */
3088 : _cairo_xlib_surface_scaled_font_fini,
3089 : _cairo_xlib_surface_scaled_glyph_fini,
3090 :
3091 : NULL, /* paint */
3092 : NULL, /* mask */
3093 : NULL, /* stroke */
3094 : NULL, /* fill */
3095 : _cairo_xlib_surface_show_glyphs,
3096 :
3097 : _cairo_xlib_surface_snapshot,
3098 : _cairo_xlib_surface_is_similar,
3099 :
3100 : NULL, /* fill_stroke */
3101 :
3102 : _cairo_xlib_surface_create_solid_pattern_surface,
3103 : _cairo_xlib_surface_can_repaint_solid_pattern_surface
3104 : };
3105 :
3106 : /**
3107 : * _cairo_surface_is_xlib:
3108 : * @surface: a #cairo_surface_t
3109 : *
3110 : * Checks if a surface is a #cairo_xlib_surface_t
3111 : *
3112 : * Return value: True if the surface is an xlib surface
3113 : **/
3114 : static cairo_bool_t
3115 0 : _cairo_surface_is_xlib (cairo_surface_t *surface)
3116 : {
3117 0 : return surface->backend == &cairo_xlib_surface_backend;
3118 : }
3119 :
3120 : /* callback from CloseDisplay */
3121 : static void
3122 0 : _cairo_xlib_surface_detach_display (cairo_xlib_display_t *display, void *data)
3123 : {
3124 0 : cairo_xlib_surface_t *surface = cairo_container_of (data,
3125 : cairo_xlib_surface_t,
3126 : close_display_hook);
3127 : Display *dpy;
3128 :
3129 0 : dpy = display->display;
3130 :
3131 : X_DEBUG ((dpy, "detach (drawable=%x)", (unsigned int) surface->drawable));
3132 :
3133 0 : if (surface->dst_picture != None) {
3134 0 : XRenderFreePicture (dpy, surface->dst_picture);
3135 0 : surface->dst_picture = None;
3136 : }
3137 :
3138 0 : if (surface->src_picture != None) {
3139 0 : XRenderFreePicture (dpy, surface->src_picture);
3140 0 : surface->src_picture = None;
3141 : }
3142 :
3143 0 : if (surface->owns_pixmap) {
3144 0 : XFreePixmap (dpy, surface->drawable);
3145 0 : surface->drawable = None;
3146 0 : surface->owns_pixmap = FALSE;
3147 : }
3148 0 : }
3149 :
3150 : static cairo_surface_t *
3151 0 : _cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen,
3152 : Drawable drawable,
3153 : Visual *visual,
3154 : XRenderPictFormat *xrender_format,
3155 : int width,
3156 : int height,
3157 : int depth)
3158 : {
3159 : cairo_xlib_surface_t *surface;
3160 : cairo_xlib_display_t *display;
3161 : cairo_status_t status;
3162 :
3163 0 : if (depth == 0) {
3164 0 : if (xrender_format) {
3165 0 : depth = xrender_format->depth;
3166 :
3167 : /* XXX find matching visual for core/dithering fallbacks? */
3168 0 : } else if (visual) {
3169 0 : Screen *scr = screen->screen;
3170 :
3171 0 : if (visual == DefaultVisualOfScreen (scr)) {
3172 0 : depth = DefaultDepthOfScreen (scr);
3173 : } else {
3174 : int j, k;
3175 :
3176 : /* This is ugly, but we have to walk over all visuals
3177 : * for the display to find the correct depth.
3178 : */
3179 0 : depth = 0;
3180 0 : for (j = 0; j < scr->ndepths; j++) {
3181 0 : Depth *d = &scr->depths[j];
3182 0 : for (k = 0; k < d->nvisuals; k++) {
3183 0 : if (&d->visuals[k] == visual) {
3184 0 : depth = d->depth;
3185 0 : goto found;
3186 : }
3187 : }
3188 : }
3189 : }
3190 : }
3191 :
3192 0 : if (depth == 0)
3193 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
3194 :
3195 : found:
3196 : ;
3197 : }
3198 :
3199 0 : surface = malloc (sizeof (cairo_xlib_surface_t));
3200 0 : if (unlikely (surface == NULL))
3201 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
3202 :
3203 0 : status = _cairo_xlib_display_acquire (screen->device, &display);
3204 0 : if (unlikely (status)) {
3205 0 : free (surface);
3206 0 : return _cairo_surface_create_in_error (_cairo_error (status));
3207 : }
3208 :
3209 0 : _cairo_xlib_display_get_xrender_version (display,
3210 : &surface->render_major,
3211 : &surface->render_minor);
3212 0 : if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
3213 0 : if (!xrender_format) {
3214 0 : if (visual) {
3215 0 : xrender_format = XRenderFindVisualFormat (display->display, visual);
3216 0 : } else if (depth == 1) {
3217 0 : xrender_format =
3218 0 : _cairo_xlib_display_get_xrender_format (display,
3219 : CAIRO_FORMAT_A1);
3220 : }
3221 : }
3222 : } else {
3223 : /* we cannot use XRender for this surface, so ensure we don't try */
3224 0 : surface->render_major = -1;
3225 0 : surface->render_minor = -1;
3226 : }
3227 :
3228 : /* initialize and hook into the CloseDisplay callback */
3229 0 : surface->close_display_hook.func = _cairo_xlib_surface_detach_display;
3230 0 : _cairo_xlib_add_close_display_hook (display,
3231 : &surface->close_display_hook);
3232 :
3233 0 : cairo_device_release (&display->base);
3234 :
3235 0 : _cairo_surface_init (&surface->base,
3236 : &cairo_xlib_surface_backend,
3237 : screen->device,
3238 : _xrender_format_to_content (xrender_format));
3239 :
3240 0 : surface->screen = screen;
3241 :
3242 0 : surface->drawable = drawable;
3243 0 : surface->owns_pixmap = FALSE;
3244 0 : surface->use_pixmap = 0;
3245 0 : surface->width = width;
3246 0 : surface->height = height;
3247 :
3248 0 : surface->buggy_repeat = ! _cairo_xlib_display_has_repeat (screen->device);
3249 0 : if (! CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES (surface)) {
3250 : /* so we can use the XTile fallback */
3251 0 : surface->buggy_repeat = TRUE;
3252 : }
3253 :
3254 0 : surface->buggy_pad_reflect = ! _cairo_xlib_display_has_reflect (screen->device);
3255 0 : if (! CAIRO_SURFACE_RENDER_HAS_EXTENDED_REPEAT (surface))
3256 0 : surface->buggy_pad_reflect = TRUE;
3257 :
3258 0 : surface->buggy_gradients = ! _cairo_xlib_display_has_gradients (screen->device);
3259 0 : if (! CAIRO_SURFACE_RENDER_HAS_GRADIENTS (surface))
3260 0 : surface->buggy_gradients = TRUE;
3261 :
3262 0 : surface->dst_picture = None;
3263 0 : surface->src_picture = None;
3264 :
3265 0 : surface->visual = visual;
3266 0 : surface->xrender_format = xrender_format;
3267 0 : surface->depth = depth;
3268 0 : surface->filter = CAIRO_FILTER_NEAREST;
3269 0 : surface->extend = CAIRO_EXTEND_NONE;
3270 0 : surface->has_component_alpha = FALSE;
3271 0 : surface->precision = PolyModePrecise;
3272 0 : surface->xtransform = identity;
3273 :
3274 0 : surface->clip_region = NULL;
3275 0 : surface->clip_rects = surface->embedded_clip_rects;
3276 0 : surface->num_clip_rects = 0;
3277 0 : surface->clip_dirty = 0;
3278 :
3279 : /*
3280 : * Compute the pixel format masks from either a XrenderFormat or
3281 : * else from a visual; failing that we assume the drawable is an
3282 : * alpha-only pixmap as it could only have been created that way
3283 : * through the cairo_xlib_surface_create_for_bitmap function.
3284 : */
3285 0 : if (xrender_format) {
3286 0 : surface->a_mask = (unsigned long)
3287 0 : surface->xrender_format->direct.alphaMask
3288 0 : << surface->xrender_format->direct.alpha;
3289 0 : surface->r_mask = (unsigned long)
3290 0 : surface->xrender_format->direct.redMask
3291 0 : << surface->xrender_format->direct.red;
3292 0 : surface->g_mask = (unsigned long)
3293 0 : surface->xrender_format->direct.greenMask
3294 0 : << surface->xrender_format->direct.green;
3295 0 : surface->b_mask = (unsigned long)
3296 0 : surface->xrender_format->direct.blueMask
3297 0 : << surface->xrender_format->direct.blue;
3298 0 : } else if (visual) {
3299 0 : surface->a_mask = 0;
3300 0 : surface->r_mask = visual->red_mask;
3301 0 : surface->g_mask = visual->green_mask;
3302 0 : surface->b_mask = visual->blue_mask;
3303 : } else {
3304 0 : if (depth < 32)
3305 0 : surface->a_mask = (1 << depth) - 1;
3306 : else
3307 0 : surface->a_mask = 0xffffffff;
3308 0 : surface->r_mask = 0;
3309 0 : surface->g_mask = 0;
3310 0 : surface->b_mask = 0;
3311 : }
3312 :
3313 0 : return &surface->base;
3314 : }
3315 :
3316 : static Screen *
3317 0 : _cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
3318 : {
3319 : int s, d, v;
3320 :
3321 0 : for (s = 0; s < ScreenCount (dpy); s++) {
3322 : Screen *screen;
3323 :
3324 0 : screen = ScreenOfDisplay (dpy, s);
3325 0 : if (visual == DefaultVisualOfScreen (screen))
3326 0 : return screen;
3327 :
3328 0 : for (d = 0; d < screen->ndepths; d++) {
3329 : Depth *depth;
3330 :
3331 0 : depth = &screen->depths[d];
3332 0 : for (v = 0; v < depth->nvisuals; v++)
3333 0 : if (visual == &depth->visuals[v])
3334 0 : return screen;
3335 : }
3336 : }
3337 :
3338 0 : return NULL;
3339 : }
3340 :
3341 : /**
3342 : * cairo_xlib_surface_create:
3343 : * @dpy: an X Display
3344 : * @drawable: an X Drawable, (a Pixmap or a Window)
3345 : * @visual: the visual to use for drawing to @drawable. The depth
3346 : * of the visual must match the depth of the drawable.
3347 : * Currently, only TrueColor visuals are fully supported.
3348 : * @width: the current width of @drawable.
3349 : * @height: the current height of @drawable.
3350 : *
3351 : * Creates an Xlib surface that draws to the given drawable.
3352 : * The way that colors are represented in the drawable is specified
3353 : * by the provided visual.
3354 : *
3355 : * Note: If @drawable is a Window, then the function
3356 : * cairo_xlib_surface_set_size() must be called whenever the size of the
3357 : * window changes.
3358 : *
3359 : * When @drawable is a Window containing child windows then drawing to
3360 : * the created surface will be clipped by those child windows. When
3361 : * the created surface is used as a source, the contents of the
3362 : * children will be included.
3363 : *
3364 : * Return value: the newly created surface
3365 : **/
3366 : cairo_surface_t *
3367 0 : cairo_xlib_surface_create (Display *dpy,
3368 : Drawable drawable,
3369 : Visual *visual,
3370 : int width,
3371 : int height)
3372 : {
3373 : Screen *scr;
3374 : cairo_xlib_screen_t *screen;
3375 : cairo_status_t status;
3376 :
3377 0 : if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
3378 : /* you're lying, and you know it! */
3379 0 : return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
3380 : }
3381 :
3382 0 : scr = _cairo_xlib_screen_from_visual (dpy, visual);
3383 0 : if (scr == NULL)
3384 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
3385 :
3386 0 : status = _cairo_xlib_screen_get (dpy, scr, &screen);
3387 0 : if (unlikely (status))
3388 0 : return _cairo_surface_create_in_error (status);
3389 :
3390 : X_DEBUG ((dpy, "create (drawable=%x)", (unsigned int) drawable));
3391 :
3392 0 : return _cairo_xlib_surface_create_internal (screen, drawable,
3393 : visual, NULL,
3394 : width, height, 0);
3395 : }
3396 :
3397 : /**
3398 : * cairo_xlib_surface_create_for_bitmap:
3399 : * @dpy: an X Display
3400 : * @bitmap: an X Drawable, (a depth-1 Pixmap)
3401 : * @screen: the X Screen associated with @bitmap
3402 : * @width: the current width of @bitmap.
3403 : * @height: the current height of @bitmap.
3404 : *
3405 : * Creates an Xlib surface that draws to the given bitmap.
3406 : * This will be drawn to as a %CAIRO_FORMAT_A1 object.
3407 : *
3408 : * Return value: the newly created surface
3409 : **/
3410 : cairo_surface_t *
3411 0 : cairo_xlib_surface_create_for_bitmap (Display *dpy,
3412 : Pixmap bitmap,
3413 : Screen *scr,
3414 : int width,
3415 : int height)
3416 : {
3417 : cairo_xlib_screen_t *screen;
3418 : cairo_status_t status;
3419 :
3420 0 : if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
3421 0 : return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
3422 :
3423 0 : status = _cairo_xlib_screen_get (dpy, scr, &screen);
3424 0 : if (unlikely (status))
3425 0 : return _cairo_surface_create_in_error (status);
3426 :
3427 : X_DEBUG ((dpy, "create_for_bitmap (drawable=%x)", (unsigned int) bitmap));
3428 :
3429 0 : return _cairo_xlib_surface_create_internal (screen, bitmap,
3430 : NULL, NULL,
3431 : width, height, 1);
3432 : }
3433 :
3434 : #if CAIRO_HAS_XLIB_XRENDER_SURFACE
3435 : /**
3436 : * cairo_xlib_surface_create_with_xrender_format:
3437 : * @dpy: an X Display
3438 : * @drawable: an X Drawable, (a Pixmap or a Window)
3439 : * @screen: the X Screen associated with @drawable
3440 : * @format: the picture format to use for drawing to @drawable. The depth
3441 : * of @format must match the depth of the drawable.
3442 : * @width: the current width of @drawable.
3443 : * @height: the current height of @drawable.
3444 : *
3445 : * Creates an Xlib surface that draws to the given drawable.
3446 : * The way that colors are represented in the drawable is specified
3447 : * by the provided picture format.
3448 : *
3449 : * Note: If @drawable is a Window, then the function
3450 : * cairo_xlib_surface_set_size() must be called whenever the size of the
3451 : * window changes.
3452 : *
3453 : * Return value: the newly created surface
3454 : **/
3455 : cairo_surface_t *
3456 0 : cairo_xlib_surface_create_with_xrender_format (Display *dpy,
3457 : Drawable drawable,
3458 : Screen *scr,
3459 : XRenderPictFormat *format,
3460 : int width,
3461 : int height)
3462 : {
3463 : cairo_xlib_screen_t *screen;
3464 : cairo_status_t status;
3465 :
3466 0 : if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
3467 0 : return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
3468 :
3469 0 : status = _cairo_xlib_screen_get (dpy, scr, &screen);
3470 0 : if (unlikely (status))
3471 0 : return _cairo_surface_create_in_error (status);
3472 :
3473 : X_DEBUG ((dpy, "create_with_xrender_format (drawable=%x)", (unsigned int) drawable));
3474 :
3475 0 : return _cairo_xlib_surface_create_internal (screen, drawable,
3476 : _visual_for_xrender_format (scr, format),
3477 : format, width, height, 0);
3478 : }
3479 :
3480 : /**
3481 : * cairo_xlib_surface_get_xrender_format:
3482 : * @surface: an xlib surface
3483 : *
3484 : * Gets the X Render picture format that @surface uses for rendering with the
3485 : * X Render extension. If the surface was created by
3486 : * cairo_xlib_surface_create_with_xrender_format() originally, the return
3487 : * value is the format passed to that constructor.
3488 : *
3489 : * Return value: the XRenderPictFormat* associated with @surface,
3490 : * or %NULL if the surface is not an xlib surface
3491 : * or if the X Render extension is not available.
3492 : *
3493 : * Since: 1.6
3494 : **/
3495 : XRenderPictFormat *
3496 0 : cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
3497 : {
3498 0 : cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
3499 :
3500 : /* Throw an error for a non-xlib surface */
3501 0 : if (! _cairo_surface_is_xlib (surface)) {
3502 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3503 0 : return NULL;
3504 : }
3505 :
3506 0 : return xlib_surface->xrender_format;
3507 : }
3508 : #endif
3509 :
3510 : /**
3511 : * cairo_xlib_surface_set_size:
3512 : * @surface: a #cairo_surface_t for the XLib backend
3513 : * @width: the new width of the surface
3514 : * @height: the new height of the surface
3515 : *
3516 : * Informs cairo of the new size of the X Drawable underlying the
3517 : * surface. For a surface created for a Window (rather than a Pixmap),
3518 : * this function must be called each time the size of the window
3519 : * changes. (For a subwindow, you are normally resizing the window
3520 : * yourself, but for a toplevel window, it is necessary to listen for
3521 : * ConfigureNotify events.)
3522 : *
3523 : * A Pixmap can never change size, so it is never necessary to call
3524 : * this function on a surface created for a Pixmap.
3525 : **/
3526 : void
3527 0 : cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
3528 : int width,
3529 : int height)
3530 : {
3531 0 : cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3532 : cairo_status_t status;
3533 :
3534 0 : if (unlikely (abstract_surface->status))
3535 0 : return;
3536 0 : if (unlikely (abstract_surface->finished)) {
3537 0 : status = _cairo_surface_set_error (abstract_surface,
3538 : _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
3539 0 : return;
3540 : }
3541 :
3542 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3543 0 : status = _cairo_surface_set_error (abstract_surface,
3544 : _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
3545 0 : return;
3546 : }
3547 :
3548 0 : if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
3549 0 : status = _cairo_surface_set_error (abstract_surface,
3550 : _cairo_error (CAIRO_STATUS_INVALID_SIZE));
3551 0 : return;
3552 : }
3553 :
3554 0 : surface->width = width;
3555 0 : surface->height = height;
3556 : }
3557 : /**
3558 : * cairo_xlib_surface_set_drawable:
3559 : * @surface: a #cairo_surface_t for the XLib backend
3560 : * @drawable: the new drawable for the surface
3561 : * @width: the width of the new drawable
3562 : * @height: the height of the new drawable
3563 : *
3564 : * Informs cairo of a new X Drawable underlying the
3565 : * surface. The drawable must match the display, screen
3566 : * and format of the existing drawable or the application
3567 : * will get X protocol errors and will probably terminate.
3568 : * No checks are done by this function to ensure this
3569 : * compatibility.
3570 : **/
3571 : void
3572 0 : cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
3573 : Drawable drawable,
3574 : int width,
3575 : int height)
3576 : {
3577 0 : cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface;
3578 : cairo_status_t status;
3579 :
3580 0 : if (unlikely (abstract_surface->status))
3581 0 : return;
3582 0 : if (unlikely (abstract_surface->finished)) {
3583 0 : status = _cairo_surface_set_error (abstract_surface,
3584 : _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
3585 0 : return;
3586 : }
3587 :
3588 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3589 0 : status = _cairo_surface_set_error (abstract_surface,
3590 : _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
3591 0 : return;
3592 : }
3593 :
3594 0 : if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
3595 0 : status = _cairo_surface_set_error (abstract_surface,
3596 : _cairo_error (CAIRO_STATUS_INVALID_SIZE));
3597 0 : return;
3598 : }
3599 :
3600 : /* XXX: and what about this case? */
3601 0 : if (surface->owns_pixmap)
3602 0 : return;
3603 :
3604 0 : if (surface->drawable != drawable) {
3605 : cairo_xlib_display_t *display;
3606 :
3607 0 : status = _cairo_xlib_display_acquire (surface->base.device, &display);
3608 0 : if (unlikely (status))
3609 0 : return;
3610 :
3611 : X_DEBUG ((display->display, "set_drawable (drawable=%x)", (unsigned int) drawable));
3612 :
3613 0 : if (surface->dst_picture != None) {
3614 0 : status = _cairo_xlib_display_queue_resource (
3615 : display,
3616 : XRenderFreePicture,
3617 : surface->dst_picture);
3618 0 : if (unlikely (status)) {
3619 0 : status = _cairo_surface_set_error (&surface->base, status);
3620 0 : return;
3621 : }
3622 :
3623 0 : surface->dst_picture = None;
3624 : }
3625 :
3626 0 : if (surface->src_picture != None) {
3627 0 : status = _cairo_xlib_display_queue_resource (
3628 : display,
3629 : XRenderFreePicture,
3630 : surface->src_picture);
3631 0 : if (unlikely (status)) {
3632 0 : status = _cairo_surface_set_error (&surface->base, status);
3633 0 : return;
3634 : }
3635 :
3636 0 : surface->src_picture = None;
3637 : }
3638 :
3639 0 : cairo_device_release (&display->base);
3640 :
3641 0 : surface->drawable = drawable;
3642 : }
3643 0 : surface->width = width;
3644 0 : surface->height = height;
3645 : }
3646 :
3647 : /**
3648 : * cairo_xlib_surface_get_display:
3649 : * @surface: a #cairo_xlib_surface_t
3650 : *
3651 : * Get the X Display for the underlying X Drawable.
3652 : *
3653 : * Return value: the display.
3654 : *
3655 : * Since: 1.2
3656 : **/
3657 : Display *
3658 0 : cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
3659 : {
3660 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3661 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3662 0 : return NULL;
3663 : }
3664 :
3665 0 : return ((cairo_xlib_display_t *) abstract_surface->device)->display;
3666 : }
3667 :
3668 : /**
3669 : * cairo_xlib_surface_get_drawable:
3670 : * @surface: a #cairo_xlib_surface_t
3671 : *
3672 : * Get the underlying X Drawable used for the surface.
3673 : *
3674 : * Return value: the drawable.
3675 : *
3676 : * Since: 1.2
3677 : **/
3678 : Drawable
3679 0 : cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
3680 : {
3681 0 : cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3682 :
3683 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3684 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3685 0 : return 0;
3686 : }
3687 :
3688 0 : return surface->drawable;
3689 : }
3690 :
3691 : /**
3692 : * cairo_xlib_surface_get_screen:
3693 : * @surface: a #cairo_xlib_surface_t
3694 : *
3695 : * Get the X Screen for the underlying X Drawable.
3696 : *
3697 : * Return value: the screen.
3698 : *
3699 : * Since: 1.2
3700 : **/
3701 : Screen *
3702 0 : cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
3703 : {
3704 0 : cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3705 :
3706 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3707 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3708 0 : return NULL;
3709 : }
3710 :
3711 0 : return surface->screen->screen;
3712 : }
3713 :
3714 : /**
3715 : * cairo_xlib_surface_get_visual:
3716 : * @surface: a #cairo_xlib_surface_t
3717 : *
3718 : * Gets the X Visual associated with @surface, suitable for use with the
3719 : * underlying X Drawable. If @surface was created by
3720 : * cairo_xlib_surface_create(), the return value is the Visual passed to that
3721 : * constructor.
3722 : *
3723 : * Return value: the Visual or %NULL if there is no appropriate Visual for
3724 : * @surface.
3725 : *
3726 : * Since: 1.2
3727 : **/
3728 : Visual *
3729 0 : cairo_xlib_surface_get_visual (cairo_surface_t *surface)
3730 : {
3731 0 : cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface;
3732 :
3733 0 : if (! _cairo_surface_is_xlib (surface)) {
3734 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3735 0 : return NULL;
3736 : }
3737 :
3738 0 : return xlib_surface->visual;
3739 : }
3740 :
3741 : /**
3742 : * cairo_xlib_surface_get_depth:
3743 : * @surface: a #cairo_xlib_surface_t
3744 : *
3745 : * Get the number of bits used to represent each pixel value.
3746 : *
3747 : * Return value: the depth of the surface in bits.
3748 : *
3749 : * Since: 1.2
3750 : **/
3751 : int
3752 0 : cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
3753 : {
3754 0 : cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3755 :
3756 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3757 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3758 0 : return 0;
3759 : }
3760 :
3761 0 : return surface->depth;
3762 : }
3763 :
3764 : /**
3765 : * cairo_xlib_surface_get_width:
3766 : * @surface: a #cairo_xlib_surface_t
3767 : *
3768 : * Get the width of the X Drawable underlying the surface in pixels.
3769 : *
3770 : * Return value: the width of the surface in pixels.
3771 : *
3772 : * Since: 1.2
3773 : **/
3774 : int
3775 0 : cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
3776 : {
3777 0 : cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3778 :
3779 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3780 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3781 0 : return 0;
3782 : }
3783 :
3784 0 : return surface->width;
3785 : }
3786 :
3787 : /**
3788 : * cairo_xlib_surface_get_height:
3789 : * @surface: a #cairo_xlib_surface_t
3790 : *
3791 : * Get the height of the X Drawable underlying the surface in pixels.
3792 : *
3793 : * Return value: the height of the surface in pixels.
3794 : *
3795 : * Since: 1.2
3796 : **/
3797 : int
3798 0 : cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
3799 : {
3800 0 : cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
3801 :
3802 0 : if (! _cairo_surface_is_xlib (abstract_surface)) {
3803 0 : _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
3804 0 : return 0;
3805 : }
3806 :
3807 0 : return surface->height;
3808 : }
3809 :
3810 : enum {
3811 : GLYPHSET_INDEX_ARGB32,
3812 : GLYPHSET_INDEX_A8,
3813 : GLYPHSET_INDEX_A1,
3814 : NUM_GLYPHSETS
3815 : };
3816 :
3817 : typedef struct _cairo_xlib_font_glyphset_free_glyphs {
3818 : GlyphSet glyphset;
3819 : int glyph_count;
3820 : unsigned long glyph_indices[128];
3821 : } cairo_xlib_font_glyphset_free_glyphs_t;
3822 :
3823 : typedef struct _cairo_xlib_font_glyphset_info {
3824 : GlyphSet glyphset;
3825 : cairo_format_t format;
3826 : XRenderPictFormat *xrender_format;
3827 : cairo_xlib_font_glyphset_free_glyphs_t *pending_free_glyphs;
3828 : } cairo_xlib_font_glyphset_info_t;
3829 :
3830 : typedef struct _cairo_xlib_surface_font_private {
3831 : cairo_scaled_font_t *scaled_font;
3832 : cairo_scaled_font_t *grayscale_font;
3833 : cairo_xlib_hook_t close_display_hook;
3834 : cairo_device_t *device;
3835 : cairo_xlib_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
3836 : } cairo_xlib_surface_font_private_t;
3837 :
3838 : /* callback from CloseDisplay */
3839 : static void
3840 0 : _cairo_xlib_surface_remove_scaled_font (cairo_xlib_display_t *display,
3841 : void *data)
3842 : {
3843 : cairo_xlib_surface_font_private_t *font_private;
3844 : cairo_scaled_font_t *scaled_font;
3845 :
3846 0 : font_private = cairo_container_of (data,
3847 : cairo_xlib_surface_font_private_t,
3848 : close_display_hook);
3849 0 : scaled_font = font_private->scaled_font;
3850 :
3851 0 : CAIRO_MUTEX_LOCK (scaled_font->mutex);
3852 0 : font_private = scaled_font->surface_private;
3853 0 : scaled_font->surface_private = NULL;
3854 :
3855 0 : _cairo_scaled_font_reset_cache (scaled_font);
3856 0 : CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
3857 :
3858 0 : if (font_private != NULL) {
3859 : int i;
3860 :
3861 0 : if (font_private->grayscale_font) {
3862 0 : cairo_scaled_font_destroy (font_private->grayscale_font);
3863 : }
3864 :
3865 0 : for (i = 0; i < NUM_GLYPHSETS; i++) {
3866 : cairo_xlib_font_glyphset_info_t *glyphset_info;
3867 :
3868 0 : glyphset_info = &font_private->glyphset_info[i];
3869 0 : if (glyphset_info->glyphset)
3870 0 : XRenderFreeGlyphSet (display->display, glyphset_info->glyphset);
3871 :
3872 0 : if (glyphset_info->pending_free_glyphs != NULL)
3873 0 : free (glyphset_info->pending_free_glyphs);
3874 : }
3875 :
3876 0 : cairo_device_destroy (font_private->device);
3877 0 : free (font_private);
3878 : }
3879 0 : }
3880 :
3881 : static cairo_status_t
3882 0 : _cairo_xlib_surface_font_init (cairo_xlib_display_t *display,
3883 : cairo_scaled_font_t *scaled_font)
3884 : {
3885 : cairo_xlib_surface_font_private_t *font_private;
3886 : int i;
3887 :
3888 0 : font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
3889 0 : if (unlikely (font_private == NULL))
3890 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3891 :
3892 0 : font_private->scaled_font = scaled_font;
3893 0 : font_private->grayscale_font = NULL;
3894 0 : font_private->device = cairo_device_reference (&display->base);
3895 :
3896 : /* initialize and hook into the CloseDisplay callback */
3897 0 : font_private->close_display_hook.func =
3898 : _cairo_xlib_surface_remove_scaled_font;
3899 0 : _cairo_xlib_add_close_display_hook (display,
3900 : &font_private->close_display_hook);
3901 :
3902 :
3903 0 : for (i = 0; i < NUM_GLYPHSETS; i++) {
3904 0 : cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
3905 0 : switch (i) {
3906 0 : case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
3907 0 : case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
3908 0 : case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
3909 0 : default: ASSERT_NOT_REACHED; break;
3910 : }
3911 0 : glyphset_info->xrender_format = NULL;
3912 0 : glyphset_info->glyphset = None;
3913 0 : glyphset_info->pending_free_glyphs = NULL;
3914 : }
3915 :
3916 0 : scaled_font->surface_private = font_private;
3917 0 : scaled_font->surface_backend = &cairo_xlib_surface_backend;
3918 :
3919 0 : return CAIRO_STATUS_SUCCESS;
3920 : }
3921 :
3922 : static void
3923 0 : _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
3924 : {
3925 : cairo_xlib_surface_font_private_t *font_private;
3926 : cairo_status_t status;
3927 :
3928 0 : font_private = scaled_font->surface_private;
3929 0 : if (font_private != NULL) {
3930 : cairo_xlib_display_t *display;
3931 : int i;
3932 :
3933 0 : if (font_private->grayscale_font) {
3934 0 : cairo_scaled_font_destroy (font_private->grayscale_font);
3935 : }
3936 0 : status = _cairo_xlib_display_acquire (font_private->device, &display);
3937 0 : if (status)
3938 0 : goto BAIL;
3939 :
3940 0 : _cairo_xlib_remove_close_display_hook (display,
3941 : &font_private->close_display_hook);
3942 :
3943 0 : for (i = 0; i < NUM_GLYPHSETS; i++) {
3944 : cairo_xlib_font_glyphset_info_t *glyphset_info;
3945 :
3946 0 : glyphset_info = &font_private->glyphset_info[i];
3947 :
3948 0 : if (glyphset_info->pending_free_glyphs != NULL)
3949 0 : free (glyphset_info->pending_free_glyphs);
3950 :
3951 0 : if (glyphset_info->glyphset) {
3952 0 : status = _cairo_xlib_display_queue_resource (display,
3953 : XRenderFreeGlyphSet,
3954 : glyphset_info->glyphset);
3955 : (void) status; /* XXX cannot propagate failure */
3956 : }
3957 : }
3958 :
3959 0 : cairo_device_release (&display->base);
3960 : BAIL:
3961 0 : cairo_device_destroy (&display->base);
3962 0 : free (font_private);
3963 : }
3964 0 : }
3965 :
3966 : static void
3967 0 : _cairo_xlib_render_free_glyphs (Display *dpy,
3968 : cairo_xlib_font_glyphset_free_glyphs_t *to_free)
3969 : {
3970 0 : XRenderFreeGlyphs (dpy,
3971 : to_free->glyphset,
3972 0 : to_free->glyph_indices,
3973 : to_free->glyph_count);
3974 0 : }
3975 :
3976 : static cairo_xlib_font_glyphset_info_t *
3977 0 : _cairo_xlib_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
3978 : {
3979 0 : return scaled_glyph->surface_private;
3980 : }
3981 :
3982 : static void
3983 0 : _cairo_xlib_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
3984 : cairo_xlib_font_glyphset_info_t *glyphset_info)
3985 : {
3986 0 : scaled_glyph->surface_private = glyphset_info;
3987 0 : }
3988 :
3989 : static void
3990 0 : _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
3991 : cairo_scaled_font_t *scaled_font)
3992 : {
3993 : cairo_xlib_surface_font_private_t *font_private;
3994 : cairo_xlib_font_glyphset_info_t *glyphset_info;
3995 :
3996 0 : if (scaled_font->finished)
3997 0 : return;
3998 :
3999 0 : font_private = scaled_font->surface_private;
4000 0 : glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
4001 0 : if (font_private != NULL && glyphset_info != NULL) {
4002 : cairo_xlib_font_glyphset_free_glyphs_t *to_free;
4003 : cairo_status_t status;
4004 :
4005 0 : to_free = glyphset_info->pending_free_glyphs;
4006 0 : if (to_free != NULL &&
4007 0 : to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
4008 : {
4009 : cairo_xlib_display_t *display;
4010 :
4011 0 : status = _cairo_xlib_display_acquire (font_private->device, &display);
4012 0 : if (status == CAIRO_STATUS_SUCCESS) {
4013 0 : status = _cairo_xlib_display_queue_work (display,
4014 : (cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs,
4015 : to_free,
4016 : free);
4017 0 : cairo_device_release (&display->base);
4018 : }
4019 : /* XXX cannot propagate failure */
4020 0 : if (unlikely (status))
4021 0 : free (to_free);
4022 :
4023 0 : to_free = glyphset_info->pending_free_glyphs = NULL;
4024 : }
4025 :
4026 0 : if (to_free == NULL) {
4027 0 : to_free = malloc (sizeof (cairo_xlib_font_glyphset_free_glyphs_t));
4028 0 : if (unlikely (to_free == NULL)) {
4029 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
4030 0 : return; /* XXX cannot propagate failure */
4031 : }
4032 :
4033 0 : to_free->glyphset = glyphset_info->glyphset;
4034 0 : to_free->glyph_count = 0;
4035 0 : glyphset_info->pending_free_glyphs = to_free;
4036 : }
4037 :
4038 0 : to_free->glyph_indices[to_free->glyph_count++] =
4039 0 : _cairo_scaled_glyph_index (scaled_glyph);
4040 : }
4041 : }
4042 :
4043 : static cairo_bool_t
4044 0 : _native_byte_order_lsb (void)
4045 : {
4046 0 : int x = 1;
4047 :
4048 0 : return *((char *) &x) == 1;
4049 : }
4050 :
4051 : static int
4052 0 : _cairo_xlib_get_glyphset_index_for_format (cairo_format_t format)
4053 : {
4054 0 : if (format == CAIRO_FORMAT_A8)
4055 0 : return GLYPHSET_INDEX_A8;
4056 0 : if (format == CAIRO_FORMAT_A1)
4057 0 : return GLYPHSET_INDEX_A1;
4058 :
4059 0 : assert (format == CAIRO_FORMAT_ARGB32);
4060 0 : return GLYPHSET_INDEX_ARGB32;
4061 : }
4062 :
4063 : static cairo_xlib_font_glyphset_info_t *
4064 0 : _cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
4065 : cairo_format_t format)
4066 : {
4067 : cairo_xlib_surface_font_private_t *font_private;
4068 : cairo_xlib_font_glyphset_info_t *glyphset_info;
4069 : int glyphset_index;
4070 :
4071 0 : glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format);
4072 0 : font_private = scaled_font->surface_private;
4073 0 : glyphset_info = &font_private->glyphset_info[glyphset_index];
4074 0 : if (glyphset_info->glyphset == None) {
4075 : cairo_xlib_display_t *display;
4076 :
4077 0 : if (_cairo_xlib_display_acquire (font_private->device, &display))
4078 0 : return NULL;
4079 :
4080 0 : glyphset_info->xrender_format =
4081 0 : _cairo_xlib_display_get_xrender_format (display,
4082 : glyphset_info->format);
4083 0 : glyphset_info->glyphset = XRenderCreateGlyphSet (display->display,
4084 0 : glyphset_info->xrender_format);
4085 :
4086 0 : cairo_device_release (&display->base);
4087 : }
4088 :
4089 0 : return glyphset_info;
4090 : }
4091 :
4092 : static cairo_bool_t
4093 0 : _cairo_xlib_glyphset_info_has_pending_free_glyph (
4094 : cairo_xlib_font_glyphset_info_t *glyphset_info,
4095 : unsigned long glyph_index)
4096 : {
4097 0 : if (glyphset_info->pending_free_glyphs != NULL) {
4098 : cairo_xlib_font_glyphset_free_glyphs_t *to_free;
4099 : int i;
4100 :
4101 0 : to_free = glyphset_info->pending_free_glyphs;
4102 0 : for (i = 0; i < to_free->glyph_count; i++) {
4103 0 : if (to_free->glyph_indices[i] == glyph_index) {
4104 0 : to_free->glyph_count--;
4105 0 : memmove (&to_free->glyph_indices[i],
4106 0 : &to_free->glyph_indices[i+1],
4107 0 : (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
4108 0 : return TRUE;
4109 : }
4110 : }
4111 : }
4112 :
4113 0 : return FALSE;
4114 : }
4115 :
4116 : static cairo_xlib_font_glyphset_info_t *
4117 0 : _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (
4118 : cairo_scaled_font_t *scaled_font,
4119 : unsigned long glyph_index,
4120 : cairo_image_surface_t *surface)
4121 : {
4122 : cairo_xlib_surface_font_private_t *font_private;
4123 : int i;
4124 :
4125 0 : font_private = scaled_font->surface_private;
4126 0 : if (font_private == NULL)
4127 0 : return NULL;
4128 :
4129 0 : if (surface != NULL) {
4130 0 : i = _cairo_xlib_get_glyphset_index_for_format (surface->format);
4131 0 : if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
4132 : &font_private->glyphset_info[i],
4133 : glyph_index))
4134 : {
4135 0 : return &font_private->glyphset_info[i];
4136 : }
4137 : } else {
4138 0 : for (i = 0; i < NUM_GLYPHSETS; i++) {
4139 0 : if (_cairo_xlib_glyphset_info_has_pending_free_glyph (
4140 : &font_private->glyphset_info[i],
4141 : glyph_index))
4142 : {
4143 0 : return &font_private->glyphset_info[i];
4144 : }
4145 : }
4146 : }
4147 :
4148 0 : return NULL;
4149 : }
4150 :
4151 : static cairo_status_t
4152 0 : _cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display,
4153 : cairo_scaled_font_t *scaled_font,
4154 : cairo_scaled_glyph_t **pscaled_glyph)
4155 : {
4156 : XGlyphInfo glyph_info;
4157 : unsigned long glyph_index;
4158 : unsigned char *data;
4159 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
4160 0 : cairo_scaled_glyph_t *scaled_glyph = *pscaled_glyph;
4161 0 : cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
4162 : cairo_bool_t already_had_glyph_surface;
4163 : cairo_xlib_font_glyphset_info_t *glyphset_info;
4164 :
4165 0 : glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
4166 :
4167 : /* check to see if we have a pending XRenderFreeGlyph for this glyph */
4168 0 : glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
4169 0 : if (glyphset_info != NULL) {
4170 0 : _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
4171 0 : return CAIRO_STATUS_SUCCESS;
4172 : }
4173 :
4174 0 : if (!glyph_surface) {
4175 0 : status = _cairo_scaled_glyph_lookup (scaled_font,
4176 : glyph_index,
4177 : CAIRO_SCALED_GLYPH_INFO_METRICS |
4178 : CAIRO_SCALED_GLYPH_INFO_SURFACE,
4179 : pscaled_glyph);
4180 0 : if (unlikely (status))
4181 0 : return status;
4182 :
4183 0 : scaled_glyph = *pscaled_glyph;
4184 0 : glyph_surface = scaled_glyph->surface;
4185 0 : already_had_glyph_surface = FALSE;
4186 : } else {
4187 0 : already_had_glyph_surface = TRUE;
4188 : }
4189 :
4190 0 : if (scaled_font->surface_private == NULL) {
4191 0 : status = _cairo_xlib_surface_font_init (display, scaled_font);
4192 0 : if (unlikely (status))
4193 0 : return status;
4194 : }
4195 :
4196 0 : glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_format (scaled_font,
4197 : glyph_surface->format);
4198 :
4199 : /* XRenderAddGlyph does not handle a glyph surface larger than the extended maximum XRequest size. */
4200 : {
4201 0 : int len = cairo_format_stride_for_width (glyphset_info->format, glyph_surface->width) * glyph_surface->height;
4202 0 : int max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display)
4203 0 : : XMaxRequestSize (display->display)) * 4 -
4204 : sz_xRenderAddGlyphsReq -
4205 0 : sz_xGlyphInfo -
4206 : 8;
4207 0 : if (len >= max_request_size)
4208 0 : return UNSUPPORTED ("glyph too large for XRequest");
4209 : }
4210 :
4211 : /* If the glyph surface has zero height or width, we create
4212 : * a clear 1x1 surface, to avoid various X server bugs.
4213 : */
4214 0 : if (glyph_surface->width == 0 || glyph_surface->height == 0) {
4215 : cairo_surface_t *tmp_surface;
4216 :
4217 0 : tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
4218 0 : status = tmp_surface->status;
4219 0 : if (unlikely (status))
4220 0 : goto BAIL;
4221 :
4222 0 : tmp_surface->device_transform = glyph_surface->base.device_transform;
4223 0 : tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
4224 :
4225 0 : glyph_surface = (cairo_image_surface_t *) tmp_surface;
4226 : }
4227 :
4228 : /* If the glyph format does not match the font format, then we
4229 : * create a temporary surface for the glyph image with the font's
4230 : * format.
4231 : */
4232 0 : if (glyph_surface->format != glyphset_info->format) {
4233 : cairo_surface_pattern_t pattern;
4234 : cairo_surface_t *tmp_surface;
4235 :
4236 0 : tmp_surface = cairo_image_surface_create (glyphset_info->format,
4237 : glyph_surface->width,
4238 : glyph_surface->height);
4239 0 : status = tmp_surface->status;
4240 0 : if (unlikely (status))
4241 0 : goto BAIL;
4242 :
4243 0 : tmp_surface->device_transform = glyph_surface->base.device_transform;
4244 0 : tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
4245 :
4246 0 : _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
4247 0 : status = _cairo_surface_paint (tmp_surface,
4248 : CAIRO_OPERATOR_SOURCE, &pattern.base,
4249 : NULL);
4250 0 : _cairo_pattern_fini (&pattern.base);
4251 :
4252 0 : glyph_surface = (cairo_image_surface_t *) tmp_surface;
4253 :
4254 0 : if (unlikely (status))
4255 0 : goto BAIL;
4256 : }
4257 :
4258 : /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
4259 0 : glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
4260 0 : glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
4261 0 : glyph_info.width = glyph_surface->width;
4262 0 : glyph_info.height = glyph_surface->height;
4263 0 : glyph_info.xOff = scaled_glyph->x_advance;
4264 0 : glyph_info.yOff = scaled_glyph->y_advance;
4265 :
4266 0 : data = glyph_surface->data;
4267 :
4268 : /* flip formats around */
4269 0 : switch (_cairo_xlib_get_glyphset_index_for_format (scaled_glyph->surface->format)) {
4270 : case GLYPHSET_INDEX_A1:
4271 : /* local bitmaps are always stored with bit == byte */
4272 0 : if (_native_byte_order_lsb() != (BitmapBitOrder (display->display) == LSBFirst)) {
4273 0 : int c = glyph_surface->stride * glyph_surface->height;
4274 : unsigned char *d;
4275 : unsigned char *new, *n;
4276 :
4277 0 : new = malloc (c);
4278 0 : if (!new) {
4279 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4280 0 : goto BAIL;
4281 : }
4282 0 : n = new;
4283 0 : d = data;
4284 : do {
4285 0 : char b = *d++;
4286 0 : b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
4287 0 : b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
4288 0 : b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
4289 0 : *n++ = b;
4290 0 : } while (--c);
4291 0 : data = new;
4292 : }
4293 0 : break;
4294 : case GLYPHSET_INDEX_A8:
4295 0 : break;
4296 : case GLYPHSET_INDEX_ARGB32:
4297 0 : if (_native_byte_order_lsb() != (ImageByteOrder (display->display) == LSBFirst)) {
4298 0 : unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
4299 : const uint32_t *d;
4300 : uint32_t *new, *n;
4301 :
4302 0 : new = malloc (4 * c);
4303 0 : if (unlikely (new == NULL)) {
4304 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
4305 0 : goto BAIL;
4306 : }
4307 0 : n = new;
4308 0 : d = (uint32_t *) data;
4309 : do {
4310 0 : *n++ = bswap_32 (*d);
4311 0 : d++;
4312 0 : } while (--c);
4313 0 : data = (uint8_t *) new;
4314 : }
4315 0 : break;
4316 : default:
4317 0 : ASSERT_NOT_REACHED;
4318 0 : break;
4319 : }
4320 : /* XXX assume X server wants pixman padding. Xft assumes this as well */
4321 :
4322 0 : struct _XDisplay *dpy = (struct _XDisplay *) display->display;
4323 0 : int req_length = sz_xRenderAddGlyphsReq + 4;
4324 0 : if (req_length & 3)
4325 0 : req_length += 4 - (req_length & 3);
4326 0 : if (dpy->bufptr + req_length > dpy->bufmax)
4327 0 : XFlush (display->display);
4328 :
4329 0 : XRenderAddGlyphs (display->display, glyphset_info->glyphset,
4330 : &glyph_index, &glyph_info, 1,
4331 : (char *) data,
4332 0 : glyph_surface->stride * glyph_surface->height);
4333 :
4334 0 : if (data != glyph_surface->data)
4335 0 : free (data);
4336 :
4337 0 : _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
4338 :
4339 : BAIL:
4340 0 : if (glyph_surface != scaled_glyph->surface)
4341 0 : cairo_surface_destroy (&glyph_surface->base);
4342 :
4343 : /* if the scaled glyph didn't already have a surface attached
4344 : * to it, release the created surface now that we have it
4345 : * uploaded to the X server. If the surface has already been
4346 : * there (eg. because image backend requested it), leave it in
4347 : * the cache
4348 : */
4349 0 : if (!already_had_glyph_surface)
4350 0 : _cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
4351 :
4352 0 : return status;
4353 : }
4354 :
4355 : typedef void (*cairo_xrender_composite_text_func_t)
4356 : (Display *dpy,
4357 : int op,
4358 : Picture src,
4359 : Picture dst,
4360 : _Xconst XRenderPictFormat *maskFormat,
4361 : int xSrc,
4362 : int ySrc,
4363 : int xDst,
4364 : int yDst,
4365 : _Xconst XGlyphElt8 *elts,
4366 : int nelt);
4367 :
4368 : /* Build a struct of the same size of #cairo_glyph_t that can be used both as
4369 : * an input glyph with double coordinates, and as "working" glyph with
4370 : * integer from-current-point offsets. */
4371 : typedef union {
4372 : cairo_glyph_t d;
4373 : unsigned long index;
4374 : struct {
4375 : unsigned long index;
4376 : int x;
4377 : int y;
4378 : } i;
4379 : } cairo_xlib_glyph_t;
4380 :
4381 : /* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */
4382 : COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t));
4383 :
4384 : /* Start a new element for the first glyph,
4385 : * or for any glyph that has unexpected position,
4386 : * or if current element has too many glyphs
4387 : * (Xrender limits each element to 252 glyphs, we limit them to 128)
4388 : *
4389 : * These same conditions need to be mirrored between
4390 : * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks
4391 : */
4392 : #define _start_new_glyph_elt(count, glyph) \
4393 : (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
4394 :
4395 : static cairo_status_t
4396 0 : _emit_glyphs_chunk (cairo_xlib_display_t *display,
4397 : cairo_xlib_surface_t *dst,
4398 : cairo_xlib_glyph_t *glyphs,
4399 : int num_glyphs,
4400 : cairo_scaled_font_t *scaled_font,
4401 : cairo_operator_t op,
4402 : cairo_xlib_surface_t *src,
4403 : cairo_surface_attributes_t *attributes,
4404 : /* info for this chunk */
4405 : int num_elts,
4406 : int width,
4407 : cairo_xlib_font_glyphset_info_t *glyphset_info)
4408 : {
4409 : /* Which XRenderCompositeText function to use */
4410 : cairo_xrender_composite_text_func_t composite_text_func;
4411 : int size;
4412 :
4413 : /* Element buffer stuff */
4414 : XGlyphElt8 *elts;
4415 : XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)];
4416 :
4417 : /* Reuse the input glyph array for output char generation */
4418 0 : char *char8 = (char *) glyphs;
4419 0 : unsigned short *char16 = (unsigned short *) glyphs;
4420 0 : unsigned int *char32 = (unsigned int *) glyphs;
4421 :
4422 : int i;
4423 : int nelt; /* Element index */
4424 : int n; /* Num output glyphs in current element */
4425 : int j; /* Num output glyphs so far */
4426 :
4427 0 : switch (width) {
4428 : case 1:
4429 : /* don't cast the 8-variant, to catch possible mismatches */
4430 0 : composite_text_func = XRenderCompositeText8;
4431 0 : size = sizeof (char);
4432 0 : break;
4433 : case 2:
4434 0 : composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
4435 0 : size = sizeof (unsigned short);
4436 0 : break;
4437 : default:
4438 : case 4:
4439 0 : composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
4440 0 : size = sizeof (unsigned int);
4441 : }
4442 :
4443 : /* Allocate element array */
4444 0 : if (num_elts <= ARRAY_LENGTH (stack_elts)) {
4445 0 : elts = stack_elts;
4446 : } else {
4447 0 : elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
4448 0 : if (unlikely (elts == NULL))
4449 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4450 : }
4451 :
4452 : /* Fill them in */
4453 0 : nelt = 0;
4454 0 : n = 0;
4455 0 : j = 0;
4456 0 : for (i = 0; i < num_glyphs; i++) {
4457 :
4458 : /* Start a new element for first output glyph,
4459 : * or for any glyph that has unexpected position,
4460 : * or if current element has too many glyphs.
4461 : *
4462 : * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs()
4463 : */
4464 0 : if (_start_new_glyph_elt (j, &glyphs[i])) {
4465 0 : if (j) {
4466 0 : elts[nelt].nchars = n;
4467 0 : nelt++;
4468 0 : n = 0;
4469 : }
4470 0 : elts[nelt].chars = char8 + size * j;
4471 0 : elts[nelt].glyphset = glyphset_info->glyphset;
4472 0 : elts[nelt].xOff = glyphs[i].i.x;
4473 0 : elts[nelt].yOff = glyphs[i].i.y;
4474 : }
4475 :
4476 0 : switch (width) {
4477 0 : case 1: char8 [j] = (char) glyphs[i].index; break;
4478 0 : case 2: char16[j] = (unsigned short) glyphs[i].index; break;
4479 : default:
4480 0 : case 4: char32[j] = (unsigned int) glyphs[i].index; break;
4481 : }
4482 :
4483 0 : n++;
4484 0 : j++;
4485 : }
4486 :
4487 0 : if (n) {
4488 0 : elts[nelt].nchars = n;
4489 0 : nelt++;
4490 : }
4491 :
4492 : /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the
4493 : * expected number of xGlyphElts. */
4494 0 : assert (nelt == num_elts);
4495 :
4496 0 : composite_text_func (display->display,
4497 : _render_operator (op),
4498 : src->src_picture,
4499 : dst->dst_picture,
4500 0 : glyphset_info->xrender_format,
4501 0 : attributes->x_offset + elts[0].xOff,
4502 0 : attributes->y_offset + elts[0].yOff,
4503 : elts[0].xOff, elts[0].yOff,
4504 : (XGlyphElt8 *) elts, nelt);
4505 :
4506 0 : if (elts != stack_elts)
4507 0 : free (elts);
4508 :
4509 0 : return CAIRO_STATUS_SUCCESS;
4510 : }
4511 :
4512 :
4513 : /* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
4514 : * enough room for padding */
4515 : #define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4)
4516 :
4517 : static cairo_status_t
4518 0 : _cairo_xlib_surface_emit_glyphs (cairo_xlib_display_t *display,
4519 : cairo_xlib_surface_t *dst,
4520 : cairo_xlib_glyph_t *glyphs,
4521 : int num_glyphs,
4522 : cairo_scaled_font_t *scaled_font,
4523 : cairo_operator_t op,
4524 : cairo_xlib_surface_t *src,
4525 : cairo_surface_attributes_t *attributes,
4526 : int *remaining_glyphs)
4527 : {
4528 : int i;
4529 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
4530 : cairo_scaled_glyph_t *scaled_glyph;
4531 0 : cairo_fixed_t x = 0, y = 0;
4532 0 : cairo_xlib_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
4533 :
4534 0 : unsigned long max_index = 0;
4535 0 : int width = 1;
4536 0 : int num_elts = 0;
4537 0 : int num_out_glyphs = 0;
4538 :
4539 0 : int max_request_size = XMaxRequestSize (display->display) * 4
4540 0 : - MAX (sz_xRenderCompositeGlyphs8Req,
4541 : MAX(sz_xRenderCompositeGlyphs16Req,
4542 : sz_xRenderCompositeGlyphs32Req));
4543 0 : int request_size = 0;
4544 :
4545 0 : _cairo_xlib_surface_ensure_dst_picture (display, dst);
4546 :
4547 0 : for (i = 0; i < num_glyphs; i++) {
4548 : int this_x, this_y;
4549 : int old_width;
4550 :
4551 0 : status = _cairo_scaled_glyph_lookup (scaled_font,
4552 0 : glyphs[i].index,
4553 : CAIRO_SCALED_GLYPH_INFO_METRICS,
4554 : &scaled_glyph);
4555 0 : if (unlikely (status))
4556 0 : return status;
4557 :
4558 0 : this_x = _cairo_lround (glyphs[i].d.x);
4559 0 : this_y = _cairo_lround (glyphs[i].d.y);
4560 :
4561 : /* Glyph skipping:
4562 : *
4563 : * We skip any glyphs that have troublesome coordinates. We want
4564 : * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
4565 : * a signed 16bit integer, otherwise it will overflow in the render
4566 : * protocol.
4567 : * To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
4568 : * a signed 15bit integer. The trivial option would be to allow
4569 : * coordinates -8192..8192, but that's kinda dull. It probably will
4570 : * take a decade or so to get monitors 8192x4096 or something. A
4571 : * negative value of -8192 on the other hand, is absolutely useless.
4572 : * Note that we do want to allow some negative positions. The glyph
4573 : * may start off the screen but part of it make it to the screen.
4574 : * Anyway, we will allow positions in the range -4096..122887. That
4575 : * will buy us a few more years before this stops working.
4576 : *
4577 : * Update: upon seeing weird glyphs, we just return and let fallback
4578 : * code do the job.
4579 : */
4580 0 : if (((this_x+4096)|(this_y+4096))&~0x3fffu)
4581 0 : break;
4582 :
4583 : /* Send unsent glyphs to the server */
4584 0 : if (_cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
4585 0 : status = _cairo_xlib_surface_add_glyph (display,
4586 : scaled_font,
4587 : &scaled_glyph);
4588 0 : if (unlikely (status)) {
4589 0 : if (status == CAIRO_INT_STATUS_UNSUPPORTED)
4590 : /* Break so we flush glyphs so far and let fallback code
4591 : * handle the rest */
4592 0 : break;
4593 :
4594 0 : return status;
4595 : }
4596 : }
4597 :
4598 0 : this_glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
4599 0 : if (!glyphset_info)
4600 0 : glyphset_info = this_glyphset_info;
4601 :
4602 : /* The invariant here is that we can always flush the glyphs
4603 : * accumulated before this one, using old_width, and they
4604 : * would fit in the request.
4605 : */
4606 0 : old_width = width;
4607 :
4608 : /* Update max glyph index */
4609 0 : if (glyphs[i].index > max_index) {
4610 0 : max_index = glyphs[i].index;
4611 0 : if (max_index >= 65536)
4612 0 : width = 4;
4613 0 : else if (max_index >= 256)
4614 0 : width = 2;
4615 0 : if (width != old_width)
4616 0 : request_size += (width - old_width) * num_out_glyphs;
4617 : }
4618 :
4619 : /* If we will pass the max request size by adding this glyph,
4620 : * flush current glyphs. Note that we account for a
4621 : * possible element being added below.
4622 : *
4623 : * Also flush if changing glyphsets, as Xrender limits one mask
4624 : * format per request, so we can either break up, or use a
4625 : * wide-enough mask format. We do the former. One reason to
4626 : * prefer the latter is the fact that Xserver ADDs all glyphs
4627 : * to the mask first, and then composes that to final surface,
4628 : * though it's not a big deal.
4629 : */
4630 0 : if (request_size + width > max_request_size - _cairo_sz_xGlyphElt ||
4631 : (this_glyphset_info != glyphset_info)) {
4632 0 : status = _emit_glyphs_chunk (display, dst, glyphs, i,
4633 : scaled_font, op, src, attributes,
4634 : num_elts, old_width, glyphset_info);
4635 0 : if (unlikely (status))
4636 0 : return status;
4637 :
4638 0 : glyphs += i;
4639 0 : num_glyphs -= i;
4640 0 : i = 0;
4641 0 : max_index = glyphs[i].index;
4642 0 : width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
4643 0 : request_size = 0;
4644 0 : num_elts = 0;
4645 0 : num_out_glyphs = 0;
4646 0 : x = y = 0;
4647 0 : glyphset_info = this_glyphset_info;
4648 : }
4649 :
4650 : /* Convert absolute glyph position to relative-to-current-point
4651 : * position */
4652 0 : glyphs[i].i.x = this_x - x;
4653 0 : glyphs[i].i.y = this_y - y;
4654 :
4655 : /* Start a new element for the first glyph,
4656 : * or for any glyph that has unexpected position,
4657 : * or if current element has too many glyphs.
4658 : *
4659 : * These same conditions are mirrored in _emit_glyphs_chunk().
4660 : */
4661 0 : if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) {
4662 0 : num_elts++;
4663 0 : request_size += _cairo_sz_xGlyphElt;
4664 : }
4665 :
4666 : /* adjust current-position */
4667 0 : x = this_x + scaled_glyph->x_advance;
4668 0 : y = this_y + scaled_glyph->y_advance;
4669 :
4670 0 : num_out_glyphs++;
4671 0 : request_size += width;
4672 : }
4673 :
4674 0 : if (num_elts) {
4675 0 : status = _emit_glyphs_chunk (display, dst, glyphs, i,
4676 : scaled_font, op, src, attributes,
4677 : num_elts, width, glyphset_info);
4678 : }
4679 :
4680 0 : *remaining_glyphs = num_glyphs - i;
4681 0 : if (*remaining_glyphs != 0 && status == CAIRO_STATUS_SUCCESS)
4682 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
4683 :
4684 0 : return status;
4685 : }
4686 :
4687 : static cairo_bool_t
4688 0 : _cairo_xlib_surface_owns_font (cairo_xlib_surface_t *dst,
4689 : cairo_scaled_font_t *scaled_font)
4690 : {
4691 : cairo_xlib_surface_font_private_t *font_private;
4692 :
4693 0 : font_private = scaled_font->surface_private;
4694 0 : if ((scaled_font->surface_backend != NULL &&
4695 0 : scaled_font->surface_backend != &cairo_xlib_surface_backend) ||
4696 0 : (font_private != NULL && font_private->device != dst->base.device))
4697 : {
4698 0 : return FALSE;
4699 : }
4700 :
4701 0 : return TRUE;
4702 : }
4703 :
4704 : /* Gets a grayscale version of scaled_font. The grayscale version is cached
4705 : * in our surface_private data.
4706 : */
4707 : static cairo_scaled_font_t *
4708 0 : _cairo_xlib_get_grayscale_font (cairo_xlib_display_t *display,
4709 : cairo_scaled_font_t *scaled_font)
4710 : {
4711 0 : cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
4712 : cairo_bool_t needs_font;
4713 :
4714 0 : if (font_private == NULL) {
4715 0 : cairo_status_t status = _cairo_xlib_surface_font_init (display, scaled_font);
4716 0 : if (unlikely (status))
4717 0 : return _cairo_scaled_font_create_in_error (status);
4718 0 : font_private = scaled_font->surface_private;
4719 : }
4720 :
4721 0 : CAIRO_MUTEX_LOCK (scaled_font->mutex);
4722 0 : needs_font = !font_private->grayscale_font;
4723 0 : CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
4724 :
4725 0 : if (needs_font) {
4726 : cairo_font_options_t options;
4727 : cairo_scaled_font_t *new_font;
4728 :
4729 0 : options = scaled_font->options;
4730 0 : options.antialias = CAIRO_ANTIALIAS_GRAY;
4731 0 : new_font = cairo_scaled_font_create (scaled_font->font_face,
4732 0 : &scaled_font->font_matrix,
4733 0 : &scaled_font->ctm, &options);
4734 :
4735 0 : CAIRO_MUTEX_LOCK (scaled_font->mutex);
4736 0 : if (!font_private->grayscale_font) {
4737 0 : font_private->grayscale_font = new_font;
4738 0 : new_font = NULL;
4739 : }
4740 0 : CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
4741 :
4742 0 : if (new_font) {
4743 0 : cairo_scaled_font_destroy (new_font);
4744 : }
4745 : }
4746 :
4747 0 : return font_private->grayscale_font;
4748 : }
4749 :
4750 : static cairo_int_status_t
4751 0 : _cairo_xlib_surface_show_glyphs (void *abstract_dst,
4752 : cairo_operator_t op,
4753 : const cairo_pattern_t *src_pattern,
4754 : cairo_glyph_t *glyphs,
4755 : int num_glyphs,
4756 : cairo_scaled_font_t *scaled_font,
4757 : cairo_clip_t *clip,
4758 : int *remaining_glyphs)
4759 : {
4760 0 : cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
4761 0 : cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst;
4762 : composite_operation_t operation;
4763 : cairo_surface_attributes_t attributes;
4764 0 : cairo_xlib_surface_t *src = NULL;
4765 0 : cairo_region_t *clip_region = NULL;
4766 : cairo_xlib_display_t *display;
4767 :
4768 0 : if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst))
4769 0 : return UNSUPPORTED ("XRender does not support CompositeText");
4770 :
4771 : /* Just let unbounded operators go through the fallback code
4772 : * instead of trying to do the fixups here */
4773 0 : if (! _cairo_operator_bounded_by_mask (op))
4774 0 : return UNSUPPORTED ("unsupported unbounded op");
4775 :
4776 : /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
4777 : * the solid source seems to be multiplied by the glyph mask, and
4778 : * then the entire thing is copied to the destination surface,
4779 : * including the fully transparent "background" of the rectangular
4780 : * glyph surface. */
4781 0 : if (op == CAIRO_OPERATOR_SOURCE &&
4782 0 : ! CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
4783 : {
4784 0 : return UNSUPPORTED ("known bug in Render");
4785 : }
4786 :
4787 : /* We can only use our code if we either have no clip or
4788 : * have a real native clip region set. If we're using
4789 : * fallback clip masking, we have to go through the full
4790 : * fallback path.
4791 : */
4792 0 : if (clip != NULL) {
4793 0 : status = _cairo_clip_get_region (clip, &clip_region);
4794 0 : assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
4795 0 : if (status)
4796 0 : return status;
4797 : }
4798 :
4799 0 : operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
4800 0 : if (operation == DO_UNSUPPORTED)
4801 0 : return UNSUPPORTED ("unsupported op");
4802 :
4803 0 : if (! _cairo_xlib_surface_owns_font (dst, scaled_font))
4804 0 : return UNSUPPORTED ("unowned font");
4805 :
4806 :
4807 0 : status = _cairo_xlib_display_acquire (dst->base.device, &display);
4808 0 : if (unlikely (status))
4809 0 : return status;
4810 :
4811 0 : if (!dst->base.permit_subpixel_antialiasing &&
4812 0 : scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) {
4813 0 : scaled_font = _cairo_xlib_get_grayscale_font (display, scaled_font);
4814 : }
4815 :
4816 : X_DEBUG ((display->display, "show_glyphs (dst=%x)", (unsigned int) dst->drawable));
4817 :
4818 0 : if (clip_region != NULL &&
4819 0 : cairo_region_num_rectangles (clip_region) == 1)
4820 : {
4821 : cairo_rectangle_int_t glyph_extents;
4822 : cairo_rectangle_int_t clip_extents;
4823 :
4824 : /* Can we do without the clip?
4825 : * Around 50% of the time the clip is redundant (firefox).
4826 : */
4827 0 : _cairo_scaled_font_glyph_approximate_extents (scaled_font,
4828 : glyphs, num_glyphs,
4829 : &glyph_extents);
4830 :
4831 0 : cairo_region_get_extents(clip_region, &clip_extents);
4832 0 : if (clip_extents.x <= glyph_extents.x &&
4833 0 : clip_extents.y <= glyph_extents.y &&
4834 0 : clip_extents.x + clip_extents.width >= glyph_extents.x + glyph_extents.width &&
4835 0 : clip_extents.y + clip_extents.height >= glyph_extents.y + glyph_extents.height)
4836 : {
4837 0 : clip_region = NULL;
4838 : }
4839 : }
4840 :
4841 0 : status = _cairo_xlib_surface_set_clip_region (dst, clip_region);
4842 0 : if (unlikely (status))
4843 0 : goto BAIL0;
4844 :
4845 : /* After passing all those tests, we're now committed to rendering
4846 : * these glyphs or to fail trying. We first upload any glyphs to
4847 : * the X server that it doesn't have already, then we draw
4848 : * them.
4849 : */
4850 :
4851 : /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
4852 : * the mask (the glyphs). This code below was executed as a side effect
4853 : * of going through the _clip_and_composite fallback code for old_show_glyphs,
4854 : * so PictOpClear was never used with CompositeText before.
4855 : */
4856 0 : if (op == CAIRO_OPERATOR_CLEAR) {
4857 0 : src_pattern = &_cairo_pattern_white.base;
4858 0 : op = CAIRO_OPERATOR_DEST_OUT;
4859 : }
4860 :
4861 0 : if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
4862 0 : status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
4863 : 0, 0, 1, 1,
4864 : CAIRO_PATTERN_ACQUIRE_NONE,
4865 : (cairo_surface_t **) &src,
4866 : &attributes);
4867 0 : if (unlikely (status))
4868 0 : goto BAIL0;
4869 : } else {
4870 : cairo_rectangle_int_t glyph_extents;
4871 :
4872 0 : status = _cairo_scaled_font_glyph_device_extents (scaled_font,
4873 : glyphs,
4874 : num_glyphs,
4875 : &glyph_extents,
4876 : NULL);
4877 0 : if (unlikely (status))
4878 0 : goto BAIL0;
4879 :
4880 0 : if (clip != NULL) {
4881 0 : if (! _cairo_rectangle_intersect (&glyph_extents,
4882 : _cairo_clip_get_extents (clip)))
4883 : {
4884 0 : goto BAIL0;
4885 : }
4886 : }
4887 :
4888 0 : status = _cairo_xlib_surface_acquire_pattern_surface (display,
4889 : dst, src_pattern,
4890 : glyph_extents.x,
4891 : glyph_extents.y,
4892 : glyph_extents.width,
4893 : glyph_extents.height,
4894 : &src, &attributes);
4895 0 : if (unlikely (status))
4896 0 : goto BAIL0;
4897 : }
4898 :
4899 0 : operation = _recategorize_composite_operation (dst, op, src,
4900 : &attributes, TRUE);
4901 0 : if (operation == DO_UNSUPPORTED) {
4902 0 : status = UNSUPPORTED ("unsupported op");
4903 0 : goto BAIL1;
4904 : }
4905 :
4906 0 : status = _cairo_xlib_surface_set_attributes (display, src, &attributes, 0, 0);
4907 0 : if (unlikely (status))
4908 0 : goto BAIL1;
4909 :
4910 0 : _cairo_scaled_font_freeze_cache (scaled_font);
4911 0 : if (_cairo_xlib_surface_owns_font (dst, scaled_font)) {
4912 0 : status = _cairo_xlib_surface_emit_glyphs (display,
4913 : dst,
4914 : (cairo_xlib_glyph_t *) glyphs,
4915 : num_glyphs,
4916 : scaled_font,
4917 : op,
4918 : src,
4919 : &attributes,
4920 : remaining_glyphs);
4921 : } else {
4922 0 : status = UNSUPPORTED ("unowned font");
4923 : }
4924 0 : _cairo_scaled_font_thaw_cache (scaled_font);
4925 :
4926 : BAIL1:
4927 0 : if (src)
4928 0 : _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
4929 : BAIL0:
4930 0 : cairo_device_release (&display->base);
4931 :
4932 0 : return status;
4933 : }
|