xftglyphs.c revision 0e0b1094
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 FT_OUTLINE_H 25#include FT_LCD_FILTER_H 26 27#include FT_SYNTHESIS_H 28 29/* 30 * Validate the memory info for a font 31 */ 32 33static void 34_XftFontValidateMemory (Display *dpy, XftFont *public) 35{ 36 XftFontInt *font = (XftFontInt *) public; 37 unsigned long glyph_memory; 38 FT_UInt glyphindex; 39 XftGlyph *xftg; 40 41 glyph_memory = 0; 42 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 43 { 44 xftg = font->glyphs[glyphindex]; 45 if (xftg) 46 { 47 glyph_memory += xftg->glyph_memory; 48 } 49 } 50 if (glyph_memory != font->glyph_memory) 51 printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n", 52 font->glyph_memory, glyph_memory); 53} 54 55/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot 56 * into a different format. For example, we want to convert a 57 * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit 58 * ARGB or ABGR bitmap. 59 * 60 * this function prepares a target descriptor for this operation. 61 * 62 * input :: target bitmap descriptor. The function will set its 63 * 'width', 'rows' and 'pitch' fields, and only these 64 * 65 * slot :: the glyph slot containing the source bitmap. this 66 * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP 67 * 68 * mode :: the requested final rendering mode. supported values are 69 * MONO, NORMAL (i.e. gray), LCD and LCD_V 70 * 71 * the function returns the size in bytes of the corresponding buffer, 72 * it's up to the caller to allocate the corresponding memory block 73 * before calling _fill_xrender_bitmap 74 * 75 * it also returns -1 in case of error (e.g. incompatible arguments, 76 * like trying to convert a gray bitmap into a monochrome one) 77 */ 78static int 79_compute_xrender_bitmap_size( FT_Bitmap* target, 80 FT_GlyphSlot slot, 81 FT_Render_Mode mode ) 82{ 83 FT_Bitmap* ftbit; 84 int width, height, pitch; 85 86 if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) 87 return -1; 88 89 /* compute the size of the final bitmap */ 90 ftbit = &slot->bitmap; 91 92 width = (int)ftbit->width; 93 height = (int)ftbit->rows; 94 pitch = (width+3) & ~3; 95 96 switch ( ftbit->pixel_mode ) 97 { 98 case FT_PIXEL_MODE_MONO: 99 if ( mode == FT_RENDER_MODE_MONO ) 100 { 101 pitch = (((width+31) & ~31) >> 3); 102 break; 103 } 104 /* fall-through */ 105 106 case FT_PIXEL_MODE_GRAY: 107 if ( mode == FT_RENDER_MODE_LCD || 108 mode == FT_RENDER_MODE_LCD_V ) 109 { 110 /* each pixel is replicated into a 32-bit ARGB value */ 111 pitch = width*4; 112 } 113 break; 114 115 case FT_PIXEL_MODE_LCD: 116 if ( mode != FT_RENDER_MODE_LCD ) 117 return -1; 118 119 /* horz pixel triplets are packed into 32-bit ARGB values */ 120 width /= 3; 121 pitch = width*4; 122 break; 123 124 case FT_PIXEL_MODE_LCD_V: 125 if ( mode != FT_RENDER_MODE_LCD_V ) 126 return -1; 127 128 /* vert pixel triplets are packed into 32-bit ARGB values */ 129 height /= 3; 130 pitch = width*4; 131 break; 132 133 default: /* unsupported source format */ 134 return -1; 135 } 136 137 target->width = (unsigned)width; 138 target->rows = (unsigned)height; 139 target->pitch = pitch; 140 target->buffer = NULL; 141 142 return pitch * height; 143} 144 145/* this functions converts the glyph bitmap found in a FT_GlyphSlot 146 * into a different format (see _compute_xrender_bitmap_size) 147 * 148 * you should call this function after _compute_xrender_bitmap_size 149 * 150 * target :: target bitmap descriptor. Note that its 'buffer' pointer 151 * must point to memory allocated by the caller 152 * 153 * slot :: the glyph slot containing the source bitmap 154 * 155 * mode :: the requested final rendering mode 156 * 157 * bgr :: boolean, set if BGR or VBGR pixel ordering is needed 158 */ 159static void 160_fill_xrender_bitmap( FT_Bitmap* target, 161 FT_GlyphSlot slot, 162 FT_Render_Mode mode, 163 int bgr ) 164{ 165 FT_Bitmap* ftbit = &slot->bitmap; 166 167 { 168 unsigned char* srcLine = ftbit->buffer; 169 unsigned char* dstLine = target->buffer; 170 int src_pitch = ftbit->pitch; 171 int width = (int)target->width; 172 int height = (int)target->rows; 173 int pitch = target->pitch; 174 int subpixel; 175 int h; 176 177 subpixel = ( mode == FT_RENDER_MODE_LCD || 178 mode == FT_RENDER_MODE_LCD_V ); 179 180 if ( src_pitch < 0 ) 181 srcLine -= ((unsigned)src_pitch * (ftbit->rows-1)); 182 183 switch ( ftbit->pixel_mode ) 184 { 185 case FT_PIXEL_MODE_MONO: 186 if ( subpixel ) /* convert mono to ARGB32 values */ 187 { 188 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 189 { 190 int x; 191 192 for ( x = 0; x < width; x++ ) 193 { 194 if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 195 ((unsigned int*)dstLine)[x] = 0xffffffffU; 196 } 197 } 198 } 199 else if ( mode == FT_RENDER_MODE_NORMAL ) /* convert mono to 8-bit gray */ 200 { 201 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 202 { 203 int x; 204 205 for ( x = 0; x < width; x++ ) 206 { 207 if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 208 dstLine[x] = 0xff; 209 } 210 } 211 } 212 else /* copy mono to mono */ 213 { 214 int bytes = (width+7) >> 3; 215 216 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 217 memcpy( dstLine, srcLine, (size_t)bytes ); 218 } 219 break; 220 221 case FT_PIXEL_MODE_GRAY: 222 if ( subpixel ) /* convert gray to ARGB32 values */ 223 { 224 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 225 { 226 int x; 227 unsigned int* dst = (unsigned int*)dstLine; 228 229 for ( x = 0; x < width; x++ ) 230 { 231 unsigned int pix = srcLine[x]; 232 233 pix |= (pix << 8); 234 pix |= (pix << 16); 235 236 dst[x] = pix; 237 } 238 } 239 } 240 else /* copy gray into gray */ 241 { 242 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 243 memcpy( dstLine, srcLine, (size_t)width ); 244 } 245 break; 246 247 case FT_PIXEL_MODE_LCD: 248 if ( !bgr ) 249 { 250 /* convert horizontal RGB into ARGB32 */ 251 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 252 { 253 int x; 254 unsigned char* src = srcLine; 255 unsigned int* dst = (unsigned int*)dstLine; 256 257 for ( x = 0; x < width; x++, src += 3 ) 258 { 259 unsigned int pix; 260 261 pix = ((unsigned int)src[0] << 16) | 262 ((unsigned int)src[1] << 8) | 263 ((unsigned int)src[2] ) | 264 ((unsigned int)src[1] << 24) ; 265 266 dst[x] = pix; 267 } 268 } 269 } 270 else 271 { 272 /* convert horizontal BGR into ARGB32 */ 273 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 274 { 275 int x; 276 unsigned char* src = srcLine; 277 unsigned int* dst = (unsigned int*)dstLine; 278 279 for ( x = 0; x < width; x++, src += 3 ) 280 { 281 unsigned int pix; 282 283 pix = ((unsigned int)src[2] << 16) | 284 ((unsigned int)src[1] << 8) | 285 ((unsigned int)src[0] ) | 286 ((unsigned int)src[1] << 24) ; 287 288 dst[x] = pix; 289 } 290 } 291 } 292 break; 293 294 default: /* FT_PIXEL_MODE_LCD_V */ 295 /* convert vertical RGB into ARGB32 */ 296 if ( !bgr ) 297 { 298 for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 299 { 300 int x; 301 unsigned char* src = srcLine; 302 unsigned int* dst = (unsigned int*)dstLine; 303 304 for ( x = 0; x < width; x++, src += 1 ) 305 { 306 unsigned int pix; 307 308 pix = ((unsigned int)src[0] << 16) | 309 ((unsigned int)src[src_pitch] << 8) | 310 ((unsigned int)src[src_pitch*2] ) | 311 ((unsigned int)src[src_pitch] << 24) ; 312 313 dst[x] = pix; 314 } 315 } 316 } 317 else 318 { 319 for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 320 { 321 int x; 322 unsigned char* src = srcLine; 323 unsigned int* dst = (unsigned int*)dstLine; 324 325 for ( x = 0; x < width; x++, src += 1 ) 326 { 327 unsigned int pix; 328 329 pix = ((unsigned int)src[src_pitch*2] << 16) | 330 ((unsigned int)src[src_pitch] << 8) | 331 ((unsigned int)src[0] ) | 332 ((unsigned int)src[src_pitch] << 24) ; 333 334 dst[x] = pix; 335 } 336 } 337 } 338 } 339 } 340} 341 342_X_EXPORT void 343XftFontLoadGlyphs (Display *dpy, 344 XftFont *pub, 345 FcBool need_bitmaps, 346 _Xconst FT_UInt *glyphs, 347 int nglyph) 348{ 349 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 350 XftFontInt *font = (XftFontInt *) pub; 351 FT_Error error; 352 FT_UInt glyphindex; 353 FT_GlyphSlot glyphslot; 354 XftGlyph *xftg; 355 Glyph glyph; 356 unsigned char bufLocal[4096]; 357 unsigned char *bufBitmap = bufLocal; 358 int bufSize = sizeof (bufLocal); 359 int size; 360 int width; 361 int height; 362 int left, right, top, bottom; 363 FT_Bitmap* ftbit; 364 FT_Bitmap local; 365 FT_Vector vector; 366 FT_Face face; 367 FT_Render_Mode mode = FT_RENDER_MODE_MONO; 368 369 if (!info) 370 return; 371 372 face = XftLockFace (&font->public); 373 374 if (!face) 375 return; 376 377 if (font->info.antialias) 378 { 379 switch (font->info.rgba) { 380 case FC_RGBA_RGB: 381 case FC_RGBA_BGR: 382 mode = FT_RENDER_MODE_LCD; 383 break; 384 case FC_RGBA_VRGB: 385 case FC_RGBA_VBGR: 386 mode = FT_RENDER_MODE_LCD_V; 387 break; 388 default: 389 mode = FT_RENDER_MODE_NORMAL; 390 } 391 } 392 393 while (nglyph--) 394 { 395 glyphindex = *glyphs++; 396 xftg = font->glyphs[glyphindex]; 397 if (!xftg) 398 continue; 399 400 if (XftDebug() & XFT_DBG_CACHE) 401 _XftFontValidateMemory (dpy, pub); 402 /* 403 * Check to see if this glyph has just been loaded, 404 * this happens when drawing the same glyph twice 405 * in a single string 406 */ 407 if (xftg->glyph_memory) 408 continue; 409 410 FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter); 411 412 error = FT_Load_Glyph (face, glyphindex, font->info.load_flags); 413 if (error) 414 { 415 /* 416 * If anti-aliasing or transforming glyphs and 417 * no outline version exists, fallback to the 418 * bitmap and let things look bad instead of 419 * missing the glyph 420 */ 421 if (font->info.load_flags & FT_LOAD_NO_BITMAP) 422 error = FT_Load_Glyph (face, glyphindex, 423 font->info.load_flags & ~FT_LOAD_NO_BITMAP); 424 if (error) 425 continue; 426 } 427 428#define FLOOR(x) ((x) & -64) 429#define CEIL(x) (((x)+63) & -64) 430#define TRUNC(x) ((x) >> 6) 431#define ROUND(x) (((x)+32) & -64) 432 433 glyphslot = face->glyph; 434 435 /* 436 * Embolden if required 437 */ 438 if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot); 439 440 /* 441 * Compute glyph metrics from FreeType information 442 */ 443 if(font->info.transform && glyphslot->format != FT_GLYPH_FORMAT_BITMAP) 444 { 445 /* 446 * calculate the true width by transforming all four corners. 447 */ 448 int xc, yc; 449 left = right = top = bottom = 0; 450 for(xc = 0; xc <= 1; xc ++) { 451 for(yc = 0; yc <= 1; yc++) { 452 vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width; 453 vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height; 454 FT_Vector_Transform(&vector, &font->info.matrix); 455 if (XftDebug() & XFT_DBG_GLYPH) 456 printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, 457 (int) vector.x, (int) vector.y); 458 if(xc == 0 && yc == 0) { 459 left = right = (int)vector.x; 460 top = bottom = (int)vector.y; 461 } else { 462 if(left > vector.x) left = (int)vector.x; 463 if(right < vector.x) right = (int)vector.x; 464 if(bottom > vector.y) bottom = (int)vector.y; 465 if(top < vector.y) top = (int)vector.y; 466 } 467 468 } 469 } 470 left = (int)FLOOR(left); 471 right = (int)CEIL(right); 472 bottom = (int)FLOOR(bottom); 473 top = CEIL(top); 474 475 } else { 476 left = (int)FLOOR( glyphslot->metrics.horiBearingX ); 477 right = (int)CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width ); 478 479 top = (int)CEIL( glyphslot->metrics.horiBearingY ); 480 bottom = (int)FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height ); 481 } 482 483 width = TRUNC(right - left); 484 height = TRUNC( top - bottom ); 485 486 /* 487 * Clip charcell glyphs to the bounding box 488 * XXX transformed? 489 */ 490 if (font->info.spacing >= FC_CHARCELL && !font->info.transform) 491 { 492 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 493 { 494 if (TRUNC(bottom) > font->public.max_advance_width) 495 { 496 int adjust; 497 498 adjust = bottom - (font->public.max_advance_width << 6); 499 if (adjust > top) 500 adjust = top; 501 top -= adjust; 502 bottom -= adjust; 503 height = font->public.max_advance_width; 504 } 505 } 506 else 507 { 508 if (TRUNC(right) > font->public.max_advance_width) 509 { 510 int adjust; 511 512 adjust = right - (font->public.max_advance_width << 6); 513 if (adjust > left) 514 adjust = left; 515 left -= adjust; 516 right -= adjust; 517 width = font->public.max_advance_width; 518 } 519 } 520 } 521 522 if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP ) 523 { 524 error = FT_Render_Glyph( face->glyph, mode ); 525 if (error) 526 continue; 527 } 528 529 FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE ); 530 531 if (font->info.spacing >= FC_MONO) 532 { 533 if (font->info.transform) 534 { 535 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 536 { 537 vector.x = 0; 538 vector.y = -face->size->metrics.max_advance; 539 } 540 else 541 { 542 vector.x = face->size->metrics.max_advance; 543 vector.y = 0; 544 } 545 FT_Vector_Transform (&vector, &font->info.matrix); 546 xftg->metrics.xOff = (short)(vector.x >> 6); 547 xftg->metrics.yOff = (short)(-(vector.y >> 6)); 548 } 549 else 550 { 551 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 552 { 553 xftg->metrics.xOff = 0; 554 xftg->metrics.yOff = (short)(-font->public.max_advance_width); 555 } 556 else 557 { 558 xftg->metrics.xOff = (short)(font->public.max_advance_width); 559 xftg->metrics.yOff = 0; 560 } 561 } 562 } 563 else 564 { 565 xftg->metrics.xOff = (short)(TRUNC(ROUND(glyphslot->advance.x))); 566 xftg->metrics.yOff = (short)(-TRUNC(ROUND(glyphslot->advance.y))); 567 } 568 569 /* compute the size of the final bitmap */ 570 ftbit = &glyphslot->bitmap; 571 572 width = (int)ftbit->width; 573 height = (int)ftbit->rows; 574 575 if (XftDebug() & XFT_DBG_GLYPH) 576 { 577 printf ("glyph %d:\n", (int) glyphindex); 578 printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n", 579 (int) glyphslot->metrics.horiBearingX, 580 (int) glyphslot->metrics.horiBearingY, 581 (int) glyphslot->metrics.width, 582 (int) glyphslot->metrics.height, 583 left, right, top, bottom, 584 width, height); 585 if (XftDebug() & XFT_DBG_GLYPHV) 586 { 587 int x, y; 588 unsigned char *line; 589 590 line = ftbit->buffer; 591 if (ftbit->pitch < 0) 592 line -= ftbit->pitch*(height-1); 593 594 for (y = 0; y < height; y++) 595 { 596 if (font->info.antialias) 597 { 598 static const char den[] = { " .:;=+*#" }; 599 for (x = 0; x < width; x++) 600 printf ("%c", den[line[x] >> 5]); 601 } 602 else 603 { 604 for (x = 0; x < width * 8; x++) 605 { 606 printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' '); 607 } 608 } 609 printf ("|\n"); 610 line += ftbit->pitch; 611 } 612 printf ("\n"); 613 } 614 } 615 616 size = _compute_xrender_bitmap_size( &local, glyphslot, mode ); 617 if ( size < 0 ) 618 continue; 619 620 xftg->metrics.width = (unsigned short)local.width; 621 xftg->metrics.height = (unsigned short)local.rows; 622 xftg->metrics.x = (short)(- glyphslot->bitmap_left); 623 xftg->metrics.y = (short)( glyphslot->bitmap_top); 624 625 /* 626 * If the glyph is relatively large (> 1% of server memory), 627 * don't send it until necessary. 628 */ 629 if (!need_bitmaps && size > info->max_glyph_memory / 100) 630 continue; 631 632 /* 633 * Make sure there is enough buffer space for the glyph. 634 */ 635 if (size > bufSize) 636 { 637 if (bufBitmap != bufLocal) 638 free (bufBitmap); 639 bufBitmap = (unsigned char *) malloc ((size_t)size); 640 if (!bufBitmap) 641 continue; 642 bufSize = size; 643 } 644 memset (bufBitmap, 0, (size_t)size); 645 646 local.buffer = bufBitmap; 647 648 _fill_xrender_bitmap( &local, glyphslot, mode, 649 (font->info.rgba == FC_RGBA_BGR || 650 font->info.rgba == FC_RGBA_VBGR ) ); 651 652 /* 653 * Copy or convert into local buffer. 654 */ 655 656 /* 657 * Use the glyph index as the wire encoding; it 658 * might be more efficient for some locales to map 659 * these by first usage to smaller values, but that 660 * would require persistently storing the map when 661 * glyphs were freed. 662 */ 663 glyph = (Glyph) glyphindex; 664 665 xftg->glyph_memory = (size_t)size + sizeof (XftGlyph); 666 if (font->format) 667 { 668 if (!font->glyphset) 669 font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 670 if ( mode == FT_RENDER_MODE_MONO ) 671 { 672 /* swap bits in each byte */ 673 if (BitmapBitOrder (dpy) != MSBFirst) 674 { 675 unsigned char *line = (unsigned char*)bufBitmap; 676 int i = size; 677 678 while (i--) 679 { 680 int c = *line; 681 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); 682 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); 683 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); 684 *line++ = (unsigned char)c; 685 } 686 } 687 } 688 else if ( mode != FT_RENDER_MODE_NORMAL ) 689 { 690 /* invert ARGB <=> BGRA */ 691 if (ImageByteOrder (dpy) != XftNativeByteOrder ()) 692 XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2); 693 } 694 XRenderAddGlyphs (dpy, font->glyphset, &glyph, 695 &xftg->metrics, 1, 696 (char *) bufBitmap, size); 697 } 698 else 699 { 700 if (size) 701 { 702 xftg->bitmap = malloc ((size_t)size); 703 if (xftg->bitmap) 704 memcpy (xftg->bitmap, bufBitmap, (size_t)size); 705 } 706 else 707 xftg->bitmap = NULL; 708 } 709 710 font->glyph_memory += xftg->glyph_memory; 711 info->glyph_memory += xftg->glyph_memory; 712 if (XftDebug() & XFT_DBG_CACHE) 713 _XftFontValidateMemory (dpy, pub); 714 if (XftDebug() & XFT_DBG_CACHEV) 715 printf ("Caching glyph 0x%x size %ld\n", glyphindex, 716 xftg->glyph_memory); 717 } 718 if (bufBitmap != bufLocal) 719 free (bufBitmap); 720 XftUnlockFace (&font->public); 721} 722 723_X_EXPORT void 724XftFontUnloadGlyphs (Display *dpy, 725 XftFont *pub, 726 _Xconst FT_UInt *glyphs, 727 int nglyph) 728{ 729 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 730 XftFontInt *font = (XftFontInt *) pub; 731 XftGlyph *xftg; 732 FT_UInt glyphindex; 733 Glyph glyphBuf[1024]; 734 int nused; 735 736 nused = 0; 737 while (nglyph--) 738 { 739 glyphindex = *glyphs++; 740 xftg = font->glyphs[glyphindex]; 741 if (!xftg) 742 continue; 743 if (xftg->glyph_memory) 744 { 745 if (font->format) 746 { 747 if (font->glyphset) 748 { 749 glyphBuf[nused++] = (Glyph) glyphindex; 750 if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) 751 { 752 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 753 nused = 0; 754 } 755 } 756 } 757 else 758 { 759 if (xftg->bitmap) 760 free (xftg->bitmap); 761 } 762 font->glyph_memory -= xftg->glyph_memory; 763 if (info) 764 info->glyph_memory -= xftg->glyph_memory; 765 } 766 free (xftg); 767 XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph)); 768 font->glyphs[glyphindex] = NULL; 769 } 770 if (font->glyphset && nused) 771 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 772} 773 774_X_EXPORT FcBool 775XftFontCheckGlyph (Display *dpy, 776 XftFont *pub, 777 FcBool need_bitmaps, 778 FT_UInt glyph, 779 FT_UInt *missing, 780 int *nmissing) 781{ 782 XftFontInt *font = (XftFontInt *) pub; 783 XftGlyph *xftg; 784 int n; 785 786 if (glyph >= font->num_glyphs) 787 return FcFalse; 788 xftg = font->glyphs[glyph]; 789 if (!xftg || (need_bitmaps && !xftg->glyph_memory)) 790 { 791 if (!xftg) 792 { 793 xftg = (XftGlyph *) malloc (sizeof (XftGlyph)); 794 if (!xftg) 795 return FcFalse; 796 XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph)); 797 xftg->bitmap = NULL; 798 xftg->glyph_memory = 0; 799 font->glyphs[glyph] = xftg; 800 } 801 n = *nmissing; 802 missing[n++] = glyph; 803 if (n == XFT_NMISSING) 804 { 805 XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n); 806 n = 0; 807 } 808 *nmissing = n; 809 return FcTrue; 810 } 811 else 812 return FcFalse; 813} 814 815_X_EXPORT FcBool 816XftCharExists (Display *dpy, 817 XftFont *pub, 818 FcChar32 ucs4) 819{ 820 if (pub->charset) 821 return FcCharSetHasChar (pub->charset, ucs4); 822 return FcFalse; 823} 824 825#define Missing ((FT_UInt) ~0) 826 827_X_EXPORT FT_UInt 828XftCharIndex (Display *dpy, 829 XftFont *pub, 830 FcChar32 ucs4) 831{ 832 XftFontInt *font = (XftFontInt *) pub; 833 FcChar32 ent, offset; 834 FT_Face face; 835 836 if (!font->hash_value) 837 return 0; 838 839 ent = ucs4 % (FcChar32)font->hash_value; 840 offset = 0; 841 while (font->hash_table[ent].ucs4 != ucs4) 842 { 843 if (font->hash_table[ent].ucs4 == (FcChar32) ~0) 844 { 845 if (!XftCharExists (dpy, pub, ucs4)) 846 return 0; 847 face = XftLockFace (pub); 848 if (!face) 849 return 0; 850 font->hash_table[ent].ucs4 = ucs4; 851 font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4); 852 XftUnlockFace (pub); 853 break; 854 } 855 if (!offset) 856 { 857 offset = ucs4 % (FcChar32)font->rehash_value; 858 if (!offset) 859 offset = 1; 860 } 861 ent = ent + offset; 862 if (ent >= font->hash_value) 863 ent -= (FcChar32)font->hash_value; 864 } 865 return font->hash_table[ent].glyph; 866} 867 868/* 869 * Pick a random glyph from the font and remove it from the cache 870 */ 871_X_HIDDEN void 872_XftFontUncacheGlyph (Display *dpy, XftFont *pub) 873{ 874 XftFontInt *font = (XftFontInt *) pub; 875 unsigned long glyph_memory; 876 FT_UInt glyphindex; 877 XftGlyph *xftg; 878 879 if (!font->glyph_memory) 880 return; 881 if (font->use_free_glyphs) 882 { 883 glyph_memory = ((unsigned long)rand() % font->glyph_memory); 884 } 885 else 886 { 887 if (font->glyphset) 888 { 889 XRenderFreeGlyphSet (dpy, font->glyphset); 890 font->glyphset = 0; 891 } 892 glyph_memory = 0; 893 } 894 895 if (XftDebug() & XFT_DBG_CACHE) 896 _XftFontValidateMemory (dpy, pub); 897 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 898 { 899 xftg = font->glyphs[glyphindex]; 900 if (xftg) 901 { 902 if (xftg->glyph_memory > glyph_memory) 903 { 904 if (XftDebug() & XFT_DBG_CACHEV) 905 printf ("Uncaching glyph 0x%x size %ld\n", 906 glyphindex, xftg->glyph_memory); 907 XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 908 if (!font->use_free_glyphs) 909 continue; 910 break; 911 } 912 glyph_memory -= xftg->glyph_memory; 913 } 914 } 915 if (XftDebug() & XFT_DBG_CACHE) 916 _XftFontValidateMemory (dpy, pub); 917} 918 919_X_HIDDEN void 920_XftFontManageMemory (Display *dpy, XftFont *pub) 921{ 922 XftFontInt *font = (XftFontInt *) pub; 923 924 if (font->max_glyph_memory) 925 { 926 if (XftDebug() & XFT_DBG_CACHE) 927 { 928 if (font->glyph_memory > font->max_glyph_memory) 929 printf ("Reduce memory for font 0x%lx from %ld to %ld\n", 930 font->glyphset ? font->glyphset : (unsigned long) font, 931 font->glyph_memory, font->max_glyph_memory); 932 } 933 while (font->glyph_memory > font->max_glyph_memory) 934 _XftFontUncacheGlyph (dpy, pub); 935 } 936 _XftDisplayManageMemory (dpy); 937} 938