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