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
4
_cairo_xlib_screen_destroy (cairo_xlib_display_t *display,
274
			    cairo_xlib_screen_t *info)
275
{
276
    Display *dpy;
277
    int i;
278

            
279
4
    dpy = display->display;
280

            
281
7
    while (! cairo_list_is_empty (&info->surfaces)) {
282
	cairo_xlib_surface_t *surface;
283

            
284
3
	surface = cairo_list_first_entry (&info->surfaces,
285
					  cairo_xlib_surface_t,
286
					  link);
287
3
	cairo_surface_finish (&surface->base);
288
    }
289

            
290
20
    for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
291
16
	if (info->gc_depths[i] != 0) {
292
3
	    XFreeGC (dpy, info->gc[i]);
293
3
	    info->gc_depths[i] = 0;
294
	}
295
    }
296

            
297
4
    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
4
    cairo_list_del (&info->link);
304

            
305
4
    free (info);
306
4
}
307

            
308
cairo_status_t
309
4
_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
4
    device = _cairo_xlib_device_create (dpy);
319
4
    status = device->status;
320
4
    if (unlikely (status))
321
        goto CLEANUP_DEVICE;
322

            
323
4
    status =  _cairo_xlib_display_acquire (device, &display);
324
4
    if (unlikely (status))
325
        goto CLEANUP_DEVICE;
326

            
327
4
    info = _cairo_xlib_display_get_screen (display, screen);
328
4
    if (info != NULL) {
329
	*out = info;
330
	goto CLEANUP_DISPLAY;
331
    }
332

            
333
4
    info = _cairo_calloc (sizeof (cairo_xlib_screen_t));
334
4
    if (unlikely (info == NULL)) {
335
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
336
	goto CLEANUP_DISPLAY;
337
    }
338

            
339
4
    info->device = device;
340
4
    info->screen = screen;
341
4
    info->has_font_options = FALSE;
342
4
    memset (info->gc_depths, 0, sizeof (info->gc_depths));
343
4
    memset (info->gc, 0, sizeof (info->gc));
344

            
345
4
    cairo_list_init (&info->surfaces);
346
4
    cairo_list_init (&info->visuals);
347
4
    cairo_list_add (&info->link, &display->screens);
348

            
349
4
    *out = info;
350

            
351
4
  CLEANUP_DISPLAY:
352
4
    cairo_device_release (&display->base);
353

            
354
4
  CLEANUP_DEVICE:
355
4
    cairo_device_destroy (device);
356
4
    return status;
357
}
358

            
359
GC
360
6
_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display,
361
                           cairo_xlib_screen_t *info,
362
			   int depth,
363
			   Drawable drawable)
364
{
365
6
    GC gc = NULL;
366
    int i;
367

            
368
18
    for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
369
15
	if (info->gc_depths[i] == depth) {
370
3
	    info->gc_depths[i] = 0;
371
3
	    gc = info->gc[i];
372
3
	    break;
373
	}
374
    }
375

            
376
6
    if (gc == NULL) {
377
	XGCValues gcv;
378

            
379
3
	gcv.graphics_exposures = False;
380
3
	gcv.fill_style = FillTiled;
381
3
	gc = XCreateGC (display->display,
382
			drawable,
383
			GCGraphicsExposures | GCFillStyle, &gcv);
384
    }
385

            
386
6
    return gc;
387
}
388

            
389
void
390
6
_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
6
    for (i = 0; i < ARRAY_LENGTH (info->gc); i++) {
398
6
	if (info->gc_depths[i] == 0)
399
6
	    break;
400
    }
401

            
402
6
    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
6
    info->gc[i] = gc;
409
6
    info->gc_depths[i] = depth;
410
6
}
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

            
421
    cairo_list_foreach_entry (visual,
422
                              cairo_xlib_visual_info_t,
423
                              &info->visuals,
424
                              link)
425
    {
426
	if (visual->visualid == v->visualid) {
427
            *out = visual;
428
            return CAIRO_STATUS_SUCCESS;
429
	}
430
    }
431

            
432
    status = _cairo_xlib_visual_info_create (display->display,
433
					     XScreenNumberOfScreen (info->screen),
434
					     v->visualid,
435
					     &visual);
436
    if (unlikely (status))
437
	return status;
438

            
439
    cairo_list_add (&visual->link, &info->visuals);
440
    *out = visual;
441
    return CAIRO_STATUS_SUCCESS;
442
}
443

            
444
cairo_font_options_t *
445
_cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info)
446
{
447
    if (! info->has_font_options) {
448
	_cairo_font_options_init_default (&info->font_options);
449
	_cairo_font_options_set_round_glyph_positions (&info->font_options, CAIRO_ROUND_GLYPH_POS_ON);
450

            
451
	if (info->screen != NULL) {
452
            cairo_xlib_display_t *display;
453

            
454
            if (! _cairo_xlib_display_acquire (info->device, &display)) {
455
                _cairo_xlib_init_screen_font_options (display->display,
456
                                                      info);
457
                cairo_device_release (&display->base);
458
            }
459
	}
460

            
461
	info->has_font_options = TRUE;
462
    }
463

            
464
    return &info->font_options;
465
}
466

            
467
#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */