xftglyphs.c revision 0e0b1094
1c76ae52dSmrg/* 2c76ae52dSmrg * Copyright © 2000 Keith Packard 3c76ae52dSmrg * 4c76ae52dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 5c76ae52dSmrg * documentation for any purpose is hereby granted without fee, provided that 6c76ae52dSmrg * the above copyright notice appear in all copies and that both that 7c76ae52dSmrg * copyright notice and this permission notice appear in supporting 8c76ae52dSmrg * documentation, and that the name of Keith Packard not be used in 9c76ae52dSmrg * advertising or publicity pertaining to distribution of the software without 10c76ae52dSmrg * specific, written prior permission. Keith Packard makes no 11c76ae52dSmrg * representations about the suitability of this software for any purpose. It 12c76ae52dSmrg * is provided "as is" without express or implied warranty. 13c76ae52dSmrg * 14c76ae52dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15c76ae52dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16c76ae52dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17c76ae52dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18c76ae52dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19c76ae52dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20c76ae52dSmrg * PERFORMANCE OF THIS SOFTWARE. 21c76ae52dSmrg */ 22c76ae52dSmrg 23c76ae52dSmrg#include "xftint.h" 247bbb83baSmrg#include FT_OUTLINE_H 2512d4a5f4Smrg#include FT_LCD_FILTER_H 267bbb83baSmrg 2712d4a5f4Smrg#include FT_SYNTHESIS_H 28c76ae52dSmrg 29c76ae52dSmrg/* 30c76ae52dSmrg * Validate the memory info for a font 31c76ae52dSmrg */ 32c76ae52dSmrg 33c76ae52dSmrgstatic void 34c76ae52dSmrg_XftFontValidateMemory (Display *dpy, XftFont *public) 35c76ae52dSmrg{ 36c76ae52dSmrg XftFontInt *font = (XftFontInt *) public; 37c76ae52dSmrg unsigned long glyph_memory; 38c76ae52dSmrg FT_UInt glyphindex; 39c76ae52dSmrg XftGlyph *xftg; 40c76ae52dSmrg 41c76ae52dSmrg glyph_memory = 0; 42c76ae52dSmrg for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 43c76ae52dSmrg { 44c76ae52dSmrg xftg = font->glyphs[glyphindex]; 45c76ae52dSmrg if (xftg) 46c76ae52dSmrg { 47c76ae52dSmrg glyph_memory += xftg->glyph_memory; 48c76ae52dSmrg } 49c76ae52dSmrg } 50c76ae52dSmrg if (glyph_memory != font->glyph_memory) 51c76ae52dSmrg printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n", 52c76ae52dSmrg font->glyph_memory, glyph_memory); 53c76ae52dSmrg} 54c76ae52dSmrg 552836776bSmrg/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot 562836776bSmrg * into a different format. For example, we want to convert a 572836776bSmrg * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit 582836776bSmrg * ARGB or ABGR bitmap. 592836776bSmrg * 602836776bSmrg * this function prepares a target descriptor for this operation. 612836776bSmrg * 622836776bSmrg * input :: target bitmap descriptor. The function will set its 632836776bSmrg * 'width', 'rows' and 'pitch' fields, and only these 642836776bSmrg * 652836776bSmrg * slot :: the glyph slot containing the source bitmap. this 662836776bSmrg * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP 672836776bSmrg * 682836776bSmrg * mode :: the requested final rendering mode. supported values are 692836776bSmrg * MONO, NORMAL (i.e. gray), LCD and LCD_V 702836776bSmrg * 712836776bSmrg * the function returns the size in bytes of the corresponding buffer, 722836776bSmrg * it's up to the caller to allocate the corresponding memory block 732836776bSmrg * before calling _fill_xrender_bitmap 742836776bSmrg * 752836776bSmrg * it also returns -1 in case of error (e.g. incompatible arguments, 762836776bSmrg * like trying to convert a gray bitmap into a monochrome one) 772836776bSmrg */ 782836776bSmrgstatic int 792836776bSmrg_compute_xrender_bitmap_size( FT_Bitmap* target, 802836776bSmrg FT_GlyphSlot slot, 812836776bSmrg FT_Render_Mode mode ) 822836776bSmrg{ 832836776bSmrg FT_Bitmap* ftbit; 842836776bSmrg int width, height, pitch; 852836776bSmrg 862836776bSmrg if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) 872836776bSmrg return -1; 882836776bSmrg 890e0b1094Smrg /* compute the size of the final bitmap */ 902836776bSmrg ftbit = &slot->bitmap; 912836776bSmrg 920e0b1094Smrg width = (int)ftbit->width; 930e0b1094Smrg height = (int)ftbit->rows; 942836776bSmrg pitch = (width+3) & ~3; 952836776bSmrg 962836776bSmrg switch ( ftbit->pixel_mode ) 972836776bSmrg { 982836776bSmrg case FT_PIXEL_MODE_MONO: 992836776bSmrg if ( mode == FT_RENDER_MODE_MONO ) 1002836776bSmrg { 1012836776bSmrg pitch = (((width+31) & ~31) >> 3); 1022836776bSmrg break; 1032836776bSmrg } 1042836776bSmrg /* fall-through */ 1052836776bSmrg 1062836776bSmrg case FT_PIXEL_MODE_GRAY: 1072836776bSmrg if ( mode == FT_RENDER_MODE_LCD || 1082836776bSmrg mode == FT_RENDER_MODE_LCD_V ) 1092836776bSmrg { 1102836776bSmrg /* each pixel is replicated into a 32-bit ARGB value */ 1112836776bSmrg pitch = width*4; 1122836776bSmrg } 1132836776bSmrg break; 1142836776bSmrg 1152836776bSmrg case FT_PIXEL_MODE_LCD: 1162836776bSmrg if ( mode != FT_RENDER_MODE_LCD ) 1172836776bSmrg return -1; 1182836776bSmrg 1192836776bSmrg /* horz pixel triplets are packed into 32-bit ARGB values */ 1202836776bSmrg width /= 3; 1212836776bSmrg pitch = width*4; 1222836776bSmrg break; 1232836776bSmrg 1242836776bSmrg case FT_PIXEL_MODE_LCD_V: 1252836776bSmrg if ( mode != FT_RENDER_MODE_LCD_V ) 1262836776bSmrg return -1; 1272836776bSmrg 1282836776bSmrg /* vert pixel triplets are packed into 32-bit ARGB values */ 1292836776bSmrg height /= 3; 1302836776bSmrg pitch = width*4; 1312836776bSmrg break; 1322836776bSmrg 1332836776bSmrg default: /* unsupported source format */ 1342836776bSmrg return -1; 1352836776bSmrg } 1362836776bSmrg 1370e0b1094Smrg target->width = (unsigned)width; 1380e0b1094Smrg target->rows = (unsigned)height; 1392836776bSmrg target->pitch = pitch; 1402836776bSmrg target->buffer = NULL; 1412836776bSmrg 1422836776bSmrg return pitch * height; 1432836776bSmrg} 1442836776bSmrg 1452836776bSmrg/* this functions converts the glyph bitmap found in a FT_GlyphSlot 1462836776bSmrg * into a different format (see _compute_xrender_bitmap_size) 1472836776bSmrg * 1482836776bSmrg * you should call this function after _compute_xrender_bitmap_size 1492836776bSmrg * 1502836776bSmrg * target :: target bitmap descriptor. Note that its 'buffer' pointer 1512836776bSmrg * must point to memory allocated by the caller 1522836776bSmrg * 1532836776bSmrg * slot :: the glyph slot containing the source bitmap 1542836776bSmrg * 1552836776bSmrg * mode :: the requested final rendering mode 1562836776bSmrg * 1572836776bSmrg * bgr :: boolean, set if BGR or VBGR pixel ordering is needed 1582836776bSmrg */ 1592836776bSmrgstatic void 1602836776bSmrg_fill_xrender_bitmap( FT_Bitmap* target, 1612836776bSmrg FT_GlyphSlot slot, 1622836776bSmrg FT_Render_Mode mode, 1632836776bSmrg int bgr ) 1642836776bSmrg{ 1652836776bSmrg FT_Bitmap* ftbit = &slot->bitmap; 1662836776bSmrg 1672836776bSmrg { 1682836776bSmrg unsigned char* srcLine = ftbit->buffer; 1692836776bSmrg unsigned char* dstLine = target->buffer; 1702836776bSmrg int src_pitch = ftbit->pitch; 1710e0b1094Smrg int width = (int)target->width; 1720e0b1094Smrg int height = (int)target->rows; 1732836776bSmrg int pitch = target->pitch; 1742836776bSmrg int subpixel; 1752836776bSmrg int h; 1762836776bSmrg 1772836776bSmrg subpixel = ( mode == FT_RENDER_MODE_LCD || 1782836776bSmrg mode == FT_RENDER_MODE_LCD_V ); 1792836776bSmrg 1802836776bSmrg if ( src_pitch < 0 ) 1810e0b1094Smrg srcLine -= ((unsigned)src_pitch * (ftbit->rows-1)); 1822836776bSmrg 1832836776bSmrg switch ( ftbit->pixel_mode ) 1842836776bSmrg { 1852836776bSmrg case FT_PIXEL_MODE_MONO: 1862836776bSmrg if ( subpixel ) /* convert mono to ARGB32 values */ 1872836776bSmrg { 1882836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 1892836776bSmrg { 1902836776bSmrg int x; 1912836776bSmrg 1922836776bSmrg for ( x = 0; x < width; x++ ) 1932836776bSmrg { 1942836776bSmrg if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 1952836776bSmrg ((unsigned int*)dstLine)[x] = 0xffffffffU; 1962836776bSmrg } 1972836776bSmrg } 1982836776bSmrg } 1992836776bSmrg else if ( mode == FT_RENDER_MODE_NORMAL ) /* convert mono to 8-bit gray */ 2002836776bSmrg { 2012836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 2022836776bSmrg { 2032836776bSmrg int x; 2042836776bSmrg 2052836776bSmrg for ( x = 0; x < width; x++ ) 2062836776bSmrg { 2072836776bSmrg if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 2082836776bSmrg dstLine[x] = 0xff; 2092836776bSmrg } 2102836776bSmrg } 2112836776bSmrg } 2122836776bSmrg else /* copy mono to mono */ 2132836776bSmrg { 2142836776bSmrg int bytes = (width+7) >> 3; 2152836776bSmrg 2162836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 2170e0b1094Smrg memcpy( dstLine, srcLine, (size_t)bytes ); 2182836776bSmrg } 2192836776bSmrg break; 2202836776bSmrg 2212836776bSmrg case FT_PIXEL_MODE_GRAY: 2222836776bSmrg if ( subpixel ) /* convert gray to ARGB32 values */ 2232836776bSmrg { 2242836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 2252836776bSmrg { 2262836776bSmrg int x; 2272836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 2282836776bSmrg 2292836776bSmrg for ( x = 0; x < width; x++ ) 2302836776bSmrg { 2312836776bSmrg unsigned int pix = srcLine[x]; 2322836776bSmrg 2332836776bSmrg pix |= (pix << 8); 2342836776bSmrg pix |= (pix << 16); 2352836776bSmrg 2362836776bSmrg dst[x] = pix; 2372836776bSmrg } 2382836776bSmrg } 2392836776bSmrg } 2402836776bSmrg else /* copy gray into gray */ 2412836776bSmrg { 2422836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 2430e0b1094Smrg memcpy( dstLine, srcLine, (size_t)width ); 2442836776bSmrg } 2452836776bSmrg break; 2462836776bSmrg 2472836776bSmrg case FT_PIXEL_MODE_LCD: 2482836776bSmrg if ( !bgr ) 2492836776bSmrg { 2502836776bSmrg /* convert horizontal RGB into ARGB32 */ 2512836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 2522836776bSmrg { 2532836776bSmrg int x; 2542836776bSmrg unsigned char* src = srcLine; 2552836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 2562836776bSmrg 2572836776bSmrg for ( x = 0; x < width; x++, src += 3 ) 2582836776bSmrg { 2592836776bSmrg unsigned int pix; 2602836776bSmrg 2612836776bSmrg pix = ((unsigned int)src[0] << 16) | 2622836776bSmrg ((unsigned int)src[1] << 8) | 2632836776bSmrg ((unsigned int)src[2] ) | 2642836776bSmrg ((unsigned int)src[1] << 24) ; 2652836776bSmrg 2662836776bSmrg dst[x] = pix; 2672836776bSmrg } 2682836776bSmrg } 2692836776bSmrg } 2702836776bSmrg else 2712836776bSmrg { 2722836776bSmrg /* convert horizontal BGR into ARGB32 */ 2732836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 2742836776bSmrg { 2752836776bSmrg int x; 2762836776bSmrg unsigned char* src = srcLine; 2772836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 2782836776bSmrg 2792836776bSmrg for ( x = 0; x < width; x++, src += 3 ) 2802836776bSmrg { 2812836776bSmrg unsigned int pix; 2822836776bSmrg 2832836776bSmrg pix = ((unsigned int)src[2] << 16) | 2842836776bSmrg ((unsigned int)src[1] << 8) | 2852836776bSmrg ((unsigned int)src[0] ) | 2862836776bSmrg ((unsigned int)src[1] << 24) ; 2872836776bSmrg 2882836776bSmrg dst[x] = pix; 2892836776bSmrg } 2902836776bSmrg } 2912836776bSmrg } 2922836776bSmrg break; 2932836776bSmrg 2942836776bSmrg default: /* FT_PIXEL_MODE_LCD_V */ 2952836776bSmrg /* convert vertical RGB into ARGB32 */ 2962836776bSmrg if ( !bgr ) 2972836776bSmrg { 2982836776bSmrg for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 2992836776bSmrg { 3002836776bSmrg int x; 3012836776bSmrg unsigned char* src = srcLine; 3022836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 3032836776bSmrg 3042836776bSmrg for ( x = 0; x < width; x++, src += 1 ) 3052836776bSmrg { 3062836776bSmrg unsigned int pix; 3072836776bSmrg 3082836776bSmrg pix = ((unsigned int)src[0] << 16) | 3092836776bSmrg ((unsigned int)src[src_pitch] << 8) | 3102836776bSmrg ((unsigned int)src[src_pitch*2] ) | 3112836776bSmrg ((unsigned int)src[src_pitch] << 24) ; 3122836776bSmrg 3132836776bSmrg dst[x] = pix; 3142836776bSmrg } 3152836776bSmrg } 3162836776bSmrg } 3172836776bSmrg else 3182836776bSmrg { 3192836776bSmrg for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 3202836776bSmrg { 3212836776bSmrg int x; 3222836776bSmrg unsigned char* src = srcLine; 3232836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 3242836776bSmrg 3252836776bSmrg for ( x = 0; x < width; x++, src += 1 ) 3262836776bSmrg { 3272836776bSmrg unsigned int pix; 3282836776bSmrg 3292836776bSmrg pix = ((unsigned int)src[src_pitch*2] << 16) | 3302836776bSmrg ((unsigned int)src[src_pitch] << 8) | 3312836776bSmrg ((unsigned int)src[0] ) | 3322836776bSmrg ((unsigned int)src[src_pitch] << 24) ; 3332836776bSmrg 3342836776bSmrg dst[x] = pix; 3352836776bSmrg } 3362836776bSmrg } 3372836776bSmrg } 3382836776bSmrg } 3392836776bSmrg } 3402836776bSmrg} 3412836776bSmrg 342c76ae52dSmrg_X_EXPORT void 343c76ae52dSmrgXftFontLoadGlyphs (Display *dpy, 344c76ae52dSmrg XftFont *pub, 345c76ae52dSmrg FcBool need_bitmaps, 346c76ae52dSmrg _Xconst FT_UInt *glyphs, 347c76ae52dSmrg int nglyph) 348c76ae52dSmrg{ 349c76ae52dSmrg XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 350c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 351c76ae52dSmrg FT_Error error; 352c76ae52dSmrg FT_UInt glyphindex; 353c76ae52dSmrg FT_GlyphSlot glyphslot; 354c76ae52dSmrg XftGlyph *xftg; 355c76ae52dSmrg Glyph glyph; 356c76ae52dSmrg unsigned char bufLocal[4096]; 357c76ae52dSmrg unsigned char *bufBitmap = bufLocal; 358c76ae52dSmrg int bufSize = sizeof (bufLocal); 3592836776bSmrg int size; 360c76ae52dSmrg int width; 361c76ae52dSmrg int height; 362c76ae52dSmrg int left, right, top, bottom; 3632836776bSmrg FT_Bitmap* ftbit; 3642836776bSmrg FT_Bitmap local; 365c76ae52dSmrg FT_Vector vector; 366c76ae52dSmrg FT_Face face; 3672836776bSmrg FT_Render_Mode mode = FT_RENDER_MODE_MONO; 368c76ae52dSmrg 369c76ae52dSmrg if (!info) 370c76ae52dSmrg return; 371c76ae52dSmrg 372c76ae52dSmrg face = XftLockFace (&font->public); 3732836776bSmrg 374c76ae52dSmrg if (!face) 375c76ae52dSmrg return; 376c76ae52dSmrg 377c76ae52dSmrg if (font->info.antialias) 378c76ae52dSmrg { 379c76ae52dSmrg switch (font->info.rgba) { 380c76ae52dSmrg case FC_RGBA_RGB: 381c76ae52dSmrg case FC_RGBA_BGR: 3822836776bSmrg mode = FT_RENDER_MODE_LCD; 383c76ae52dSmrg break; 384c76ae52dSmrg case FC_RGBA_VRGB: 385c76ae52dSmrg case FC_RGBA_VBGR: 3862836776bSmrg mode = FT_RENDER_MODE_LCD_V; 387c76ae52dSmrg break; 3882836776bSmrg default: 3892836776bSmrg mode = FT_RENDER_MODE_NORMAL; 390c76ae52dSmrg } 391c76ae52dSmrg } 392c76ae52dSmrg 393c76ae52dSmrg while (nglyph--) 394c76ae52dSmrg { 395c76ae52dSmrg glyphindex = *glyphs++; 396c76ae52dSmrg xftg = font->glyphs[glyphindex]; 397c76ae52dSmrg if (!xftg) 398c76ae52dSmrg continue; 3992836776bSmrg 400c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 401c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 402c76ae52dSmrg /* 403c76ae52dSmrg * Check to see if this glyph has just been loaded, 404c76ae52dSmrg * this happens when drawing the same glyph twice 405c76ae52dSmrg * in a single string 406c76ae52dSmrg */ 407c76ae52dSmrg if (xftg->glyph_memory) 408c76ae52dSmrg continue; 4092836776bSmrg 4102836776bSmrg FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter); 4112836776bSmrg 412c76ae52dSmrg error = FT_Load_Glyph (face, glyphindex, font->info.load_flags); 413c76ae52dSmrg if (error) 414c76ae52dSmrg { 415c76ae52dSmrg /* 416c76ae52dSmrg * If anti-aliasing or transforming glyphs and 417c76ae52dSmrg * no outline version exists, fallback to the 418c76ae52dSmrg * bitmap and let things look bad instead of 419c76ae52dSmrg * missing the glyph 420c76ae52dSmrg */ 421c76ae52dSmrg if (font->info.load_flags & FT_LOAD_NO_BITMAP) 422c76ae52dSmrg error = FT_Load_Glyph (face, glyphindex, 423c76ae52dSmrg font->info.load_flags & ~FT_LOAD_NO_BITMAP); 424c76ae52dSmrg if (error) 425c76ae52dSmrg continue; 426c76ae52dSmrg } 427c76ae52dSmrg 428c76ae52dSmrg#define FLOOR(x) ((x) & -64) 429c76ae52dSmrg#define CEIL(x) (((x)+63) & -64) 430c76ae52dSmrg#define TRUNC(x) ((x) >> 6) 431c76ae52dSmrg#define ROUND(x) (((x)+32) & -64) 4322836776bSmrg 433c76ae52dSmrg glyphslot = face->glyph; 434c76ae52dSmrg 435c76ae52dSmrg /* 436c76ae52dSmrg * Embolden if required 437c76ae52dSmrg */ 438c76ae52dSmrg if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot); 439c76ae52dSmrg 440c76ae52dSmrg /* 441c76ae52dSmrg * Compute glyph metrics from FreeType information 442c76ae52dSmrg */ 4432836776bSmrg if(font->info.transform && glyphslot->format != FT_GLYPH_FORMAT_BITMAP) 444c76ae52dSmrg { 445c76ae52dSmrg /* 446c76ae52dSmrg * calculate the true width by transforming all four corners. 447c76ae52dSmrg */ 448c76ae52dSmrg int xc, yc; 449c76ae52dSmrg left = right = top = bottom = 0; 450c76ae52dSmrg for(xc = 0; xc <= 1; xc ++) { 451c76ae52dSmrg for(yc = 0; yc <= 1; yc++) { 452c76ae52dSmrg vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width; 453c76ae52dSmrg vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height; 4542836776bSmrg FT_Vector_Transform(&vector, &font->info.matrix); 455c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPH) 4562836776bSmrg printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, 457c76ae52dSmrg (int) vector.x, (int) vector.y); 458c76ae52dSmrg if(xc == 0 && yc == 0) { 4590e0b1094Smrg left = right = (int)vector.x; 4600e0b1094Smrg top = bottom = (int)vector.y; 461c76ae52dSmrg } else { 4620e0b1094Smrg if(left > vector.x) left = (int)vector.x; 4630e0b1094Smrg if(right < vector.x) right = (int)vector.x; 4640e0b1094Smrg if(bottom > vector.y) bottom = (int)vector.y; 4650e0b1094Smrg if(top < vector.y) top = (int)vector.y; 466c76ae52dSmrg } 467c76ae52dSmrg 468c76ae52dSmrg } 469c76ae52dSmrg } 4700e0b1094Smrg left = (int)FLOOR(left); 4710e0b1094Smrg right = (int)CEIL(right); 4720e0b1094Smrg bottom = (int)FLOOR(bottom); 4730e0b1094Smrg top = CEIL(top); 474c76ae52dSmrg 475c76ae52dSmrg } else { 4760e0b1094Smrg left = (int)FLOOR( glyphslot->metrics.horiBearingX ); 4770e0b1094Smrg right = (int)CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width ); 478c76ae52dSmrg 4790e0b1094Smrg top = (int)CEIL( glyphslot->metrics.horiBearingY ); 4800e0b1094Smrg bottom = (int)FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height ); 481c76ae52dSmrg } 482c76ae52dSmrg 483c76ae52dSmrg width = TRUNC(right - left); 484c76ae52dSmrg height = TRUNC( top - bottom ); 485c76ae52dSmrg 486c76ae52dSmrg /* 487c76ae52dSmrg * Clip charcell glyphs to the bounding box 488c76ae52dSmrg * XXX transformed? 489c76ae52dSmrg */ 490c76ae52dSmrg if (font->info.spacing >= FC_CHARCELL && !font->info.transform) 491c76ae52dSmrg { 492c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 493c76ae52dSmrg { 494c76ae52dSmrg if (TRUNC(bottom) > font->public.max_advance_width) 495c76ae52dSmrg { 496c76ae52dSmrg int adjust; 4972836776bSmrg 498c76ae52dSmrg adjust = bottom - (font->public.max_advance_width << 6); 499c76ae52dSmrg if (adjust > top) 500c76ae52dSmrg adjust = top; 501c76ae52dSmrg top -= adjust; 502c76ae52dSmrg bottom -= adjust; 503c76ae52dSmrg height = font->public.max_advance_width; 504c76ae52dSmrg } 505c76ae52dSmrg } 506c76ae52dSmrg else 507c76ae52dSmrg { 508c76ae52dSmrg if (TRUNC(right) > font->public.max_advance_width) 509c76ae52dSmrg { 510c76ae52dSmrg int adjust; 5112836776bSmrg 512c76ae52dSmrg adjust = right - (font->public.max_advance_width << 6); 513c76ae52dSmrg if (adjust > left) 514c76ae52dSmrg adjust = left; 515c76ae52dSmrg left -= adjust; 516c76ae52dSmrg right -= adjust; 517c76ae52dSmrg width = font->public.max_advance_width; 518c76ae52dSmrg } 519c76ae52dSmrg } 520c76ae52dSmrg } 521c76ae52dSmrg 5222836776bSmrg if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP ) 5232836776bSmrg { 5242836776bSmrg error = FT_Render_Glyph( face->glyph, mode ); 5252836776bSmrg if (error) 5262836776bSmrg continue; 5272836776bSmrg } 528c76ae52dSmrg 5292836776bSmrg FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE ); 530c76ae52dSmrg 531c76ae52dSmrg if (font->info.spacing >= FC_MONO) 532c76ae52dSmrg { 533c76ae52dSmrg if (font->info.transform) 534c76ae52dSmrg { 535c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 536c76ae52dSmrg { 537c76ae52dSmrg vector.x = 0; 538c76ae52dSmrg vector.y = -face->size->metrics.max_advance; 539c76ae52dSmrg } 540c76ae52dSmrg else 541c76ae52dSmrg { 542c76ae52dSmrg vector.x = face->size->metrics.max_advance; 543c76ae52dSmrg vector.y = 0; 544c76ae52dSmrg } 545c76ae52dSmrg FT_Vector_Transform (&vector, &font->info.matrix); 5460e0b1094Smrg xftg->metrics.xOff = (short)(vector.x >> 6); 5470e0b1094Smrg xftg->metrics.yOff = (short)(-(vector.y >> 6)); 548c76ae52dSmrg } 549c76ae52dSmrg else 550c76ae52dSmrg { 551c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 552c76ae52dSmrg { 553c76ae52dSmrg xftg->metrics.xOff = 0; 5540e0b1094Smrg xftg->metrics.yOff = (short)(-font->public.max_advance_width); 555c76ae52dSmrg } 556c76ae52dSmrg else 557c76ae52dSmrg { 5580e0b1094Smrg xftg->metrics.xOff = (short)(font->public.max_advance_width); 559c76ae52dSmrg xftg->metrics.yOff = 0; 560c76ae52dSmrg } 561c76ae52dSmrg } 562c76ae52dSmrg } 563c76ae52dSmrg else 564c76ae52dSmrg { 5650e0b1094Smrg xftg->metrics.xOff = (short)(TRUNC(ROUND(glyphslot->advance.x))); 5660e0b1094Smrg xftg->metrics.yOff = (short)(-TRUNC(ROUND(glyphslot->advance.y))); 567c76ae52dSmrg } 568c76ae52dSmrg 5690e0b1094Smrg /* compute the size of the final bitmap */ 5702836776bSmrg ftbit = &glyphslot->bitmap; 571c76ae52dSmrg 5720e0b1094Smrg width = (int)ftbit->width; 5730e0b1094Smrg height = (int)ftbit->rows; 574c76ae52dSmrg 575c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPH) 576c76ae52dSmrg { 577c76ae52dSmrg printf ("glyph %d:\n", (int) glyphindex); 578c76ae52dSmrg printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n", 579c76ae52dSmrg (int) glyphslot->metrics.horiBearingX, 580c76ae52dSmrg (int) glyphslot->metrics.horiBearingY, 581c76ae52dSmrg (int) glyphslot->metrics.width, 582c76ae52dSmrg (int) glyphslot->metrics.height, 583c76ae52dSmrg left, right, top, bottom, 584c76ae52dSmrg width, height); 585c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPHV) 586c76ae52dSmrg { 587c76ae52dSmrg int x, y; 588c76ae52dSmrg unsigned char *line; 589c76ae52dSmrg 5902836776bSmrg line = ftbit->buffer; 5912836776bSmrg if (ftbit->pitch < 0) 5922836776bSmrg line -= ftbit->pitch*(height-1); 5932836776bSmrg 5942836776bSmrg for (y = 0; y < height; y++) 595c76ae52dSmrg { 5962836776bSmrg if (font->info.antialias) 597c76ae52dSmrg { 5982836776bSmrg static const char den[] = { " .:;=+*#" }; 5992836776bSmrg for (x = 0; x < width; x++) 600c76ae52dSmrg printf ("%c", den[line[x] >> 5]); 601c76ae52dSmrg } 602c76ae52dSmrg else 603c76ae52dSmrg { 6042836776bSmrg for (x = 0; x < width * 8; x++) 605c76ae52dSmrg { 606c76ae52dSmrg printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' '); 607c76ae52dSmrg } 608c76ae52dSmrg } 609c76ae52dSmrg printf ("|\n"); 6102836776bSmrg line += ftbit->pitch; 611c76ae52dSmrg } 612c76ae52dSmrg printf ("\n"); 613c76ae52dSmrg } 614c76ae52dSmrg } 615c76ae52dSmrg 6162836776bSmrg size = _compute_xrender_bitmap_size( &local, glyphslot, mode ); 6172836776bSmrg if ( size < 0 ) 6182836776bSmrg continue; 6192836776bSmrg 6200e0b1094Smrg xftg->metrics.width = (unsigned short)local.width; 6210e0b1094Smrg xftg->metrics.height = (unsigned short)local.rows; 6220e0b1094Smrg xftg->metrics.x = (short)(- glyphslot->bitmap_left); 6230e0b1094Smrg xftg->metrics.y = (short)( glyphslot->bitmap_top); 6242836776bSmrg 6252836776bSmrg /* 6262836776bSmrg * If the glyph is relatively large (> 1% of server memory), 6272836776bSmrg * don't send it until necessary. 6282836776bSmrg */ 6292836776bSmrg if (!need_bitmaps && size > info->max_glyph_memory / 100) 6302836776bSmrg continue; 6312836776bSmrg 6322836776bSmrg /* 6332836776bSmrg * Make sure there is enough buffer space for the glyph. 6342836776bSmrg */ 6352836776bSmrg if (size > bufSize) 6362836776bSmrg { 6372836776bSmrg if (bufBitmap != bufLocal) 6382836776bSmrg free (bufBitmap); 6390e0b1094Smrg bufBitmap = (unsigned char *) malloc ((size_t)size); 6402836776bSmrg if (!bufBitmap) 6412836776bSmrg continue; 6422836776bSmrg bufSize = size; 6432836776bSmrg } 6440e0b1094Smrg memset (bufBitmap, 0, (size_t)size); 6452836776bSmrg 6462836776bSmrg local.buffer = bufBitmap; 6472836776bSmrg 6482836776bSmrg _fill_xrender_bitmap( &local, glyphslot, mode, 6492836776bSmrg (font->info.rgba == FC_RGBA_BGR || 6502836776bSmrg font->info.rgba == FC_RGBA_VBGR ) ); 6512836776bSmrg 6522836776bSmrg /* 6532836776bSmrg * Copy or convert into local buffer. 6542836776bSmrg */ 6552836776bSmrg 656c76ae52dSmrg /* 657c76ae52dSmrg * Use the glyph index as the wire encoding; it 658c76ae52dSmrg * might be more efficient for some locales to map 659c76ae52dSmrg * these by first usage to smaller values, but that 660c76ae52dSmrg * would require persistently storing the map when 661c76ae52dSmrg * glyphs were freed. 662c76ae52dSmrg */ 663c76ae52dSmrg glyph = (Glyph) glyphindex; 664c76ae52dSmrg 6650e0b1094Smrg xftg->glyph_memory = (size_t)size + sizeof (XftGlyph); 6662836776bSmrg if (font->format) 667c76ae52dSmrg { 6682836776bSmrg if (!font->glyphset) 6692836776bSmrg font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 6702836776bSmrg if ( mode == FT_RENDER_MODE_MONO ) 671c76ae52dSmrg { 6722836776bSmrg /* swap bits in each byte */ 6732836776bSmrg if (BitmapBitOrder (dpy) != MSBFirst) 674c76ae52dSmrg { 6752836776bSmrg unsigned char *line = (unsigned char*)bufBitmap; 6762836776bSmrg int i = size; 6772836776bSmrg 6782836776bSmrg while (i--) 679c76ae52dSmrg { 6802836776bSmrg int c = *line; 6812836776bSmrg c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); 6822836776bSmrg c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); 6832836776bSmrg c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); 6840e0b1094Smrg *line++ = (unsigned char)c; 685c76ae52dSmrg } 686c76ae52dSmrg } 687c76ae52dSmrg } 6882836776bSmrg else if ( mode != FT_RENDER_MODE_NORMAL ) 689c76ae52dSmrg { 6902836776bSmrg /* invert ARGB <=> BGRA */ 691c76ae52dSmrg if (ImageByteOrder (dpy) != XftNativeByteOrder ()) 6922836776bSmrg XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2); 693c76ae52dSmrg } 6942836776bSmrg XRenderAddGlyphs (dpy, font->glyphset, &glyph, 6952836776bSmrg &xftg->metrics, 1, 6962836776bSmrg (char *) bufBitmap, size); 697c76ae52dSmrg } 698c76ae52dSmrg else 699c76ae52dSmrg { 7002836776bSmrg if (size) 701c76ae52dSmrg { 7020e0b1094Smrg xftg->bitmap = malloc ((size_t)size); 7032836776bSmrg if (xftg->bitmap) 7040e0b1094Smrg memcpy (xftg->bitmap, bufBitmap, (size_t)size); 705c76ae52dSmrg } 706c76ae52dSmrg else 7072836776bSmrg xftg->bitmap = NULL; 708c76ae52dSmrg } 7092836776bSmrg 710c76ae52dSmrg font->glyph_memory += xftg->glyph_memory; 711c76ae52dSmrg info->glyph_memory += xftg->glyph_memory; 712c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 713c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 714c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHEV) 715c76ae52dSmrg printf ("Caching glyph 0x%x size %ld\n", glyphindex, 716c76ae52dSmrg xftg->glyph_memory); 717c76ae52dSmrg } 718c76ae52dSmrg if (bufBitmap != bufLocal) 719c76ae52dSmrg free (bufBitmap); 720c76ae52dSmrg XftUnlockFace (&font->public); 721c76ae52dSmrg} 722c76ae52dSmrg 723c76ae52dSmrg_X_EXPORT void 724c76ae52dSmrgXftFontUnloadGlyphs (Display *dpy, 725c76ae52dSmrg XftFont *pub, 726c76ae52dSmrg _Xconst FT_UInt *glyphs, 727c76ae52dSmrg int nglyph) 728c76ae52dSmrg{ 729c76ae52dSmrg XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 730c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 731c76ae52dSmrg XftGlyph *xftg; 732c76ae52dSmrg FT_UInt glyphindex; 733c76ae52dSmrg Glyph glyphBuf[1024]; 734c76ae52dSmrg int nused; 7352836776bSmrg 736c76ae52dSmrg nused = 0; 737c76ae52dSmrg while (nglyph--) 738c76ae52dSmrg { 739c76ae52dSmrg glyphindex = *glyphs++; 740c76ae52dSmrg xftg = font->glyphs[glyphindex]; 741c76ae52dSmrg if (!xftg) 742c76ae52dSmrg continue; 743c76ae52dSmrg if (xftg->glyph_memory) 744c76ae52dSmrg { 745c76ae52dSmrg if (font->format) 746c76ae52dSmrg { 747c76ae52dSmrg if (font->glyphset) 748c76ae52dSmrg { 749c76ae52dSmrg glyphBuf[nused++] = (Glyph) glyphindex; 750c76ae52dSmrg if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) 751c76ae52dSmrg { 752c76ae52dSmrg XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 753c76ae52dSmrg nused = 0; 754c76ae52dSmrg } 755c76ae52dSmrg } 756c76ae52dSmrg } 757c76ae52dSmrg else 758c76ae52dSmrg { 759c76ae52dSmrg if (xftg->bitmap) 760c76ae52dSmrg free (xftg->bitmap); 761c76ae52dSmrg } 762c76ae52dSmrg font->glyph_memory -= xftg->glyph_memory; 763c76ae52dSmrg if (info) 764c76ae52dSmrg info->glyph_memory -= xftg->glyph_memory; 765c76ae52dSmrg } 766c76ae52dSmrg free (xftg); 767c76ae52dSmrg XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph)); 7680d590c07Smrg font->glyphs[glyphindex] = NULL; 7692836776bSmrg } 770c76ae52dSmrg if (font->glyphset && nused) 771c76ae52dSmrg XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 772c76ae52dSmrg} 773c76ae52dSmrg 774c76ae52dSmrg_X_EXPORT FcBool 775c76ae52dSmrgXftFontCheckGlyph (Display *dpy, 776c76ae52dSmrg XftFont *pub, 777c76ae52dSmrg FcBool need_bitmaps, 778c76ae52dSmrg FT_UInt glyph, 779c76ae52dSmrg FT_UInt *missing, 780c76ae52dSmrg int *nmissing) 781c76ae52dSmrg{ 782c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 783c76ae52dSmrg XftGlyph *xftg; 784c76ae52dSmrg int n; 7852836776bSmrg 786c76ae52dSmrg if (glyph >= font->num_glyphs) 787c76ae52dSmrg return FcFalse; 788c76ae52dSmrg xftg = font->glyphs[glyph]; 789c76ae52dSmrg if (!xftg || (need_bitmaps && !xftg->glyph_memory)) 790c76ae52dSmrg { 791c76ae52dSmrg if (!xftg) 792c76ae52dSmrg { 793c76ae52dSmrg xftg = (XftGlyph *) malloc (sizeof (XftGlyph)); 794c76ae52dSmrg if (!xftg) 795c76ae52dSmrg return FcFalse; 796c76ae52dSmrg XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph)); 7970d590c07Smrg xftg->bitmap = NULL; 798c76ae52dSmrg xftg->glyph_memory = 0; 799c76ae52dSmrg font->glyphs[glyph] = xftg; 800c76ae52dSmrg } 801c76ae52dSmrg n = *nmissing; 802c76ae52dSmrg missing[n++] = glyph; 803c76ae52dSmrg if (n == XFT_NMISSING) 804c76ae52dSmrg { 805c76ae52dSmrg XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n); 806c76ae52dSmrg n = 0; 807c76ae52dSmrg } 808c76ae52dSmrg *nmissing = n; 809c76ae52dSmrg return FcTrue; 810c76ae52dSmrg } 811c76ae52dSmrg else 812c76ae52dSmrg return FcFalse; 813c76ae52dSmrg} 814c76ae52dSmrg 815c76ae52dSmrg_X_EXPORT FcBool 816c76ae52dSmrgXftCharExists (Display *dpy, 817c76ae52dSmrg XftFont *pub, 818c76ae52dSmrg FcChar32 ucs4) 819c76ae52dSmrg{ 820c76ae52dSmrg if (pub->charset) 821c76ae52dSmrg return FcCharSetHasChar (pub->charset, ucs4); 822c76ae52dSmrg return FcFalse; 823c76ae52dSmrg} 824c76ae52dSmrg 825c76ae52dSmrg#define Missing ((FT_UInt) ~0) 826c76ae52dSmrg 827c76ae52dSmrg_X_EXPORT FT_UInt 8282836776bSmrgXftCharIndex (Display *dpy, 829c76ae52dSmrg XftFont *pub, 830c76ae52dSmrg FcChar32 ucs4) 831c76ae52dSmrg{ 832c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 833c76ae52dSmrg FcChar32 ent, offset; 834c76ae52dSmrg FT_Face face; 8352836776bSmrg 836c76ae52dSmrg if (!font->hash_value) 837c76ae52dSmrg return 0; 838c76ae52dSmrg 8390e0b1094Smrg ent = ucs4 % (FcChar32)font->hash_value; 840c76ae52dSmrg offset = 0; 841c76ae52dSmrg while (font->hash_table[ent].ucs4 != ucs4) 842c76ae52dSmrg { 843c76ae52dSmrg if (font->hash_table[ent].ucs4 == (FcChar32) ~0) 844c76ae52dSmrg { 845c76ae52dSmrg if (!XftCharExists (dpy, pub, ucs4)) 846c76ae52dSmrg return 0; 847c76ae52dSmrg face = XftLockFace (pub); 848c76ae52dSmrg if (!face) 849c76ae52dSmrg return 0; 850c76ae52dSmrg font->hash_table[ent].ucs4 = ucs4; 851c76ae52dSmrg font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4); 852c76ae52dSmrg XftUnlockFace (pub); 853c76ae52dSmrg break; 854c76ae52dSmrg } 855c76ae52dSmrg if (!offset) 856c76ae52dSmrg { 8570e0b1094Smrg offset = ucs4 % (FcChar32)font->rehash_value; 858c76ae52dSmrg if (!offset) 859c76ae52dSmrg offset = 1; 860c76ae52dSmrg } 861c76ae52dSmrg ent = ent + offset; 862c76ae52dSmrg if (ent >= font->hash_value) 8630e0b1094Smrg ent -= (FcChar32)font->hash_value; 864c76ae52dSmrg } 865c76ae52dSmrg return font->hash_table[ent].glyph; 866c76ae52dSmrg} 867c76ae52dSmrg 868c76ae52dSmrg/* 869c76ae52dSmrg * Pick a random glyph from the font and remove it from the cache 870c76ae52dSmrg */ 871c76ae52dSmrg_X_HIDDEN void 872c76ae52dSmrg_XftFontUncacheGlyph (Display *dpy, XftFont *pub) 873c76ae52dSmrg{ 874c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 875c76ae52dSmrg unsigned long glyph_memory; 876c76ae52dSmrg FT_UInt glyphindex; 877c76ae52dSmrg XftGlyph *xftg; 8782836776bSmrg 879c76ae52dSmrg if (!font->glyph_memory) 880c76ae52dSmrg return; 881c76ae52dSmrg if (font->use_free_glyphs) 882c76ae52dSmrg { 8830e0b1094Smrg glyph_memory = ((unsigned long)rand() % font->glyph_memory); 884c76ae52dSmrg } 885c76ae52dSmrg else 886c76ae52dSmrg { 887c76ae52dSmrg if (font->glyphset) 888c76ae52dSmrg { 889c76ae52dSmrg XRenderFreeGlyphSet (dpy, font->glyphset); 890c76ae52dSmrg font->glyphset = 0; 891c76ae52dSmrg } 892c76ae52dSmrg glyph_memory = 0; 893c76ae52dSmrg } 8942836776bSmrg 895c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 896c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 897c76ae52dSmrg for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 898c76ae52dSmrg { 899c76ae52dSmrg xftg = font->glyphs[glyphindex]; 900c76ae52dSmrg if (xftg) 901c76ae52dSmrg { 902c76ae52dSmrg if (xftg->glyph_memory > glyph_memory) 903c76ae52dSmrg { 904c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHEV) 905c76ae52dSmrg printf ("Uncaching glyph 0x%x size %ld\n", 906c76ae52dSmrg glyphindex, xftg->glyph_memory); 907c76ae52dSmrg XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 908c76ae52dSmrg if (!font->use_free_glyphs) 909c76ae52dSmrg continue; 910c76ae52dSmrg break; 911c76ae52dSmrg } 912c76ae52dSmrg glyph_memory -= xftg->glyph_memory; 913c76ae52dSmrg } 914c76ae52dSmrg } 915c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 916c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 917c76ae52dSmrg} 918c76ae52dSmrg 919c76ae52dSmrg_X_HIDDEN void 920c76ae52dSmrg_XftFontManageMemory (Display *dpy, XftFont *pub) 921c76ae52dSmrg{ 922c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 923c76ae52dSmrg 924c76ae52dSmrg if (font->max_glyph_memory) 925c76ae52dSmrg { 926c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 927c76ae52dSmrg { 928c76ae52dSmrg if (font->glyph_memory > font->max_glyph_memory) 929c76ae52dSmrg printf ("Reduce memory for font 0x%lx from %ld to %ld\n", 930c76ae52dSmrg font->glyphset ? font->glyphset : (unsigned long) font, 931c76ae52dSmrg font->glyph_memory, font->max_glyph_memory); 932c76ae52dSmrg } 933c76ae52dSmrg while (font->glyph_memory > font->max_glyph_memory) 934c76ae52dSmrg _XftFontUncacheGlyph (dpy, pub); 935c76ae52dSmrg } 936c76ae52dSmrg _XftDisplayManageMemory (dpy); 937c76ae52dSmrg} 938