]> git.wh0rd.org Git - fontconfig.git/blob - src/fcfreetype.c
Debug output for unknown ps weight names. ignore italic_angle for PS fonts
[fontconfig.git] / src / fcfreetype.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcfreetype.c,v 1.11 2002/08/31 22:17:32 keithp Exp $
3  *
4  * Copyright © 2001 Keith Packard
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 /*
26   Copyright © 2002-2003 by Juliusz Chroboczek
27
28   Permission is hereby granted, free of charge, to any person obtaining a copy
29   of this software and associated documentation files (the "Software"), to deal
30   in the Software without restriction, including without limitation the rights
31   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32   copies of the Software, and to permit persons to whom the Software is
33   furnished to do so, subject to the following conditions:
34
35   The above copyright notice and this permission notice shall be included in
36   all copies or substantial portions of the Software.
37
38   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
41   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44   THE SOFTWARE.
45 */
46
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include "fcint.h"
51 #include <freetype/freetype.h>
52 #include <freetype/internal/ftobjs.h>
53 #include <freetype/tttables.h>
54 #include <freetype/ftsnames.h>
55 #include <freetype/ttnameid.h>
56 #include <freetype/t1tables.h>
57
58 #if (FREETYPE_MINOR > 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH >= 4))
59 #include <freetype/ftbdf.h>
60 #include <freetype/ftmodule.h>
61 #define USE_FTBDF
62 #define HAS_BDF_PROPERTY(f) ((f) && (f)->driver && \
63                              (f)->driver->root.clazz->get_interface)
64 #define MY_Get_BDF_Property(f,n,p) (HAS_BDF_PROPERTY(f) ? \
65                                     FT_Get_BDF_Property(f,n,p) : \
66                                     FT_Err_Invalid_Argument)
67 #endif
68
69
70 /*
71  * Keep Han languages separated by eliminating languages
72  * that the codePageRange bits says aren't supported
73  */
74
75 static const struct {
76     int             bit;
77     const FcChar8   *lang;
78 } FcCodePageRange[] = {
79     { 17,       (const FcChar8 *) "ja" },
80     { 18,       (const FcChar8 *) "zh-cn" },
81     { 19,       (const FcChar8 *) "ko" },
82     { 20,       (const FcChar8 *) "zh-tw" },
83 };
84
85 #define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
86
87 FcBool
88 FcFreeTypeIsExclusiveLang (const FcChar8  *lang)
89 {
90     int     i;
91
92     for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
93     {
94         if (FcLangCompare (lang, FcCodePageRange[i].lang) != FcLangDifferentLang)
95             return FcTrue;
96     }
97     return FcFalse;
98 }
99
100 #define FC_NAME_PRIO_LANG           0x0f00
101 #define FC_NAME_PRIO_LANG_ENGLISH   0x0200
102 #define FC_NAME_PRIO_LANG_LATIN     0x0100
103 #define FC_NAME_PRIO_LANG_NONE      0x0000
104
105 #define FC_NAME_PRIO_ENC            0x00f0
106 #define FC_NAME_PRIO_ENC_UNICODE    0x0010
107 #define FC_NAME_PRIO_ENC_NONE       0x0000
108
109 #define FC_NAME_PRIO_NAME           0x000f
110 #define FC_NAME_PRIO_NAME_FAMILY    0x0002
111 #define FC_NAME_PRIO_NAME_PS        0x0001
112 #define FC_NAME_PRIO_NAME_NONE      0x0000
113
114 static FcBool
115 FcUcs4IsLatin (FcChar32 ucs4)
116 {
117     FcChar32    page = ucs4 >> 8;
118     
119     if (page <= 2)
120         return FcTrue;
121     if (page == 0x1e)
122         return FcTrue;
123     if (0x20 <= page && page <= 0x23)
124         return FcTrue;
125     if (page == 0xfb)
126         return FcTrue;
127     /* halfwidth forms, don't include kana or white parens */
128     if (0xff01 <= ucs4 && ucs4 <= 0xff5e)
129         return FcTrue;
130     return FcFalse;
131 }
132
133 static FcBool
134 FcUtf8IsLatin (FcChar8 *str, int len)
135 {
136     while (len)
137     {
138         FcChar32    ucs4;
139         int         clen = FcUtf8ToUcs4 (str, &ucs4, len);
140         if (clen <= 0)
141             return FcFalse;
142         if (!FcUcs4IsLatin (ucs4))
143             return FcFalse;
144         len -= clen;
145         str += clen;
146     }
147     return FcTrue;
148 }
149
150 /* Order is significant.  For example, some B&H fonts are hinted by
151    URW++, and both strings appear in the notice. */
152
153 static const struct {
154     const FcChar8   *notice;
155     const FcChar8   *foundry;
156 } FcNoticeFoundries[] = {
157     { (const FcChar8*) "Bigelow",       (const FcChar8 *) "b&h" },
158     { (const FcChar8*) "Adobe",         (const FcChar8 *) "adobe" },
159     { (const FcChar8*) "Bitstream",     (const FcChar8 *) "bitsteam" },
160     { (const FcChar8*) "Monotype",      (const FcChar8 *) "monotype" },
161     { (const FcChar8*) "Linotype",      (const FcChar8 *) "linotype" },
162     { (const FcChar8*) "LINOTYPE-HELL", (const FcChar8 *) "linotype" },
163     { (const FcChar8*) "IBM",           (const FcChar8 *) "ibm" },
164     { (const FcChar8*) "URW",           (const FcChar8 *) "urw" },
165     { (const FcChar8*) "International Typeface Corporation", 
166                                         (const FcChar8 *) "itc" },
167     { (const FcChar8*) "Tiro Typeworks",(const FcChar8 *) "tiro" },
168     { (const FcChar8*) "XFree86",       (const FcChar8 *) "xfree86" },
169     { (const FcChar8*) "Microsoft",     (const FcChar8 *) "microsoft" },
170     { (const FcChar8*) "Omega",         (const FcChar8 *) "omega" },
171     { (const FcChar8*) "Font21",        (const FcChar8 *) "hwan" },
172     { (const FcChar8*) "HanYang System",(const FcChar8 *) "hanyang" }
173 };
174
175 #define NUM_NOTICE_FOUNDRIES    (sizeof (FcNoticeFoundries) / sizeof (FcNoticeFoundries[0]))
176
177 static const FcChar8 *
178 FcNoticeFoundry(const char *notice)
179 {
180     int i;
181
182     if (notice)
183         for(i = 0; i < NUM_NOTICE_FOUNDRIES; i++)
184             if (strstr ((const char *) notice, (const char *) FcNoticeFoundries[i].notice))
185                 return FcNoticeFoundries[i].foundry;
186     return 0;
187 }
188
189 static FcBool
190 FcVendorMatch(const char *vendor, const char *vendor_string)
191 {
192     /* vendor is not necessarily NUL-terminated. */
193     int i, len;
194     
195     len = strlen(vendor_string);
196     if (memcmp(vendor, vendor_string, len) != 0)
197         return FcFalse;
198     for (i = len; i < 4; i++)
199         if (vendor[i] != ' ' && vendor[i] != '\0')
200             return FcFalse;
201     return FcTrue;
202 }
203
204 /* This table is partly taken from ttmkfdir by Joerg Pommnitz. */
205
206 /* It should not contain useless entries (such as UNKN) nor duplicate
207    entries for padding both with spaces and NULs. */
208
209 static const struct {
210     const FcChar8   *vendor;
211     const FcChar8   *foundry;
212 } FcVendorFoundries[] = {
213     { (const FcChar8*) "ADBE", (const FcChar8 *) "adobe"},
214     { (const FcChar8*) "AGFA", (const FcChar8 *) "agfa"},
215     { (const FcChar8*) "ALTS", (const FcChar8 *) "altsys"},
216     { (const FcChar8*) "APPL", (const FcChar8 *) "apple"},
217     { (const FcChar8*) "ARPH", (const FcChar8 *) "arphic"},
218     { (const FcChar8*) "ATEC", (const FcChar8 *) "alltype"},
219     { (const FcChar8*) "B&H",  (const FcChar8 *) "b&h"},
220     { (const FcChar8*) "BITS", (const FcChar8 *) "bitstream"},
221     { (const FcChar8*) "CANO", (const FcChar8 *) "cannon"},
222     { (const FcChar8*) "DYNA", (const FcChar8 *) "dynalab"},
223     { (const FcChar8*) "EPSN", (const FcChar8 *) "epson"},
224     { (const FcChar8*) "FJ",   (const FcChar8 *) "fujitsu"},
225     { (const FcChar8*) "IBM",  (const FcChar8 *) "ibm"},
226     { (const FcChar8*) "ITC",  (const FcChar8 *) "itc"},
227     { (const FcChar8*) "IMPR", (const FcChar8 *) "impress"},
228     { (const FcChar8*) "LARA", (const FcChar8 *) "larabiefonts"},
229     { (const FcChar8*) "LEAF", (const FcChar8 *) "interleaf"},
230     { (const FcChar8*) "LETR", (const FcChar8 *) "letraset"},
231     { (const FcChar8*) "LINO", (const FcChar8 *) "linotype"},
232     { (const FcChar8*) "MACR", (const FcChar8 *) "macromedia"},
233     { (const FcChar8*) "MONO", (const FcChar8 *) "monotype"},
234     { (const FcChar8*) "MS",   (const FcChar8 *) "microsoft"},
235     { (const FcChar8*) "MT",   (const FcChar8 *) "monotype"},
236     { (const FcChar8*) "NEC",  (const FcChar8 *) "nec"},
237     { (const FcChar8*) "PARA", (const FcChar8 *) "paratype"},
238     { (const FcChar8*) "QMSI", (const FcChar8 *) "qms"},
239     { (const FcChar8*) "RICO", (const FcChar8 *) "ricoh"},
240     { (const FcChar8*) "URW",  (const FcChar8 *) "urw"},
241     { (const FcChar8*) "Y&Y",  (const FcChar8 *) "y&y"}
242 };
243
244 #define NUM_VENDOR_FOUNDRIES    (sizeof (FcVendorFoundries) / sizeof (FcVendorFoundries[0]))
245
246 static const FcChar8 *
247 FcVendorFoundry(const char *vendor)
248 {
249     int i;
250     
251     if (vendor)
252         for(i = 0; i < NUM_VENDOR_FOUNDRIES; i++)
253             if (FcVendorMatch (vendor, FcVendorFoundries[i].vendor))
254                 return FcVendorFoundries[i].foundry;
255     return 0;
256 }
257
258
259 FcPattern *
260 FcFreeTypeQuery (const FcChar8  *file,
261                  int            id,
262                  FcBlanks       *blanks,
263                  int            *count)
264 {
265     FT_Face         face;
266     FcPattern       *pat;
267     int             slant;
268     int             weight;
269     int             width = -1;
270     int             i;
271     FcCharSet       *cs;
272     FcLangSet       *ls;
273     FT_Library      ftLibrary;
274     FcChar8         *family = 0;
275     FcChar8         *style = 0;
276     const FcChar8   *foundry = 0;
277     int             spacing;
278     TT_OS2          *os2;
279     PS_FontInfoRec  psfontinfo;
280     TT_Header       *head;
281     const FcChar8   *exclusiveLang = 0;
282     FT_SfntName     sname;
283     FT_UInt         snamei, snamec;
284     FcBool          family_allocated = FcFalse;
285     FcBool          style_allocated = FcFalse;
286     int             family_prio = 0;
287     int             style_prio = 0;
288
289     if (FT_Init_FreeType (&ftLibrary))
290         return 0;
291     
292     if (FT_New_Face (ftLibrary, (char *) file, id, &face))
293         goto bail;
294
295     *count = face->num_faces;
296
297     pat = FcPatternCreate ();
298     if (!pat)
299         goto bail0;
300
301     if (!FcPatternAddBool (pat, FC_OUTLINE,
302                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
303         goto bail1;
304
305     if (!FcPatternAddBool (pat, FC_SCALABLE,
306                            (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
307         goto bail1;
308
309
310     slant = FC_SLANT_ROMAN;
311     if (face->style_flags & FT_STYLE_FLAG_ITALIC)
312         slant = FC_SLANT_ITALIC;
313
314
315     weight = FC_WEIGHT_MEDIUM;
316     if (face->style_flags & FT_STYLE_FLAG_BOLD)
317         weight = FC_WEIGHT_BOLD;
318
319     /*
320      * Get the OS/2 table
321      */
322     os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
323
324     /*
325      * Look first in the OS/2 table for the foundry, if
326      * not found here, the various notices will be searched for
327      * that information, either from the sfnt name tables or
328      * the Postscript FontInfo dictionary.  Finally, the
329      * BDF properties will queried.
330      */
331     
332     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
333         foundry = FcVendorFoundry(os2->achVendID);
334
335     /*
336      * Grub through the name table looking for family
337      * and style names.  FreeType makes quite a hash
338      * of them
339      */
340     snamec = FT_Get_Sfnt_Name_Count (face);
341     for (snamei = 0; snamei < snamec; snamei++)
342     {
343         FcChar8         *utf8;
344         int             len;
345         int             wchar;
346         FcChar8         *src;
347         int             src_len;
348         FcChar8         *u8;
349         FcChar32        ucs4;
350         int             ilen, olen;
351         int             prio = 0;
352         
353         const FcCharMap *map;
354         enum {
355             FcNameEncodingUtf16, 
356             FcNameEncodingAppleRoman,
357             FcNameEncodingLatin1 
358         } encoding;
359         
360         
361         if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
362             break;
363         
364         /*
365          * Look for Unicode strings
366          */
367         switch (sname.platform_id) {
368         case TT_PLATFORM_APPLE_UNICODE:
369             /*
370              * All APPLE_UNICODE encodings are Utf16 BE
371              *
372              * Because there's no language id for Unicode,
373              * assume it's English
374              */
375             prio |= FC_NAME_PRIO_LANG_ENGLISH;
376             prio |= FC_NAME_PRIO_ENC_UNICODE;
377             encoding = FcNameEncodingUtf16;
378             break;
379         case TT_PLATFORM_MACINTOSH:
380             switch (sname.encoding_id) {
381             case TT_MAC_ID_ROMAN:
382                 encoding = FcNameEncodingAppleRoman;
383                 break;
384             default:
385                 continue;
386             }
387             switch (sname.language_id) {
388             case TT_MAC_LANGID_ENGLISH:
389                 prio |= FC_NAME_PRIO_LANG_ENGLISH;
390                 break;
391             default:
392                 /*
393                  * Sometimes Microsoft language ids
394                  * end up in the macintosh table.  This
395                  * is often accompanied by data in
396                  * some mystic encoding.  Ignore these names
397                  */
398                 if (sname.language_id >= 0x100)
399                     continue;
400                 break;
401             }
402             break;
403         case TT_PLATFORM_MICROSOFT:
404             switch (sname.encoding_id) {
405             case TT_MS_ID_UNICODE_CS:
406                 encoding = FcNameEncodingUtf16;
407                 prio |= FC_NAME_PRIO_ENC_UNICODE;
408                 break;
409             default:
410                 continue;
411             }
412             switch (sname.language_id & 0xff) {
413             case 0x09:
414                 prio |= FC_NAME_PRIO_LANG_ENGLISH;
415                 break;
416             default:
417                 break;
418             }
419             break;
420         case TT_PLATFORM_ISO:
421             switch (sname.encoding_id) {
422             case TT_ISO_ID_10646:
423                 encoding = FcNameEncodingUtf16;
424                 prio |= FC_NAME_PRIO_ENC_UNICODE;
425                 break;
426             case TT_ISO_ID_7BIT_ASCII:
427             case TT_ISO_ID_8859_1:
428                 encoding = FcNameEncodingLatin1;
429                 break;
430             default:
431                 continue;
432             }
433             break;
434         default:
435             continue;
436         }
437         
438         /*
439          * Look for family and style names 
440          */
441         switch (sname.name_id) {
442         case TT_NAME_ID_FONT_FAMILY:
443             prio |= FC_NAME_PRIO_NAME_FAMILY;
444             break;
445         case TT_NAME_ID_PS_NAME:
446             prio |= FC_NAME_PRIO_NAME_PS;
447             break;
448         case TT_NAME_ID_FONT_SUBFAMILY:
449         case TT_NAME_ID_TRADEMARK:
450         case TT_NAME_ID_MANUFACTURER:
451             break;
452         default:
453             continue;
454         }
455             
456         src = (FcChar8 *) sname.string;
457         src_len = sname.string_len;
458         
459         switch (encoding) {
460         case FcNameEncodingUtf16:
461             /*
462              * Convert Utf16 to Utf8
463              */
464             
465             if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
466                 continue;
467     
468             /*
469              * Allocate plenty of space.  Freed below
470              */
471             utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
472             if (!utf8)
473                 continue;
474                 
475             u8 = utf8;
476             
477             while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
478             {
479                 src_len -= ilen;
480                 src += ilen;
481                 olen = FcUcs4ToUtf8 (ucs4, u8);
482                 u8 += olen;
483             }
484             *u8 = '\0';
485             break;
486         case FcNameEncodingLatin1:
487             /*
488              * Convert Latin1 to Utf8. Freed below
489              */
490             utf8 = malloc (src_len * 2 + 1);
491             if (!utf8)
492                 continue;
493
494             u8 = utf8;
495             while (src_len > 0)
496             {
497                 ucs4 = *src++;
498                 src_len--;
499                 olen = FcUcs4ToUtf8 (ucs4, u8);
500                 u8 += olen;
501             }
502             *u8 = '\0';
503             break;
504         case FcNameEncodingAppleRoman:
505             /*
506              * Convert AppleRoman to Utf8
507              */
508             map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
509             if (!map)
510                 continue;
511
512             /* freed below */
513             utf8 = malloc (src_len * 3 + 1);
514             if (!utf8)
515                 continue;
516
517             u8 = utf8;
518             while (src_len > 0)
519             {
520                 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
521                 src_len--;
522                 olen = FcUcs4ToUtf8 (ucs4, u8);
523                 u8 += olen;
524             }
525             *u8 = '\0';
526             break;
527         default:
528             continue;
529         }
530         if ((prio & FC_NAME_PRIO_LANG) == FC_NAME_PRIO_LANG_NONE)
531             if (FcUtf8IsLatin (utf8, strlen ((char *) utf8)))
532                 prio |= FC_NAME_PRIO_LANG_LATIN;
533                                
534         if (FcDebug () & FC_DBG_SCANV)
535             printf ("\nfound name (name %d platform %d encoding %d language 0x%x prio 0x%x) %s\n",
536                     sname.name_id, sname.platform_id,
537                     sname.encoding_id, sname.language_id,
538                     prio, utf8);
539     
540         switch (sname.name_id) {
541         case TT_NAME_ID_FONT_FAMILY:
542         case TT_NAME_ID_PS_NAME:
543             if (!family || prio > family_prio)
544             {
545                 if (family)
546                     free (family);
547                 family = utf8;
548                 utf8 = 0;
549                 family_allocated = FcTrue;
550                 family_prio = prio;
551             }
552             break;
553         case TT_NAME_ID_FONT_SUBFAMILY:
554             if (!style || prio > style_prio)
555             {
556                 if (style)
557                     free (style);
558                 style = utf8;
559                 utf8 = 0;
560                 style_allocated = FcTrue;
561                 style_prio = prio;
562             }
563             break;
564         case TT_NAME_ID_TRADEMARK:
565         case TT_NAME_ID_MANUFACTURER:
566             /* If the foundry wasn't found in the OS/2 table, look here */
567             if(!foundry)
568                 foundry = FcNoticeFoundry(utf8);
569             break;
570         }
571         if (utf8)
572             free (utf8);
573     }
574     
575     if (!family)
576         family = (FcChar8 *) face->family_name;
577     
578     if (!style)
579         style = (FcChar8 *) face->style_name;
580     
581     if (!family)
582     {
583         FcChar8 *start, *end;
584         
585         start = (FcChar8 *) strrchr ((char *) file, '/');
586         if (start)
587             start++;
588         else
589             start = (FcChar8 *) file;
590         end = (FcChar8 *) strrchr ((char *) start, '.');
591         if (!end)
592             end = start + strlen ((char *) start);
593         /* freed below */
594         family = malloc (end - start + 1);
595         strncpy ((char *) family, (char *) start, end - start);
596         family[end - start] = '\0';
597         family_allocated = FcTrue;
598     }
599
600     if (FcDebug() & FC_DBG_SCAN)
601         printf ("\"%s\" \"%s\" ", family, style ? style : (FcChar8 *) "<none>");
602
603     if (!FcPatternAddString (pat, FC_FAMILY, family))
604     {
605         if (family_allocated)
606             free (family);
607         if (style_allocated)
608             free (style);
609         goto bail1;
610     }
611
612     if (family_allocated)
613         free (family);
614
615     if (style)
616     {
617         if (!FcPatternAddString (pat, FC_STYLE, style))
618         {
619             if (style_allocated)
620                 free (style);
621             goto bail1;
622         }
623         if (style_allocated)
624             free (style);
625     }
626
627     if (!FcPatternAddString (pat, FC_FILE, file))
628         goto bail1;
629
630     if (!FcPatternAddInteger (pat, FC_INDEX, id))
631         goto bail1;
632
633     if (!FcPatternAddString (pat, FC_SOURCE, (FcChar8 *) "FreeType"))
634         goto bail1;
635
636 #if 0
637     /*
638      * don't even try this -- CJK 'monospace' fonts are really
639      * dual width, and most other fonts don't bother to set
640      * the attribute.  Sigh.
641      */
642     if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
643         if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
644             goto bail1;
645 #endif
646
647     /*
648      * Find the font revision (if available)
649      */
650     head = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
651     if (head)
652     {
653         if (!FcPatternAddInteger (pat, FC_FONTVERSION, head->Font_Revision))
654             goto bail1;
655     }
656     else
657     {
658         if (!FcPatternAddInteger (pat, FC_FONTVERSION, 0))
659             goto bail1;
660     }
661
662     if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
663     {
664         for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
665         {
666             FT_ULong    bits;
667             int         bit;
668             if (FcCodePageRange[i].bit < 32)
669             {
670                 bits = os2->ulCodePageRange1;
671                 bit = FcCodePageRange[i].bit;
672             }
673             else
674             {
675                 bits = os2->ulCodePageRange2;
676                 bit = FcCodePageRange[i].bit - 32;
677             }
678             if (bits & (1 << bit))
679             {
680                 /* 
681                  * If the font advertises support for multiple
682                  * "exclusive" languages, then include support
683                  * for any language found to have coverage
684                  */
685                 if (exclusiveLang)
686                 {
687                     exclusiveLang = 0;
688                     break;
689                 }
690                 exclusiveLang = FcCodePageRange[i].lang;
691             }
692         }
693     }
694
695     if (os2 && os2->version != 0xffff)
696     {
697         if (os2->usWeightClass == 0)
698             weight = -1;
699         else if (os2->usWeightClass < 150)
700             weight = FC_WEIGHT_THIN;
701         else if (os2->usWeightClass < 250)
702             weight = FC_WEIGHT_EXTRALIGHT;
703         else if (os2->usWeightClass < 350)
704             weight = FC_WEIGHT_LIGHT;
705         else if (os2->usWeightClass < 450)
706             weight = FC_WEIGHT_REGULAR;
707         else if (os2->usWeightClass < 550)
708             weight = FC_WEIGHT_MEDIUM;
709         else if (os2->usWeightClass < 650)
710             weight = FC_WEIGHT_SEMIBOLD;
711         else if (os2->usWeightClass < 750)
712             weight = FC_WEIGHT_BOLD;
713         else if (os2->usWeightClass < 850)
714             weight = FC_WEIGHT_EXTRABOLD;
715         else if (os2->usWeightClass < 950)
716             weight = FC_WEIGHT_BLACK;
717         else
718             weight = FC_WEIGHT_MEDIUM;
719
720         switch (os2->usWidthClass) {
721         case 1: width = FC_WIDTH_ULTRACONDENSED; break;
722         case 2: width = FC_WIDTH_EXTRACONDENSED; break;
723         case 3: width = FC_WIDTH_CONDENSED; break;
724         case 4: width = FC_WIDTH_SEMICONDENSED; break;
725         case 5: width = FC_WIDTH_NORMAL; break;
726         case 6: width = FC_WIDTH_SEMIEXPANDED; break;
727         case 7: width = FC_WIDTH_EXPANDED; break;
728         case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
729         case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
730         }
731     }
732
733     /*
734      * Type 1: Check for FontInfo dictionary information
735      * Code from g2@magestudios.net (Gerard Escalante)
736      */
737     
738     if (FT_Get_PS_Font_Info(face, &psfontinfo) == 0)
739     {
740         if (psfontinfo.weight)
741         {
742             static struct {
743                 char    *name;
744                 int     value;
745             } ps_weights[] = {
746                 { "thin",               FC_WEIGHT_THIN },
747                 { "extralight",         FC_WEIGHT_EXTRALIGHT },
748                 { "ultralight",         FC_WEIGHT_ULTRALIGHT },
749                 { "light",              FC_WEIGHT_LIGHT },
750                 { "regular",            FC_WEIGHT_REGULAR },
751                 { "normal",             FC_WEIGHT_NORMAL },
752                 { "medium",             FC_WEIGHT_MEDIUM },
753                 { "demibold",           FC_WEIGHT_DEMIBOLD },
754                 { "semibold",           FC_WEIGHT_SEMIBOLD },
755                 { "bold",               FC_WEIGHT_BOLD },
756                 { "extrabold",          FC_WEIGHT_EXTRABOLD },
757                 { "ultrabold",          FC_WEIGHT_ULTRABOLD },
758                 { "black",              FC_WEIGHT_BLACK },
759                 { "heavy",              FC_WEIGHT_HEAVY },
760             };
761 #define NUM_PS_WEIGHTS  (sizeof (ps_weights) / sizeof (ps_weights[0]))
762             int w;
763             for (w = 0; w < NUM_PS_WEIGHTS; w++)
764                 if (!FcStrCmpIgnoreCase ((FcChar8 *) ps_weights[w].name,
765                                          (FcChar8 *) psfontinfo.weight))
766                 {
767                     weight = ps_weights[w].value;
768                     break;
769                 }
770             if (FcDebug () & FC_DBG_SCANV)
771             {
772                 if (w == NUM_PS_WEIGHTS)
773                     printf ("\tunknown PS weight name %s\n", psfontinfo.weight);
774             }
775         }
776      
777 #if 0
778         /* 
779          * Don't bother with italic_angle; FreeType already extracts that
780          * information for us and sticks it into style_flags
781          */
782         if (psfontinfo.italic_angle)
783             slant = FC_SLANT_ITALIC; 
784         else
785             slant = FC_SLANT_ROMAN; 
786 #endif
787
788         if(!foundry)
789             foundry = FcNoticeFoundry(psfontinfo.notice);
790     }
791     
792 #ifdef USE_FTBDF
793     /*
794      * Finally, look for a FOUNDRY BDF property if no other
795      * mechanism has managed to locate a foundry
796      */
797
798     if (!foundry)
799     {
800         int             rc;
801         BDF_PropertyRec prop;
802         rc = MY_Get_BDF_Property(face, "FOUNDRY", &prop);
803         if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM)
804             foundry = prop.u.atom;
805     }
806
807     if (width == -1)
808     {
809         BDF_PropertyRec prop;
810         if (MY_Get_BDF_Property(face, "RELATIVE_SETWIDTH", &prop) == 0 &&
811             (prop.type == BDF_PROPERTY_TYPE_INTEGER ||
812              prop.type == BDF_PROPERTY_TYPE_CARDINAL))
813         {
814             FT_Int32    value;
815             
816             if (prop.type == BDF_PROPERTY_TYPE_INTEGER)
817                 value = prop.u.integer;
818             else
819                 value = (FT_Int32) prop.u.cardinal;
820             switch ((value + 5) / 10) {
821             case 1: width = FC_WIDTH_ULTRACONDENSED; break;
822             case 2: width = FC_WIDTH_EXTRACONDENSED; break;
823             case 3: width = FC_WIDTH_CONDENSED; break;
824             case 4: width = FC_WIDTH_SEMICONDENSED; break;
825             case 5: width = FC_WIDTH_NORMAL; break;
826             case 6: width = FC_WIDTH_SEMIEXPANDED; break;
827             case 7: width = FC_WIDTH_EXPANDED; break;
828             case 8: width = FC_WIDTH_EXTRAEXPANDED; break;
829             case 9: width = FC_WIDTH_ULTRAEXPANDED; break;
830             }
831         }
832         else if (MY_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
833                  prop.type == BDF_PROPERTY_TYPE_ATOM)
834         {
835             static struct {
836                 FcChar8     *width_name;
837                 int         width;
838             } FcSetWidths[] = {
839                 { "Condensed",      FC_WIDTH_CONDENSED },
840                 { "SemiCondensed",  FC_WIDTH_SEMICONDENSED },
841                 { "Normal",         FC_WIDTH_NORMAL },
842             };
843             int i;
844
845             if (FcDebug () & FC_DBG_SCANV)
846                 printf ("\nsetwidth: %s\n", prop.u.atom);
847             for (i = 0; i < sizeof (FcSetWidths) / sizeof (FcSetWidths[0]); i++)
848                 if (!FcStrCmpIgnoreCase ((FcChar8 *) prop.u.atom,
849                                          FcSetWidths[i].width_name))
850                 {
851                     width = FcSetWidths[i].width;
852                     break;
853                 }
854         }
855     }
856
857 #endif
858
859     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
860         goto bail1;
861
862     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
863         goto bail1;
864
865     if (width != -1)
866         if (!FcPatternAddInteger (pat, FC_WIDTH, width))
867             goto bail1;
868
869     if(foundry) 
870     {
871         if(!FcPatternAddString (pat, FC_FOUNDRY, foundry))
872             goto bail1;
873     }
874
875     /*
876      * Compute the unicode coverage for the font
877      */
878     cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
879     if (!cs)
880         goto bail1;
881
882     /*
883      * Skip over PCF fonts that have no encoded characters; they're
884      * usually just Unicode fonts transcoded to some legacy encoding
885      */
886     if (FcCharSetCount (cs) == 0)
887     {
888         if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
889             goto bail2;
890     }
891
892     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
893         goto bail2;
894
895     ls = FcFreeTypeLangSet (cs, exclusiveLang);
896     if (!ls)
897         goto bail2;
898
899     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
900         goto bail2;
901
902     if (spacing != FC_PROPORTIONAL)
903         if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
904             goto bail2;
905
906     /*
907      * Drop our reference to the charset
908      */
909     FcCharSetDestroy (cs);
910     
911     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
912     {
913         for (i = 0; i < face->num_fixed_sizes; i++)
914             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
915                                      (double) face->available_sizes[i].height))
916                 goto bail1;
917         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
918             goto bail1;
919     }
920
921     FT_Done_Face (face);
922     FT_Done_FreeType (ftLibrary);
923     return pat;
924
925 bail2:
926     FcCharSetDestroy (cs);
927 bail1:
928     FcPatternDestroy (pat);
929 bail0:
930     FT_Done_Face (face);
931 bail:
932     FT_Done_FreeType (ftLibrary);
933     return 0;
934 }
935
936
937 /*
938  * Figure out whether the available freetype has FT_Get_Next_Char
939  */
940
941 #if FREETYPE_MAJOR > 2
942 # define HAS_NEXT_CHAR
943 #else
944 # if FREETYPE_MAJOR == 2
945 #  if FREETYPE_MINOR > 0
946 #   define HAS_NEXT_CHAR
947 #  else
948 #   if FREETYPE_MINOR == 0
949 #    if FREETYPE_PATCH >= 9
950 #     define HAS_NEXT_CHAR
951 #    endif
952 #   endif
953 #  endif
954 # endif
955 #endif
956
957 /*
958  * For our purposes, this approximation is sufficient
959  */
960 #ifndef HAS_NEXT_CHAR
961 #define FT_Get_First_Char(face, gi) ((*(gi) = 1), 1)
962 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
963                                           (*(gi) = 0), 0 : \
964                                           (*(gi) = 1), (ucs4) + 1)
965 #warning "No FT_Get_Next_Char"
966 #endif
967
968 typedef struct _FcCharEnt {
969     FcChar16        bmp;
970     unsigned char   encode;
971 } FcCharEnt;
972
973 struct _FcCharMap {
974     const FcCharEnt *ent;
975     int             nent;
976 };
977
978 typedef struct _FcFontDecode {
979     FT_Encoding     encoding;
980     const FcCharMap *map;
981     FcChar32        max;
982 } FcFontDecode;
983
984 static const FcCharEnt AppleRomanEnt[] = {
985     { 0x0020, 0x20 }, /* SPACE */
986     { 0x0021, 0x21 }, /* EXCLAMATION MARK */
987     { 0x0022, 0x22 }, /* QUOTATION MARK */
988     { 0x0023, 0x23 }, /* NUMBER SIGN */
989     { 0x0024, 0x24 }, /* DOLLAR SIGN */
990     { 0x0025, 0x25 }, /* PERCENT SIGN */
991     { 0x0026, 0x26 }, /* AMPERSAND */
992     { 0x0027, 0x27 }, /* APOSTROPHE */
993     { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
994     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
995     { 0x002A, 0x2A }, /* ASTERISK */
996     { 0x002B, 0x2B }, /* PLUS SIGN */
997     { 0x002C, 0x2C }, /* COMMA */
998     { 0x002D, 0x2D }, /* HYPHEN-MINUS */
999     { 0x002E, 0x2E }, /* FULL STOP */
1000     { 0x002F, 0x2F }, /* SOLIDUS */
1001     { 0x0030, 0x30 }, /* DIGIT ZERO */
1002     { 0x0031, 0x31 }, /* DIGIT ONE */
1003     { 0x0032, 0x32 }, /* DIGIT TWO */
1004     { 0x0033, 0x33 }, /* DIGIT THREE */
1005     { 0x0034, 0x34 }, /* DIGIT FOUR */
1006     { 0x0035, 0x35 }, /* DIGIT FIVE */
1007     { 0x0036, 0x36 }, /* DIGIT SIX */
1008     { 0x0037, 0x37 }, /* DIGIT SEVEN */
1009     { 0x0038, 0x38 }, /* DIGIT EIGHT */
1010     { 0x0039, 0x39 }, /* DIGIT NINE */
1011     { 0x003A, 0x3A }, /* COLON */
1012     { 0x003B, 0x3B }, /* SEMICOLON */
1013     { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1014     { 0x003D, 0x3D }, /* EQUALS SIGN */
1015     { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1016     { 0x003F, 0x3F }, /* QUESTION MARK */
1017     { 0x0040, 0x40 }, /* COMMERCIAL AT */
1018     { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1019     { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1020     { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1021     { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1022     { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1023     { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1024     { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1025     { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1026     { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1027     { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1028     { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1029     { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1030     { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1031     { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1032     { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1033     { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1034     { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1035     { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1036     { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1037     { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1038     { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1039     { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1040     { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1041     { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1042     { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1043     { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1044     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1045     { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1046     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1047     { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1048     { 0x005F, 0x5F }, /* LOW LINE */
1049     { 0x0060, 0x60 }, /* GRAVE ACCENT */
1050     { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1051     { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1052     { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1053     { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1054     { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1055     { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1056     { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1057     { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1058     { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1059     { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1060     { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1061     { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1062     { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1063     { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1064     { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1065     { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1066     { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1067     { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1068     { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1069     { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1070     { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1071     { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1072     { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1073     { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1074     { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1075     { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1076     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1077     { 0x007C, 0x7C }, /* VERTICAL LINE */
1078     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1079     { 0x007E, 0x7E }, /* TILDE */
1080     { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1081     { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1082     { 0x00A2, 0xA2 }, /* CENT SIGN */
1083     { 0x00A3, 0xA3 }, /* POUND SIGN */
1084     { 0x00A5, 0xB4 }, /* YEN SIGN */
1085     { 0x00A7, 0xA4 }, /* SECTION SIGN */
1086     { 0x00A8, 0xAC }, /* DIAERESIS */
1087     { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1088     { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1089     { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1090     { 0x00AC, 0xC2 }, /* NOT SIGN */
1091     { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1092     { 0x00AF, 0xF8 }, /* MACRON */
1093     { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1094     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1095     { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1096     { 0x00B5, 0xB5 }, /* MICRO SIGN */
1097     { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1098     { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1099     { 0x00B8, 0xFC }, /* CEDILLA */
1100     { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1101     { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1102     { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1103     { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1104     { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1105     { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1106     { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1107     { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1108     { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1109     { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1110     { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1111     { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1112     { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1113     { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1114     { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1115     { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1116     { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1117     { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1118     { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1119     { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1120     { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1121     { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1122     { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1123     { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1124     { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1125     { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1126     { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1127     { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1128     { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1129     { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1130     { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1131     { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1132     { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1133     { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1134     { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1135     { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1136     { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1137     { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1138     { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1139     { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1140     { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1141     { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1142     { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1143     { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1144     { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1145     { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1146     { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1147     { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1148     { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1149     { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1150     { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1151     { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1152     { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1153     { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1154     { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1155     { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1156     { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1157     { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1158     { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1159     { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1160     { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1161     { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1162     { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1163     { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1164     { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1165     { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1166     { 0x02C7, 0xFF }, /* CARON */
1167     { 0x02D8, 0xF9 }, /* BREVE */
1168     { 0x02D9, 0xFA }, /* DOT ABOVE */
1169     { 0x02DA, 0xFB }, /* RING ABOVE */
1170     { 0x02DB, 0xFE }, /* OGONEK */
1171     { 0x02DC, 0xF7 }, /* SMALL TILDE */
1172     { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1173     { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1174     { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1175     { 0x2013, 0xD0 }, /* EN DASH */
1176     { 0x2014, 0xD1 }, /* EM DASH */
1177     { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1178     { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1179     { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1180     { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1181     { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1182     { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
1183     { 0x2020, 0xA0 }, /* DAGGER */
1184     { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
1185     { 0x2022, 0xA5 }, /* BULLET */
1186     { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
1187     { 0x2030, 0xE4 }, /* PER MILLE SIGN */
1188     { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
1189     { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
1190     { 0x2044, 0xDA }, /* FRACTION SLASH */
1191     { 0x20AC, 0xDB }, /* EURO SIGN */
1192     { 0x2122, 0xAA }, /* TRADE MARK SIGN */
1193     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
1194     { 0x2206, 0xC6 }, /* INCREMENT */
1195     { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
1196     { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
1197     { 0x221A, 0xC3 }, /* SQUARE ROOT */
1198     { 0x221E, 0xB0 }, /* INFINITY */
1199     { 0x222B, 0xBA }, /* INTEGRAL */
1200     { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
1201     { 0x2260, 0xAD }, /* NOT EQUAL TO */
1202     { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
1203     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
1204     { 0x25CA, 0xD7 }, /* LOZENGE */
1205     { 0xF8FF, 0xF0 }, /* Apple logo */
1206     { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
1207     { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
1208 };
1209
1210 static const FcCharMap AppleRoman = {
1211     AppleRomanEnt,
1212     sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
1213 };
1214
1215 static const FcCharEnt AdobeSymbolEnt[] = {
1216     { 0x0020, 0x20 }, /* SPACE  # space */
1217     { 0x0021, 0x21 }, /* EXCLAMATION MARK       # exclam */
1218     { 0x0023, 0x23 }, /* NUMBER SIGN    # numbersign */
1219     { 0x0025, 0x25 }, /* PERCENT SIGN   # percent */
1220     { 0x0026, 0x26 }, /* AMPERSAND      # ampersand */
1221     { 0x0028, 0x28 }, /* LEFT PARENTHESIS       # parenleft */
1222     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS      # parenright */
1223     { 0x002B, 0x2B }, /* PLUS SIGN      # plus */
1224     { 0x002C, 0x2C }, /* COMMA  # comma */
1225     { 0x002E, 0x2E }, /* FULL STOP      # period */
1226     { 0x002F, 0x2F }, /* SOLIDUS        # slash */
1227     { 0x0030, 0x30 }, /* DIGIT ZERO     # zero */
1228     { 0x0031, 0x31 }, /* DIGIT ONE      # one */
1229     { 0x0032, 0x32 }, /* DIGIT TWO      # two */
1230     { 0x0033, 0x33 }, /* DIGIT THREE    # three */
1231     { 0x0034, 0x34 }, /* DIGIT FOUR     # four */
1232     { 0x0035, 0x35 }, /* DIGIT FIVE     # five */
1233     { 0x0036, 0x36 }, /* DIGIT SIX      # six */
1234     { 0x0037, 0x37 }, /* DIGIT SEVEN    # seven */
1235     { 0x0038, 0x38 }, /* DIGIT EIGHT    # eight */
1236     { 0x0039, 0x39 }, /* DIGIT NINE     # nine */
1237     { 0x003A, 0x3A }, /* COLON  # colon */
1238     { 0x003B, 0x3B }, /* SEMICOLON      # semicolon */
1239     { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1240     { 0x003D, 0x3D }, /* EQUALS SIGN    # equal */
1241     { 0x003E, 0x3E }, /* GREATER-THAN SIGN      # greater */
1242     { 0x003F, 0x3F }, /* QUESTION MARK  # question */
1243     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET    # bracketleft */
1244     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET   # bracketright */
1245     { 0x005F, 0x5F }, /* LOW LINE       # underscore */
1246     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET     # braceleft */
1247     { 0x007C, 0x7C }, /* VERTICAL LINE  # bar */
1248     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET    # braceright */
1249     { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1250     { 0x00AC, 0xD8 }, /* NOT SIGN       # logicalnot */
1251     { 0x00B0, 0xB0 }, /* DEGREE SIGN    # degree */
1252     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN        # plusminus */
1253     { 0x00B5, 0x6D }, /* MICRO SIGN     # mu */
1254     { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN    # multiply */
1255     { 0x00F7, 0xB8 }, /* DIVISION SIGN  # divide */
1256     { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1257     { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA     # Alpha */
1258     { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA      # Beta */
1259     { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA     # Gamma */
1260     { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA     # Delta */
1261     { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON   # Epsilon */
1262     { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA      # Zeta */
1263     { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA       # Eta */
1264     { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA     # Theta */
1265     { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA      # Iota */
1266     { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA     # Kappa */
1267     { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA     # Lambda */
1268     { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU        # Mu */
1269     { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU        # Nu */
1270     { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI        # Xi */
1271     { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON   # Omicron */
1272     { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI        # Pi */
1273     { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO       # Rho */
1274     { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA     # Sigma */
1275     { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU       # Tau */
1276     { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON   # Upsilon */
1277     { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI       # Phi */
1278     { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI       # Chi */
1279     { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI       # Psi */
1280     { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA     # Omega */
1281     { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA       # alpha */
1282     { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA        # beta */
1283     { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA       # gamma */
1284     { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA       # delta */
1285     { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON     # epsilon */
1286     { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA        # zeta */
1287     { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1288     { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA       # theta */
1289     { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA        # iota */
1290     { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA       # kappa */
1291     { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA       # lambda */
1292     { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU  # mu */
1293     { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU  # nu */
1294     { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI  # xi */
1295     { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON     # omicron */
1296     { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI  # pi */
1297     { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
1298     { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
1299     { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA       # sigma */
1300     { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
1301     { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON     # upsilon */
1302     { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
1303     { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
1304     { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
1305     { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA       # omega */
1306     { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL     # theta1 */
1307     { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
1308     { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL       # phi1 */
1309     { 0x03D6, 0x76 }, /* GREEK PI SYMBOL        # omega1 */
1310     { 0x2022, 0xB7 }, /* BULLET # bullet */
1311     { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS    # ellipsis */
1312     { 0x2032, 0xA2 }, /* PRIME  # minute */
1313     { 0x2033, 0xB2 }, /* DOUBLE PRIME   # second */
1314     { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
1315     { 0x20AC, 0xA0 }, /* EURO SIGN      # Euro */
1316     { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
1317     { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P       # weierstrass */
1318     { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
1319     { 0x2126, 0x57 }, /* OHM SIGN       # Omega */
1320     { 0x2135, 0xC0 }, /* ALEF SYMBOL    # aleph */
1321     { 0x2190, 0xAC }, /* LEFTWARDS ARROW        # arrowleft */
1322     { 0x2191, 0xAD }, /* UPWARDS ARROW  # arrowup */
1323     { 0x2192, 0xAE }, /* RIGHTWARDS ARROW       # arrowright */
1324     { 0x2193, 0xAF }, /* DOWNWARDS ARROW        # arrowdown */
1325     { 0x2194, 0xAB }, /* LEFT RIGHT ARROW       # arrowboth */
1326     { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS  # carriagereturn */
1327     { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
1328     { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW   # arrowdblup */
1329     { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW        # arrowdblright */
1330     { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
1331     { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW        # arrowdblboth */
1332     { 0x2200, 0x22 }, /* FOR ALL        # universal */
1333     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL   # partialdiff */
1334     { 0x2203, 0x24 }, /* THERE EXISTS   # existential */
1335     { 0x2205, 0xC6 }, /* EMPTY SET      # emptyset */
1336     { 0x2206, 0x44 }, /* INCREMENT      # Delta */
1337     { 0x2207, 0xD1 }, /* NABLA  # gradient */
1338     { 0x2208, 0xCE }, /* ELEMENT OF     # element */
1339     { 0x2209, 0xCF }, /* NOT AN ELEMENT OF      # notelement */
1340     { 0x220B, 0x27 }, /* CONTAINS AS MEMBER     # suchthat */
1341     { 0x220F, 0xD5 }, /* N-ARY PRODUCT  # product */
1342     { 0x2211, 0xE5 }, /* N-ARY SUMMATION        # summation */
1343     { 0x2212, 0x2D }, /* MINUS SIGN     # minus */
1344     { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
1345     { 0x2217, 0x2A }, /* ASTERISK OPERATOR      # asteriskmath */
1346     { 0x221A, 0xD6 }, /* SQUARE ROOT    # radical */
1347     { 0x221D, 0xB5 }, /* PROPORTIONAL TO        # proportional */
1348     { 0x221E, 0xA5 }, /* INFINITY       # infinity */
1349     { 0x2220, 0xD0 }, /* ANGLE  # angle */
1350     { 0x2227, 0xD9 }, /* LOGICAL AND    # logicaland */
1351     { 0x2228, 0xDA }, /* LOGICAL OR     # logicalor */
1352     { 0x2229, 0xC7 }, /* INTERSECTION   # intersection */
1353     { 0x222A, 0xC8 }, /* UNION  # union */
1354     { 0x222B, 0xF2 }, /* INTEGRAL       # integral */
1355     { 0x2234, 0x5C }, /* THEREFORE      # therefore */
1356     { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
1357     { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
1358     { 0x2248, 0xBB }, /* ALMOST EQUAL TO        # approxequal */
1359     { 0x2260, 0xB9 }, /* NOT EQUAL TO   # notequal */
1360     { 0x2261, 0xBA }, /* IDENTICAL TO   # equivalence */
1361     { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO  # lessequal */
1362     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO       # greaterequal */
1363     { 0x2282, 0xCC }, /* SUBSET OF      # propersubset */
1364     { 0x2283, 0xC9 }, /* SUPERSET OF    # propersuperset */
1365     { 0x2284, 0xCB }, /* NOT A SUBSET OF        # notsubset */
1366     { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO  # reflexsubset */
1367     { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO        # reflexsuperset */
1368     { 0x2295, 0xC5 }, /* CIRCLED PLUS   # circleplus */
1369     { 0x2297, 0xC4 }, /* CIRCLED TIMES  # circlemultiply */
1370     { 0x22A5, 0x5E }, /* UP TACK        # perpendicular */
1371     { 0x22C5, 0xD7 }, /* DOT OPERATOR   # dotmath */
1372     { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL      # integraltp */
1373     { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL   # integralbt */
1374     { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET    # angleleft */
1375     { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET   # angleright */
1376     { 0x25CA, 0xE0 }, /* LOZENGE        # lozenge */
1377     { 0x2660, 0xAA }, /* BLACK SPADE SUIT       # spade */
1378     { 0x2663, 0xA7 }, /* BLACK CLUB SUIT        # club */
1379     { 0x2665, 0xA9 }, /* BLACK HEART SUIT       # heart */
1380     { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT     # diamond */
1381     { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF   # copyrightserif (CUS) */
1382     { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF  # registerserif (CUS) */
1383     { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF  # trademarkserif (CUS) */
1384     { 0xF8E5, 0x60 }, /* RADICAL EXTENDER       # radicalex (CUS) */
1385     { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER        # arrowvertex (CUS) */
1386     { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER      # arrowhorizex (CUS) */
1387     { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF     # registersans (CUS) */
1388     { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF      # copyrightsans (CUS) */
1389     { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF     # trademarksans (CUS) */
1390     { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
1391     { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER    # parenleftex (CUS) */
1392     { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM      # parenleftbt (CUS) */
1393     { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP        # bracketlefttp (CUS) */
1394     { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER   # bracketleftex (CUS) */
1395     { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM     # bracketleftbt (CUS) */
1396     { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
1397     { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
1398     { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM      # braceleftbt (CUS) */
1399     { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
1400     { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER      # integralex (CUS) */
1401     { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP        # parenrighttp (CUS) */
1402     { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER   # parenrightex (CUS) */
1403     { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM     # parenrightbt (CUS) */
1404     { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP       # bracketrighttp (CUS) */
1405     { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER  # bracketrightex (CUS) */
1406     { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM    # bracketrightbt (CUS) */
1407     { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP        # bracerighttp (CUS) */
1408     { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID        # bracerightmid (CUS) */
1409     { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM     # bracerightbt (CUS) */
1410 };
1411
1412 static const FcCharMap AdobeSymbol = {
1413     AdobeSymbolEnt,
1414     sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
1415 };
1416     
1417 static const FcFontDecode fcFontDecoders[] = {
1418     { ft_encoding_unicode,      0,              (1 << 21) - 1 },
1419     { ft_encoding_symbol,       &AdobeSymbol,   (1 << 16) - 1 },
1420     { ft_encoding_apple_roman,  &AppleRoman,    (1 << 16) - 1 },
1421 };
1422
1423 #define NUM_DECODE  (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
1424
1425 FcChar32
1426 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
1427 {
1428     int         low, high, mid;
1429     FcChar16    bmp;
1430
1431     low = 0;
1432     high = map->nent - 1;
1433     if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
1434         return ~0;
1435     while (low <= high)
1436     {
1437         mid = (high + low) >> 1;
1438         bmp = map->ent[mid].bmp;
1439         if (ucs4 == bmp)
1440             return (FT_ULong) map->ent[mid].encode;
1441         if (ucs4 < bmp)
1442             high = mid - 1;
1443         else
1444             low = mid + 1;
1445     }
1446     return ~0;
1447 }
1448
1449 FcChar32
1450 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
1451 {
1452     int     i;
1453
1454     for (i = 0; i < map->nent; i++)
1455         if (map->ent[i].encode == private)
1456             return (FcChar32) map->ent[i].bmp;
1457     return ~0;
1458 }
1459
1460 const FcCharMap *
1461 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
1462 {
1463     int i;
1464
1465     for (i = 0; i < NUM_DECODE; i++)
1466         if (fcFontDecoders[i].encoding == encoding)
1467             return fcFontDecoders[i].map;
1468     return 0;
1469 }
1470
1471 /*
1472  * Map a UCS4 glyph to a glyph index.  Use all available encoding
1473  * tables to try and find one that works.  This information is expected
1474  * to be cached by higher levels, so performance isn't critical
1475  */
1476
1477 FT_UInt
1478 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
1479 {
1480     int             initial, offset, decode;
1481     FT_UInt         glyphindex;
1482     FcChar32        charcode;
1483
1484     initial = 0;
1485     /*
1486      * Find the current encoding
1487      */
1488     if (face->charmap)
1489     {
1490         for (; initial < NUM_DECODE; initial++)
1491             if (fcFontDecoders[initial].encoding == face->charmap->encoding)
1492                 break;
1493         if (initial == NUM_DECODE)
1494             initial = 0;
1495     }
1496     /*
1497      * Check each encoding for the glyph, starting with the current one
1498      */
1499     for (offset = 0; offset < NUM_DECODE; offset++)
1500     {
1501         decode = (initial + offset) % NUM_DECODE;
1502         if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
1503             if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
1504                 continue;
1505         if (fcFontDecoders[decode].map)
1506         {
1507             charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
1508             if (charcode == ~0)
1509                 continue;
1510         }
1511         else
1512             charcode = ucs4;
1513         glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
1514         if (glyphindex)
1515             return glyphindex;
1516     }
1517     return 0;
1518 }
1519
1520 static FcBool
1521 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, 
1522                       FT_UInt glyph, FcBlanks *blanks,
1523                       FT_Pos *advance)
1524 {
1525     FT_Int          load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
1526     FT_GlyphSlot    slot;
1527     
1528     /*
1529      * When using scalable fonts, only report those glyphs
1530      * which can be scaled; otherwise those fonts will
1531      * only be available at some sizes, and never when
1532      * transformed.  Avoid this by simply reporting bitmap-only
1533      * glyphs as missing
1534      */
1535     if (face->face_flags & FT_FACE_FLAG_SCALABLE)
1536         load_flags |= FT_LOAD_NO_BITMAP;
1537     
1538     if (FT_Load_Glyph (face, glyph, load_flags))
1539         return FcFalse;
1540     
1541     slot = face->glyph;
1542     if (!glyph)
1543         return FcFalse;
1544     
1545     *advance = slot->metrics.horiAdvance;
1546
1547     switch (slot->format) {
1548     case ft_glyph_format_bitmap:
1549         /*
1550          * Bitmaps are assumed to be reasonable; if
1551          * this proves to be a rash assumption, this
1552          * code can be easily modified
1553          */
1554         return FcTrue;
1555     case ft_glyph_format_outline:
1556         /*
1557          * Glyphs with contours are always OK
1558          */
1559         if (slot->outline.n_contours != 0)
1560             return FcTrue;
1561         /*
1562          * Glyphs with no contours are only OK if
1563          * they're members of the Blanks set specified
1564          * in the configuration.  If blanks isn't set,
1565          * then allow any glyph to be blank
1566          */
1567         if (!blanks || FcBlanksIsMember (blanks, ucs4))
1568             return FcTrue;
1569         /* fall through ... */
1570     default:
1571         break;
1572     }
1573     return FcFalse;
1574 }
1575
1576 FcCharSet *
1577 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
1578 {
1579     FcChar32        page, off, max, ucs4;
1580 #ifdef CHECK
1581     FcChar32        font_max = 0;
1582 #endif
1583     FcCharSet       *fcs;
1584     FcCharLeaf      *leaf;
1585     const FcCharMap *map;
1586     int             o;
1587     int             i;
1588     FT_UInt         glyph;
1589     FT_Pos          advance, all_advance = 0;
1590     FcBool          has_advance = FcFalse, fixed_advance = FcTrue;
1591
1592     fcs = FcCharSetCreate ();
1593     if (!fcs)
1594         goto bail0;
1595     
1596     for (o = 0; o < NUM_DECODE; o++)
1597     {
1598         if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
1599             continue;
1600         map = fcFontDecoders[o].map;
1601         if (map)
1602         {
1603             /*
1604              * Non-Unicode tables are easy; there's a list of all possible
1605              * characters
1606              */
1607             for (i = 0; i < map->nent; i++)
1608             {
1609                 ucs4 = map->ent[i].bmp;
1610                 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
1611                 if (glyph && 
1612                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
1613                 {
1614                     if (!has_advance)
1615                     {
1616                         has_advance = FcTrue;
1617                         all_advance = advance;
1618                     }
1619                     else if (advance != all_advance)
1620                         fixed_advance = FcFalse;
1621                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
1622                     if (!leaf)
1623                         goto bail1;
1624                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
1625 #ifdef CHECK
1626                     if (ucs4 > font_max)
1627                         font_max = ucs4;
1628 #endif
1629                 }
1630             }
1631         }
1632         else
1633         {
1634             FT_UInt gindex;
1635           
1636             max = fcFontDecoders[o].max;
1637             /*
1638              * Find the first encoded character in the font
1639              */
1640             if (FT_Get_Char_Index (face, 0))
1641             {
1642                 ucs4 = 0;
1643                 gindex = 1;
1644             }
1645             else
1646             {
1647                 ucs4 = FT_Get_Next_Char (face, 0, &gindex);
1648                 if (!ucs4)
1649                     gindex = 0;
1650             }
1651
1652             while (gindex)
1653             {
1654                 page = ucs4 >> 8;
1655                 leaf = 0;
1656                 while ((ucs4 >> 8) == page)
1657                 {
1658                     glyph = FT_Get_Char_Index (face, ucs4);
1659                     if (glyph && FcFreeTypeCheckGlyph (face, ucs4, 
1660                                                        glyph, blanks, &advance))
1661                     {
1662                         if (!has_advance)
1663                         {
1664                             has_advance = FcTrue;
1665                             all_advance = advance;
1666                         }
1667                         else if (advance != all_advance)
1668                             fixed_advance = FcFalse;
1669                         if (!leaf)
1670                         {
1671                             leaf = FcCharSetFindLeafCreate (fcs, ucs4);
1672                             if (!leaf)
1673                                 goto bail1;
1674                         }
1675                         off = ucs4 & 0xff;
1676                         leaf->map[off >> 5] |= (1 << (off & 0x1f));
1677 #ifdef CHECK
1678                         if (ucs4 > font_max)
1679                             font_max = ucs4;
1680 #endif
1681                     }
1682                     ucs4++;
1683                 }
1684                 ucs4 = FT_Get_Next_Char (face, ucs4 - 1, &gindex);
1685                 if (!ucs4)
1686                     gindex = 0;
1687             }
1688 #ifdef CHECK
1689             for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
1690             {
1691                 FcBool      FT_Has, FC_Has;
1692
1693                 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
1694                 FC_Has = FcCharSetHasChar (fcs, ucs4);
1695                 if (FT_Has != FC_Has)
1696                 {
1697                     printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
1698                 }
1699             }
1700 #endif
1701         }
1702     }
1703 #ifdef CHECK
1704     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
1705     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
1706     {
1707         FcBool  has_char = FcFreeTypeCharIndex (face, ucs4) != 0;
1708         FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
1709
1710         if (has_char && !has_bit)
1711             printf ("Bitmap missing char 0x%x\n", ucs4);
1712         else if (!has_char && has_bit)
1713             printf ("Bitmap extra char 0x%x\n", ucs4);
1714     }
1715 #endif
1716     if (fixed_advance)
1717         *spacing = FC_MONO;
1718     else
1719         *spacing = FC_PROPORTIONAL;
1720     return fcs;
1721 bail1:
1722     FcCharSetDestroy (fcs);
1723 bail0:
1724     return 0;
1725 }
1726
1727 FcCharSet *
1728 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
1729 {
1730     int spacing;
1731
1732     return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
1733 }