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 
27 static int
_XftCloseDisplay(Display * dpy,XExtCodes * codes)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 *
_XftDisplayInfoGet(Display * dpy,FcBool createIfNecessary)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 	info->hasSolid = FcFalse;
110 	if (major > 0 || (major == 0 && minor >= 10))
111 	    info->hasSolid = FcTrue;
112 
113 	pf.type = PictTypeDirect;
114 	pf.depth = 32;
115 	pf.direct.redMask = 0xff;
116 	pf.direct.greenMask = 0xff;
117 	pf.direct.blueMask = 0xff;
118 	pf.direct.alphaMask = 0xff;
119 	info->solidFormat = XRenderFindFormat (dpy,
120 					       (PictFormatType|
121 						PictFormatDepth|
122 						PictFormatRedMask|
123 						PictFormatGreenMask|
124 						PictFormatBlueMask|
125 						PictFormatAlphaMask),
126 					       &pf,
127 					       0);
128     }
129     if (XftDebug () & XFT_DBG_RENDER)
130     {
131 	Visual		    *visual = DefaultVisual (dpy, DefaultScreen (dpy));
132 	XRenderPictFormat   *format = XRenderFindVisualFormat (dpy, visual);
133 
134 	printf ("XftDisplayInfoGet Default visual 0x%x ",
135 		(int) visual->visualid);
136 	if (format)
137 	{
138 	    if (format->type == PictTypeDirect)
139 	    {
140 		printf ("format %d,%d,%d,%d\n",
141 			format->direct.alpha,
142 			format->direct.red,
143 			format->direct.green,
144 			format->direct.blue);
145 	    }
146 	    else
147 	    {
148 		printf ("format indexed\n");
149 	    }
150 	}
151 	else
152 	    printf ("No Render format for default visual\n");
153 
154 	printf ("XftDisplayInfoGet initialized, hasRender set to \"%s\"\n",
155 		info->hasRender ? "True" : "False");
156     }
157     for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
158     {
159 	info->colors[i].screen = -1;
160 	info->colors[i].pict = 0;
161     }
162     info->fonts = NULL;
163 
164     info->next = _XftDisplayInfo;
165     _XftDisplayInfo = info;
166 
167     info->glyph_memory = 0;
168     info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
169 						   XFT_MAX_GLYPH_MEMORY, 0,
170 						   XFT_DPY_MAX_GLYPH_MEMORY);
171     if (XftDebug () & XFT_DBG_CACHE)
172 	printf ("global max cache memory %ld\n", info->max_glyph_memory);
173 
174 
175     info->num_unref_fonts = 0;
176     info->max_unref_fonts = XftDefaultGetInteger (dpy,
177 						  XFT_MAX_UNREF_FONTS, 0,
178 						  XFT_DPY_MAX_UNREF_FONTS);
179     if (XftDebug() & XFT_DBG_CACHE)
180 	printf ("global max unref fonts %d\n", info->max_unref_fonts);
181 
182     memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH);
183     return info;
184 
185 bail1:
186     free (info);
187 bail0:
188     if (XftDebug () & XFT_DBG_RENDER)
189     {
190 	printf ("XftDisplayInfoGet failed to initialize, Xft unhappy\n");
191     }
192     return NULL;
193 }
194 
195 /*
196  * Reduce memory usage in X server
197  */
198 
199 static void
_XftDisplayValidateMemory(XftDisplayInfo * info)200 _XftDisplayValidateMemory (XftDisplayInfo *info)
201 {
202     XftFont	    *public;
203     XftFontInt	    *font;
204     unsigned long   glyph_memory;
205 
206     glyph_memory = 0;
207     for (public = info->fonts; public; public = font->next)
208     {
209 	font = (XftFontInt *) public;
210 	glyph_memory += font->glyph_memory;
211     }
212     if (glyph_memory != info->glyph_memory)
213 	printf ("Display glyph cache incorrect has %ld bytes, should have %ld\n",
214 		info->glyph_memory, glyph_memory);
215 }
216 
217 _X_HIDDEN void
_XftDisplayManageMemory(Display * dpy)218 _XftDisplayManageMemory (Display *dpy)
219 {
220     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
221     unsigned long   glyph_memory;
222     XftFont	    *public;
223     XftFontInt	    *font;
224 
225     if (!info || !info->max_glyph_memory)
226 	return;
227     if (XftDebug () & XFT_DBG_CACHE)
228     {
229 	if (info->glyph_memory > info->max_glyph_memory)
230 	    printf ("Reduce global memory from %ld to %ld\n",
231 		    info->glyph_memory, info->max_glyph_memory);
232 	_XftDisplayValidateMemory (info);
233     }
234     while (info->glyph_memory > info->max_glyph_memory)
235     {
236 	glyph_memory = (unsigned long)rand () % info->glyph_memory;
237 	public = info->fonts;
238 	while (public)
239 	{
240 	    font = (XftFontInt *) public;
241 
242 	    if (font->glyph_memory > glyph_memory)
243 	    {
244 		_XftFontUncacheGlyph (dpy, public);
245 		break;
246 	    }
247 	    public = font->next;
248 	    glyph_memory -= font->glyph_memory;
249 	}
250     }
251     if (XftDebug () & XFT_DBG_CACHE)
252 	_XftDisplayValidateMemory (info);
253 }
254 
255 _X_EXPORT Bool
XftDefaultHasRender(Display * dpy)256 XftDefaultHasRender (Display *dpy)
257 {
258     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
259 
260     if (!info)
261 	return False;
262     return info->hasRender;
263 }
264 
265 _X_EXPORT Bool
XftDefaultSet(Display * dpy,FcPattern * defaults)266 XftDefaultSet (Display *dpy, FcPattern *defaults)
267 {
268     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
269 
270     if (!info)
271 	return False;
272     if (info->defaults)
273 	FcPatternDestroy (info->defaults);
274     info->defaults = defaults;
275     if (!info->max_glyph_memory)
276 	info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY;
277     info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
278 						   XFT_MAX_GLYPH_MEMORY, 0,
279 						   (int)info->max_glyph_memory);
280     if (!info->max_unref_fonts)
281 	info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS;
282     info->max_unref_fonts = XftDefaultGetInteger (dpy,
283 						  XFT_MAX_UNREF_FONTS, 0,
284 						  info->max_unref_fonts);
285     return True;
286 }
287 
288 _X_HIDDEN int
XftDefaultParseBool(const char * v)289 XftDefaultParseBool (const char *v)
290 {
291     char    c0, c1;
292 
293     c0 = *v;
294     if (isupper ((int)c0))
295 	c0 = (char)tolower (c0);
296     if (c0 == 't' || c0 == 'y' || c0 == '1')
297 	return 1;
298     if (c0 == 'f' || c0 == 'n' || c0 == '0')
299 	return 0;
300     if (c0 == 'o')
301     {
302 	c1 = v[1];
303 	if (isupper ((int)c1))
304 	    c1 = (char)tolower (c1);
305 	if (c1 == 'n')
306 	    return 1;
307 	if (c1 == 'f')
308 	    return 0;
309     }
310     return -1;
311 }
312 
313 static Bool
_XftDefaultInitBool(Display * dpy,FcPattern * pat,const char * option)314 _XftDefaultInitBool (Display *dpy, FcPattern *pat, const char *option)
315 {
316     char    *v;
317     int	    i;
318 
319     v = XGetDefault (dpy, "Xft", option);
320     if (v && (i = XftDefaultParseBool (v)) >= 0)
321 	return FcPatternAddBool (pat, option, i != 0);
322     return True;
323 }
324 
325 static Bool
_XftDefaultInitDouble(Display * dpy,FcPattern * pat,const char * option)326 _XftDefaultInitDouble (Display *dpy, FcPattern *pat, const char *option)
327 {
328     char    *v, *e;
329     double  d;
330 
331     v = XGetDefault (dpy, "Xft", option);
332     if (v)
333     {
334 	d = strtod (v, &e);
335 	if (e != v)
336 	    return FcPatternAddDouble (pat, option, d);
337     }
338     return True;
339 }
340 
341 static Bool
_XftDefaultInitInteger(Display * dpy,FcPattern * pat,const char * option)342 _XftDefaultInitInteger (Display *dpy, FcPattern *pat, const char *option)
343 {
344     char    *v, *e;
345     int	    i;
346 
347     v = XGetDefault (dpy, "Xft", option);
348     if (v)
349     {
350 	if (FcNameConstant ((FcChar8 *) v, &i))
351 	    return FcPatternAddInteger (pat, option, i);
352 	i = (int)strtol (v, &e, 0);
353 	if (e != v)
354 	    return FcPatternAddInteger (pat, option, i);
355     }
356     return True;
357 }
358 
359 static FcPattern *
_XftDefaultInit(Display * dpy)360 _XftDefaultInit (Display *dpy)
361 {
362     FcPattern	*pat;
363 
364     pat = FcPatternCreate ();
365     if (!pat)
366 	goto bail0;
367 
368     if (!_XftDefaultInitDouble (dpy, pat, FC_SCALE))
369 	goto bail1;
370     if (!_XftDefaultInitDouble (dpy, pat, FC_DPI))
371 	goto bail1;
372     if (!_XftDefaultInitBool (dpy, pat, XFT_RENDER))
373 	goto bail1;
374     if (!_XftDefaultInitInteger (dpy, pat, FC_RGBA))
375 	goto bail1;
376     if (!_XftDefaultInitInteger (dpy, pat, FC_LCD_FILTER))
377 	goto bail1;
378     if (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS))
379 	goto bail1;
380     if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN))
381 	goto bail1;
382     if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT))
383 	goto bail1;
384     if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE))
385 	goto bail1;
386     if (!_XftDefaultInitBool (dpy, pat, FC_HINTING))
387 	goto bail1;
388     if (!_XftDefaultInitBool (dpy, pat, FC_MINSPACE))
389 	goto bail1;
390     if (!_XftDefaultInitInteger (dpy, pat, XFT_MAX_GLYPH_MEMORY))
391 	goto bail1;
392 
393     return pat;
394 
395 bail1:
396     FcPatternDestroy (pat);
397 bail0:
398     return NULL;
399 }
400 
401 static FcResult
_XftDefaultGet(Display * dpy,const char * object,int screen,FcValue * v)402 _XftDefaultGet (Display *dpy, const char *object, int screen, FcValue *v)
403 {
404     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
405     FcResult	    r;
406 
407     if (!info)
408 	return FcResultNoMatch;
409 
410     if (!info->defaults)
411     {
412 	info->defaults = _XftDefaultInit (dpy);
413 	if (!info->defaults)
414 	    return FcResultNoMatch;
415     }
416     r = FcPatternGet (info->defaults, object, screen, v);
417     if (r == FcResultNoId && screen > 0)
418 	r = FcPatternGet (info->defaults, object, 0, v);
419     return r;
420 }
421 
422 _X_HIDDEN Bool
XftDefaultGetBool(Display * dpy,const char * object,int screen,Bool def)423 XftDefaultGetBool (Display *dpy, const char *object, int screen, Bool def)
424 {
425     FcResult	    r;
426     FcValue	    v;
427 
428     r = _XftDefaultGet (dpy, object, screen, &v);
429     if (r != FcResultMatch || v.type != FcTypeBool)
430 	return def;
431     return v.u.b;
432 }
433 
434 _X_HIDDEN int
XftDefaultGetInteger(Display * dpy,const char * object,int screen,int def)435 XftDefaultGetInteger (Display *dpy, const char *object, int screen, int def)
436 {
437     FcResult	    r;
438     FcValue	    v;
439 
440     r = _XftDefaultGet (dpy, object, screen, &v);
441     if (r != FcResultMatch || v.type != FcTypeInteger)
442 	return def;
443     return v.u.i;
444 }
445 
446 _X_HIDDEN double
XftDefaultGetDouble(Display * dpy,const char * object,int screen,double def)447 XftDefaultGetDouble (Display *dpy, const char *object, int screen, double def)
448 {
449     FcResult	    r;
450     FcValue	    v;
451 
452     r = _XftDefaultGet (dpy, object, screen, &v);
453     if (r != FcResultMatch || v.type != FcTypeDouble)
454 	return def;
455     return v.u.d;
456 }
457 
458 _X_EXPORT void
XftDefaultSubstitute(Display * dpy,int screen,FcPattern * pattern)459 XftDefaultSubstitute (Display *dpy, int screen, FcPattern *pattern)
460 {
461     FcValue	v;
462     double	dpi;
463 
464     if (FcPatternGet (pattern, XFT_RENDER, 0, &v) == FcResultNoMatch)
465     {
466 	FcPatternAddBool (pattern, XFT_RENDER,
467 			   XftDefaultGetBool (dpy, XFT_RENDER, screen,
468 					      XftDefaultHasRender (dpy)));
469     }
470     if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch)
471     {
472 	FcPatternAddBool (pattern, FC_ANTIALIAS,
473 			   XftDefaultGetBool (dpy, FC_ANTIALIAS, screen,
474 					      True));
475     }
476     if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch)
477     {
478 	FcPatternAddBool (pattern, FC_EMBOLDEN,
479 			   XftDefaultGetBool (dpy, FC_EMBOLDEN, screen,
480 					      False));
481     }
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     if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch)
489     {
490 	FcPatternAddInteger (pattern, FC_HINT_STYLE,
491 			     XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen,
492 						   FC_HINT_FULL));
493     }
494     if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch)
495     {
496 	FcPatternAddBool (pattern, FC_AUTOHINT,
497 			  XftDefaultGetBool (dpy, FC_AUTOHINT, screen,
498 					     False));
499     }
500     if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch)
501     {
502 	int	subpixel = FC_RGBA_UNKNOWN;
503 #if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
504 	if (XftDefaultHasRender (dpy))
505 	{
506 	    int render_order = XRenderQuerySubpixelOrder (dpy, screen);
507 	    switch (render_order) {
508 	    default:
509 	    case SubPixelUnknown:	subpixel = FC_RGBA_UNKNOWN; break;
510 	    case SubPixelHorizontalRGB:	subpixel = FC_RGBA_RGB; break;
511 	    case SubPixelHorizontalBGR:	subpixel = FC_RGBA_BGR; break;
512 	    case SubPixelVerticalRGB:	subpixel = FC_RGBA_VRGB; break;
513 	    case SubPixelVerticalBGR:	subpixel = FC_RGBA_VBGR; break;
514 	    case SubPixelNone:		subpixel = FC_RGBA_NONE; break;
515 	    }
516 	}
517 #endif
518 	FcPatternAddInteger (pattern, FC_RGBA,
519 			      XftDefaultGetInteger (dpy, FC_RGBA, screen,
520 						    subpixel));
521     }
522     if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch)
523     {
524 	FcPatternAddInteger (pattern, FC_LCD_FILTER,
525 			     XftDefaultGetInteger (dpy, FC_LCD_FILTER, screen,
526 						   FC_LCD_DEFAULT));
527     }
528     if (FcPatternGet (pattern, FC_MINSPACE, 0, &v) == FcResultNoMatch)
529     {
530 	FcPatternAddBool (pattern, FC_MINSPACE,
531 			   XftDefaultGetBool (dpy, FC_MINSPACE, screen,
532 					      False));
533     }
534     if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch)
535     {
536 	dpi = (((double) DisplayHeight (dpy, screen) * 25.4) /
537 	       (double) DisplayHeightMM (dpy, screen));
538 	FcPatternAddDouble (pattern, FC_DPI,
539 			    XftDefaultGetDouble (dpy, FC_DPI, screen,
540 						 dpi));
541     }
542     if (FcPatternGet (pattern, FC_SCALE, 0, &v) == FcResultNoMatch)
543     {
544 	FcPatternAddDouble (pattern, FC_SCALE,
545 			    XftDefaultGetDouble (dpy, FC_SCALE, screen, 1.0));
546     }
547     if (FcPatternGet (pattern, XFT_MAX_GLYPH_MEMORY, 0, &v) == FcResultNoMatch)
548     {
549 	FcPatternAddInteger (pattern, XFT_MAX_GLYPH_MEMORY,
550 			     XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY,
551 						   screen,
552 						   XFT_FONT_MAX_GLYPH_MEMORY));
553     }
554     FcDefaultSubstitute (pattern);
555 }
556 
557