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