1 /* Cairo - a vector graphics library with display and print output
3 * Copyright © 2005 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Red Hat, Inc.
32 * Partially on code from xftdpy.c
34 * Copyright © 2000 Keith Packard
36 * Permission to use, copy, modify, distribute, and sell this software and its
37 * documentation for any purpose is hereby granted without fee, provided that
38 * the above copyright notice appear in all copies and that both that
39 * copyright notice and this permission notice appear in supporting
40 * documentation, and that the name of Keith Packard not be used in
41 * advertising or publicity pertaining to distribution of the software without
42 * specific, written prior permission. Keith Packard makes no
43 * representations about the suitability of this software for any purpose. It
44 * is provided "as is" without express or implied warranty.
46 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
47 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
48 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
49 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
50 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
51 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
52 * PERFORMANCE OF THIS SOFTWARE.
57 #include "cairo-xlib-private.h"
58 #include "cairo-xlib-xrender-private.h"
60 #include "cairo-xlib-surface-private.h"
62 #include <fontconfig/fontconfig.h>
65 parse_boolean (const char *v
)
70 if (c0
== 't' || c0
== 'T' || c0
== 'y' || c0
== 'Y' || c0
== '1')
72 if (c0
== 'f' || c0
== 'F' || c0
== 'n' || c0
== 'N' || c0
== '0')
77 if (c1
== 'n' || c1
== 'N')
79 if (c1
== 'f' || c1
== 'F')
87 get_boolean_default (Display
*dpy
,
94 v
= XGetDefault (dpy
, "Xft", option
);
96 i
= parse_boolean (v
);
107 get_integer_default (Display
*dpy
,
113 v
= XGetDefault (dpy
, "Xft", option
);
115 #if CAIRO_HAS_FC_FONT
116 if (FcNameConstant ((FcChar8
*) v
, value
))
120 *value
= strtol (v
, &e
, 0);
128 #ifndef FC_RGBA_UNKNOWN
129 #define FC_RGBA_UNKNOWN 0
130 #define FC_RGBA_RGB 1
131 #define FC_RGBA_BGR 2
132 #define FC_RGBA_VRGB 3
133 #define FC_RGBA_VBGR 4
134 #define FC_RGBA_NONE 5
138 #define FC_HINT_NONE 0
139 #define FC_HINT_SLIGHT 1
140 #define FC_HINT_MEDIUM 2
141 #define FC_HINT_FULL 3
146 _cairo_xlib_init_screen_font_options (Display
*dpy
,
147 cairo_xlib_screen_info_t
*info
)
149 cairo_bool_t xft_hinting
;
150 cairo_bool_t xft_antialias
;
153 cairo_antialias_t antialias
;
154 cairo_subpixel_order_t subpixel_order
;
155 cairo_hint_style_t hint_style
;
157 if (!get_boolean_default (dpy
, "antialias", &xft_antialias
))
158 xft_antialias
= TRUE
;
160 if (!get_boolean_default (dpy
, "hinting", &xft_hinting
))
163 if (!get_integer_default (dpy
, "hintstyle", &xft_hintstyle
))
164 xft_hintstyle
= FC_HINT_FULL
;
166 if (!get_integer_default (dpy
, "rgba", &xft_rgba
))
168 xft_rgba
= FC_RGBA_UNKNOWN
;
170 #if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
171 if (info
->has_render
)
173 int render_order
= XRenderQuerySubpixelOrder (dpy
,
174 XScreenNumberOfScreen (info
->screen
));
176 switch (render_order
)
179 case SubPixelUnknown
:
180 xft_rgba
= FC_RGBA_UNKNOWN
;
182 case SubPixelHorizontalRGB
:
183 xft_rgba
= FC_RGBA_RGB
;
185 case SubPixelHorizontalBGR
:
186 xft_rgba
= FC_RGBA_BGR
;
188 case SubPixelVerticalRGB
:
189 xft_rgba
= FC_RGBA_VRGB
;
191 case SubPixelVerticalBGR
:
192 xft_rgba
= FC_RGBA_VBGR
;
195 xft_rgba
= FC_RGBA_NONE
;
203 switch (xft_hintstyle
) {
205 hint_style
= CAIRO_HINT_STYLE_NONE
;
208 hint_style
= CAIRO_HINT_STYLE_SLIGHT
;
211 hint_style
= CAIRO_HINT_STYLE_MEDIUM
;
214 hint_style
= CAIRO_HINT_STYLE_FULL
;
217 hint_style
= CAIRO_HINT_STYLE_DEFAULT
;
220 hint_style
= CAIRO_HINT_STYLE_NONE
;
225 subpixel_order
= CAIRO_SUBPIXEL_ORDER_RGB
;
228 subpixel_order
= CAIRO_SUBPIXEL_ORDER_BGR
;
231 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VRGB
;
234 subpixel_order
= CAIRO_SUBPIXEL_ORDER_VBGR
;
236 case FC_RGBA_UNKNOWN
:
239 subpixel_order
= CAIRO_SUBPIXEL_ORDER_DEFAULT
;
243 if (subpixel_order
== CAIRO_SUBPIXEL_ORDER_DEFAULT
)
244 antialias
= CAIRO_ANTIALIAS_GRAY
;
246 antialias
= CAIRO_ANTIALIAS_SUBPIXEL
;
248 antialias
= CAIRO_ANTIALIAS_NONE
;
251 cairo_font_options_set_hint_style (&info
->font_options
, hint_style
);
252 cairo_font_options_set_antialias (&info
->font_options
, antialias
);
253 cairo_font_options_set_subpixel_order (&info
->font_options
, subpixel_order
);
254 cairo_font_options_set_hint_metrics (&info
->font_options
, CAIRO_HINT_METRICS_ON
);
257 cairo_xlib_screen_info_t
*
258 _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t
*info
)
260 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info
->ref_count
));
262 _cairo_reference_count_inc (&info
->ref_count
);
268 _cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t
*info
)
270 cairo_xlib_visual_info_t
**visuals
;
274 CAIRO_MUTEX_LOCK (info
->mutex
);
276 dpy
= info
->display
->display
;
280 old
= info
->gc_depths
;
281 } while (_cairo_atomic_int_cmpxchg (&info
->gc_depths
, old
, 0) != old
);
283 old
= info
->gc_depths
;
286 for (i
= 0; i
< ARRAY_LENGTH (info
->gc
); i
++) {
287 if (old
>> (8*i
) & 0x7f)
288 XFreeGC (dpy
, info
->gc
[i
]);
291 visuals
= _cairo_array_index (&info
->visuals
, 0);
292 for (i
= 0; i
< _cairo_array_num_elements (&info
->visuals
); i
++)
293 _cairo_xlib_visual_info_destroy (dpy
, visuals
[i
]);
294 _cairo_array_truncate (&info
->visuals
, 0);
296 CAIRO_MUTEX_UNLOCK (info
->mutex
);
300 _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t
*info
)
302 cairo_xlib_screen_info_t
**prev
;
303 cairo_xlib_screen_info_t
*list
;
305 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info
->ref_count
));
307 if (! _cairo_reference_count_dec_and_test (&info
->ref_count
))
310 CAIRO_MUTEX_LOCK (info
->display
->mutex
);
311 for (prev
= &info
->display
->screens
; (list
= *prev
); prev
= &list
->next
) {
317 CAIRO_MUTEX_UNLOCK (info
->display
->mutex
);
319 _cairo_xlib_screen_info_close_display (info
);
321 _cairo_xlib_display_destroy (info
->display
);
323 _cairo_array_fini (&info
->visuals
);
325 CAIRO_MUTEX_FINI (info
->mutex
);
331 _cairo_xlib_screen_info_get (cairo_xlib_display_t
*display
,
333 cairo_xlib_screen_info_t
**out
)
335 cairo_xlib_screen_info_t
*info
= NULL
, **prev
;
337 CAIRO_MUTEX_LOCK (display
->mutex
);
338 if (display
->closed
) {
339 CAIRO_MUTEX_UNLOCK (display
->mutex
);
340 return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED
);
343 for (prev
= &display
->screens
; (info
= *prev
); prev
= &(*prev
)->next
) {
344 if (info
->screen
== screen
) {
348 if (prev
!= &display
->screens
) {
350 info
->next
= display
->screens
;
351 display
->screens
= info
;
356 CAIRO_MUTEX_UNLOCK (display
->mutex
);
359 info
= _cairo_xlib_screen_info_reference (info
);
361 info
= malloc (sizeof (cairo_xlib_screen_info_t
));
362 if (unlikely (info
== NULL
))
363 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
365 CAIRO_REFERENCE_COUNT_INIT (&info
->ref_count
, 2); /* Add one for display cache */
366 CAIRO_MUTEX_INIT (info
->mutex
);
367 info
->display
= _cairo_xlib_display_reference (display
);
368 info
->screen
= screen
;
369 info
->has_render
= FALSE
;
370 info
->has_font_options
= FALSE
;
372 memset (info
->gc
, 0, sizeof (info
->gc
));
374 _cairo_array_init (&info
->visuals
,
375 sizeof (cairo_xlib_visual_info_t
*));
378 Display
*dpy
= display
->display
;
379 int event_base
, error_base
;
381 info
->has_render
= (XRenderQueryExtension (dpy
, &event_base
, &error_base
) &&
382 (XRenderFindVisualFormat (dpy
, DefaultVisual (dpy
, DefaultScreen (dpy
))) != 0));
385 /* Small window of opportunity for two screen infos for the same
386 * Screen - just wastes a little bit of memory but should not cause
389 CAIRO_MUTEX_LOCK (display
->mutex
);
390 info
->next
= display
->screens
;
391 display
->screens
= info
;
392 CAIRO_MUTEX_UNLOCK (display
->mutex
);
396 return CAIRO_STATUS_SUCCESS
;
401 _cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t
*info
,
412 old
= info
->gc_depths
;
416 if (((old
>> 0) & 0x7f) == depth
)
418 else if (((old
>> 8) & 0x7f) == depth
)
420 else if (((old
>> 16) & 0x7f) == depth
)
422 else if (((old
>> 24) & 0x7f) == depth
)
428 new = old
& ~(0xff << (8*i
));
429 } while (_cairo_atomic_int_cmpxchg (&info
->gc_depths
, old
, new) != old
);
431 if (likely (gc
!= NULL
)) {
432 (void) _cairo_atomic_ptr_cmpxchg (&info
->gc
[i
], gc
, NULL
);
434 if (old
& 0x80 << (8 * i
))
435 *dirty
|= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC
;
440 gcv
.graphics_exposures
= False
;
441 return XCreateGC (info
->display
->display
, drawable
,
442 GCGraphicsExposures
, &gcv
);
446 _cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t
*info
,
449 cairo_bool_t reset_clip
)
453 depth
|= reset_clip
? 0x80 : 0;
457 old
= info
->gc_depths
;
459 if (((old
>> 0) & 0x7f) == 0)
461 else if (((old
>> 8) & 0x7f) == 0)
463 else if (((old
>> 16) & 0x7f) == 0)
465 else if (((old
>> 24) & 0x7f) == 0)
470 new = old
| (depth
<< (8*i
));
471 } while (_cairo_atomic_ptr_cmpxchg (&info
->gc
[i
], NULL
, gc
) != NULL
);
472 } while (_cairo_atomic_int_cmpxchg (&info
->gc_depths
, old
, new) != old
);
477 if (unlikely (_cairo_xlib_display_queue_work (info
->display
,
478 (cairo_xlib_notify_func
) XFreeGC
,
482 /* leak the server side resource... */
488 _cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t
*info
,
496 CAIRO_MUTEX_LOCK (info
->mutex
);
497 for (i
= 0; i
< ARRAY_LENGTH (info
->gc
); i
++) {
498 if (((info
->gc_depths
>> (8*i
)) & 0x7f) == depth
) {
499 if (info
->gc_depths
& 0x80 << (8*i
))
500 *dirty
|= CAIRO_XLIB_SURFACE_CLIP_DIRTY_GC
;
502 info
->gc_depths
&= ~(0xff << (8*i
));
507 CAIRO_MUTEX_UNLOCK (info
->mutex
);
512 gcv
.graphics_exposures
= False
;
513 gc
= XCreateGC (info
->display
->display
, drawable
,
514 GCGraphicsExposures
, &gcv
);
521 _cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t
*info
,
524 cairo_bool_t reset_clip
)
528 depth
|= reset_clip
? 0x80 : 0;
530 CAIRO_MUTEX_LOCK (info
->mutex
);
531 for (i
= 0; i
< ARRAY_LENGTH (info
->gc
); i
++) {
532 if (((info
->gc_depths
>> (8*i
)) & 0x7f) == 0)
536 if (i
== ARRAY_LENGTH (info
->gc
)) {
537 cairo_status_t status
;
539 /* perform random substitution to ensure fair caching over depths */
540 i
= rand () % ARRAY_LENGTH (info
->gc
);
542 _cairo_xlib_display_queue_work (info
->display
,
543 (cairo_xlib_notify_func
) XFreeGC
,
546 if (unlikely (status
)) {
547 /* leak the server side resource... */
548 XFree ((char *) info
->gc
[i
]);
553 info
->gc_depths
&= ~(0xff << (8*i
));
554 info
->gc_depths
|= depth
<< (8*i
);
555 CAIRO_MUTEX_UNLOCK (info
->mutex
);
560 _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t
*info
,
562 cairo_xlib_visual_info_t
**out
)
564 Display
*dpy
= info
->display
->display
;
565 cairo_xlib_visual_info_t
**visuals
, *ret
= NULL
;
566 cairo_status_t status
;
569 CAIRO_MUTEX_LOCK (info
->mutex
);
570 visuals
= _cairo_array_index (&info
->visuals
, 0);
571 n_visuals
= _cairo_array_num_elements (&info
->visuals
);
572 for (i
= 0; i
< n_visuals
; i
++) {
573 if (visuals
[i
]->visualid
== visual
->visualid
) {
578 CAIRO_MUTEX_UNLOCK (info
->mutex
);
582 return CAIRO_STATUS_SUCCESS
;
585 status
= _cairo_xlib_visual_info_create (dpy
,
586 XScreenNumberOfScreen (info
->screen
),
589 if (unlikely (status
))
592 CAIRO_MUTEX_LOCK (info
->mutex
);
593 if (n_visuals
!= _cairo_array_num_elements (&info
->visuals
)) {
594 /* check that another thread has not added our visual */
595 int new_visuals
= _cairo_array_num_elements (&info
->visuals
);
596 visuals
= _cairo_array_index (&info
->visuals
, 0);
597 for (i
= n_visuals
; i
< new_visuals
; i
++) {
598 if (visuals
[i
]->visualid
== visual
->visualid
) {
599 _cairo_xlib_visual_info_destroy (dpy
, ret
);
604 if (i
== new_visuals
)
605 status
= _cairo_array_append (&info
->visuals
, &ret
);
607 status
= _cairo_array_append (&info
->visuals
, &ret
);
608 CAIRO_MUTEX_UNLOCK (info
->mutex
);
610 if (unlikely (status
)) {
611 _cairo_xlib_visual_info_destroy (dpy
, ret
);
616 return CAIRO_STATUS_SUCCESS
;
619 cairo_font_options_t
*
620 _cairo_xlib_screen_get_font_options (cairo_xlib_screen_info_t
*info
)
622 if (info
->has_font_options
)
623 return &info
->font_options
;
625 CAIRO_MUTEX_LOCK (info
->mutex
);
626 if (! info
->has_font_options
) {
627 Display
*dpy
= info
->display
->display
;
629 _cairo_font_options_init_default (&info
->font_options
);
631 if (info
->screen
!= NULL
)
632 _cairo_xlib_init_screen_font_options (dpy
, info
);
634 info
->has_font_options
= TRUE
;
636 CAIRO_MUTEX_UNLOCK (info
->mutex
);
638 return &info
->font_options
;