xftglyphs.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#include <freetype/ftoutln.h> 25 26#if HAVE_FT_GLYPHSLOT_EMBOLDEN 27#include <freetype/ftsynth.h> 28#endif 29 30static const int filters[3][3] = { 31 /* red */ 32#if 0 33{ 65538*4/7,65538*2/7,65538*1/7 }, 34 /* green */ 35{ 65536*1/4, 65536*2/4, 65537*1/4 }, 36 /* blue */ 37{ 65538*1/7,65538*2/7,65538*4/7 }, 38#endif 39{ 65538*9/13,65538*3/13,65538*1/13 }, 40 /* green */ 41{ 65538*1/6, 65538*4/6, 65538*1/6 }, 42 /* blue */ 43{ 65538*1/13,65538*3/13,65538*9/13 }, 44}; 45 46/* 47 * Validate the memory info for a font 48 */ 49 50static void 51_XftFontValidateMemory (Display *dpy, XftFont *public) 52{ 53 XftFontInt *font = (XftFontInt *) public; 54 unsigned long glyph_memory; 55 FT_UInt glyphindex; 56 XftGlyph *xftg; 57 58 glyph_memory = 0; 59 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 60 { 61 xftg = font->glyphs[glyphindex]; 62 if (xftg) 63 { 64 glyph_memory += xftg->glyph_memory; 65 } 66 } 67 if (glyph_memory != font->glyph_memory) 68 printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n", 69 font->glyph_memory, glyph_memory); 70} 71 72_X_EXPORT void 73XftFontLoadGlyphs (Display *dpy, 74 XftFont *pub, 75 FcBool need_bitmaps, 76 _Xconst FT_UInt *glyphs, 77 int nglyph) 78{ 79 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 80 XftFontInt *font = (XftFontInt *) pub; 81 FT_Error error; 82 FT_UInt glyphindex; 83 FT_GlyphSlot glyphslot; 84 XftGlyph *xftg; 85 Glyph glyph; 86 unsigned char bufLocal[4096]; 87 unsigned char *bufBitmap = bufLocal; 88 int bufSize = sizeof (bufLocal); 89 int size, pitch; 90 unsigned char bufLocalRgba[4096]; 91 unsigned char *bufBitmapRgba = bufLocalRgba; 92 int bufSizeRgba = sizeof (bufLocalRgba); 93 int sizergba, pitchrgba, widthrgba; 94 int width; 95 int height; 96 int left, right, top, bottom; 97 int hmul = 1; 98 int vmul = 1; 99 FT_Bitmap ftbit; 100 FT_Matrix matrix; 101 FT_Vector vector; 102 Bool subpixel = False; 103 FT_Face face; 104 105 if (!info) 106 return; 107 108 face = XftLockFace (&font->public); 109 110 if (!face) 111 return; 112 113 matrix.xx = matrix.yy = 0x10000L; 114 matrix.xy = matrix.yx = 0; 115 116 if (font->info.antialias) 117 { 118 switch (font->info.rgba) { 119 case FC_RGBA_RGB: 120 case FC_RGBA_BGR: 121 matrix.xx *= 3; 122 subpixel = True; 123 hmul = 3; 124 break; 125 case FC_RGBA_VRGB: 126 case FC_RGBA_VBGR: 127 matrix.yy *= 3; 128 vmul = 3; 129 subpixel = True; 130 break; 131 } 132 } 133 134 while (nglyph--) 135 { 136 glyphindex = *glyphs++; 137 xftg = font->glyphs[glyphindex]; 138 if (!xftg) 139 continue; 140 141 if (XftDebug() & XFT_DBG_CACHE) 142 _XftFontValidateMemory (dpy, pub); 143 /* 144 * Check to see if this glyph has just been loaded, 145 * this happens when drawing the same glyph twice 146 * in a single string 147 */ 148 if (xftg->glyph_memory) 149 continue; 150 151 error = FT_Load_Glyph (face, glyphindex, font->info.load_flags); 152 if (error) 153 { 154 /* 155 * If anti-aliasing or transforming glyphs and 156 * no outline version exists, fallback to the 157 * bitmap and let things look bad instead of 158 * missing the glyph 159 */ 160 if (font->info.load_flags & FT_LOAD_NO_BITMAP) 161 error = FT_Load_Glyph (face, glyphindex, 162 font->info.load_flags & ~FT_LOAD_NO_BITMAP); 163 if (error) 164 continue; 165 } 166 167#define FLOOR(x) ((x) & -64) 168#define CEIL(x) (((x)+63) & -64) 169#define TRUNC(x) ((x) >> 6) 170#define ROUND(x) (((x)+32) & -64) 171 172 glyphslot = face->glyph; 173 174#if HAVE_FT_GLYPHSLOT_EMBOLDEN 175 /* 176 * Embolden if required 177 */ 178 if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot); 179#endif 180 181 /* 182 * Compute glyph metrics from FreeType information 183 */ 184 if(font->info.transform && glyphslot->format != ft_glyph_format_bitmap) 185 { 186 /* 187 * calculate the true width by transforming all four corners. 188 */ 189 int xc, yc; 190 left = right = top = bottom = 0; 191 for(xc = 0; xc <= 1; xc ++) { 192 for(yc = 0; yc <= 1; yc++) { 193 vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width; 194 vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height; 195 FT_Vector_Transform(&vector, &font->info.matrix); 196 if (XftDebug() & XFT_DBG_GLYPH) 197 printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, 198 (int) vector.x, (int) vector.y); 199 if(xc == 0 && yc == 0) { 200 left = right = vector.x; 201 top = bottom = vector.y; 202 } else { 203 if(left > vector.x) left = vector.x; 204 if(right < vector.x) right = vector.x; 205 if(bottom > vector.y) bottom = vector.y; 206 if(top < vector.y) top = vector.y; 207 } 208 209 } 210 } 211 left = FLOOR(left); 212 right = CEIL(right); 213 bottom = FLOOR(bottom); 214 top = CEIL(top); 215 216 } else { 217 left = FLOOR( glyphslot->metrics.horiBearingX ); 218 right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width ); 219 220 top = CEIL( glyphslot->metrics.horiBearingY ); 221 bottom = FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height ); 222 } 223 224 width = TRUNC(right - left); 225 height = TRUNC( top - bottom ); 226 227 /* 228 * Clip charcell glyphs to the bounding box 229 * XXX transformed? 230 */ 231 if (font->info.spacing >= FC_CHARCELL && !font->info.transform) 232 { 233 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 234 { 235 if (TRUNC(bottom) > font->public.max_advance_width) 236 { 237 int adjust; 238 239 adjust = bottom - (font->public.max_advance_width << 6); 240 if (adjust > top) 241 adjust = top; 242 top -= adjust; 243 bottom -= adjust; 244 height = font->public.max_advance_width; 245 } 246 } 247 else 248 { 249 if (TRUNC(right) > font->public.max_advance_width) 250 { 251 int adjust; 252 253 adjust = right - (font->public.max_advance_width << 6); 254 if (adjust > left) 255 adjust = left; 256 left -= adjust; 257 right -= adjust; 258 width = font->public.max_advance_width; 259 } 260 } 261 } 262 263 if (font->info.antialias) 264 pitch = (width * hmul + 3) & ~3; 265 else 266 pitch = ((width + 31) & ~31) >> 3; 267 268 size = pitch * height * vmul; 269 270 xftg->metrics.width = width; 271 xftg->metrics.height = height; 272 xftg->metrics.x = -TRUNC(left); 273 xftg->metrics.y = TRUNC(top); 274 275 if (font->info.spacing >= FC_MONO) 276 { 277 if (font->info.transform) 278 { 279 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 280 { 281 vector.x = 0; 282 vector.y = -face->size->metrics.max_advance; 283 } 284 else 285 { 286 vector.x = face->size->metrics.max_advance; 287 vector.y = 0; 288 } 289 FT_Vector_Transform (&vector, &font->info.matrix); 290 xftg->metrics.xOff = vector.x >> 6; 291 xftg->metrics.yOff = -(vector.y >> 6); 292 } 293 else 294 { 295 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 296 { 297 xftg->metrics.xOff = 0; 298 xftg->metrics.yOff = -font->public.max_advance_width; 299 } 300 else 301 { 302 xftg->metrics.xOff = font->public.max_advance_width; 303 xftg->metrics.yOff = 0; 304 } 305 } 306 } 307 else 308 { 309 xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x)); 310 xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y)); 311 } 312 313 /* 314 * If the glyph is relatively large (> 1% of server memory), 315 * don't send it until necessary 316 */ 317 if (!need_bitmaps && size > info->max_glyph_memory / 100) 318 continue; 319 320 /* 321 * Make sure there's enough buffer space for the glyph 322 */ 323 if (size > bufSize) 324 { 325 if (bufBitmap != bufLocal) 326 free (bufBitmap); 327 bufBitmap = (unsigned char *) malloc (size); 328 if (!bufBitmap) 329 continue; 330 bufSize = size; 331 } 332 memset (bufBitmap, 0, size); 333 334 /* 335 * Rasterize into the local buffer 336 */ 337 switch (glyphslot->format) { 338 case ft_glyph_format_outline: 339 ftbit.width = width * hmul; 340 ftbit.rows = height * vmul; 341 ftbit.pitch = pitch; 342 if (font->info.antialias) 343 ftbit.pixel_mode = ft_pixel_mode_grays; 344 else 345 ftbit.pixel_mode = ft_pixel_mode_mono; 346 347 ftbit.buffer = bufBitmap; 348 349 if (subpixel) 350 FT_Outline_Transform (&glyphslot->outline, &matrix); 351 352 FT_Outline_Translate ( &glyphslot->outline, -left*hmul, -bottom*vmul ); 353 354 FT_Outline_Get_Bitmap( _XftFTlibrary, &glyphslot->outline, &ftbit ); 355 break; 356 case ft_glyph_format_bitmap: 357 if (font->info.antialias) 358 { 359 unsigned char *srcLine, *dstLine; 360 int height; 361 int x; 362 int h, v; 363 364 srcLine = glyphslot->bitmap.buffer; 365 dstLine = bufBitmap; 366 height = glyphslot->bitmap.rows; 367 while (height--) 368 { 369 for (x = 0; x < glyphslot->bitmap.width; x++) 370 { 371 /* always MSB bitmaps */ 372 unsigned char a = ((srcLine[x >> 3] & (0x80 >> (x & 7))) ? 373 0xff : 0x00); 374 if (subpixel) 375 { 376 for (v = 0; v < vmul; v++) 377 for (h = 0; h < hmul; h++) 378 dstLine[v * pitch + x*hmul + h] = a; 379 } 380 else 381 dstLine[x] = a; 382 } 383 dstLine += pitch * vmul; 384 srcLine += glyphslot->bitmap.pitch; 385 } 386 } 387 else 388 { 389 unsigned char *srcLine, *dstLine; 390 int h, bytes; 391 392 srcLine = glyphslot->bitmap.buffer; 393 dstLine = bufBitmap; 394 h = glyphslot->bitmap.rows; 395 bytes = (glyphslot->bitmap.width + 7) >> 3; 396 while (h--) 397 { 398 memcpy (dstLine, srcLine, bytes); 399 dstLine += pitch; 400 srcLine += glyphslot->bitmap.pitch; 401 } 402 } 403 break; 404 default: 405 if (XftDebug() & XFT_DBG_GLYPH) 406 printf ("glyph %d is not in a usable format\n", 407 (int) glyphindex); 408 continue; 409 } 410 411 if (XftDebug() & XFT_DBG_GLYPH) 412 { 413 printf ("glyph %d:\n", (int) glyphindex); 414 printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n", 415 (int) glyphslot->metrics.horiBearingX, 416 (int) glyphslot->metrics.horiBearingY, 417 (int) glyphslot->metrics.width, 418 (int) glyphslot->metrics.height, 419 left, right, top, bottom, 420 width, height); 421 if (XftDebug() & XFT_DBG_GLYPHV) 422 { 423 int x, y; 424 unsigned char *line; 425 426 line = bufBitmap; 427 for (y = 0; y < height * vmul; y++) 428 { 429 if (font->info.antialias) 430 { 431 static char den[] = { " .:;=+*#" }; 432 for (x = 0; x < pitch; x++) 433 printf ("%c", den[line[x] >> 5]); 434 } 435 else 436 { 437 for (x = 0; x < pitch * 8; x++) 438 { 439 printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' '); 440 } 441 } 442 printf ("|\n"); 443 line += pitch; 444 } 445 printf ("\n"); 446 } 447 } 448 449 /* 450 * Use the glyph index as the wire encoding; it 451 * might be more efficient for some locales to map 452 * these by first usage to smaller values, but that 453 * would require persistently storing the map when 454 * glyphs were freed. 455 */ 456 glyph = (Glyph) glyphindex; 457 458 if (subpixel) 459 { 460 int x, y; 461 unsigned char *in_line, *out_line, *in; 462 unsigned int *out; 463 unsigned int red, green, blue; 464 int rf, gf, bf; 465 int s; 466 int o, os; 467 468 /* 469 * Filter the glyph to soften the color fringes 470 */ 471 widthrgba = width; 472 pitchrgba = (widthrgba * 4 + 3) & ~3; 473 sizergba = pitchrgba * height; 474 475 os = 1; 476 switch (font->info.rgba) { 477 case FC_RGBA_VRGB: 478 os = pitch; 479 case FC_RGBA_RGB: 480 default: 481 rf = 0; 482 gf = 1; 483 bf = 2; 484 break; 485 case FC_RGBA_VBGR: 486 os = pitch; 487 case FC_RGBA_BGR: 488 bf = 0; 489 gf = 1; 490 rf = 2; 491 break; 492 } 493 if (sizergba > bufSizeRgba) 494 { 495 if (bufBitmapRgba != bufLocalRgba) 496 free (bufBitmapRgba); 497 bufBitmapRgba = (unsigned char *) malloc (sizergba); 498 if (!bufBitmapRgba) 499 continue; 500 bufSizeRgba = sizergba; 501 } 502 memset (bufBitmapRgba, 0, sizergba); 503 in_line = bufBitmap; 504 out_line = bufBitmapRgba; 505 for (y = 0; y < height; y++) 506 { 507 in = in_line; 508 out = (unsigned int *) out_line; 509 in_line += pitch * vmul; 510 out_line += pitchrgba; 511 for (x = 0; x < width * hmul; x += hmul) 512 { 513 red = green = blue = 0; 514 o = 0; 515 for (s = 0; s < 3; s++) 516 { 517 red += filters[rf][s]*in[x+o]; 518 green += filters[gf][s]*in[x+o]; 519 blue += filters[bf][s]*in[x+o]; 520 o += os; 521 } 522 red = red / 65536; 523 green = green / 65536; 524 blue = blue / 65536; 525 *out++ = (green << 24) | (red << 16) | (green << 8) | blue; 526 } 527 } 528 529 xftg->glyph_memory = sizergba + sizeof (XftGlyph); 530 if (font->format) 531 { 532 if (!font->glyphset) 533 font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 534 if (ImageByteOrder (dpy) != XftNativeByteOrder ()) 535 XftSwapCARD32 ((CARD32 *) bufBitmapRgba, sizergba >> 2); 536 XRenderAddGlyphs (dpy, font->glyphset, &glyph, 537 &xftg->metrics, 1, 538 (char *) bufBitmapRgba, sizergba); 539 } 540 else 541 { 542 if (sizergba) 543 { 544 xftg->bitmap = malloc (sizergba); 545 if (xftg->bitmap) 546 memcpy (xftg->bitmap, bufBitmapRgba, sizergba); 547 } 548 else 549 xftg->bitmap = NULL; 550 } 551 } 552 else 553 { 554 xftg->glyph_memory = size + sizeof (XftGlyph); 555 if (font->format) 556 { 557 /* 558 * swap bit order around; FreeType is always MSBFirst 559 */ 560 if (!font->info.antialias) 561 { 562 if (BitmapBitOrder (dpy) != MSBFirst) 563 { 564 unsigned char *line; 565 unsigned char c; 566 int i; 567 568 line = (unsigned char *) bufBitmap; 569 i = size; 570 while (i--) 571 { 572 c = *line; 573 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); 574 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); 575 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); 576 *line++ = c; 577 } 578 } 579 } 580 if (!font->glyphset) 581 font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 582 XRenderAddGlyphs (dpy, font->glyphset, &glyph, 583 &xftg->metrics, 1, 584 (char *) bufBitmap, size); 585 } 586 else 587 { 588 if (size) 589 { 590 xftg->bitmap = malloc (size); 591 if (xftg->bitmap) 592 memcpy (xftg->bitmap, bufBitmap, size); 593 } 594 else 595 xftg->bitmap = NULL; 596 } 597 } 598 font->glyph_memory += xftg->glyph_memory; 599 info->glyph_memory += xftg->glyph_memory; 600 if (XftDebug() & XFT_DBG_CACHE) 601 _XftFontValidateMemory (dpy, pub); 602 if (XftDebug() & XFT_DBG_CACHEV) 603 printf ("Caching glyph 0x%x size %ld\n", glyphindex, 604 xftg->glyph_memory); 605 } 606 if (bufBitmap != bufLocal) 607 free (bufBitmap); 608 if (bufBitmapRgba != bufLocalRgba) 609 free (bufBitmapRgba); 610 XftUnlockFace (&font->public); 611} 612 613_X_EXPORT void 614XftFontUnloadGlyphs (Display *dpy, 615 XftFont *pub, 616 _Xconst FT_UInt *glyphs, 617 int nglyph) 618{ 619 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 620 XftFontInt *font = (XftFontInt *) pub; 621 XftGlyph *xftg; 622 FT_UInt glyphindex; 623 Glyph glyphBuf[1024]; 624 int nused; 625 626 nused = 0; 627 while (nglyph--) 628 { 629 glyphindex = *glyphs++; 630 xftg = font->glyphs[glyphindex]; 631 if (!xftg) 632 continue; 633 if (xftg->glyph_memory) 634 { 635 if (font->format) 636 { 637 if (font->glyphset) 638 { 639 glyphBuf[nused++] = (Glyph) glyphindex; 640 if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) 641 { 642 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 643 nused = 0; 644 } 645 } 646 } 647 else 648 { 649 if (xftg->bitmap) 650 free (xftg->bitmap); 651 } 652 font->glyph_memory -= xftg->glyph_memory; 653 if (info) 654 info->glyph_memory -= xftg->glyph_memory; 655 } 656 free (xftg); 657 XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph)); 658 font->glyphs[glyphindex] = NULL; 659 } 660 if (font->glyphset && nused) 661 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 662} 663 664_X_EXPORT FcBool 665XftFontCheckGlyph (Display *dpy, 666 XftFont *pub, 667 FcBool need_bitmaps, 668 FT_UInt glyph, 669 FT_UInt *missing, 670 int *nmissing) 671{ 672 XftFontInt *font = (XftFontInt *) pub; 673 XftGlyph *xftg; 674 int n; 675 676 if (glyph >= font->num_glyphs) 677 return FcFalse; 678 xftg = font->glyphs[glyph]; 679 if (!xftg || (need_bitmaps && !xftg->glyph_memory)) 680 { 681 if (!xftg) 682 { 683 xftg = (XftGlyph *) malloc (sizeof (XftGlyph)); 684 if (!xftg) 685 return FcFalse; 686 XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph)); 687 xftg->bitmap = NULL; 688 xftg->glyph_memory = 0; 689 font->glyphs[glyph] = xftg; 690 } 691 n = *nmissing; 692 missing[n++] = glyph; 693 if (n == XFT_NMISSING) 694 { 695 XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n); 696 n = 0; 697 } 698 *nmissing = n; 699 return FcTrue; 700 } 701 else 702 return FcFalse; 703} 704 705_X_EXPORT FcBool 706XftCharExists (Display *dpy, 707 XftFont *pub, 708 FcChar32 ucs4) 709{ 710 if (pub->charset) 711 return FcCharSetHasChar (pub->charset, ucs4); 712 return FcFalse; 713} 714 715#define Missing ((FT_UInt) ~0) 716 717_X_EXPORT FT_UInt 718XftCharIndex (Display *dpy, 719 XftFont *pub, 720 FcChar32 ucs4) 721{ 722 XftFontInt *font = (XftFontInt *) pub; 723 FcChar32 ent, offset; 724 FT_Face face; 725 726 if (!font->hash_value) 727 return 0; 728 729 ent = ucs4 % font->hash_value; 730 offset = 0; 731 while (font->hash_table[ent].ucs4 != ucs4) 732 { 733 if (font->hash_table[ent].ucs4 == (FcChar32) ~0) 734 { 735 if (!XftCharExists (dpy, pub, ucs4)) 736 return 0; 737 face = XftLockFace (pub); 738 if (!face) 739 return 0; 740 font->hash_table[ent].ucs4 = ucs4; 741 font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4); 742 XftUnlockFace (pub); 743 break; 744 } 745 if (!offset) 746 { 747 offset = ucs4 % font->rehash_value; 748 if (!offset) 749 offset = 1; 750 } 751 ent = ent + offset; 752 if (ent >= font->hash_value) 753 ent -= font->hash_value; 754 } 755 return font->hash_table[ent].glyph; 756} 757 758/* 759 * Pick a random glyph from the font and remove it from the cache 760 */ 761_X_HIDDEN void 762_XftFontUncacheGlyph (Display *dpy, XftFont *pub) 763{ 764 XftFontInt *font = (XftFontInt *) pub; 765 unsigned long glyph_memory; 766 FT_UInt glyphindex; 767 XftGlyph *xftg; 768 769 if (!font->glyph_memory) 770 return; 771 if (font->use_free_glyphs) 772 { 773 glyph_memory = rand() % font->glyph_memory; 774 } 775 else 776 { 777 if (font->glyphset) 778 { 779 XRenderFreeGlyphSet (dpy, font->glyphset); 780 font->glyphset = 0; 781 } 782 glyph_memory = 0; 783 } 784 785 if (XftDebug() & XFT_DBG_CACHE) 786 _XftFontValidateMemory (dpy, pub); 787 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 788 { 789 xftg = font->glyphs[glyphindex]; 790 if (xftg) 791 { 792 if (xftg->glyph_memory > glyph_memory) 793 { 794 if (XftDebug() & XFT_DBG_CACHEV) 795 printf ("Uncaching glyph 0x%x size %ld\n", 796 glyphindex, xftg->glyph_memory); 797 XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 798 if (!font->use_free_glyphs) 799 continue; 800 break; 801 } 802 glyph_memory -= xftg->glyph_memory; 803 } 804 } 805 if (XftDebug() & XFT_DBG_CACHE) 806 _XftFontValidateMemory (dpy, pub); 807} 808 809_X_HIDDEN void 810_XftFontManageMemory (Display *dpy, XftFont *pub) 811{ 812 XftFontInt *font = (XftFontInt *) pub; 813 814 if (font->max_glyph_memory) 815 { 816 if (XftDebug() & XFT_DBG_CACHE) 817 { 818 if (font->glyph_memory > font->max_glyph_memory) 819 printf ("Reduce memory for font 0x%lx from %ld to %ld\n", 820 font->glyphset ? font->glyphset : (unsigned long) font, 821 font->glyph_memory, font->max_glyph_memory); 822 } 823 while (font->glyph_memory > font->max_glyph_memory) 824 _XftFontUncacheGlyph (dpy, pub); 825 } 826 _XftDisplayManageMemory (dpy); 827} 828