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