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