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