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