Fixed texturing in Gallium.
[cairo/gpu.git] / src / cairo-xlib-screen.c
blobe491a3337997b2d76ae3c8fe705f445f5318fe4b
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.
55 #include "cairoint.h"
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>
64 static int
65 parse_boolean (const char *v)
67 char c0, c1;
69 c0 = *v;
70 if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
71 return 1;
72 if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0')
73 return 0;
74 if (c0 == 'o')
76 c1 = v[1];
77 if (c1 == 'n' || c1 == 'N')
78 return 1;
79 if (c1 == 'f' || c1 == 'F')
80 return 0;
83 return -1;
86 static cairo_bool_t
87 get_boolean_default (Display *dpy,
88 const char *option,
89 cairo_bool_t *value)
91 char *v;
92 int i;
94 v = XGetDefault (dpy, "Xft", option);
95 if (v) {
96 i = parse_boolean (v);
97 if (i >= 0) {
98 *value = i;
99 return TRUE;
103 return FALSE;
106 static cairo_bool_t
107 get_integer_default (Display *dpy,
108 const char *option,
109 int *value)
111 char *v, *e;
113 v = XGetDefault (dpy, "Xft", option);
114 if (v) {
115 #if CAIRO_HAS_FC_FONT
116 if (FcNameConstant ((FcChar8 *) v, value))
117 return TRUE;
118 #endif
120 *value = strtol (v, &e, 0);
121 if (e != v)
122 return TRUE;
125 return FALSE;
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
135 #endif
137 #ifndef FC_HINT_NONE
138 #define FC_HINT_NONE 0
139 #define FC_HINT_SLIGHT 1
140 #define FC_HINT_MEDIUM 2
141 #define FC_HINT_FULL 3
142 #endif
145 static void
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;
151 int xft_hintstyle;
152 int xft_rgba;
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))
161 xft_hinting = TRUE;
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)
178 default:
179 case SubPixelUnknown:
180 xft_rgba = FC_RGBA_UNKNOWN;
181 break;
182 case SubPixelHorizontalRGB:
183 xft_rgba = FC_RGBA_RGB;
184 break;
185 case SubPixelHorizontalBGR:
186 xft_rgba = FC_RGBA_BGR;
187 break;
188 case SubPixelVerticalRGB:
189 xft_rgba = FC_RGBA_VRGB;
190 break;
191 case SubPixelVerticalBGR:
192 xft_rgba = FC_RGBA_VBGR;
193 break;
194 case SubPixelNone:
195 xft_rgba = FC_RGBA_NONE;
196 break;
199 #endif
202 if (xft_hinting) {
203 switch (xft_hintstyle) {
204 case FC_HINT_NONE:
205 hint_style = CAIRO_HINT_STYLE_NONE;
206 break;
207 case FC_HINT_SLIGHT:
208 hint_style = CAIRO_HINT_STYLE_SLIGHT;
209 break;
210 case FC_HINT_MEDIUM:
211 hint_style = CAIRO_HINT_STYLE_MEDIUM;
212 break;
213 case FC_HINT_FULL:
214 hint_style = CAIRO_HINT_STYLE_FULL;
215 break;
216 default:
217 hint_style = CAIRO_HINT_STYLE_DEFAULT;
219 } else {
220 hint_style = CAIRO_HINT_STYLE_NONE;
223 switch (xft_rgba) {
224 case FC_RGBA_RGB:
225 subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
226 break;
227 case FC_RGBA_BGR:
228 subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
229 break;
230 case FC_RGBA_VRGB:
231 subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
232 break;
233 case FC_RGBA_VBGR:
234 subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
235 break;
236 case FC_RGBA_UNKNOWN:
237 case FC_RGBA_NONE:
238 default:
239 subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
242 if (xft_antialias) {
243 if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT)
244 antialias = CAIRO_ANTIALIAS_GRAY;
245 else
246 antialias = CAIRO_ANTIALIAS_SUBPIXEL;
247 } else {
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);
264 return info;
267 void
268 _cairo_xlib_screen_info_close_display (cairo_xlib_screen_info_t *info)
270 cairo_xlib_visual_info_t **visuals;
271 Display *dpy;
272 int i, old;
274 CAIRO_MUTEX_LOCK (info->mutex);
276 dpy = info->display->display;
278 #if HAS_ATOMIC_OPS
279 do {
280 old = info->gc_depths;
281 } while (_cairo_atomic_int_cmpxchg (&info->gc_depths, old, 0) != old);
282 #else
283 old = info->gc_depths;
284 #endif
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);
299 void
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))
308 return;
310 CAIRO_MUTEX_LOCK (info->display->mutex);
311 for (prev = &info->display->screens; (list = *prev); prev = &list->next) {
312 if (list == info) {
313 *prev = info->next;
314 break;
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);
327 free (info);
330 cairo_status_t
331 _cairo_xlib_screen_info_get (cairo_xlib_display_t *display,
332 Screen *screen,
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) {
346 * MRU the list
348 if (prev != &display->screens) {
349 *prev = info->next;
350 info->next = display->screens;
351 display->screens = info;
353 break;
356 CAIRO_MUTEX_UNLOCK (display->mutex);
358 if (info != NULL) {
359 info = _cairo_xlib_screen_info_reference (info);
360 } else {
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;
371 info->gc_depths = 0;
372 memset (info->gc, 0, sizeof (info->gc));
374 _cairo_array_init (&info->visuals,
375 sizeof (cairo_xlib_visual_info_t*));
377 if (screen) {
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
387 * any corruption.
389 CAIRO_MUTEX_LOCK (display->mutex);
390 info->next = display->screens;
391 display->screens = info;
392 CAIRO_MUTEX_UNLOCK (display->mutex);
395 *out = info;
396 return CAIRO_STATUS_SUCCESS;
399 #if HAS_ATOMIC_OPS
401 _cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info,
402 unsigned int depth,
403 Drawable drawable,
404 unsigned int *dirty)
406 XGCValues gcv;
407 int i, new, old;
408 GC gc;
410 do {
411 gc = NULL;
412 old = info->gc_depths;
413 if (old == 0)
414 break;
416 if (((old >> 0) & 0x7f) == depth)
417 i = 0;
418 else if (((old >> 8) & 0x7f) == depth)
419 i = 1;
420 else if (((old >> 16) & 0x7f) == depth)
421 i = 2;
422 else if (((old >> 24) & 0x7f) == depth)
423 i = 3;
424 else
425 break;
427 gc = info->gc[i];
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;
437 return gc;
440 gcv.graphics_exposures = False;
441 return XCreateGC (info->display->display, drawable,
442 GCGraphicsExposures, &gcv);
445 void
446 _cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info,
447 unsigned int depth,
448 GC gc,
449 cairo_bool_t reset_clip)
451 int i, old, new;
453 depth |= reset_clip ? 0x80 : 0;
454 do {
455 do {
456 i = -1;
457 old = info->gc_depths;
459 if (((old >> 0) & 0x7f) == 0)
460 i = 0;
461 else if (((old >> 8) & 0x7f) == 0)
462 i = 1;
463 else if (((old >> 16) & 0x7f) == 0)
464 i = 2;
465 else if (((old >> 24) & 0x7f) == 0)
466 i = 3;
467 else
468 goto out;
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);
474 return;
476 out:
477 if (unlikely (_cairo_xlib_display_queue_work (info->display,
478 (cairo_xlib_notify_func) XFreeGC,
480 NULL)))
482 /* leak the server side resource... */
483 XFree ((char *) gc);
486 #else
488 _cairo_xlib_screen_get_gc (cairo_xlib_screen_info_t *info,
489 unsigned int depth,
490 Drawable drawable,
491 unsigned int *dirty)
493 GC gc = NULL;
494 int i;
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));
503 gc = info->gc[i];
504 break;
507 CAIRO_MUTEX_UNLOCK (info->mutex);
509 if (gc == NULL) {
510 XGCValues gcv;
512 gcv.graphics_exposures = False;
513 gc = XCreateGC (info->display->display, drawable,
514 GCGraphicsExposures, &gcv);
517 return gc;
520 void
521 _cairo_xlib_screen_put_gc (cairo_xlib_screen_info_t *info,
522 unsigned int depth,
523 GC gc,
524 cairo_bool_t reset_clip)
526 int i;
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)
533 break;
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);
541 status =
542 _cairo_xlib_display_queue_work (info->display,
543 (cairo_xlib_notify_func) XFreeGC,
544 info->gc[i],
545 NULL);
546 if (unlikely (status)) {
547 /* leak the server side resource... */
548 XFree ((char *) info->gc[i]);
552 info->gc[i] = gc;
553 info->gc_depths &= ~(0xff << (8*i));
554 info->gc_depths |= depth << (8*i);
555 CAIRO_MUTEX_UNLOCK (info->mutex);
557 #endif
559 cairo_status_t
560 _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info,
561 Visual *visual,
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;
567 int i, n_visuals;
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) {
574 ret = visuals[i];
575 break;
578 CAIRO_MUTEX_UNLOCK (info->mutex);
580 if (ret != NULL) {
581 *out = ret;
582 return CAIRO_STATUS_SUCCESS;
585 status = _cairo_xlib_visual_info_create (dpy,
586 XScreenNumberOfScreen (info->screen),
587 visual->visualid,
588 &ret);
589 if (unlikely (status))
590 return 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);
600 ret = visuals[i];
601 break;
604 if (i == new_visuals)
605 status = _cairo_array_append (&info->visuals, &ret);
606 } else
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);
612 return status;
615 *out = 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;