tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-xlib-screen.c
1 /* Cairo - a vector graphics library with display and print output
2  *
3  * Copyright © 2005 Red Hat, Inc.
4  *
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.
12  *
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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16  * You should have received a copy of the MPL along with this library
17  * in the file COPYING-MPL-1.1
18  *
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/
23  *
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.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * The Initial Developer of the Original Code is Red Hat, Inc.
31  *
32  * Partially on code from xftdpy.c
33  *
34  * Copyright © 2000 Keith Packard
35  *
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.
45  *
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.
53  */
54
55 #include "cairoint.h"
56
57 #if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
58
59 #include "cairo-xlib-private.h"
60 #include "cairo-xlib-xrender-private.h"
61
62 #include "cairo-xlib-surface-private.h"
63 #include "cairo-error-private.h"
64 #include "cairo-list-inline.h"
65
66 #include "cairo-fontconfig-private.h"
67
68 static int
69 parse_boolean (const char *v)
70 {
71     char c0, c1;
72
73     c0 = *v;
74     if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1')
75         return 1;
76     if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0')
77         return 0;
78     if (c0 == 'o')
79     {
80         c1 = v[1];
81         if (c1 == 'n' || c1 == 'N')
82             return 1;
83         if (c1 == 'f' || c1 == 'F')
84             return 0;
85     }
86
87     return -1;
88 }
89
90 static cairo_bool_t
91 get_boolean_default (Display       *dpy,
92                      const char    *option,
93                      cairo_bool_t  *value)
94 {
95     char *v;
96     int i;
97
98     v = XGetDefault (dpy, "Xft", option);
99     if (v) {
100         i = parse_boolean (v);
101         if (i >= 0) {
102             *value = i;
103             return TRUE;
104         }
105     }
106
107     return FALSE;
108 }
109
110 static cairo_bool_t
111 get_integer_default (Display    *dpy,
112                      const char *option,
113                      int        *value)
114 {
115     char *v, *e;
116
117     v = XGetDefault (dpy, "Xft", option);
118     if (v) {
119 #if CAIRO_HAS_FC_FONT
120         if (FcNameConstant ((FcChar8 *) v, value))
121             return TRUE;
122 #endif
123
124         *value = strtol (v, &e, 0);
125         if (e != v)
126             return TRUE;
127     }
128
129     return FALSE;
130 }
131
132 static void
133 _cairo_xlib_init_screen_font_options (Display *dpy,
134                                       cairo_xlib_screen_t *info)
135 {
136     cairo_bool_t xft_hinting;
137     cairo_bool_t xft_antialias;
138     int xft_hintstyle;
139     int xft_rgba;
140     int xft_lcdfilter;
141     cairo_antialias_t antialias;
142     cairo_subpixel_order_t subpixel_order;
143     cairo_lcd_filter_t lcd_filter;
144     cairo_hint_style_t hint_style;
145
146     if (!get_boolean_default (dpy, "antialias", &xft_antialias))
147         xft_antialias = TRUE;
148
149     if (!get_integer_default (dpy, "lcdfilter", &xft_lcdfilter)) {
150         /* -1 is an non-existant Fontconfig constant used to differentiate
151          * the case when no lcdfilter property is available.
152          */
153         xft_lcdfilter = -1;
154     }
155
156     if (!get_boolean_default (dpy, "hinting", &xft_hinting))
157         xft_hinting = TRUE;
158
159     if (!get_integer_default (dpy, "hintstyle", &xft_hintstyle))
160         xft_hintstyle = FC_HINT_FULL;
161
162     if (!get_integer_default (dpy, "rgba", &xft_rgba))
163     {
164         cairo_xlib_display_t *display = (cairo_xlib_display_t *) info->device;
165
166         xft_rgba = FC_RGBA_UNKNOWN;
167
168 #if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
169         if (display->render_major > 0 || display->render_minor >= 6) {
170             int render_order = XRenderQuerySubpixelOrder (dpy,
171                                                           XScreenNumberOfScreen (info->screen));
172
173             switch (render_order) {
174             default:
175             case SubPixelUnknown:
176                 xft_rgba = FC_RGBA_UNKNOWN;
177                 break;
178             case SubPixelHorizontalRGB:
179                 xft_rgba = FC_RGBA_RGB;
180                 break;
181             case SubPixelHorizontalBGR:
182                 xft_rgba = FC_RGBA_BGR;
183                 break;
184             case SubPixelVerticalRGB:
185                 xft_rgba = FC_RGBA_VRGB;
186                 break;
187             case SubPixelVerticalBGR:
188                 xft_rgba = FC_RGBA_VBGR;
189                 break;
190             case SubPixelNone:
191                 xft_rgba = FC_RGBA_NONE;
192                 break;
193             }
194         }
195 #endif
196     }
197
198     if (xft_hinting) {
199         switch (xft_hintstyle) {
200         case FC_HINT_NONE:
201             hint_style = CAIRO_HINT_STYLE_NONE;
202             break;
203         case FC_HINT_SLIGHT:
204             hint_style = CAIRO_HINT_STYLE_SLIGHT;
205             break;
206         case FC_HINT_MEDIUM:
207             hint_style = CAIRO_HINT_STYLE_MEDIUM;
208             break;
209         case FC_HINT_FULL:
210             hint_style = CAIRO_HINT_STYLE_FULL;
211             break;
212         default:
213             hint_style = CAIRO_HINT_STYLE_DEFAULT;
214         }
215     } else {
216         hint_style = CAIRO_HINT_STYLE_NONE;
217     }
218
219     switch (xft_rgba) {
220     case FC_RGBA_RGB:
221         subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
222         break;
223     case FC_RGBA_BGR:
224         subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
225         break;
226     case FC_RGBA_VRGB:
227         subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
228         break;
229     case FC_RGBA_VBGR:
230         subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
231         break;
232     case FC_RGBA_UNKNOWN:
233     case FC_RGBA_NONE:
234     default:
235         subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
236     }
237
238     switch (xft_lcdfilter) {
239     case FC_LCD_NONE:
240         lcd_filter = CAIRO_LCD_FILTER_NONE;
241         break;
242     case FC_LCD_DEFAULT:
243         lcd_filter = CAIRO_LCD_FILTER_FIR5;
244         break;
245     case FC_LCD_LIGHT:
246         lcd_filter = CAIRO_LCD_FILTER_FIR3;
247         break;
248     case FC_LCD_LEGACY:
249         lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL;
250         break;
251     default:
252         lcd_filter = CAIRO_LCD_FILTER_DEFAULT;
253         break;
254     }
255
256     if (xft_antialias) {
257         if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT)
258             antialias = CAIRO_ANTIALIAS_GRAY;
259         else
260             antialias = CAIRO_ANTIALIAS_SUBPIXEL;
261     } else {
262         antialias = CAIRO_ANTIALIAS_NONE;
263     }
264
265     cairo_font_options_set_hint_style (&info->font_options, hint_style);
266     cairo_font_options_set_antialias (&info->font_options, antialias);
267     cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order);
268     _cairo_font_options_set_lcd_filter (&info->font_options, lcd_filter);
269     cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON);
270 }
271
272 void
273 _cairo_xlib_screen_destroy (cairo_xlib_display_t *display,
274                             cairo_xlib_screen_t *info)
275 {
276     Display *dpy;
277     int i;
278
279     dpy = display->display;
280
281     while (! cairo_list_is_empty (&info->surfaces)) {
282         cairo_xlib_surface_t *surface;
283
284         surface = cairo_list_first_entry (&info->surfaces,
285                                           cairo_xlib_surface_t,
286                                           link);
287         cairo_surface_finish (&surface->base);
288     }
289
290     for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
291         if (info->gc_depths[i] != 0) {
292             XFreeGC (dpy, info->gc[i]);
293             info->gc_depths[i] = 0;
294         }
295     }
296
297     while (! cairo_list_is_empty (&info->visuals)) {
298         _cairo_xlib_visual_info_destroy (cairo_list_first_entry (&info->visuals,
299                                                                  cairo_xlib_visual_info_t,
300                                                                  link));
301     }
302
303     cairo_list_del (&info->link);
304
305     free (info);
306 }
307
308 cairo_status_t
309 _cairo_xlib_screen_get (Display *dpy,
310                         Screen *screen,
311                         cairo_xlib_screen_t **out)
312 {
313     cairo_xlib_display_t *display;
314     cairo_device_t *device;
315     cairo_xlib_screen_t *info;
316     cairo_status_t status;
317
318     device = _cairo_xlib_device_create (dpy);
319     status = device->status;
320     if (unlikely (status))
321         goto CLEANUP_DEVICE;
322
323     status =  _cairo_xlib_display_acquire (device, &display);
324     if (unlikely (status))
325         goto CLEANUP_DEVICE;
326
327     info = _cairo_xlib_display_get_screen (display, screen);
328     if (info != NULL) {
329         *out = info;
330         goto CLEANUP_DISPLAY;
331     }
332
333     info = malloc (sizeof (cairo_xlib_screen_t));
334     if (unlikely (info == NULL)) {
335         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
336         goto CLEANUP_DISPLAY;
337     }
338
339     info->device = device;
340     info->screen = screen;
341     info->has_font_options = FALSE;
342     memset (info->gc_depths, 0, sizeof (info->gc_depths));
343     memset (info->gc, 0, sizeof (info->gc));
344
345     cairo_list_init (&info->surfaces);
346     cairo_list_init (&info->visuals);
347     cairo_list_add (&info->link, &display->screens);
348
349     *out = info;
350
351   CLEANUP_DISPLAY:
352     cairo_device_release (&display->base);
353
354   CLEANUP_DEVICE:
355     cairo_device_destroy (device);
356     return status;
357 }
358
359 GC
360 _cairo_xlib_screen_get_gc (cairo_xlib_display_t *display,
361                            cairo_xlib_screen_t *info,
362                            int depth,
363                            Drawable drawable)
364 {
365     GC gc = NULL;
366     int i;
367
368     for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
369         if (info->gc_depths[i] == depth) {
370             info->gc_depths[i] = 0;
371             gc = info->gc[i];
372             break;
373         }
374     }
375
376     if (gc == NULL) {
377         XGCValues gcv;
378
379         gcv.graphics_exposures = False;
380         gcv.fill_style = FillTiled;
381         gc = XCreateGC (display->display,
382                         drawable,
383                         GCGraphicsExposures | GCFillStyle, &gcv);
384     }
385
386     return gc;
387 }
388
389 void
390 _cairo_xlib_screen_put_gc (cairo_xlib_display_t *display,
391                            cairo_xlib_screen_t *info,
392                            int depth,
393                            GC gc)
394 {
395     int i;
396
397     for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
398         if (info->gc_depths[i] == 0)
399             break;
400     }
401
402     if (i == ARRAY_LENGTH (info->gc)) {
403         /* perform random substitution to ensure fair caching over depths */
404         i = rand () % ARRAY_LENGTH (info->gc);
405         XFreeGC(display->display, info->gc[i]);
406     }
407
408     info->gc[i] = gc;
409     info->gc_depths[i] = depth;
410 }
411
412 cairo_status_t
413 _cairo_xlib_screen_get_visual_info (cairo_xlib_display_t *display,
414                                     cairo_xlib_screen_t *info,
415                                     Visual *v,
416                                     cairo_xlib_visual_info_t **out)
417 {
418     cairo_xlib_visual_info_t *visual;
419     cairo_status_t status;
420     int screen_number;
421
422     cairo_list_foreach_entry (visual,
423                               cairo_xlib_visual_info_t,
424                               &info->visuals,
425                               link)
426     {
427         if (visual->visualid == v->visualid) {
428             *out = visual;
429             return CAIRO_STATUS_SUCCESS;
430         }
431     }
432
433     screen_number = XScreenNumberOfScreen (info->screen);
434     if (screen_number < 0)
435         return CAIRO_STATUS_NEGATIVE_COUNT;
436
437     status = _cairo_xlib_visual_info_create (display->display,
438                                              screen_number,
439                                              v->visualid,
440                                              &visual);
441     if (unlikely (status))
442         return status;
443
444     cairo_list_add (&visual->link, &info->visuals);
445     *out = visual;
446     return CAIRO_STATUS_SUCCESS;
447 }
448
449 cairo_font_options_t *
450 _cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info)
451 {
452     if (! info->has_font_options) {
453         _cairo_font_options_init_default (&info->font_options);
454         _cairo_font_options_set_round_glyph_positions (&info->font_options, CAIRO_ROUND_GLYPH_POS_ON);
455
456         if (info->screen != NULL) {
457             cairo_xlib_display_t *display;
458
459             if (! _cairo_xlib_display_acquire (info->device, &display)) {
460                 _cairo_xlib_init_screen_font_options (display->display,
461                                                       info);
462                 cairo_device_release (&display->base);
463             }
464         }
465
466         info->has_font_options = TRUE;
467     }
468
469     return &info->font_options;
470 }
471
472 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */