Initialize Tizen 2.3
[framework/uifw/xorg/lib/libxft.git] / src / xftfreetype.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
25 _X_HIDDEN FT_Library  _XftFTlibrary;
26
27 #define FT_Matrix_Equal(a,b)    ((a)->xx == (b)->xx && \
28                                  (a)->yy == (b)->yy && \
29                                  (a)->xy == (b)->xy && \
30                                  (a)->yx == (b)->yx)
31 /*
32  * List of all open files (each face in a file is managed separately)
33  */
34
35 static XftFtFile *_XftFtFiles;
36 static int XftMaxFreeTypeFiles = 5;
37
38 static XftFtFile *
39 _XftGetFile (const FcChar8 *file, int id)
40 {
41     XftFtFile   *f;
42
43     if (!XftInitFtLibrary ())
44         return NULL;
45
46     for (f = _XftFtFiles; f; f = f->next)
47     {
48         if (!strcmp (f->file, (char *) file) && f->id == id)
49         {
50             ++f->ref;
51             if (XftDebug () & XFT_DBG_REF)
52                 printf ("FontFile %s/%d matches existing (%d)\n",
53                         file, id, f->ref);
54             return f;
55         }
56     }
57     f = malloc (sizeof (XftFtFile) + strlen ((char *) file) + 1);
58     if (!f)
59         return NULL;
60
61     XftMemAlloc (XFT_MEM_FILE, sizeof (XftFtFile) + strlen ((char *) file) + 1);
62     if (XftDebug () & XFT_DBG_REF)
63         printf ("FontFile %s/%d matches new\n",
64                 file, id);
65     f->next = _XftFtFiles;
66     _XftFtFiles = f;
67
68     f->ref = 1;
69
70     f->file = (char *) (f+1);
71     strcpy (f->file, (char *) file);
72     f->id = id;
73
74     f->lock = 0;
75     f->face = NULL;
76     f->xsize = 0;
77     f->ysize = 0;
78     f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0;
79     return f;
80 }
81
82 static XftFtFile *
83 _XftGetFaceFile (FT_Face face)
84 {
85     XftFtFile   *f;
86
87     f = malloc (sizeof (XftFtFile));
88     if (!f)
89         return NULL;
90     XftMemAlloc (XFT_MEM_FILE, sizeof(XftFtFile));
91     f->next = NULL;
92
93     f->ref = 1;
94
95     f->file = NULL;
96     f->id = 0;
97     f->lock = 0;
98     f->face = face;
99     f->xsize = 0;
100     f->ysize = 0;
101     f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0;
102     return f;
103 }
104
105 static int
106 _XftNumFiles (void)
107 {
108     XftFtFile   *f;
109     int         count = 0;
110     for (f = _XftFtFiles; f; f = f->next)
111         if (f->face && !f->lock)
112             ++count;
113     return count;
114 }
115
116 static XftFtFile *
117 _XftNthFile (int n)
118 {
119     XftFtFile   *f;
120     int         count = 0;
121     for (f = _XftFtFiles; f; f = f->next)
122         if (f->face && !f->lock)
123             if (count++ == n)
124                 break;
125     return f;
126 }
127
128 static void
129 _XftUncacheFiles (void)
130 {
131     int         n;
132     XftFtFile   *f;
133     while ((n = _XftNumFiles ()) > XftMaxFreeTypeFiles)
134     {
135         f = _XftNthFile (rand () % n);
136         if (f)
137         {
138             if (XftDebug() & XFT_DBG_REF)
139                 printf ("Discard file %s/%d from cache\n",
140                         f->file, f->id);
141             FT_Done_Face (f->face);
142             f->face = NULL;
143         }
144     }
145 }
146
147 static FT_Face
148 _XftLockFile (XftFtFile *f)
149 {
150     ++f->lock;
151     if (!f->face)
152     {
153         if (XftDebug() & XFT_DBG_REF)
154             printf ("Loading file %s/%d\n", f->file, f->id);
155         if (FT_New_Face (_XftFTlibrary, f->file, f->id, &f->face))
156             --f->lock;
157
158         f->xsize = 0;
159         f->ysize = 0;
160         f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0;
161         _XftUncacheFiles ();
162     }
163     return f->face;
164 }
165
166 static void
167 _XftLockError (const char *reason)
168 {
169     fprintf (stderr, "Xft: locking error %s\n", reason);
170 }
171
172 static void
173 _XftUnlockFile (XftFtFile *f)
174 {
175     if (--f->lock < 0)
176         _XftLockError ("too many file unlocks");
177 }
178
179 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
180 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
181
182 _X_HIDDEN FcBool
183 _XftSetFace (XftFtFile *f, FT_F26Dot6 xsize, FT_F26Dot6 ysize, FT_Matrix *matrix)
184 {
185     FT_Face face = f->face;
186
187     if (f->xsize != xsize || f->ysize != ysize)
188     {
189         if (XftDebug() & XFT_DBG_GLYPH)
190             printf ("Set face size to %dx%d (%dx%d)\n",
191                     (int) (xsize >> 6), (int) (ysize >> 6), (int) xsize, (int) ysize);
192         /*
193          * Bitmap only faces must match exactly, so find the closest
194          * one (height dominant search)
195          */
196         if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
197         {
198             int         i, best = 0;
199
200 #define xft_abs(a)      ((a) < 0 ? -(a) : (a))
201 #define dist(a,b)       (xft_abs((a)-(b)))
202
203             for (i = 1; i < face->num_fixed_sizes; i++)
204             {
205                 if (dist (ysize, Y_SIZE(face,i)) <
206                     dist (ysize, Y_SIZE(face, best)) ||
207                     (dist (ysize, Y_SIZE(face, i)) ==
208                      dist (ysize, Y_SIZE(face, best)) &&
209                      dist (xsize, X_SIZE(face, i)) <
210                      dist (xsize, X_SIZE(face, best))))
211                 {
212                     best = i;
213                 }
214             }
215             /*
216              * Freetype 2.1.7 and earlier used width/height
217              * for matching sizes in the BDF and PCF loaders.
218              * This has been fixed for 2.1.8.  Because BDF and PCF
219              * files have but a single strike per file, we can
220              * simply try both sizes.
221              */
222             if (FT_Set_Char_Size (face, face->available_sizes[best].x_ppem,
223                                   face->available_sizes[best].y_ppem, 0, 0) != 0
224                 &&
225                 FT_Set_Char_Size (face, face->available_sizes[best].width << 6,
226                                   face->available_sizes[best].height << 6,
227                                   0, 0) != 0)
228             {
229                 return False;
230             }
231         }
232         else
233         {
234             if (FT_Set_Char_Size (face, xsize, ysize, 0, 0))
235             {
236                 return False;
237             }
238         }
239         f->xsize = xsize;
240         f->ysize = ysize;
241     }
242     if (!FT_Matrix_Equal (&f->matrix, matrix))
243     {
244         if (XftDebug() & XFT_DBG_GLYPH)
245             printf ("Set face matrix to (%g,%g,%g,%g)\n",
246                     (double) matrix->xx / 0x10000,
247                     (double) matrix->xy / 0x10000,
248                     (double) matrix->yx / 0x10000,
249                     (double) matrix->yy / 0x10000);
250         FT_Set_Transform (face, matrix, NULL);
251         f->matrix = *matrix;
252     }
253     return True;
254 }
255
256 static void
257 _XftReleaseFile (XftFtFile *f)
258 {
259     XftFtFile   **prev;
260
261     if (--f->ref != 0)
262         return;
263     if (f->lock)
264         _XftLockError ("Attempt to close locked file");
265     if (f->file)
266     {
267         for (prev = &_XftFtFiles; *prev; prev = &(*prev)->next)
268         {
269             if (*prev == f)
270             {
271                 *prev = f->next;
272                 break;
273             }
274         }
275         if (f->face)
276             FT_Done_Face (f->face);
277     }
278     XftMemFree (XFT_MEM_FILE,
279                 sizeof (XftFtFile) + (f->file ? strlen (f->file) + 1 : 0));
280     free (f);
281 }
282
283 /*
284  * Find a prime larger than the minimum reasonable hash size
285  */
286
287 static FcChar32
288 _XftSqrt (FcChar32 a)
289 {
290     FcChar32        l, h, m;
291
292     l = 2;
293     h = a/2;
294     while ((h-l) > 1)
295     {
296         m = (h+l) >> 1;
297         if (m * m < a)
298             l = m;
299         else
300             h = m;
301     }
302     return h;
303 }
304
305 static FcBool
306 _XftIsPrime (FcChar32 i)
307 {
308     FcChar32    l, t;
309
310     if (i < 2)
311         return FcFalse;
312     if ((i & 1) == 0)
313     {
314         if (i == 2)
315             return FcTrue;
316         return FcFalse;
317     }
318     l = _XftSqrt (i) + 1;
319     for (t = 3; t <= l; t += 2)
320         if (i % t == 0)
321             return FcFalse;
322     return FcTrue;
323 }
324
325 static FcChar32
326 _XftHashSize (FcChar32 num_unicode)
327 {
328     /* at least 31.25 % extra space */
329     FcChar32    hash = num_unicode + (num_unicode >> 2) + (num_unicode >> 4);
330
331     if ((hash & 1) == 0)
332         hash++;
333     while (!_XftIsPrime (hash))
334         hash += 2;
335     return hash;
336 }
337
338 _X_EXPORT FT_Face
339 XftLockFace (XftFont *public)
340 {
341     XftFontInt  *font = (XftFontInt *) public;
342     XftFontInfo *fi = &font->info;
343     FT_Face     face;
344
345     face = _XftLockFile (fi->file);
346     /*
347      * Make sure the face is usable at the requested size
348      */
349     if (face && !_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix))
350     {
351         _XftUnlockFile (fi->file);
352         face = NULL;
353     }
354     return face;
355 }
356
357 _X_EXPORT void
358 XftUnlockFace (XftFont *public)
359 {
360     XftFontInt  *font = (XftFontInt *) public;
361     _XftUnlockFile (font->info.file);
362 }
363
364 static FcBool
365 XftFontInfoFill (Display *dpy, _Xconst FcPattern *pattern, XftFontInfo *fi)
366 {
367     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
368     FcChar8         *filename;
369     int             id;
370     double          dsize;
371     double          aspect;
372     FcMatrix        *font_matrix;
373     FcBool          hinting, vertical_layout, autohint, global_advance;
374     int             hint_style;
375     FcChar32        hash, *hashp;
376     FT_Face         face;
377     int             nhash;
378     FcBool          bitmap;
379
380     if (!info)
381         return FcFalse;
382
383     /*
384      * Initialize the whole XftFontInfo so that padding doesn't interfere with
385      * hash or XftFontInfoEqual().
386      */
387
388     memset (fi, '\0', sizeof(*fi));
389
390     /*
391      * Find the associated file
392      */
393     switch (FcPatternGetString (pattern, FC_FILE, 0, &filename)) {
394     case FcResultNoMatch:
395         filename = NULL;
396         break;
397     case FcResultMatch:
398         break;
399     default:
400         goto bail0;
401     }
402
403     switch (FcPatternGetInteger (pattern, FC_INDEX, 0, &id)) {
404     case FcResultNoMatch:
405         id = 0;
406         break;
407     case FcResultMatch:
408         break;
409     default:
410         goto bail0;
411     }
412
413     if (filename)
414         fi->file = _XftGetFile (filename, id);
415     else if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &face) == FcResultMatch
416              && face)
417         fi->file = _XftGetFaceFile (face);
418     if (!fi->file)
419         goto bail0;
420
421     /*
422      * Compute pixel size
423      */
424     if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch)
425         goto bail1;
426
427     if (FcPatternGetDouble (pattern, FC_ASPECT, 0, &aspect) != FcResultMatch)
428         aspect = 1.0;
429
430     fi->ysize = (FT_F26Dot6) (dsize * 64.0);
431     fi->xsize = (FT_F26Dot6) (dsize * aspect * 64.0);
432
433     if (XftDebug() & XFT_DBG_OPEN)
434         printf ("XftFontInfoFill: %s: %d (%g pixels)\n",
435                 (filename ? filename : (FcChar8 *) "<none>"), id, dsize);
436     /*
437      * Get antialias value
438      */
439     switch (FcPatternGetBool (pattern, FC_ANTIALIAS, 0, &fi->antialias)) {
440     case FcResultNoMatch:
441         fi->antialias = True;
442         break;
443     case FcResultMatch:
444         break;
445     default:
446         goto bail1;
447     }
448
449     /*
450      * Get rgba value
451      */
452     switch (FcPatternGetInteger (pattern, FC_RGBA, 0, &fi->rgba)) {
453     case FcResultNoMatch:
454         fi->rgba = FC_RGBA_UNKNOWN;
455         break;
456     case FcResultMatch:
457         break;
458     default:
459         goto bail1;
460     }
461
462     /*
463      * Get lcd_filter value
464      */
465     switch (FcPatternGetInteger (pattern, FC_LCD_FILTER, 0, &fi->lcd_filter)) {
466     case FcResultNoMatch:
467         fi->lcd_filter = FC_LCD_DEFAULT;
468         break;
469     case FcResultMatch:
470         break;
471     default:
472         goto bail1;
473     }
474
475     /*
476      * Get matrix and transform values
477      */
478     switch (FcPatternGetMatrix (pattern, FC_MATRIX, 0, &font_matrix)) {
479     case FcResultNoMatch:
480         fi->matrix.xx = fi->matrix.yy = 0x10000;
481         fi->matrix.xy = fi->matrix.yx = 0;
482         break;
483     case FcResultMatch:
484         fi->matrix.xx = 0x10000L * font_matrix->xx;
485         fi->matrix.yy = 0x10000L * font_matrix->yy;
486         fi->matrix.xy = 0x10000L * font_matrix->xy;
487         fi->matrix.yx = 0x10000L * font_matrix->yx;
488         break;
489     default:
490         goto bail1;
491     }
492
493     fi->transform = (fi->matrix.xx != 0x10000 || fi->matrix.xy != 0 ||
494                      fi->matrix.yx != 0 || fi->matrix.yy != 0x10000);
495
496     /*
497      * Get render value, set to false if no Render extension present
498      */
499     if (info->hasRender)
500     {
501         switch (FcPatternGetBool (pattern, XFT_RENDER, 0, &fi->render)) {
502         case FcResultNoMatch:
503             fi->render = info->hasRender;
504             break;
505         case FcResultMatch:
506             break;
507         default:
508             goto bail1;
509         }
510     }
511     else
512         fi->render = FcFalse;
513
514     /*
515      * Compute glyph load flags
516      */
517     fi->load_flags = FT_LOAD_DEFAULT;
518
519 #ifndef XFT_EMBEDDED_BITMAP
520 #define XFT_EMBEDDED_BITMAP "embeddedbitmap"
521 #endif
522
523     switch (FcPatternGetBool (pattern, XFT_EMBEDDED_BITMAP, 0, &bitmap)) {
524     case FcResultNoMatch:
525         bitmap = FcFalse;
526         break;
527     case FcResultMatch:
528         break;
529     default:
530         goto bail1;
531     }
532
533     /* disable bitmaps when anti-aliasing or transforming glyphs */
534     if ((!bitmap && fi->antialias) || fi->transform)
535         fi->load_flags |= FT_LOAD_NO_BITMAP;
536
537     /* disable hinting if requested */
538     switch (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting)) {
539     case FcResultNoMatch:
540         hinting = FcTrue;
541         break;
542     case FcResultMatch:
543         break;
544     default:
545         goto bail1;
546     }
547
548     switch (FcPatternGetBool (pattern, FC_EMBOLDEN, 0, &fi->embolden)) {
549     case FcResultNoMatch:
550         fi->embolden = FcFalse;
551         break;
552     case FcResultMatch:
553         break;
554     default:
555         goto bail1;
556     }
557
558     switch (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style)) {
559     case FcResultNoMatch:
560         hint_style = FC_HINT_FULL;
561         break;
562     case FcResultMatch:
563         break;
564     default:
565         goto bail1;
566     }
567
568     if (!hinting
569         || hint_style == FC_HINT_NONE
570         )
571     {
572         fi->load_flags |= FT_LOAD_NO_HINTING;
573     }
574
575     /* Figure out the load target, which modifies the hinting
576      * behavior of FreeType based on the intended use of the glyphs.
577      */
578     if (fi->antialias)
579     {
580         if (FC_HINT_NONE < hint_style && hint_style < FC_HINT_FULL)
581         {
582             fi->load_flags |= FT_LOAD_TARGET_LIGHT;
583         }
584         else
585         {
586             /* autohinter will snap stems to integer widths, when
587              * the LCD targets are used.
588              */
589             switch (fi->rgba) {
590             case FC_RGBA_RGB:
591             case FC_RGBA_BGR:
592                 fi->load_flags |= FT_LOAD_TARGET_LCD;
593                 break;
594             case FC_RGBA_VRGB:
595             case FC_RGBA_VBGR:
596                 fi->load_flags |= FT_LOAD_TARGET_LCD_V;
597                 break;
598             }
599         }
600     }
601     else
602         fi->load_flags |= FT_LOAD_TARGET_MONO;
603
604     /* set vertical layout if requested */
605     switch (FcPatternGetBool (pattern, FC_VERTICAL_LAYOUT, 0, &vertical_layout)) {
606     case FcResultNoMatch:
607         vertical_layout = FcFalse;
608         break;
609     case FcResultMatch:
610         break;
611     default:
612         goto bail1;
613     }
614
615     if (vertical_layout)
616         fi->load_flags |= FT_LOAD_VERTICAL_LAYOUT;
617
618     /* force autohinting if requested */
619     switch (FcPatternGetBool (pattern, FC_AUTOHINT, 0, &autohint)) {
620     case FcResultNoMatch:
621         autohint = FcFalse;
622         break;
623     case FcResultMatch:
624         break;
625     default:
626         goto bail1;
627     }
628
629     if (autohint)
630         fi->load_flags |= FT_LOAD_FORCE_AUTOHINT;
631
632     /* disable global advance width (for broken DynaLab TT CJK fonts) */
633     switch (FcPatternGetBool (pattern, FC_GLOBAL_ADVANCE, 0, &global_advance)) {
634     case FcResultNoMatch:
635         global_advance = FcTrue;
636         break;
637     case FcResultMatch:
638         break;
639     default:
640         goto bail1;
641     }
642
643     if (!global_advance)
644         fi->load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
645
646     /*
647      * Get requested spacing value
648      */
649     switch (FcPatternGetInteger (pattern, FC_SPACING, 0, &fi->spacing)) {
650     case FcResultNoMatch:
651         fi->spacing = FC_PROPORTIONAL;
652         break;
653     case FcResultMatch:
654         break;
655     default:
656         goto bail1;
657     }
658
659     /*
660      * Check for minspace
661      */
662
663     switch (FcPatternGetBool (pattern, FC_MINSPACE, 0, &fi->minspace)) {
664     case FcResultNoMatch:
665         fi->minspace = FcFalse;
666         break;
667     case FcResultMatch:
668         break;
669     default:
670         goto bail1;
671     }
672     /*
673      * Check for fixed pixel spacing
674      */
675     switch (FcPatternGetInteger (pattern, FC_CHAR_WIDTH, 0, &fi->char_width)) {
676     case FcResultNoMatch:
677         fi->char_width = 0;
678         break;
679     case FcResultMatch:
680         if (fi->char_width)
681             fi->spacing = FC_MONO;
682         break;
683     default:
684         goto bail1;
685     }
686
687     /*
688      * Step over hash value in the structure
689      */
690     hash = 0;
691     hashp = (FcChar32 *) fi + 1;
692     nhash = (sizeof (XftFontInfo) / sizeof (FcChar32)) - 1;
693
694     while (nhash--)
695         hash += *hashp++;
696     fi->hash = hash;
697
698     /*
699      * All done
700      */
701     return FcTrue;
702
703 bail1:
704     _XftReleaseFile (fi->file);
705     fi->file = NULL;
706 bail0:
707     return FcFalse;
708 }
709
710 static void
711 XftFontInfoEmpty (Display *dpy, XftFontInfo *fi)
712 {
713     if (fi->file)
714         _XftReleaseFile (fi->file);
715 }
716
717 XftFontInfo *
718 XftFontInfoCreate (Display *dpy, _Xconst FcPattern *pattern)
719 {
720     XftFontInfo *fi = malloc (sizeof (XftFontInfo));
721
722     if (!fi)
723         return NULL;
724
725     if (!XftFontInfoFill (dpy, pattern, fi))
726     {
727         free (fi);
728         fi = NULL;
729     }
730     XftMemAlloc (XFT_MEM_FONT, sizeof (XftFontInfo));
731     return fi;
732 }
733
734 _X_EXPORT void
735 XftFontInfoDestroy (Display *dpy, XftFontInfo *fi)
736 {
737     XftFontInfoEmpty (dpy, fi);
738     XftMemFree (XFT_MEM_FONT, sizeof (XftFontInfo));
739     free (fi);
740 }
741
742 _X_EXPORT FcChar32
743 XftFontInfoHash (_Xconst XftFontInfo *fi)
744 {
745     return fi->hash;
746 }
747
748 _X_EXPORT FcBool
749 XftFontInfoEqual (_Xconst XftFontInfo *a, _Xconst XftFontInfo *b)
750 {
751     return memcmp ((void *) a, (void *) b, sizeof (XftFontInfo)) == 0;
752 }
753
754 _X_EXPORT XftFont *
755 XftFontOpenInfo (Display        *dpy,
756                  FcPattern      *pattern,
757                  XftFontInfo    *fi)
758 {
759     XftDisplayInfo      *info = _XftDisplayInfoGet (dpy, True);
760     FT_Face             face;
761     XftFont             **bucket;
762     XftFontInt          *font;
763     XRenderPictFormat   *format;
764     FcCharSet           *charset;
765     FcChar32            num_unicode;
766     FcChar32            hash_value;
767     FcChar32            rehash_value;
768     FcBool              antialias;
769     int                 max_glyph_memory;
770     int                 alloc_size;
771     int                 ascent, descent, height;
772     int                 i;
773     int                 num_glyphs;
774
775     if (!info)
776         return NULL;
777     /*
778      * Find a matching previously opened font
779      */
780     bucket = &info->fontHash[fi->hash % XFT_NUM_FONT_HASH];
781     for (font = (XftFontInt *) *bucket; font; font = (XftFontInt *) font->hash_next)
782         if (XftFontInfoEqual (&font->info, fi))
783         {
784             if (!font->ref++)
785                 --info->num_unref_fonts;
786             FcPatternDestroy (pattern);
787             return &font->public;
788         }
789
790     /*
791      * No existing font, create another.
792      */
793
794     if (XftDebug () & XFT_DBG_CACHE)
795         printf ("New font %s/%d size %dx%d\n",
796                 fi->file->file, fi->file->id,
797                 (int) fi->xsize >> 6, (int) fi->ysize >> 6);
798
799     if (FcPatternGetInteger (pattern, XFT_MAX_GLYPH_MEMORY, 0,
800                              &max_glyph_memory) != FcResultMatch)
801         max_glyph_memory = XFT_FONT_MAX_GLYPH_MEMORY;
802
803     face = _XftLockFile (fi->file);
804     if (!face)
805         goto bail0;
806
807     if (!_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix))
808         goto bail1;
809
810     /*
811      * Get the set of Unicode codepoints covered by the font.
812      * If the incoming pattern doesn't provide this data, go
813      * off and compute it.  Yes, this is expensive, but it's
814      * required to map Unicode to glyph indices.
815      */
816     if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) == FcResultMatch)
817         charset = FcCharSetCopy (charset);
818     else
819         charset = FcFreeTypeCharSet (face, FcConfigGetBlanks (NULL));
820
821     antialias = fi->antialias;
822     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
823         antialias = FcFalse;
824
825     /*
826      * Find the appropriate picture format
827      */
828     if (fi->render)
829     {
830         if (antialias)
831         {
832             switch (fi->rgba) {
833             case FC_RGBA_RGB:
834             case FC_RGBA_BGR:
835             case FC_RGBA_VRGB:
836             case FC_RGBA_VBGR:
837                 format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
838                 break;
839             default:
840                 format = XRenderFindStandardFormat (dpy, PictStandardA8);
841                 break;
842             }
843         }
844         else
845         {
846             format = XRenderFindStandardFormat (dpy, PictStandardA1);
847         }
848
849         if (!format)
850             goto bail2;
851     }
852     else
853         format = NULL;
854
855     if (charset)
856     {
857         num_unicode = FcCharSetCount (charset);
858         hash_value = _XftHashSize (num_unicode);
859         rehash_value = hash_value - 2;
860     }
861     else
862     {
863         num_unicode = 0;
864         hash_value = 0;
865         rehash_value = 0;
866     }
867
868     /*
869      * Sometimes the glyphs are numbered 1..n, other times 0..n-1,
870      * accept either numbering scheme by making room in the table
871      */
872     num_glyphs = face->num_glyphs + 1;
873     alloc_size = (sizeof (XftFontInt) +
874                   num_glyphs * sizeof (XftGlyph *) +
875                   hash_value * sizeof (XftUcsHash));
876     font = malloc (alloc_size);
877
878     if (!font)
879         goto bail2;
880
881     XftMemAlloc (XFT_MEM_FONT, alloc_size);
882
883     /*
884      * Public fields
885      */
886     if (fi->transform)
887     {
888         FT_Vector       vector;
889
890         vector.x = 0;
891         vector.y = face->size->metrics.descender;
892         FT_Vector_Transform (&vector, &fi->matrix);
893         descent = -(vector.y >> 6);
894
895         vector.x = 0;
896         vector.y = face->size->metrics.ascender;
897         FT_Vector_Transform (&vector, &fi->matrix);
898         ascent = vector.y >> 6;
899
900         if (fi->minspace)
901             height = ascent + descent;
902         else
903         {
904             vector.x = 0;
905             vector.y = face->size->metrics.height;
906             FT_Vector_Transform (&vector, &fi->matrix);
907             height = vector.y >> 6;
908         }
909     }
910     else
911     {
912         descent = -(face->size->metrics.descender >> 6);
913         ascent = face->size->metrics.ascender >> 6;
914         if (fi->minspace)
915             height = ascent + descent;
916         else
917             height = face->size->metrics.height >> 6;
918     }
919     font->public.ascent = ascent;
920     font->public.descent = descent;
921     font->public.height = height;
922
923     if (fi->char_width)
924         font->public.max_advance_width = fi->char_width;
925     else
926     {
927         if (fi->transform)
928         {
929             FT_Vector   vector;
930             vector.x = face->size->metrics.max_advance;
931             vector.y = 0;
932             FT_Vector_Transform (&vector, &fi->matrix);
933             font->public.max_advance_width = vector.x >> 6;
934         }
935         else
936             font->public.max_advance_width = face->size->metrics.max_advance >> 6;
937     }
938     font->public.charset = charset;
939     font->public.pattern = pattern;
940
941     /*
942      * Management fields
943      */
944     font->ref = 1;
945
946     font->next = info->fonts;
947     info->fonts = &font->public;
948
949     font->hash_next = *bucket;
950     *bucket = &font->public;
951
952     /*
953      * Copy the info over
954      */
955     font->info = *fi;
956     /*
957      * reset the antialias field.  It can't
958      * be set correctly until the font is opened,
959      * which doesn't happen in XftFontInfoFill
960      */
961     font->info.antialias = antialias;
962     /*
963      * bump XftFile reference count
964      */
965     font->info.file->ref++;
966
967     /*
968      * Per glyph information
969      */
970     font->glyphs = (XftGlyph **) (font + 1);
971     memset (font->glyphs, '\0', num_glyphs * sizeof (XftGlyph *));
972     font->num_glyphs = num_glyphs;
973     /*
974      * Unicode hash table information
975      */
976     font->hash_table = (XftUcsHash *) (font->glyphs + font->num_glyphs);
977     for (i = 0; i < hash_value; i++)
978     {
979         font->hash_table[i].ucs4 = ((FcChar32) ~0);
980         font->hash_table[i].glyph = 0;
981     }
982     font->hash_value = hash_value;
983     font->rehash_value = rehash_value;
984     /*
985      * X specific fields
986      */
987     font->glyphset = 0;
988     font->format = format;
989
990     /*
991      * Glyph memory management fields
992      */
993     font->glyph_memory = 0;
994     font->max_glyph_memory = max_glyph_memory;
995     font->use_free_glyphs = info->use_free_glyphs;
996
997     _XftUnlockFile (fi->file);
998
999     return &font->public;
1000
1001 bail2:
1002     FcCharSetDestroy (charset);
1003 bail1:
1004     _XftUnlockFile (fi->file);
1005 bail0:
1006     return NULL;
1007 }
1008
1009 _X_EXPORT XftFont *
1010 XftFontOpenPattern (Display *dpy, FcPattern *pattern)
1011 {
1012     XftFontInfo     info;
1013     XftFont         *font;
1014
1015     if (!XftFontInfoFill (dpy, pattern, &info))
1016         return NULL;
1017
1018     font = XftFontOpenInfo (dpy, pattern, &info);
1019     XftFontInfoEmpty (dpy, &info);
1020     return font;
1021 }
1022
1023 _X_EXPORT XftFont *
1024 XftFontCopy (Display *dpy, XftFont *public)
1025 {
1026     XftFontInt      *font = (XftFontInt *) public;
1027
1028     font->ref++;
1029     return public;
1030 }
1031
1032 static void
1033 XftFontDestroy (Display *dpy, XftFont *public)
1034 {
1035     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
1036     XftFontInt      *font = (XftFontInt *) public;
1037     int             i;
1038
1039     /* note reduction in memory use */
1040     if (info)
1041         info->glyph_memory -= font->glyph_memory;
1042     /* Clean up the info */
1043     XftFontInfoEmpty (dpy, &font->info);
1044     /* Free the glyphset */
1045     if (font->glyphset)
1046         XRenderFreeGlyphSet (dpy, font->glyphset);
1047     /* Free the glyphs */
1048     for (i = 0; i < font->num_glyphs; i++)
1049     {
1050         XftGlyph        *xftg = font->glyphs[i];
1051         if (xftg)
1052         {
1053             if (xftg->bitmap)
1054                 free (xftg->bitmap);
1055             free (xftg);
1056         }
1057     }
1058
1059     /* Free the pattern and the charset */
1060     FcPatternDestroy (font->public.pattern);
1061     FcCharSetDestroy (font->public.charset);
1062
1063     /* Finally, free the font structure */
1064     XftMemFree (XFT_MEM_FONT, sizeof (XftFontInt) +
1065                 font->num_glyphs * sizeof (XftGlyph *) +
1066                 font->hash_value * sizeof (XftUcsHash));
1067     free (font);
1068 }
1069
1070 static XftFont *
1071 XftFontFindNthUnref (XftDisplayInfo *info, int n)
1072 {
1073     XftFont     *public;
1074     XftFontInt  *font;
1075
1076     for (public = info->fonts; public; public = font->next)
1077     {
1078         font = (XftFontInt*) public;
1079         if (!font->ref && !n--)
1080             break;
1081     }
1082     return public;
1083 }
1084
1085 _X_HIDDEN void
1086 XftFontManageMemory (Display *dpy)
1087 {
1088     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
1089     XftFont         **prev;
1090     XftFont         *public;
1091     XftFontInt      *font;
1092
1093     if (!info)
1094         return;
1095     while (info->num_unref_fonts > info->max_unref_fonts)
1096     {
1097         public = XftFontFindNthUnref (info, rand() % info->num_unref_fonts);
1098         font = (XftFontInt *) public;
1099
1100         if (XftDebug () & XFT_DBG_CACHE)
1101             printf ("freeing unreferenced font %s/%d size %dx%d\n",
1102                     font->info.file->file, font->info.file->id,
1103                     (int) font->info.xsize >> 6, (int) font->info.ysize >> 6);
1104
1105         /* Unhook from display list */
1106         for (prev = &info->fonts; *prev; prev = &(*(XftFontInt **) prev)->next)
1107         {
1108             if (*prev == public)
1109             {
1110                 *prev = font->next;
1111                 break;
1112             }
1113         }
1114         /* Unhook from hash list */
1115         for (prev = &info->fontHash[font->info.hash % XFT_NUM_FONT_HASH];
1116              *prev;
1117              prev = &(*(XftFontInt **) prev)->hash_next)
1118         {
1119             if (*prev == public)
1120             {
1121                 *prev = font->hash_next;
1122                 break;
1123             }
1124         }
1125         /* Destroy the font */
1126         XftFontDestroy (dpy, public);
1127         --info->num_unref_fonts;
1128     }
1129 }
1130
1131 _X_EXPORT void
1132 XftFontClose (Display *dpy, XftFont *public)
1133 {
1134     XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
1135     XftFontInt      *font = (XftFontInt *) public;
1136
1137     if (--font->ref != 0)
1138         return;
1139
1140     if (info)
1141     {
1142         ++info->num_unref_fonts;
1143         XftFontManageMemory (dpy);
1144     }
1145     else
1146     {
1147         XftFontDestroy (dpy, public);
1148     }
1149 }
1150
1151 _X_EXPORT FcBool
1152 XftInitFtLibrary (void)
1153 {
1154     if (_XftFTlibrary)
1155         return FcTrue;
1156     if (FT_Init_FreeType (&_XftFTlibrary))
1157         return FcFalse;
1158     return FcTrue;
1159 }