upload tizen2.0 source
[framework/uifw/xorg/lib/libxft.git] / src / xftglyphs.c
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 #include <freetype/ftlcdfil.h>
26
27 #include <freetype/ftsynth.h>
28
29 /*
30  * Validate the memory info for a font
31  */
32
33 static 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  */
78 static 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 = ftbit->width;
93     height = 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 = width;
138     target->rows = 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  */
159 static 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 = target->width;
172         int             height = 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 -= 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, 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, 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
343 XftFontLoadGlyphs (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 = vector.x;
460                         top = bottom = vector.y;
461                     } else {
462                         if(left > vector.x) left = vector.x;
463                         if(right < vector.x) right = vector.x;
464                         if(bottom > vector.y) bottom = vector.y;
465                         if(top < vector.y) top = vector.y;
466                     }
467
468                 }
469             }
470             left = FLOOR(left);
471             right = CEIL(right);
472             bottom = FLOOR(bottom);
473             top = CEIL(top);
474
475         } else {
476             left  = FLOOR( glyphslot->metrics.horiBearingX );
477             right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width );
478
479             top    = CEIL( glyphslot->metrics.horiBearingY );
480             bottom = 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 = vector.x >> 6;
547                 xftg->metrics.yOff = -(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 = -font->public.max_advance_width;
555                 }
556                 else
557                 {
558                     xftg->metrics.xOff = font->public.max_advance_width;
559                     xftg->metrics.yOff = 0;
560                 }
561             }
562         }
563         else
564         {
565             xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x));
566             xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y));
567         }
568
569         // compute the size of the final bitmap
570         ftbit = &glyphslot->bitmap;
571
572         width = ftbit->width;
573         height = 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  = local.width;
621         xftg->metrics.height = local.rows;
622         xftg->metrics.x      = - glyphslot->bitmap_left;
623         xftg->metrics.y      =   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);
640             if (!bufBitmap)
641                 continue;
642             bufSize = size;
643         }
644         memset (bufBitmap, 0, 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 + 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++ = 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);
703                 if (xftg->bitmap)
704                     memcpy (xftg->bitmap, bufBitmap, 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
724 XftFontUnloadGlyphs (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
775 XftFontCheckGlyph (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
816 XftCharExists (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
828 XftCharIndex (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 % 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 % font->rehash_value;
858             if (!offset)
859                 offset = 1;
860         }
861         ent = ent + offset;
862         if (ent >= font->hash_value)
863             ent -= 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 = 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 }