xftdpy.c revision 0e0b1094
1c76ae52dSmrg/*
2c76ae52dSmrg * Copyright © 2000 Keith Packard
3c76ae52dSmrg *
4c76ae52dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
5c76ae52dSmrg * documentation for any purpose is hereby granted without fee, provided that
6c76ae52dSmrg * the above copyright notice appear in all copies and that both that
7c76ae52dSmrg * copyright notice and this permission notice appear in supporting
8c76ae52dSmrg * documentation, and that the name of Keith Packard not be used in
9c76ae52dSmrg * advertising or publicity pertaining to distribution of the software without
10c76ae52dSmrg * specific, written prior permission.  Keith Packard makes no
11c76ae52dSmrg * representations about the suitability of this software for any purpose.  It
12c76ae52dSmrg * is provided "as is" without express or implied warranty.
13c76ae52dSmrg *
14c76ae52dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15c76ae52dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16c76ae52dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17c76ae52dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18c76ae52dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19c76ae52dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20c76ae52dSmrg * PERFORMANCE OF THIS SOFTWARE.
21c76ae52dSmrg */
22c76ae52dSmrg
23c76ae52dSmrg#include "xftint.h"
24c76ae52dSmrg
25c76ae52dSmrg_X_HIDDEN XftDisplayInfo	*_XftDisplayInfo;
26c76ae52dSmrg
27c76ae52dSmrgstatic int
28c76ae52dSmrg_XftCloseDisplay (Display *dpy, XExtCodes *codes)
29c76ae52dSmrg{
30c76ae52dSmrg    XftDisplayInfo  *info, **prev;
31c76ae52dSmrg
32c76ae52dSmrg    info = _XftDisplayInfoGet (dpy, FcFalse);
33c76ae52dSmrg    if (!info)
34c76ae52dSmrg	return 0;
35da9cf437Smrg
36c76ae52dSmrg    /*
37c76ae52dSmrg     * Get rid of any dangling unreferenced fonts
38c76ae52dSmrg     */
39c76ae52dSmrg    info->max_unref_fonts = 0;
40c76ae52dSmrg    XftFontManageMemory (dpy);
41da9cf437Smrg
42c76ae52dSmrg    /*
43c76ae52dSmrg     * Clean up the default values
44c76ae52dSmrg     */
45c76ae52dSmrg    if (info->defaults)
46c76ae52dSmrg	FcPatternDestroy (info->defaults);
47da9cf437Smrg
48c76ae52dSmrg    /*
49c76ae52dSmrg     * Unhook from the global list
50c76ae52dSmrg     */
51c76ae52dSmrg    for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
52c76ae52dSmrg	if (info->display == dpy)
53c76ae52dSmrg	    break;
54c76ae52dSmrg    *prev = info->next;
55da9cf437Smrg
56c76ae52dSmrg    free (info);
57c76ae52dSmrg    return 0;
58c76ae52dSmrg}
59c76ae52dSmrg
60c76ae52dSmrg
61c76ae52dSmrg_X_HIDDEN XftDisplayInfo *
62c76ae52dSmrg_XftDisplayInfoGet (Display *dpy, FcBool createIfNecessary)
63c76ae52dSmrg{
64c76ae52dSmrg    XftDisplayInfo	*info, **prev;
65c76ae52dSmrg    XRenderPictFormat	pf;
66c76ae52dSmrg    int			i;
67c76ae52dSmrg    int			event_base, error_base;
68c76ae52dSmrg
69c76ae52dSmrg    for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
70c76ae52dSmrg    {
71c76ae52dSmrg	if (info->display == dpy)
72c76ae52dSmrg	{
73c76ae52dSmrg	    /*
74c76ae52dSmrg	     * MRU the list
75c76ae52dSmrg	     */
76c76ae52dSmrg	    if (prev != &_XftDisplayInfo)
77c76ae52dSmrg	    {
78c76ae52dSmrg		*prev = info->next;
79c76ae52dSmrg		info->next = _XftDisplayInfo;
80c76ae52dSmrg		_XftDisplayInfo = info;
81c76ae52dSmrg	    }
82c76ae52dSmrg	    return info;
83c76ae52dSmrg	}
84c76ae52dSmrg    }
85c76ae52dSmrg    if (!createIfNecessary)
860d590c07Smrg	return NULL;
87c76ae52dSmrg
88c76ae52dSmrg    info = (XftDisplayInfo *) malloc (sizeof (XftDisplayInfo));
89c76ae52dSmrg    if (!info)
90c76ae52dSmrg	goto bail0;
91c76ae52dSmrg    info->codes = XAddExtension (dpy);
92c76ae52dSmrg    if (!info->codes)
93c76ae52dSmrg	goto bail1;
94c76ae52dSmrg    (void) XESetCloseDisplay (dpy, info->codes->extension, _XftCloseDisplay);
95c76ae52dSmrg
96c76ae52dSmrg    info->display = dpy;
970d590c07Smrg    info->defaults = NULL;
980d590c07Smrg    info->solidFormat = NULL;
99c76ae52dSmrg    info->hasRender = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
1000d590c07Smrg		       (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != NULL));
101c76ae52dSmrg    info->use_free_glyphs = FcTrue;
102c76ae52dSmrg    if (info->hasRender)
103c76ae52dSmrg    {
104c76ae52dSmrg	int major, minor;
105c76ae52dSmrg	XRenderQueryVersion (dpy, &major, &minor);
106c76ae52dSmrg	if (major < 0 || (major == 0 && minor <= 2))
107c76ae52dSmrg	    info->use_free_glyphs = FcFalse;
108c76ae52dSmrg
10916b8d512Smrg	info->hasSolid = FcFalse;
11016b8d512Smrg	if (major > 0 || (major == 0 && minor >= 10))
11116b8d512Smrg	    info->hasSolid = FcTrue;
11216b8d512Smrg
113c76ae52dSmrg	pf.type = PictTypeDirect;
114c76ae52dSmrg	pf.depth = 32;
115c76ae52dSmrg	pf.direct.redMask = 0xff;
116c76ae52dSmrg	pf.direct.greenMask = 0xff;
117c76ae52dSmrg	pf.direct.blueMask = 0xff;
118c76ae52dSmrg	pf.direct.alphaMask = 0xff;
119c76ae52dSmrg	info->solidFormat = XRenderFindFormat (dpy,
120c76ae52dSmrg					       (PictFormatType|
121c76ae52dSmrg						PictFormatDepth|
122c76ae52dSmrg						PictFormatRedMask|
123c76ae52dSmrg						PictFormatGreenMask|
124c76ae52dSmrg						PictFormatBlueMask|
125c76ae52dSmrg						PictFormatAlphaMask),
126c76ae52dSmrg					       &pf,
127c76ae52dSmrg					       0);
128c76ae52dSmrg    }
129c76ae52dSmrg    if (XftDebug () & XFT_DBG_RENDER)
130c76ae52dSmrg    {
131c76ae52dSmrg	Visual		    *visual = DefaultVisual (dpy, DefaultScreen (dpy));
132c76ae52dSmrg	XRenderPictFormat   *format = XRenderFindVisualFormat (dpy, visual);
133da9cf437Smrg
134da9cf437Smrg	printf ("XftDisplayInfoGet Default visual 0x%x ",
135c76ae52dSmrg		(int) visual->visualid);
136c76ae52dSmrg	if (format)
137c76ae52dSmrg	{
138c76ae52dSmrg	    if (format->type == PictTypeDirect)
139c76ae52dSmrg	    {
140c76ae52dSmrg		printf ("format %d,%d,%d,%d\n",
141c76ae52dSmrg			format->direct.alpha,
142c76ae52dSmrg			format->direct.red,
143c76ae52dSmrg			format->direct.green,
144c76ae52dSmrg			format->direct.blue);
145c76ae52dSmrg	    }
146c76ae52dSmrg	    else
147c76ae52dSmrg	    {
148c76ae52dSmrg		printf ("format indexed\n");
149c76ae52dSmrg	    }
150c76ae52dSmrg	}
151c76ae52dSmrg	else
152c76ae52dSmrg	    printf ("No Render format for default visual\n");
153da9cf437Smrg
154c76ae52dSmrg	printf ("XftDisplayInfoGet initialized, hasRender set to \"%s\"\n",
155c76ae52dSmrg		info->hasRender ? "True" : "False");
156c76ae52dSmrg    }
157c76ae52dSmrg    for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
158c76ae52dSmrg    {
159c76ae52dSmrg	info->colors[i].screen = -1;
160c76ae52dSmrg	info->colors[i].pict = 0;
161c76ae52dSmrg    }
1620d590c07Smrg    info->fonts = NULL;
163da9cf437Smrg
164c76ae52dSmrg    info->next = _XftDisplayInfo;
165c76ae52dSmrg    _XftDisplayInfo = info;
1660d590c07Smrg
167be3b088cSmrg    info->glyph_memory = 0;
1680e0b1094Smrg    info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
169c76ae52dSmrg						   XFT_MAX_GLYPH_MEMORY, 0,
170c76ae52dSmrg						   XFT_DPY_MAX_GLYPH_MEMORY);
171c76ae52dSmrg    if (XftDebug () & XFT_DBG_CACHE)
172c76ae52dSmrg	printf ("global max cache memory %ld\n", info->max_glyph_memory);
173c76ae52dSmrg
174da9cf437Smrg
175c76ae52dSmrg    info->num_unref_fonts = 0;
176c76ae52dSmrg    info->max_unref_fonts = XftDefaultGetInteger (dpy,
177c76ae52dSmrg						  XFT_MAX_UNREF_FONTS, 0,
178c76ae52dSmrg						  XFT_DPY_MAX_UNREF_FONTS);
179c76ae52dSmrg    if (XftDebug() & XFT_DBG_CACHE)
180c76ae52dSmrg	printf ("global max unref fonts %d\n", info->max_unref_fonts);
181c76ae52dSmrg
182c76ae52dSmrg    memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH);
183c76ae52dSmrg    return info;
184da9cf437Smrg
185c76ae52dSmrgbail1:
186c76ae52dSmrg    free (info);
187c76ae52dSmrgbail0:
188c76ae52dSmrg    if (XftDebug () & XFT_DBG_RENDER)
189c76ae52dSmrg    {
190c76ae52dSmrg	printf ("XftDisplayInfoGet failed to initialize, Xft unhappy\n");
191c76ae52dSmrg    }
1920d590c07Smrg    return NULL;
193c76ae52dSmrg}
194c76ae52dSmrg
195c76ae52dSmrg/*
196c76ae52dSmrg * Reduce memory usage in X server
197c76ae52dSmrg */
198c76ae52dSmrg
199c76ae52dSmrgstatic void
200c76ae52dSmrg_XftDisplayValidateMemory (XftDisplayInfo *info)
201c76ae52dSmrg{
202c76ae52dSmrg    XftFont	    *public;
203c76ae52dSmrg    XftFontInt	    *font;
204c76ae52dSmrg    unsigned long   glyph_memory;
205c76ae52dSmrg
206c76ae52dSmrg    glyph_memory = 0;
207c76ae52dSmrg    for (public = info->fonts; public; public = font->next)
208c76ae52dSmrg    {
209c76ae52dSmrg	font = (XftFontInt *) public;
210c76ae52dSmrg	glyph_memory += font->glyph_memory;
211c76ae52dSmrg    }
212c76ae52dSmrg    if (glyph_memory != info->glyph_memory)
213c76ae52dSmrg	printf ("Display glyph cache incorrect has %ld bytes, should have %ld\n",
214c76ae52dSmrg		info->glyph_memory, glyph_memory);
215c76ae52dSmrg}
216c76ae52dSmrg
217c76ae52dSmrg_X_HIDDEN void
218c76ae52dSmrg_XftDisplayManageMemory (Display *dpy)
219c76ae52dSmrg{
220c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
221c76ae52dSmrg    unsigned long   glyph_memory;
222c76ae52dSmrg    XftFont	    *public;
223c76ae52dSmrg    XftFontInt	    *font;
224c76ae52dSmrg
225c76ae52dSmrg    if (!info || !info->max_glyph_memory)
226c76ae52dSmrg	return;
227c76ae52dSmrg    if (XftDebug () & XFT_DBG_CACHE)
228c76ae52dSmrg    {
229c76ae52dSmrg	if (info->glyph_memory > info->max_glyph_memory)
230c76ae52dSmrg	    printf ("Reduce global memory from %ld to %ld\n",
231c76ae52dSmrg		    info->glyph_memory, info->max_glyph_memory);
232c76ae52dSmrg	_XftDisplayValidateMemory (info);
233c76ae52dSmrg    }
234c76ae52dSmrg    while (info->glyph_memory > info->max_glyph_memory)
235c76ae52dSmrg    {
2360e0b1094Smrg	glyph_memory = (unsigned long)rand () % info->glyph_memory;
237c76ae52dSmrg	public = info->fonts;
238c76ae52dSmrg	while (public)
239c76ae52dSmrg	{
240c76ae52dSmrg	    font = (XftFontInt *) public;
241c76ae52dSmrg
242c76ae52dSmrg	    if (font->glyph_memory > glyph_memory)
243c76ae52dSmrg	    {
244c76ae52dSmrg		_XftFontUncacheGlyph (dpy, public);
245c76ae52dSmrg		break;
246c76ae52dSmrg	    }
247c76ae52dSmrg	    public = font->next;
248c76ae52dSmrg	    glyph_memory -= font->glyph_memory;
249c76ae52dSmrg	}
250c76ae52dSmrg    }
251c76ae52dSmrg    if (XftDebug () & XFT_DBG_CACHE)
252c76ae52dSmrg	_XftDisplayValidateMemory (info);
253c76ae52dSmrg}
254c76ae52dSmrg
255c76ae52dSmrg_X_EXPORT Bool
256c76ae52dSmrgXftDefaultHasRender (Display *dpy)
257c76ae52dSmrg{
258c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
259c76ae52dSmrg
260c76ae52dSmrg    if (!info)
261c76ae52dSmrg	return False;
262c76ae52dSmrg    return info->hasRender;
263c76ae52dSmrg}
264c76ae52dSmrg
265c76ae52dSmrg_X_EXPORT Bool
266c76ae52dSmrgXftDefaultSet (Display *dpy, FcPattern *defaults)
267c76ae52dSmrg{
268c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
269c76ae52dSmrg
270c76ae52dSmrg    if (!info)
271c76ae52dSmrg	return False;
272c76ae52dSmrg    if (info->defaults)
273c76ae52dSmrg	FcPatternDestroy (info->defaults);
274c76ae52dSmrg    info->defaults = defaults;
275c76ae52dSmrg    if (!info->max_glyph_memory)
276c76ae52dSmrg	info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY;
2770e0b1094Smrg    info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
278c76ae52dSmrg						   XFT_MAX_GLYPH_MEMORY, 0,
2790e0b1094Smrg						   (int)info->max_glyph_memory);
280c76ae52dSmrg    if (!info->max_unref_fonts)
281c76ae52dSmrg	info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS;
282c76ae52dSmrg    info->max_unref_fonts = XftDefaultGetInteger (dpy,
283c76ae52dSmrg						  XFT_MAX_UNREF_FONTS, 0,
284c76ae52dSmrg						  info->max_unref_fonts);
285c76ae52dSmrg    return True;
286c76ae52dSmrg}
287c76ae52dSmrg
288c76ae52dSmrg_X_HIDDEN int
289da9cf437SmrgXftDefaultParseBool (const char *v)
290c76ae52dSmrg{
291c76ae52dSmrg    char    c0, c1;
292c76ae52dSmrg
293c76ae52dSmrg    c0 = *v;
294c76ae52dSmrg    if (isupper ((int)c0))
2950e0b1094Smrg	c0 = (char)tolower (c0);
296c76ae52dSmrg    if (c0 == 't' || c0 == 'y' || c0 == '1')
297c76ae52dSmrg	return 1;
298c76ae52dSmrg    if (c0 == 'f' || c0 == 'n' || c0 == '0')
299c76ae52dSmrg	return 0;
300c76ae52dSmrg    if (c0 == 'o')
301c76ae52dSmrg    {
302c76ae52dSmrg	c1 = v[1];
303c76ae52dSmrg	if (isupper ((int)c1))
3040e0b1094Smrg	    c1 = (char)tolower (c1);
305c76ae52dSmrg	if (c1 == 'n')
306c76ae52dSmrg	    return 1;
307c76ae52dSmrg	if (c1 == 'f')
308c76ae52dSmrg	    return 0;
309c76ae52dSmrg    }
310c76ae52dSmrg    return -1;
311c76ae52dSmrg}
312c76ae52dSmrg
313c76ae52dSmrgstatic Bool
314da9cf437Smrg_XftDefaultInitBool (Display *dpy, FcPattern *pat, const char *option)
315c76ae52dSmrg{
316c76ae52dSmrg    char    *v;
317c76ae52dSmrg    int	    i;
318c76ae52dSmrg
319c76ae52dSmrg    v = XGetDefault (dpy, "Xft", option);
320c76ae52dSmrg    if (v && (i = XftDefaultParseBool (v)) >= 0)
321c76ae52dSmrg	return FcPatternAddBool (pat, option, i != 0);
322c76ae52dSmrg    return True;
323c76ae52dSmrg}
324c76ae52dSmrg
325c76ae52dSmrgstatic Bool
326da9cf437Smrg_XftDefaultInitDouble (Display *dpy, FcPattern *pat, const char *option)
327c76ae52dSmrg{
328c76ae52dSmrg    char    *v, *e;
329c76ae52dSmrg    double  d;
330c76ae52dSmrg
331c76ae52dSmrg    v = XGetDefault (dpy, "Xft", option);
332c76ae52dSmrg    if (v)
333c76ae52dSmrg    {
334c76ae52dSmrg	d = strtod (v, &e);
335c76ae52dSmrg	if (e != v)
336c76ae52dSmrg	    return FcPatternAddDouble (pat, option, d);
337c76ae52dSmrg    }
338c76ae52dSmrg    return True;
339c76ae52dSmrg}
340c76ae52dSmrg
341c76ae52dSmrgstatic Bool
342da9cf437Smrg_XftDefaultInitInteger (Display *dpy, FcPattern *pat, const char *option)
343c76ae52dSmrg{
344c76ae52dSmrg    char    *v, *e;
345c76ae52dSmrg    int	    i;
346c76ae52dSmrg
347c76ae52dSmrg    v = XGetDefault (dpy, "Xft", option);
348c76ae52dSmrg    if (v)
349c76ae52dSmrg    {
350c76ae52dSmrg	if (FcNameConstant ((FcChar8 *) v, &i))
351c76ae52dSmrg	    return FcPatternAddInteger (pat, option, i);
3520e0b1094Smrg	i = (int)strtol (v, &e, 0);
353c76ae52dSmrg	if (e != v)
354c76ae52dSmrg	    return FcPatternAddInteger (pat, option, i);
355c76ae52dSmrg    }
356c76ae52dSmrg    return True;
357c76ae52dSmrg}
358c76ae52dSmrg
359c76ae52dSmrgstatic FcPattern *
360c76ae52dSmrg_XftDefaultInit (Display *dpy)
361c76ae52dSmrg{
362c76ae52dSmrg    FcPattern	*pat;
363c76ae52dSmrg
364c76ae52dSmrg    pat = FcPatternCreate ();
365c76ae52dSmrg    if (!pat)
366c76ae52dSmrg	goto bail0;
367c76ae52dSmrg
368c76ae52dSmrg    if (!_XftDefaultInitDouble (dpy, pat, FC_SCALE))
369c76ae52dSmrg	goto bail1;
370c76ae52dSmrg    if (!_XftDefaultInitDouble (dpy, pat, FC_DPI))
371c76ae52dSmrg	goto bail1;
372c76ae52dSmrg    if (!_XftDefaultInitBool (dpy, pat, XFT_RENDER))
373c76ae52dSmrg	goto bail1;
374c76ae52dSmrg    if (!_XftDefaultInitInteger (dpy, pat, FC_RGBA))
375c76ae52dSmrg	goto bail1;
376da9cf437Smrg    if (!_XftDefaultInitInteger (dpy, pat, FC_LCD_FILTER))
377da9cf437Smrg	goto bail1;
378c76ae52dSmrg    if (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS))
379c76ae52dSmrg	goto bail1;
380c76ae52dSmrg    if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN))
381c76ae52dSmrg	goto bail1;
382c76ae52dSmrg    if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT))
383c76ae52dSmrg	goto bail1;
384c76ae52dSmrg    if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE))
385c76ae52dSmrg	goto bail1;
386c76ae52dSmrg    if (!_XftDefaultInitBool (dpy, pat, FC_HINTING))
387c76ae52dSmrg	goto bail1;
388c76ae52dSmrg    if (!_XftDefaultInitBool (dpy, pat, FC_MINSPACE))
389c76ae52dSmrg	goto bail1;
390c76ae52dSmrg    if (!_XftDefaultInitInteger (dpy, pat, XFT_MAX_GLYPH_MEMORY))
391c76ae52dSmrg	goto bail1;
392da9cf437Smrg
393c76ae52dSmrg    return pat;
394da9cf437Smrg
395c76ae52dSmrgbail1:
396c76ae52dSmrg    FcPatternDestroy (pat);
397c76ae52dSmrgbail0:
3980d590c07Smrg    return NULL;
399c76ae52dSmrg}
400c76ae52dSmrg
401c76ae52dSmrgstatic FcResult
402c76ae52dSmrg_XftDefaultGet (Display *dpy, const char *object, int screen, FcValue *v)
403c76ae52dSmrg{
404c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
405c76ae52dSmrg    FcResult	    r;
406c76ae52dSmrg
407c76ae52dSmrg    if (!info)
408c76ae52dSmrg	return FcResultNoMatch;
409da9cf437Smrg
410c76ae52dSmrg    if (!info->defaults)
411c76ae52dSmrg    {
412c76ae52dSmrg	info->defaults = _XftDefaultInit (dpy);
413c76ae52dSmrg	if (!info->defaults)
414c76ae52dSmrg	    return FcResultNoMatch;
415c76ae52dSmrg    }
416c76ae52dSmrg    r = FcPatternGet (info->defaults, object, screen, v);
417c76ae52dSmrg    if (r == FcResultNoId && screen > 0)
418c76ae52dSmrg	r = FcPatternGet (info->defaults, object, 0, v);
419c76ae52dSmrg    return r;
420c76ae52dSmrg}
421c76ae52dSmrg
422c76ae52dSmrg_X_HIDDEN Bool
423c76ae52dSmrgXftDefaultGetBool (Display *dpy, const char *object, int screen, Bool def)
424c76ae52dSmrg{
425c76ae52dSmrg    FcResult	    r;
426c76ae52dSmrg    FcValue	    v;
427c76ae52dSmrg
428c76ae52dSmrg    r = _XftDefaultGet (dpy, object, screen, &v);
429c76ae52dSmrg    if (r != FcResultMatch || v.type != FcTypeBool)
430c76ae52dSmrg	return def;
431c76ae52dSmrg    return v.u.b;
432c76ae52dSmrg}
433c76ae52dSmrg
434c76ae52dSmrg_X_HIDDEN int
435c76ae52dSmrgXftDefaultGetInteger (Display *dpy, const char *object, int screen, int def)
436c76ae52dSmrg{
437c76ae52dSmrg    FcResult	    r;
438c76ae52dSmrg    FcValue	    v;
439c76ae52dSmrg
440c76ae52dSmrg    r = _XftDefaultGet (dpy, object, screen, &v);
441c76ae52dSmrg    if (r != FcResultMatch || v.type != FcTypeInteger)
442c76ae52dSmrg	return def;
443c76ae52dSmrg    return v.u.i;
444c76ae52dSmrg}
445c76ae52dSmrg
446c76ae52dSmrg_X_HIDDEN double
447c76ae52dSmrgXftDefaultGetDouble (Display *dpy, const char *object, int screen, double def)
448c76ae52dSmrg{
449c76ae52dSmrg    FcResult	    r;
450c76ae52dSmrg    FcValue	    v;
451c76ae52dSmrg
452c76ae52dSmrg    r = _XftDefaultGet (dpy, object, screen, &v);
453c76ae52dSmrg    if (r != FcResultMatch || v.type != FcTypeDouble)
454c76ae52dSmrg	return def;
455c76ae52dSmrg    return v.u.d;
456c76ae52dSmrg}
457c76ae52dSmrg
458c76ae52dSmrg_X_EXPORT void
459c76ae52dSmrgXftDefaultSubstitute (Display *dpy, int screen, FcPattern *pattern)
460c76ae52dSmrg{
461c76ae52dSmrg    FcValue	v;
462c76ae52dSmrg    double	dpi;
463c76ae52dSmrg
464c76ae52dSmrg    if (FcPatternGet (pattern, XFT_RENDER, 0, &v) == FcResultNoMatch)
465c76ae52dSmrg    {
466c76ae52dSmrg	FcPatternAddBool (pattern, XFT_RENDER,
467da9cf437Smrg			   XftDefaultGetBool (dpy, XFT_RENDER, screen,
468c76ae52dSmrg					      XftDefaultHasRender (dpy)));
469c76ae52dSmrg    }
470c76ae52dSmrg    if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch)
471c76ae52dSmrg    {
472c76ae52dSmrg	FcPatternAddBool (pattern, FC_ANTIALIAS,
473c76ae52dSmrg			   XftDefaultGetBool (dpy, FC_ANTIALIAS, screen,
474c76ae52dSmrg					      True));
475c76ae52dSmrg    }
476c76ae52dSmrg    if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch)
477c76ae52dSmrg    {
478c76ae52dSmrg	FcPatternAddBool (pattern, FC_EMBOLDEN,
479c76ae52dSmrg			   XftDefaultGetBool (dpy, FC_EMBOLDEN, screen,
480c76ae52dSmrg					      False));
481c76ae52dSmrg    }
482c76ae52dSmrg    if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
483c76ae52dSmrg    {
484c76ae52dSmrg	FcPatternAddBool (pattern, FC_HINTING,
485c76ae52dSmrg			  XftDefaultGetBool (dpy, FC_HINTING, screen,
486c76ae52dSmrg					     True));
487c76ae52dSmrg    }
488c76ae52dSmrg    if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch)
489c76ae52dSmrg    {
490c76ae52dSmrg	FcPatternAddInteger (pattern, FC_HINT_STYLE,
491c76ae52dSmrg			     XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen,
492c76ae52dSmrg						   FC_HINT_FULL));
493c76ae52dSmrg    }
494c76ae52dSmrg    if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch)
495c76ae52dSmrg    {
496c76ae52dSmrg	FcPatternAddBool (pattern, FC_AUTOHINT,
497c76ae52dSmrg			  XftDefaultGetBool (dpy, FC_AUTOHINT, screen,
498c76ae52dSmrg					     False));
499c76ae52dSmrg    }
500c76ae52dSmrg    if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch)
501c76ae52dSmrg    {
502c76ae52dSmrg	int	subpixel = FC_RGBA_UNKNOWN;
503c76ae52dSmrg#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
504c76ae52dSmrg	if (XftDefaultHasRender (dpy))
505c76ae52dSmrg	{
506c76ae52dSmrg	    int render_order = XRenderQuerySubpixelOrder (dpy, screen);
507c76ae52dSmrg	    switch (render_order) {
508c76ae52dSmrg	    default:
509c76ae52dSmrg	    case SubPixelUnknown:	subpixel = FC_RGBA_UNKNOWN; break;
510c76ae52dSmrg	    case SubPixelHorizontalRGB:	subpixel = FC_RGBA_RGB; break;
511c76ae52dSmrg	    case SubPixelHorizontalBGR:	subpixel = FC_RGBA_BGR; break;
512c76ae52dSmrg	    case SubPixelVerticalRGB:	subpixel = FC_RGBA_VRGB; break;
513c76ae52dSmrg	    case SubPixelVerticalBGR:	subpixel = FC_RGBA_VBGR; break;
514c76ae52dSmrg	    case SubPixelNone:		subpixel = FC_RGBA_NONE; break;
515c76ae52dSmrg	    }
516c76ae52dSmrg	}
517c76ae52dSmrg#endif
518c76ae52dSmrg	FcPatternAddInteger (pattern, FC_RGBA,
519da9cf437Smrg			      XftDefaultGetInteger (dpy, FC_RGBA, screen,
520c76ae52dSmrg						    subpixel));
521c76ae52dSmrg    }
522da9cf437Smrg    if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch)
523da9cf437Smrg    {
524da9cf437Smrg	FcPatternAddInteger (pattern, FC_LCD_FILTER,
525da9cf437Smrg			     XftDefaultGetInteger (dpy, FC_LCD_FILTER, screen,
526da9cf437Smrg						   FC_LCD_DEFAULT));
527da9cf437Smrg    }
528c76ae52dSmrg    if (FcPatternGet (pattern, FC_MINSPACE, 0, &v) == FcResultNoMatch)
529c76ae52dSmrg    {
530c76ae52dSmrg	FcPatternAddBool (pattern, FC_MINSPACE,
531c76ae52dSmrg			   XftDefaultGetBool (dpy, FC_MINSPACE, screen,
532c76ae52dSmrg					      False));
533c76ae52dSmrg    }
534c76ae52dSmrg    if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch)
535c76ae52dSmrg    {
536da9cf437Smrg	dpi = (((double) DisplayHeight (dpy, screen) * 25.4) /
537c76ae52dSmrg	       (double) DisplayHeightMM (dpy, screen));
538da9cf437Smrg	FcPatternAddDouble (pattern, FC_DPI,
539da9cf437Smrg			    XftDefaultGetDouble (dpy, FC_DPI, screen,
540c76ae52dSmrg						 dpi));
541c76ae52dSmrg    }
542c76ae52dSmrg    if (FcPatternGet (pattern, FC_SCALE, 0, &v) == FcResultNoMatch)
543c76ae52dSmrg    {
544c76ae52dSmrg	FcPatternAddDouble (pattern, FC_SCALE,
545c76ae52dSmrg			    XftDefaultGetDouble (dpy, FC_SCALE, screen, 1.0));
546c76ae52dSmrg    }
547c76ae52dSmrg    if (FcPatternGet (pattern, XFT_MAX_GLYPH_MEMORY, 0, &v) == FcResultNoMatch)
548c76ae52dSmrg    {
549c76ae52dSmrg	FcPatternAddInteger (pattern, XFT_MAX_GLYPH_MEMORY,
550c76ae52dSmrg			     XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY,
551c76ae52dSmrg						   screen,
552c76ae52dSmrg						   XFT_FONT_MAX_GLYPH_MEMORY));
553c76ae52dSmrg    }
554c76ae52dSmrg    FcDefaultSubstitute (pattern);
555c76ae52dSmrg}
556c76ae52dSmrg
557