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