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