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