xftglyphs.c revision 120fad34
1/* 2 * Copyright © 2022 Thomas E. Dickey 3 * Copyright © 2000 Keith Packard 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting documentation, and 9 * that the name of the above copyright holders not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. The above copyright holders make no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO 16 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 17 * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE 18 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#include "xftint.h" 25#include FT_OUTLINE_H 26#include FT_LCD_FILTER_H 27 28#include FT_SYNTHESIS_H 29 30#include FT_GLYPH_H 31 32typedef double m3x3[3][3]; 33 34static void 35m3x3_uniform(m3x3 m) 36{ 37 m[0][0] = m[1][1] = m[2][2] = 1.0; 38 m[0][1] = m[1][0] = m[0][2] = m[1][2] = m[2][0] = m[2][1] = 0; 39} 40 41static void 42m3x3_transform(FT_Vector *v, m3x3 m) 43{ 44 double x, y; 45 46 x = (double)v->x; 47 y = (double)v->y; 48 v->x = (FT_Pos)(x * m[0][0] + y * m[0][1] + m[0][2] + 0.5); 49 v->y = (FT_Pos)(x * m[1][0] + y * m[1][1] + m[1][2] + 0.5); 50} 51 52static void 53m3x3_invert(m3x3 m, m3x3 mi) 54{ 55 double det; 56 57 det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]); 58 det -= m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]); 59 det += m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); 60 det = 1.0 / det; 61 mi[0][0] = det * (m[1][1] * m[2][2] - m[1][2] * m[2][1]); 62 mi[1][0] = det * (m[1][2] * m[2][0] - m[1][0] * m[2][2]); 63 mi[2][0] = det * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); 64 mi[0][1] = det * (m[0][2] * m[2][1] - m[0][1] * m[2][2]); 65 mi[1][1] = det * (m[0][0] * m[2][2] - m[0][2] * m[2][0]); 66 mi[2][1] = det * (m[0][1] * m[2][0] - m[0][0] * m[2][1]); 67 mi[0][2] = det * (m[0][1] * m[1][2] - m[0][2] * m[1][1]); 68 mi[1][2] = det * (m[0][2] * m[1][0] - m[0][0] * m[1][2]); 69 mi[2][2] = det * (m[0][0] * m[1][1] - m[0][1] * m[1][0]); 70} 71 72/* 73 * Validate the memory info for a font 74 */ 75 76static void 77_XftFontValidateMemory (Display *dpy _X_UNUSED, XftFont *public) 78{ 79 XftFontInt *font = (XftFontInt *) public; 80 unsigned long glyph_memory; 81 FT_UInt glyphindex; 82 XftGlyph *xftg; 83 84 glyph_memory = 0; 85 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 86 { 87 xftg = font->glyphs[glyphindex]; 88 if (xftg) 89 { 90 glyph_memory += xftg->glyph_memory; 91 } 92 } 93 if (glyph_memory != font->glyph_memory) 94 printf ("Font glyph cache incorrect has %lu bytes, should have %lu\n", 95 font->glyph_memory, glyph_memory); 96} 97 98/* 99 * Validate the glyph usage-links for a font. 100 */ 101static void 102_XftValidateGlyphUsage(XftFontInt *font) 103{ 104 if (font->newest != FT_UINT_MAX) { 105 FT_UInt forward; 106 FT_UInt reverse; 107 FT_UInt next; 108 XftGlyphUsage *x1st = (XftGlyphUsage *) font->glyphs[font->newest]; 109 XftGlyphUsage *xuse = x1st; 110 for (forward = 1, 111 next = x1st->newer; 112 xuse != NULL && 113 next != font->newest; 114 next = xuse->newer) { 115 if (next >= font->num_glyphs) { 116 printf("Xft: out of range; %d\n", next); 117 break; 118 } 119 if (++forward > font->total_inuse) { 120 printf("Xft: too many in-use glyphs (%d vs %d)\n", 121 forward, font->total_inuse); 122 if (forward > font->total_inuse + 10) 123 break; 124 } 125 xuse = (XftGlyphUsage *) font->glyphs[next]; 126 } 127 if (forward < font->total_inuse) { 128 printf("Xft: too few in-use glyphs (%u vs %d)\n", 129 forward, font->total_inuse); 130 } 131 for (reverse = 1, 132 next = x1st->older; 133 xuse != NULL && 134 next != font->newest; 135 next = xuse->older) { 136 if (next >= font->num_glyphs) { 137 printf("Xft out of range; %d\n", next); 138 break; 139 } 140 if (++reverse > font->total_inuse) { 141 printf("Xft: too many in-use glyphs (%d vs %d)\n", 142 reverse, font->total_inuse); 143 if (reverse > font->total_inuse + 10) 144 break; 145 } 146 xuse = (XftGlyphUsage *) font->glyphs[next]; 147 } 148 if (reverse < font->total_inuse) { 149 printf("Xft: too few in-use glyphs (%u vs %d)\n", 150 reverse, font->total_inuse); 151 } 152 if (forward != reverse) { 153 printf("Xft: forward %d vs reverse %d\n", 154 forward, reverse); 155 exit(1); 156 } 157 } 158} 159 160/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot 161 * into a different format. For example, we want to convert a 162 * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit 163 * ARGB or ABGR bitmap. 164 * 165 * this function prepares a target descriptor for this operation. 166 * 167 * input :: target bitmap descriptor. The function will set its 168 * 'width', 'rows' and 'pitch' fields, and only these 169 * 170 * slot :: the glyph slot containing the source bitmap. this 171 * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP 172 * 173 * mode :: the requested final rendering mode. supported values are 174 * MONO, NORMAL (i.e. gray), LCD and LCD_V 175 * 176 * the function returns the size in bytes of the corresponding buffer, 177 * it's up to the caller to allocate the corresponding memory block 178 * before calling _fill_xrender_bitmap 179 * 180 * it also returns -1 in case of error (e.g. incompatible arguments, 181 * like trying to convert a gray bitmap into a monochrome one) 182 */ 183static int 184_compute_xrender_bitmap_size( FT_Bitmap* target, 185 FT_GlyphSlot slot, 186 FT_Render_Mode mode, 187 FT_Matrix* matrix, 188 m3x3 m ) 189{ 190 FT_Bitmap* ftbit; 191 int width, height, pitch; 192 193 if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) 194 return -1; 195 196 /* compute the size of the final bitmap */ 197 ftbit = &slot->bitmap; 198 199 width = (int)ftbit->width; 200 height = (int)ftbit->rows; 201 202 if ( matrix && mode == FT_RENDER_MODE_NORMAL ) 203 { 204 FT_Matrix mirror, inverse; 205 FT_Vector vector; 206 int xc, yc; 207 int left, right, top, bottom; 208 209 left = right = top = bottom = 0; 210 for (xc = 0; xc <= 1; xc++) { 211 for (yc = 0; yc <= 1; yc++) { 212 vector.x = xc * width; 213 vector.y = yc * height; 214 FT_Vector_Transform(&vector, matrix); 215 if (xc == 0 && yc == 0) { 216 left = right = (int)vector.x; 217 top = bottom = (int)vector.y; 218 } else { 219 if (left > vector.x) left = (int)vector.x; 220 if (right < vector.x) right = (int)vector.x; 221 if (bottom > vector.y) bottom = (int)vector.y; 222 if (top < vector.y) top = (int)vector.y; 223 } 224 } 225 } 226 width = (int)(right - left); 227 height = (int)(top - bottom); 228 229 mirror.xx = + 0x10000; 230 mirror.yy = - 0x10000; 231 mirror.xy = mirror.yx = 0; 232 inverse = *matrix; 233 FT_Matrix_Multiply(&mirror, &inverse); 234 FT_Matrix_Invert(&inverse); 235 FT_Matrix_Multiply(&mirror, &inverse); 236 237 vector.x = vector.y = 0; 238 FT_Vector_Transform(&vector, &inverse); 239 left = (int)vector.x; 240 bottom = (int)vector.y; 241 vector.x = width; 242 vector.y = height; 243 FT_Vector_Transform(&vector, &inverse); 244 right = (int)vector.x; 245 top = (int)vector.y; 246 left = (right - left) - (int)ftbit->width; 247 bottom = (top - bottom) - (int)ftbit->rows; 248 249 m[0][0] = (double)inverse.xx / 0x10000; 250 m[0][1] = (double)inverse.xy / 0x10000; 251 m[1][0] = (double)inverse.yx / 0x10000; 252 m[1][1] = (double)inverse.yy / 0x10000; 253 m[0][2] = (double)-left / 2; 254 m[1][2] = (double)-bottom / 2; 255 m[2][0] = m[2][1] = 0.0; 256 m[2][2] = 1.0; 257 } 258 pitch = (width+3) & ~3; 259 260 switch ( ftbit->pixel_mode ) 261 { 262 case FT_PIXEL_MODE_MONO: 263 if ( mode == FT_RENDER_MODE_MONO ) 264 { 265 pitch = (((width+31) & ~31) >> 3); 266 break; 267 } 268 /* fall-through */ 269 270 case FT_PIXEL_MODE_GRAY: 271 if ( mode == FT_RENDER_MODE_LCD || 272 mode == FT_RENDER_MODE_LCD_V ) 273 { 274 /* each pixel is replicated into a 32-bit ARGB value */ 275 pitch = width*4; 276 } 277 break; 278 279 case FT_PIXEL_MODE_BGRA: 280 pitch = width * 4; 281 break; 282 283 case FT_PIXEL_MODE_LCD: 284 if ( mode != FT_RENDER_MODE_LCD ) 285 return -1; 286 287 /* horz pixel triplets are packed into 32-bit ARGB values */ 288 width /= 3; 289 pitch = width*4; 290 break; 291 292 case FT_PIXEL_MODE_LCD_V: 293 if ( mode != FT_RENDER_MODE_LCD_V ) 294 return -1; 295 296 /* vert pixel triplets are packed into 32-bit ARGB values */ 297 height /= 3; 298 pitch = width*4; 299 break; 300 301 default: /* unsupported source format */ 302 return -1; 303 } 304 305 target->width = (unsigned)width; 306 target->rows = (unsigned)height; 307 target->pitch = pitch; 308 target->buffer = NULL; 309 310 return pitch * height; 311} 312 313/* this functions converts the glyph bitmap found in a FT_GlyphSlot 314 * into a different format while scaling by applying the given matrix 315 * (see _compute_xrender_bitmap_size) 316 * 317 * you should call this function after _compute_xrender_bitmap_size 318 * 319 * target :: target bitmap descriptor. Note that its 'buffer' pointer 320 * must point to memory allocated by the caller 321 * 322 * source :: the source bitmap descriptor 323 * 324 * matrix :: the scaling matrix to apply 325 */ 326static void 327_scaled_fill_xrender_bitmap( FT_Bitmap* target, 328 FT_Bitmap* source, 329 m3x3 m ) 330{ 331 unsigned char* src_buf = source->buffer; 332 unsigned char* dst_line = target->buffer; 333 int src_pitch = source->pitch; 334 int width = (int) target->width; 335 int height = (int) target->rows; 336 int pitch = target->pitch; 337 int i, x, y; 338 FT_Vector vector, vector0; 339 int sampling_width; 340 int sampling_height; 341 int sample_count; 342 343 if ( src_pitch < 0 ) 344 src_buf -= ((unsigned) src_pitch * (source->rows - 1)); 345 346 /* compute how many source pixels a target pixel spans */ 347 vector.x = 1; 348 vector.y = 1; 349 m3x3_transform(&vector, m); 350 vector0.x = 0; 351 vector0.y = 0; 352 m3x3_transform(&vector0, m); 353 sampling_width = (int) ((vector.x - vector0.x) / 2); 354 sampling_height = (int) ((vector.y - vector0.y) / 2); 355 if (sampling_width < 0) sampling_width = -sampling_width; 356 if (sampling_height < 0) sampling_height = -sampling_height; 357 sample_count = (2 * sampling_width + 1) * (2 * sampling_height + 1); 358 359 for ( y = height; y > 0; y--, dst_line += pitch ) 360 { 361 for ( x = 0; x < width; x++ ) 362 { 363 unsigned char* src; 364 365 /* compute target pixel location in source space */ 366 vector.x = x; 367 vector.y = height - y; 368 m3x3_transform(&vector, m); 369 370 if (source->pixel_mode == FT_PIXEL_MODE_BGRA) 371 { 372 if (vector.x < -sampling_width 373 || vector.x > (source->width + (unsigned) sampling_width)) 374 continue; 375 if (vector.y < -sampling_height 376 || vector.y > (source->rows + (unsigned) sampling_height)) 377 continue; 378 } 379 else 380 { 381 if (vector.x < 0 || vector.x >= source->width) 382 continue; 383 if (vector.y < 0 || vector.y >= source->rows) 384 continue; 385 } 386 387 switch ( source->pixel_mode ) 388 { 389 case FT_PIXEL_MODE_MONO: /* convert mono to 8-bit gray, scale using nearest pixel */ 390 src = src_buf + (vector.y * src_pitch); 391 if ( src[(vector.x >> 3)] & (0x80 >> (vector.x & 7)) ) 392 dst_line[x] = 0xff; 393 break; 394 395 case FT_PIXEL_MODE_GRAY: /* scale using nearest pixel */ 396 src = src_buf + (vector.y * src_pitch); 397 dst_line[x] = src[vector.x]; 398 break; 399 400 case FT_PIXEL_MODE_BGRA: /* scale by averaging all relevant source pixels, keep BGRA format */ 401 { 402 int sample_x, sample_y; 403 int bgra[4] = { 0, 0, 0, 0 }; 404 405 for (sample_y = - sampling_height; sample_y < sampling_height + 1; ++sample_y) 406 { 407 int src_y = (int) (vector.y + sample_y); 408 409 if (src_y < 0 || (FT_Pos) src_y >= source->rows) 410 continue; 411 src = src_buf + (src_y * src_pitch); 412 for (sample_x = - sampling_width; sample_x < sampling_width + 1; ++sample_x) 413 { 414 int src_x = (int) (vector.x + sample_x); 415 416 if (src_x < 0 || (FT_Pos) src_x >= source->width) 417 continue; 418 for (i = 0; i < 4; ++i) 419 bgra[i] += src[src_x * 4 + i]; 420 } 421 } 422 423 for (i = 0; i < 4; ++i) 424 dst_line[4 * x + i] = (unsigned char) (bgra[i] / sample_count); 425 break; 426 } 427 } 428 } 429 } 430} 431 432/* this functions converts the glyph bitmap found in a FT_GlyphSlot 433 * into a different format (see _compute_xrender_bitmap_size) 434 * 435 * you should call this function after _compute_xrender_bitmap_size 436 * 437 * target :: target bitmap descriptor. Note that its 'buffer' pointer 438 * must point to memory allocated by the caller 439 * 440 * slot :: the glyph slot containing the source bitmap 441 * 442 * mode :: the requested final rendering mode 443 * 444 * bgr :: boolean, set if BGR or VBGR pixel ordering is needed 445 */ 446static void 447_fill_xrender_bitmap( FT_Bitmap* target, 448 FT_GlyphSlot slot, 449 FT_Render_Mode mode, 450 int bgr ) 451{ 452 FT_Bitmap* ftbit = &slot->bitmap; 453 454 { 455 unsigned char* srcLine = ftbit->buffer; 456 unsigned char* dstLine = target->buffer; 457 int src_pitch = ftbit->pitch; 458 int width = (int)target->width; 459 int height = (int)target->rows; 460 int pitch = target->pitch; 461 int subpixel; 462 int h; 463 464 subpixel = ( mode == FT_RENDER_MODE_LCD || 465 mode == FT_RENDER_MODE_LCD_V ); 466 467 if ( src_pitch < 0 ) 468 srcLine -= ((unsigned)src_pitch * (ftbit->rows-1)); 469 470 switch ( ftbit->pixel_mode ) 471 { 472 case FT_PIXEL_MODE_MONO: 473 if ( subpixel ) /* convert mono to ARGB32 values */ 474 { 475 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 476 { 477 int x; 478 479 for ( x = 0; x < width; x++ ) 480 { 481 if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 482 ((unsigned int*)dstLine)[x] = 0xffffffffU; 483 } 484 } 485 } 486 else if ( mode == FT_RENDER_MODE_NORMAL ) /* convert mono to 8-bit gray */ 487 { 488 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 489 { 490 int x; 491 492 for ( x = 0; x < width; x++ ) 493 { 494 if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 495 dstLine[x] = 0xff; 496 } 497 } 498 } 499 else /* copy mono to mono */ 500 { 501 int bytes = (width+7) >> 3; 502 503 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 504 memcpy( dstLine, srcLine, (size_t)bytes ); 505 } 506 break; 507 508 case FT_PIXEL_MODE_GRAY: 509 if ( subpixel ) /* convert gray to ARGB32 values */ 510 { 511 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 512 { 513 int x; 514 unsigned int* dst = (unsigned int*)dstLine; 515 516 for ( x = 0; x < width; x++ ) 517 { 518 unsigned int pix = srcLine[x]; 519 520 pix |= (pix << 8); 521 pix |= (pix << 16); 522 523 dst[x] = pix; 524 } 525 } 526 } 527 else /* copy gray into gray */ 528 { 529 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 530 memcpy( dstLine, srcLine, (size_t)width ); 531 } 532 break; 533 534 case FT_PIXEL_MODE_BGRA: /* Preserve BGRA format */ 535 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 536 memcpy( dstLine, srcLine, (size_t) width * 4 ); 537 break; 538 539 case FT_PIXEL_MODE_LCD: 540 if ( !bgr ) 541 { 542 /* convert horizontal RGB into ARGB32 */ 543 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 544 { 545 int x; 546 unsigned char* src = srcLine; 547 unsigned int* dst = (unsigned int*)dstLine; 548 549 for ( x = 0; x < width; x++, src += 3 ) 550 { 551 unsigned int pix; 552 553 pix = ((unsigned int)src[0] << 16) | 554 ((unsigned int)src[1] << 8) | 555 ((unsigned int)src[2] ) | 556 ((unsigned int)src[1] << 24) ; 557 558 dst[x] = pix; 559 } 560 } 561 } 562 else 563 { 564 /* convert horizontal BGR into ARGB32 */ 565 for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 566 { 567 int x; 568 unsigned char* src = srcLine; 569 unsigned int* dst = (unsigned int*)dstLine; 570 571 for ( x = 0; x < width; x++, src += 3 ) 572 { 573 unsigned int pix; 574 575 pix = ((unsigned int)src[2] << 16) | 576 ((unsigned int)src[1] << 8) | 577 ((unsigned int)src[0] ) | 578 ((unsigned int)src[1] << 24) ; 579 580 dst[x] = pix; 581 } 582 } 583 } 584 break; 585 586 default: /* FT_PIXEL_MODE_LCD_V */ 587 /* convert vertical RGB into ARGB32 */ 588 if ( !bgr ) 589 { 590 for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 591 { 592 int x; 593 unsigned char* src = srcLine; 594 unsigned int* dst = (unsigned int*)dstLine; 595 596 for ( x = 0; x < width; x++, src += 1 ) 597 { 598 unsigned int pix; 599 600 pix = ((unsigned int)src[0] << 16) | 601 ((unsigned int)src[src_pitch] << 8) | 602 ((unsigned int)src[src_pitch*2] ) | 603 ((unsigned int)src[src_pitch] << 24) ; 604 605 dst[x] = pix; 606 } 607 } 608 } 609 else 610 { 611 for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 612 { 613 int x; 614 unsigned char* src = srcLine; 615 unsigned int* dst = (unsigned int*)dstLine; 616 617 for ( x = 0; x < width; x++, src += 1 ) 618 { 619 unsigned int pix; 620 621 pix = ((unsigned int)src[src_pitch*2] << 16) | 622 ((unsigned int)src[src_pitch] << 8) | 623 ((unsigned int)src[0] ) | 624 ((unsigned int)src[src_pitch] << 24) ; 625 626 dst[x] = pix; 627 } 628 } 629 } 630 } 631 } 632} 633 634_X_EXPORT void 635XftFontLoadGlyphs (Display *dpy, 636 XftFont *pub, 637 FcBool need_bitmaps, 638 _Xconst FT_UInt *glyphs, 639 int nglyph) 640{ 641 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 642 XftFontInt *font = (XftFontInt *) pub; 643 FT_Error error; 644 FT_UInt glyphindex; 645 FT_GlyphSlot glyphslot; 646 XftGlyph *xftg; 647 Glyph glyph; 648 unsigned char bufLocal[4096]; 649 unsigned char *bufBitmap = bufLocal; 650 int bufSize = sizeof (bufLocal); 651 int size; 652 int width; 653 int height; 654 int left, right, top, bottom; 655 FT_Bitmap* ftbit; 656 FT_Bitmap local; 657 FT_Vector vector; 658 m3x3 m; 659 FT_Face face; 660 FT_Render_Mode mode = FT_RENDER_MODE_MONO; 661 FcBool transform; 662 FcBool glyph_transform; 663 664 if (!info) 665 return; 666 667 face = XftLockFace (&font->public); 668 669 if (!face) 670 return; 671 672 if (font->info.color) 673 mode = FT_RENDER_MODE_NORMAL; 674 if (font->info.antialias) 675 { 676 switch (font->info.rgba) { 677 case FC_RGBA_RGB: 678 case FC_RGBA_BGR: 679 mode = FT_RENDER_MODE_LCD; 680 break; 681 case FC_RGBA_VRGB: 682 case FC_RGBA_VBGR: 683 mode = FT_RENDER_MODE_LCD_V; 684 break; 685 default: 686 mode = FT_RENDER_MODE_NORMAL; 687 } 688 } 689 690 transform = font->info.transform && mode != FT_RENDER_MODE_MONO; 691 692 while (nglyph--) 693 { 694 glyphindex = *glyphs++; 695 xftg = font->glyphs[glyphindex]; 696 if (!xftg) 697 continue; 698 699 if (XftDebug() & XFT_DBG_CACHE) 700 _XftFontValidateMemory (dpy, pub); 701 /* 702 * Check to see if this glyph has just been loaded, 703 * this happens when drawing the same glyph twice 704 * in a single string 705 */ 706 if (xftg->glyph_memory) 707 continue; 708 709 FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter); 710 711 error = FT_Load_Glyph (face, glyphindex, font->info.load_flags); 712 if (error) 713 { 714 /* 715 * If anti-aliasing or transforming glyphs and 716 * no outline version exists, fallback to the 717 * bitmap and let things look bad instead of 718 * missing the glyph 719 */ 720 if (font->info.load_flags & FT_LOAD_NO_BITMAP) 721 error = FT_Load_Glyph (face, glyphindex, 722 font->info.load_flags & ~FT_LOAD_NO_BITMAP); 723 if (error) 724 continue; 725 } 726 727#define FLOOR(x) ((x) & -64) 728#define CEIL(x) (((x)+63) & -64) 729#define TRUNC(x) ((x) >> 6) 730#define ROUND(x) (((x)+32) & -64) 731 732 glyphslot = face->glyph; 733 734 /* 735 * Embolden if required 736 */ 737 if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot); 738 739 /* 740 * Compute glyph metrics from FreeType information 741 */ 742 if (transform) 743 { 744 /* 745 * calculate the true width by transforming all four corners. 746 */ 747 int xc, yc; 748 left = right = top = bottom = 0; 749 for (xc = 0; xc <= 1; xc++) { 750 for (yc = 0; yc <= 1; yc++) { 751 vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width; 752 vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height; 753 FT_Vector_Transform(&vector, &font->info.matrix); 754 if (XftDebug() & XFT_DBG_GLYPH) 755 printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, 756 (int) vector.x, (int) vector.y); 757 if (xc == 0 && yc == 0) { 758 left = right = (int)vector.x; 759 top = bottom = (int)vector.y; 760 } else { 761 if (left > vector.x) left = (int)vector.x; 762 if (right < vector.x) right = (int)vector.x; 763 if (bottom > vector.y) bottom = (int)vector.y; 764 if (top < vector.y) top = (int)vector.y; 765 } 766 767 } 768 } 769 left = (int)FLOOR(left); 770 right = (int)CEIL(right); 771 bottom = (int)FLOOR(bottom); 772 top = (int)CEIL(top); 773 774 } else { 775 left = (int)FLOOR( glyphslot->metrics.horiBearingX ); 776 right = (int)CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width ); 777 778 top = (int)CEIL( glyphslot->metrics.horiBearingY ); 779 bottom = (int)FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height ); 780 } 781 782 /* 783 * Clip charcell glyphs to the bounding box 784 * XXX transformed? 785 */ 786 if (font->info.spacing >= FC_CHARCELL && !transform) 787 { 788 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 789 { 790 if (TRUNC(bottom) > font->public.max_advance_width) 791 { 792 int adjust; 793 794 adjust = bottom - (font->public.max_advance_width << 6); 795 if (adjust > top) 796 adjust = top; 797 top -= adjust; 798 bottom -= adjust; 799 } 800 } 801 else 802 { 803 if (TRUNC(right) > font->public.max_advance_width) 804 { 805 int adjust; 806 807 adjust = right - (font->public.max_advance_width << 6); 808 if (adjust > left) 809 adjust = left; 810 left -= adjust; 811 right -= adjust; 812 } 813 } 814 } 815 816 glyph_transform = transform; 817 if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP ) 818 { 819 error = FT_Render_Glyph( face->glyph, mode ); 820 if (error) 821 continue; 822 glyph_transform = False; 823 } 824 825 FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE ); 826 827 if (font->info.spacing >= FC_MONO) 828 { 829 if (transform) 830 { 831 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 832 { 833 vector.x = 0; 834 vector.y = -face->size->metrics.max_advance; 835 } 836 else 837 { 838 vector.x = face->size->metrics.max_advance; 839 vector.y = 0; 840 } 841 FT_Vector_Transform(&vector, &font->info.matrix); 842 xftg->metrics.xOff = (short)(TRUNC(ROUND(vector.x))); 843 xftg->metrics.yOff = (short)(TRUNC(ROUND(vector.y))); 844 } 845 else 846 { 847 if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 848 { 849 xftg->metrics.xOff = 0; 850 xftg->metrics.yOff = (short)(-font->public.max_advance_width); 851 } 852 else 853 { 854 xftg->metrics.xOff = (short)(font->public.max_advance_width); 855 xftg->metrics.yOff = 0; 856 } 857 } 858 } 859 else 860 { 861 xftg->metrics.xOff = (short)(TRUNC(ROUND(glyphslot->advance.x))); 862 xftg->metrics.yOff = (short)(-TRUNC(ROUND(glyphslot->advance.y))); 863 } 864 865 /* compute the size of the final bitmap */ 866 ftbit = &glyphslot->bitmap; 867 868 width = (int)ftbit->width; 869 height = (int)ftbit->rows; 870 871 if (XftDebug() & XFT_DBG_GLYPH) 872 { 873 printf ("glyph %d:\n", (int) glyphindex); 874 printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n", 875 (int) glyphslot->metrics.horiBearingX, 876 (int) glyphslot->metrics.horiBearingY, 877 (int) glyphslot->metrics.width, 878 (int) glyphslot->metrics.height, 879 left, right, top, bottom, 880 width, height); 881 if (XftDebug() & XFT_DBG_GLYPHV) 882 { 883 int x, y; 884 unsigned char *line; 885 886 line = ftbit->buffer; 887 if (ftbit->pitch < 0) 888 line -= ftbit->pitch*(height-1); 889 890 for (y = 0; y < height; y++) 891 { 892 if (font->info.antialias) 893 { 894 static const char den[] = { " .:;=+*#" }; 895 for (x = 0; x < width; x++) 896 printf ("%c", den[line[x] >> 5]); 897 } 898 else 899 { 900 for (x = 0; x < width * 8; x++) 901 { 902 printf ("%c", (line[x>>3] & (1 << (x & 7))) ? '#' : ' '); 903 } 904 } 905 printf ("|\n"); 906 line += ftbit->pitch; 907 } 908 printf ("\n"); 909 } 910 } 911 912 m3x3_uniform(m); 913 size = _compute_xrender_bitmap_size( &local, glyphslot, mode, glyph_transform ? &font->info.matrix : NULL, m ); 914 if ( size < 0 ) 915 continue; 916 917 xftg->metrics.width = (unsigned short)local.width; 918 xftg->metrics.height = (unsigned short)local.rows; 919 if (glyph_transform) 920 { 921 m3x3 mi; 922 923 m3x3_invert(m, mi); 924 vector.x = - glyphslot->bitmap_left; 925 vector.y = glyphslot->bitmap_top; 926 m3x3_transform(&vector, mi); 927 xftg->metrics.x = (short)vector.x; 928 xftg->metrics.y = (short)vector.y; 929 } 930 else 931 { 932 xftg->metrics.x = (short)(- glyphslot->bitmap_left); 933 xftg->metrics.y = (short)( glyphslot->bitmap_top); 934 } 935 936 /* 937 * If the glyph is relatively large (> 1% of server memory), 938 * don't send it until necessary. 939 */ 940 if (!need_bitmaps && ((unsigned long) size > (info->max_glyph_memory / 100))) 941 continue; 942 943 /* 944 * Make sure there is enough buffer space for the glyph. 945 */ 946 if (size > bufSize) 947 { 948 if (bufBitmap != bufLocal) 949 free (bufBitmap); 950 bufBitmap = (unsigned char *) malloc ((size_t)size); 951 if (!bufBitmap) 952 continue; 953 bufSize = size; 954 } 955 memset (bufBitmap, 0, (size_t)size); 956 957 local.buffer = bufBitmap; 958 959 if (mode == FT_RENDER_MODE_NORMAL && glyph_transform) 960 _scaled_fill_xrender_bitmap(&local, &glyphslot->bitmap, m); 961 else 962 _fill_xrender_bitmap( &local, glyphslot, mode, 963 (font->info.rgba == FC_RGBA_BGR || 964 font->info.rgba == FC_RGBA_VBGR) ); 965 966 /* 967 * Copy or convert into local buffer. 968 */ 969 970 /* 971 * Use the glyph index as the wire encoding; it 972 * might be more efficient for some locales to map 973 * these by first usage to smaller values, but that 974 * would require persistently storing the map when 975 * glyphs were freed. 976 */ 977 glyph = (Glyph) glyphindex; 978 979 if (xftg->picture) 980 { 981 XRenderFreePicture(dpy, xftg->picture); 982 xftg->picture = 0; 983 } 984 xftg->glyph_memory = (size_t)size + font->sizeof_glyph; 985 if (font->format) 986 { 987 if (!font->glyphset) 988 font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 989 if ( mode == FT_RENDER_MODE_MONO ) 990 { 991 /* swap bits in each byte */ 992 if (BitmapBitOrder (dpy) != MSBFirst) 993 { 994 unsigned char *line = (unsigned char*)bufBitmap; 995 int i = size; 996 997 while (i--) 998 { 999 int c = *line; 1000 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); 1001 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); 1002 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); 1003 *line++ = (unsigned char)c; 1004 } 1005 } 1006 } 1007 else if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA || mode != FT_RENDER_MODE_NORMAL) 1008 { 1009 /* invert ARGB <=> BGRA */ 1010 if (ImageByteOrder (dpy) != XftNativeByteOrder ()) 1011 XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2); 1012 } 1013 1014 if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) 1015 { 1016 Pixmap pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), local.width, local.rows, 32); 1017 GC gc = XCreateGC(dpy, pixmap, 0, NULL); 1018 XImage image = { 1019 (int) local.width, (int) local.rows, 0, ZPixmap, (char *)bufBitmap, 1020 dpy->byte_order, dpy->bitmap_unit, dpy->bitmap_bit_order, 32, 1021 32, (int) (local.width * 4 - (unsigned) local.pitch), 32, 1022 0, 0, 0, NULL, { NULL } 1023 }; 1024 1025 XInitImage(&image); 1026 XPutImage(dpy, pixmap, gc, &image, 0, 0, 0, 0, local.width, local.rows); 1027 xftg->picture = XRenderCreatePicture(dpy, pixmap, font->format, 0, NULL); 1028 1029 XFreeGC(dpy, gc); 1030 XFreePixmap(dpy, pixmap); 1031 /* 1032 * Record 256 times higher memory pressure for unrotated 1033 * pictures, and maximum for rotated pictures. 1034 */ 1035 if (font->info.matrix.xy || font->info.matrix.yx) 1036 xftg->glyph_memory += font->max_glyph_memory - (unsigned long) size; 1037 else 1038 xftg->glyph_memory += (size_t)size * 255; 1039 } 1040 else 1041 XRenderAddGlyphs (dpy, font->glyphset, &glyph, 1042 &xftg->metrics, 1, 1043 (char *) bufBitmap, size); 1044 } 1045 else 1046 { 1047 if (size) 1048 { 1049 xftg->bitmap = malloc ((size_t)size); 1050 if (xftg->bitmap) 1051 memcpy (xftg->bitmap, bufBitmap, (size_t)size); 1052 } 1053 else 1054 xftg->bitmap = NULL; 1055 } 1056 1057 font->glyph_memory += xftg->glyph_memory; 1058 info->glyph_memory += xftg->glyph_memory; 1059 if (XftDebug() & XFT_DBG_CACHE) 1060 _XftFontValidateMemory (dpy, pub); 1061 if (XftDebug() & XFT_DBG_CACHEV) 1062 printf ("Caching glyph 0x%x size %lu\n", glyphindex, 1063 xftg->glyph_memory); 1064 1065 if (font->track_mem_usage) { 1066 XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1067 1068 if (font->newest == FT_UINT_MAX) { 1069 xuse->older = glyphindex; 1070 xuse->newer = glyphindex; 1071 if (XftDebug() & XFT_DBG_USAGE) 1072 printf("alloc %p -> %d: %p USE %d.%d\n", 1073 (void *) font, glyphindex, 1074 (void *) xuse, xuse->older, xuse->newer); 1075 } else { 1076 XftGlyphUsage *xnew; 1077 XftGlyphUsage *xold; 1078 1079 assert(font->glyphs[font->newest] != NULL); 1080 xnew = (XftGlyphUsage *) font->glyphs[font->newest]; 1081 1082 assert(font->glyphs[xnew->newer] != NULL); 1083 xold = (XftGlyphUsage *) font->glyphs[xnew->newer]; 1084 1085 xuse->older = font->newest; 1086 xuse->newer = xnew->newer; 1087 xnew->newer = glyphindex; 1088 xold->older = glyphindex; 1089 if (XftDebug() & XFT_DBG_USAGE) 1090 printf("alloc %p -> %d: %p USE %d.%d, %p NEW %d.%d %p OLD %d.%d\n", 1091 (void *) font, glyphindex, 1092 (void *) xuse, xuse->older, xuse->newer, 1093 (void *) xnew, xnew->older, xnew->newer, 1094 (void *) xold, xold->older, xold->newer); 1095 } 1096 1097 font->newest = glyphindex; 1098 font->total_inuse++; 1099 if (XftDebug() & XFT_DBG_USAGE) 1100 _XftValidateGlyphUsage(font); 1101 } 1102 } 1103 if (bufBitmap != bufLocal) 1104 free (bufBitmap); 1105 XftUnlockFace (&font->public); 1106} 1107 1108_X_EXPORT void 1109XftFontUnloadGlyphs (Display *dpy, 1110 XftFont *pub, 1111 _Xconst FT_UInt *glyphs, 1112 int nglyph) 1113{ 1114 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 1115 XftFontInt *font = (XftFontInt *) pub; 1116 XftGlyph *xftg; 1117 FT_UInt glyphindex; 1118 Glyph glyphBuf[1024]; 1119 int nused; 1120 1121 nused = 0; 1122 while (nglyph--) 1123 { 1124 glyphindex = *glyphs++; 1125 xftg = font->glyphs[glyphindex]; 1126 if (!xftg) 1127 continue; 1128 if (xftg->glyph_memory) 1129 { 1130 if (XftDebug() & XFT_DBG_CACHEV) 1131 printf ("Uncaching glyph 0x%x size %lu\n", 1132 glyphindex, xftg->glyph_memory); 1133 if (font->format) 1134 { 1135 if (xftg->picture) 1136 XRenderFreePicture(dpy, xftg->picture); 1137 else if (font->glyphset) 1138 { 1139 glyphBuf[nused++] = (Glyph) glyphindex; 1140 if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) 1141 { 1142 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 1143 nused = 0; 1144 } 1145 } 1146 } 1147 else if (xftg->bitmap) 1148 free (xftg->bitmap); 1149 font->glyph_memory -= xftg->glyph_memory; 1150 if (info) 1151 info->glyph_memory -= xftg->glyph_memory; 1152 } 1153 1154 if (font->track_mem_usage) { 1155 XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1156 XftGlyphUsage *xtmp; 1157 1158 if (XftDebug() & XFT_DBG_USAGE) 1159 printf("free %p -> %p USE %d.%d\n", 1160 (void *) font, (void *) xuse, xuse->older, xuse->newer); 1161 1162 if (xuse->older != FT_UINT_MAX) { 1163 xtmp = (XftGlyphUsage *) font->glyphs[xuse->older]; 1164 if (xtmp != NULL) { 1165 /* update link around to oldest glyph */ 1166 xtmp->newer = xuse->newer; 1167 } 1168 if (font->newest == glyphindex) { 1169 if (font->newest == xuse->older) 1170 font->newest = FT_UINT_MAX; 1171 else 1172 font->newest = xuse->older; 1173 } 1174 } 1175 if (xuse->newer != FT_UINT_MAX) { 1176 xtmp = (XftGlyphUsage *) font->glyphs[xuse->newer]; 1177 if (xtmp != NULL) { 1178 /* update link around to newest glyph */ 1179 xtmp->older = xuse->older; 1180 } 1181 } 1182 if (font->total_inuse) { 1183 font->total_inuse--; 1184 } else { 1185 fprintf (stderr, "Xft: glyph count error\n"); 1186 } 1187 if (XftDebug() & XFT_DBG_USAGE) 1188 _XftValidateGlyphUsage(font); 1189 } 1190 1191 free (xftg); 1192 XftMemFree (XFT_MEM_GLYPH, font->sizeof_glyph); 1193 font->glyphs[glyphindex] = NULL; 1194 } 1195 if (font->glyphset && nused) 1196 XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 1197} 1198 1199_X_EXPORT FcBool 1200XftFontCheckGlyph (Display *dpy, 1201 XftFont *pub, 1202 FcBool need_bitmaps, 1203 FT_UInt glyph, 1204 FT_UInt *missing, 1205 int *nmissing) 1206{ 1207 XftFontInt *font = (XftFontInt *) pub; 1208 XftGlyph *xftg; 1209 int n; 1210 1211 if (glyph >= font->num_glyphs) 1212 return FcFalse; 1213 xftg = font->glyphs[glyph]; 1214 if (!xftg || (need_bitmaps && !xftg->glyph_memory)) 1215 { 1216 if (!xftg) 1217 { 1218 xftg = malloc (font->sizeof_glyph); 1219 if (!xftg) 1220 return FcFalse; 1221 XftMemAlloc (XFT_MEM_GLYPH, font->sizeof_glyph); 1222 1223 xftg->bitmap = NULL; 1224 xftg->glyph_memory = 0; 1225 xftg->picture = 0; 1226 font->glyphs[glyph] = xftg; 1227 1228 if (font->track_mem_usage) { 1229 XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1230 xuse->older = FT_UINT_MAX; 1231 xuse->newer = FT_UINT_MAX; 1232 } 1233 } 1234 n = *nmissing; 1235 missing[n++] = glyph; 1236 if (n == XFT_NMISSING) 1237 { 1238 XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n); 1239 n = 0; 1240 } 1241 *nmissing = n; 1242 return FcTrue; 1243 } 1244 1245 /* 1246 * Make unloading faster by moving newly-referenced glyphs to the front 1247 * of the list, leaving the less-used glyphs on the end. 1248 */ 1249 if (font->track_mem_usage 1250 && font->total_inuse > 10 1251 && font->newest != FT_UINT_MAX 1252 && font->newest != glyph) 1253 { 1254 XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1255 XftGlyphUsage *xtmp = (XftGlyphUsage *) font->glyphs[font->newest]; 1256 XftGlyphUsage *xold; 1257 XftGlyphUsage *xnew; 1258 1259 /* delink */ 1260 xold = (XftGlyphUsage *) font->glyphs[xuse->older]; 1261 xnew = (XftGlyphUsage *) font->glyphs[xuse->newer]; 1262 assert(xold != NULL); 1263 assert(xnew != NULL); 1264 xold->newer = xuse->newer; 1265 xnew->older = xuse->older; 1266 1267 /* relink */ 1268 xnew = (XftGlyphUsage *) font->glyphs[xtmp->newer]; 1269 assert(xnew != NULL); 1270 xnew->older = glyph; 1271 xuse->older = font->newest; 1272 xuse->newer = xtmp->newer; 1273 xtmp->newer = glyph; 1274 1275 font->newest = glyph; 1276 } 1277 return FcFalse; 1278} 1279 1280_X_EXPORT FcBool 1281XftCharExists (Display *dpy _X_UNUSED, 1282 XftFont *pub, 1283 FcChar32 ucs4) 1284{ 1285 if (pub->charset) 1286 return FcCharSetHasChar (pub->charset, ucs4); 1287 return FcFalse; 1288} 1289 1290#define Missing ((FT_UInt) ~0) 1291 1292_X_EXPORT FT_UInt 1293XftCharIndex (Display *dpy, 1294 XftFont *pub, 1295 FcChar32 ucs4) 1296{ 1297 XftFontInt *font = (XftFontInt *) pub; 1298 FcChar32 ent, offset; 1299 FT_Face face; 1300 1301 if (!font->hash_value) 1302 return 0; 1303 1304 ent = ucs4 % (FcChar32)font->hash_value; 1305 offset = 0; 1306 while (font->hash_table[ent].ucs4 != ucs4) 1307 { 1308 if (font->hash_table[ent].ucs4 == (FcChar32) ~0) 1309 { 1310 if (!XftCharExists (dpy, pub, ucs4)) 1311 return 0; 1312 face = XftLockFace (pub); 1313 if (!face) 1314 return 0; 1315 font->hash_table[ent].ucs4 = ucs4; 1316 font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4); 1317 XftUnlockFace (pub); 1318 break; 1319 } 1320 if (!offset) 1321 { 1322 offset = ucs4 % (FcChar32)font->rehash_value; 1323 if (!offset) 1324 offset = 1; 1325 } 1326 ent = ent + offset; 1327 if (ent >= (FcChar32)font->hash_value) 1328 ent -= (FcChar32)font->hash_value; 1329 } 1330 return font->hash_table[ent].glyph; 1331} 1332 1333/* 1334 * Remove glyph(s) from the font to reduce memory-usage. 1335 */ 1336_X_HIDDEN void 1337_XftFontUncacheGlyph (Display *dpy, XftFont *pub) 1338{ 1339 XftFontInt *font = (XftFontInt *) pub; 1340 unsigned long glyph_memory; 1341 FT_UInt glyphindex; 1342 XftGlyph *xftg; 1343 1344 if (!font->glyph_memory) 1345 return; 1346 1347 if (XftDebug() & XFT_DBG_CACHE) 1348 _XftFontValidateMemory (dpy, pub); 1349 1350 if (font->track_mem_usage) 1351 { 1352 /* 1353 * Remove the oldest glyph from the font. 1354 */ 1355 if (font->newest != FT_UINT_MAX) { 1356 XftGlyphUsage *xuse = (XftGlyphUsage *) font->glyphs[font->newest]; 1357 if ((glyphindex = xuse->newer) != FT_UINT_MAX) 1358 XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 1359 } 1360 } 1361 else if (font->use_free_glyphs) 1362 { 1363 /* 1364 * Pick a random glyph from the font and remove it from the cache 1365 */ 1366 glyph_memory = ((unsigned long)rand() % font->glyph_memory); 1367 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 1368 { 1369 xftg = font->glyphs[glyphindex]; 1370 if (xftg) 1371 { 1372 if (xftg->glyph_memory > glyph_memory) 1373 { 1374 XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 1375 break; 1376 } 1377 glyph_memory -= xftg->glyph_memory; 1378 } 1379 } 1380 } 1381 else 1382 { 1383 /* 1384 * Free all glyphs, since they are part of a set. 1385 */ 1386 if (font->glyphset) 1387 { 1388 XRenderFreeGlyphSet (dpy, font->glyphset); 1389 font->glyphset = 0; 1390 } 1391 for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 1392 { 1393 xftg = font->glyphs[glyphindex]; 1394 if (xftg) 1395 { 1396 if (xftg->glyph_memory > 0) 1397 { 1398 XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 1399 } 1400 } 1401 } 1402 } 1403 1404 if (XftDebug() & XFT_DBG_CACHE) 1405 _XftFontValidateMemory (dpy, pub); 1406} 1407 1408_X_HIDDEN void 1409_XftFontManageMemory (Display *dpy, XftFont *pub) 1410{ 1411 XftFontInt *font = (XftFontInt *) pub; 1412 1413 if (font->max_glyph_memory) 1414 { 1415 if (XftDebug() & XFT_DBG_CACHE) 1416 { 1417 if (font->glyph_memory > font->max_glyph_memory) 1418 printf ("Reduce memory for font 0x%lx from %lu to %lu\n", 1419 font->glyphset ? font->glyphset : (unsigned long) font, 1420 font->glyph_memory, font->max_glyph_memory); 1421 } 1422 while (font->glyph_memory > font->max_glyph_memory) 1423 _XftFontUncacheGlyph (dpy, pub); 1424 } 1425 _XftDisplayManageMemory (dpy); 1426} 1427