]> git.wh0rd.org Git - fontconfig.git/blob - src/fcfreetype.c
Extract spacing from XLFD atom
[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         if (width == -1 &&
861             MY_Get_BDF_Property (face, "SETWIDTH_NAME", &prop) == 0 &&
862             prop.type == BDF_PROPERTY_TYPE_ATOM)
863         {
864             width = FcIsWidth (prop.u.atom);
865             if (FcDebug () & FC_DBG_SCANV)
866                 printf ("\tsetwidth %s maps to %d\n", prop.u.atom, width);
867         }
868     }
869
870 #endif
871
872     /*
873      * Look for weight, width and slant names in the style value
874      */
875     if (style)
876     {
877         if (weight == -1)
878         {
879             weight = FcContainsWeight (style);
880             if (FcDebug() & FC_DBG_SCANV)
881                 printf ("\tStyle %s maps to weight %d\n", style, weight);
882         }
883         if (width == -1)
884         {
885             width = FcContainsWidth (style);
886             if (FcDebug() & FC_DBG_SCANV)
887                 printf ("\tStyle %s maps to width %d\n", style, width);
888         }
889         if (slant == -1)
890         {
891             slant = FcContainsSlant (style);
892             if (FcDebug() & FC_DBG_SCANV)
893                 printf ("\tStyle %s maps to slant %d\n", style, slant);
894         }
895     }
896     /*
897      * Pull default values from the FreeType flags if more
898      * specific values not found above
899      */
900     if (slant == -1)
901     {
902         slant = FC_SLANT_ROMAN;
903         if (face->style_flags & FT_STYLE_FLAG_ITALIC)
904             slant = FC_SLANT_ITALIC;
905     }
906
907     if (weight == -1)
908     {
909         weight = FC_WEIGHT_MEDIUM;
910         if (face->style_flags & FT_STYLE_FLAG_BOLD)
911             weight = FC_WEIGHT_BOLD;
912     }
913
914     if (!FcPatternAddInteger (pat, FC_SLANT, slant))
915         goto bail1;
916
917     if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
918         goto bail1;
919
920     if (width != -1)
921         if (!FcPatternAddInteger (pat, FC_WIDTH, width))
922             goto bail1;
923
924     if(foundry) 
925     {
926         if(!FcPatternAddString (pat, FC_FOUNDRY, foundry))
927             goto bail1;
928     }
929
930     /*
931      * Compute the unicode coverage for the font
932      */
933     cs = FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
934     if (!cs)
935         goto bail1;
936
937 #ifdef USE_FTBDF
938     /* For PCF fonts, override the computed spacing with the one from
939        the property */
940     if(MY_Get_BDF_Property(face, "SPACING", &prop) == 0 &&
941        prop.type == BDF_PROPERTY_TYPE_ATOM) {
942         if(strcmp(prop.u.atom, "c") || strcmp(prop.u.atom, "C"))
943             spacing = FC_CHARCELL;
944         else if(strcmp(prop.u.atom, "m") || strcmp(prop.u.atom, "M"))
945             spacing = FC_MONO;
946         else if(strcmp(prop.u.atom, "p") || strcmp(prop.u.atom, "P"))
947             spacing = FC_PROPORTIONAL;
948     }
949 #endif
950
951     /*
952      * Skip over PCF fonts that have no encoded characters; they're
953      * usually just Unicode fonts transcoded to some legacy encoding
954      */
955     if (FcCharSetCount (cs) == 0)
956     {
957         if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
958             goto bail2;
959     }
960
961     if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
962         goto bail2;
963
964     ls = FcFreeTypeLangSet (cs, exclusiveLang);
965     if (!ls)
966         goto bail2;
967
968     if (!FcPatternAddLangSet (pat, FC_LANG, ls))
969         goto bail2;
970
971     if (spacing != FC_PROPORTIONAL)
972         if (!FcPatternAddInteger (pat, FC_SPACING, spacing))
973             goto bail2;
974
975     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
976     {
977         for (i = 0; i < face->num_fixed_sizes; i++)
978             if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
979                                      (double) face->available_sizes[i].height))
980                 goto bail1;
981         if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
982             goto bail1;
983 #ifdef USE_FTBDF
984         if(face->num_fixed_sizes == 1) {
985             int rc;
986             int value;
987             BDF_PropertyRec prop;
988
989             rc = MY_Get_BDF_Property(face, "PIXEL_SIZE", &prop);
990             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
991                 value = prop.u.integer;
992             else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
993                 value = prop.u.cardinal;
994             else
995                 goto nevermind;
996             if(value != face->available_sizes[0].height)
997                 /* ``impossible'' */
998                 goto nevermind;
999
1000             rc = MY_Get_BDF_Property(face, "POINT_SIZE", &prop);
1001             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1002                 value = prop.u.integer;
1003             else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1004                 value = prop.u.cardinal;
1005             else
1006                 goto nevermind;
1007             if(!FcPatternAddDouble(pat, FC_SIZE, value / 10.0))
1008                 goto nevermind;
1009
1010             rc = MY_Get_BDF_Property(face, "RESOLUTION_Y", &prop);
1011             if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
1012                 value = prop.u.integer;
1013             else if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_CARDINAL)
1014                 value = prop.u.cardinal;
1015             else
1016                 goto nevermind;
1017             if(!FcPatternAddDouble(pat, FC_DPI, (double)value))
1018                 goto nevermind;
1019
1020         }
1021     nevermind:
1022         ;
1023 #endif
1024     }
1025
1026     /*
1027      * Drop our reference to the charset
1028      */
1029     FcCharSetDestroy (cs);
1030     
1031     /*
1032      * Deallocate family/style values
1033      */
1034     
1035     if (family_allocated)
1036         free (family);
1037     if (style_allocated)
1038         free (style);
1039     
1040     FT_Done_Face (face);
1041     FT_Done_FreeType (ftLibrary);
1042     return pat;
1043
1044 bail2:
1045     FcCharSetDestroy (cs);
1046 bail1:
1047     FcPatternDestroy (pat);
1048     if (family_allocated)
1049         free (family);
1050     if (style_allocated)
1051         free (style);
1052 bail0:
1053     FT_Done_Face (face);
1054 bail:
1055     FT_Done_FreeType (ftLibrary);
1056     return 0;
1057 }
1058
1059
1060 /*
1061  * Figure out whether the available freetype has FT_Get_Next_Char
1062  */
1063
1064 #if FREETYPE_MAJOR > 2
1065 # define HAS_NEXT_CHAR
1066 #else
1067 # if FREETYPE_MAJOR == 2
1068 #  if FREETYPE_MINOR > 0
1069 #   define HAS_NEXT_CHAR
1070 #  else
1071 #   if FREETYPE_MINOR == 0
1072 #    if FREETYPE_PATCH >= 9
1073 #     define HAS_NEXT_CHAR
1074 #    endif
1075 #   endif
1076 #  endif
1077 # endif
1078 #endif
1079
1080 /*
1081  * For our purposes, this approximation is sufficient
1082  */
1083 #ifndef HAS_NEXT_CHAR
1084 #define FT_Get_First_Char(face, gi) ((*(gi) = 1), 1)
1085 #define FT_Get_Next_Char(face, ucs4, gi) ((ucs4) >= 0xffffff ? \
1086                                           (*(gi) = 0), 0 : \
1087                                           (*(gi) = 1), (ucs4) + 1)
1088 #warning "No FT_Get_Next_Char"
1089 #endif
1090
1091 typedef struct _FcCharEnt {
1092     FcChar16        bmp;
1093     unsigned char   encode;
1094 } FcCharEnt;
1095
1096 struct _FcCharMap {
1097     const FcCharEnt *ent;
1098     int             nent;
1099 };
1100
1101 typedef struct _FcFontDecode {
1102     FT_Encoding     encoding;
1103     const FcCharMap *map;
1104     FcChar32        max;
1105 } FcFontDecode;
1106
1107 static const FcCharEnt AppleRomanEnt[] = {
1108     { 0x0020, 0x20 }, /* SPACE */
1109     { 0x0021, 0x21 }, /* EXCLAMATION MARK */
1110     { 0x0022, 0x22 }, /* QUOTATION MARK */
1111     { 0x0023, 0x23 }, /* NUMBER SIGN */
1112     { 0x0024, 0x24 }, /* DOLLAR SIGN */
1113     { 0x0025, 0x25 }, /* PERCENT SIGN */
1114     { 0x0026, 0x26 }, /* AMPERSAND */
1115     { 0x0027, 0x27 }, /* APOSTROPHE */
1116     { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
1117     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
1118     { 0x002A, 0x2A }, /* ASTERISK */
1119     { 0x002B, 0x2B }, /* PLUS SIGN */
1120     { 0x002C, 0x2C }, /* COMMA */
1121     { 0x002D, 0x2D }, /* HYPHEN-MINUS */
1122     { 0x002E, 0x2E }, /* FULL STOP */
1123     { 0x002F, 0x2F }, /* SOLIDUS */
1124     { 0x0030, 0x30 }, /* DIGIT ZERO */
1125     { 0x0031, 0x31 }, /* DIGIT ONE */
1126     { 0x0032, 0x32 }, /* DIGIT TWO */
1127     { 0x0033, 0x33 }, /* DIGIT THREE */
1128     { 0x0034, 0x34 }, /* DIGIT FOUR */
1129     { 0x0035, 0x35 }, /* DIGIT FIVE */
1130     { 0x0036, 0x36 }, /* DIGIT SIX */
1131     { 0x0037, 0x37 }, /* DIGIT SEVEN */
1132     { 0x0038, 0x38 }, /* DIGIT EIGHT */
1133     { 0x0039, 0x39 }, /* DIGIT NINE */
1134     { 0x003A, 0x3A }, /* COLON */
1135     { 0x003B, 0x3B }, /* SEMICOLON */
1136     { 0x003C, 0x3C }, /* LESS-THAN SIGN */
1137     { 0x003D, 0x3D }, /* EQUALS SIGN */
1138     { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
1139     { 0x003F, 0x3F }, /* QUESTION MARK */
1140     { 0x0040, 0x40 }, /* COMMERCIAL AT */
1141     { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
1142     { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
1143     { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
1144     { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
1145     { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
1146     { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
1147     { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
1148     { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
1149     { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
1150     { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
1151     { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
1152     { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
1153     { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
1154     { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
1155     { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
1156     { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
1157     { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
1158     { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
1159     { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
1160     { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
1161     { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
1162     { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
1163     { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
1164     { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
1165     { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
1166     { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
1167     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
1168     { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
1169     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
1170     { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
1171     { 0x005F, 0x5F }, /* LOW LINE */
1172     { 0x0060, 0x60 }, /* GRAVE ACCENT */
1173     { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
1174     { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
1175     { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
1176     { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
1177     { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
1178     { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
1179     { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
1180     { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
1181     { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
1182     { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
1183     { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
1184     { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
1185     { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
1186     { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
1187     { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
1188     { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
1189     { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
1190     { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
1191     { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
1192     { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
1193     { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
1194     { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
1195     { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
1196     { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
1197     { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
1198     { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
1199     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
1200     { 0x007C, 0x7C }, /* VERTICAL LINE */
1201     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
1202     { 0x007E, 0x7E }, /* TILDE */
1203     { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
1204     { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
1205     { 0x00A2, 0xA2 }, /* CENT SIGN */
1206     { 0x00A3, 0xA3 }, /* POUND SIGN */
1207     { 0x00A5, 0xB4 }, /* YEN SIGN */
1208     { 0x00A7, 0xA4 }, /* SECTION SIGN */
1209     { 0x00A8, 0xAC }, /* DIAERESIS */
1210     { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
1211     { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
1212     { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
1213     { 0x00AC, 0xC2 }, /* NOT SIGN */
1214     { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
1215     { 0x00AF, 0xF8 }, /* MACRON */
1216     { 0x00B0, 0xA1 }, /* DEGREE SIGN */
1217     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
1218     { 0x00B4, 0xAB }, /* ACUTE ACCENT */
1219     { 0x00B5, 0xB5 }, /* MICRO SIGN */
1220     { 0x00B6, 0xA6 }, /* PILCROW SIGN */
1221     { 0x00B7, 0xE1 }, /* MIDDLE DOT */
1222     { 0x00B8, 0xFC }, /* CEDILLA */
1223     { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
1224     { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
1225     { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
1226     { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
1227     { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
1228     { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
1229     { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
1230     { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
1231     { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
1232     { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
1233     { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
1234     { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
1235     { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
1236     { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
1237     { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
1238     { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
1239     { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
1240     { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
1241     { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
1242     { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
1243     { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
1244     { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
1245     { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
1246     { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
1247     { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
1248     { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
1249     { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
1250     { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
1251     { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
1252     { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
1253     { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
1254     { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
1255     { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
1256     { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
1257     { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
1258     { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
1259     { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
1260     { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
1261     { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
1262     { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
1263     { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
1264     { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
1265     { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
1266     { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
1267     { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
1268     { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
1269     { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
1270     { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
1271     { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
1272     { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
1273     { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
1274     { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
1275     { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
1276     { 0x00F7, 0xD6 }, /* DIVISION SIGN */
1277     { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
1278     { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
1279     { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
1280     { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
1281     { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
1282     { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
1283     { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
1284     { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
1285     { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
1286     { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
1287     { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
1288     { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
1289     { 0x02C7, 0xFF }, /* CARON */
1290     { 0x02D8, 0xF9 }, /* BREVE */
1291     { 0x02D9, 0xFA }, /* DOT ABOVE */
1292     { 0x02DA, 0xFB }, /* RING ABOVE */
1293     { 0x02DB, 0xFE }, /* OGONEK */
1294     { 0x02DC, 0xF7 }, /* SMALL TILDE */
1295     { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
1296     { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
1297     { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
1298     { 0x2013, 0xD0 }, /* EN DASH */
1299     { 0x2014, 0xD1 }, /* EM DASH */
1300     { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
1301     { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
1302     { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
1303     { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
1304     { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
1305     { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
1306     { 0x2020, 0xA0 }, /* DAGGER */
1307     { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
1308     { 0x2022, 0xA5 }, /* BULLET */
1309     { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
1310     { 0x2030, 0xE4 }, /* PER MILLE SIGN */
1311     { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
1312     { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
1313     { 0x2044, 0xDA }, /* FRACTION SLASH */
1314     { 0x20AC, 0xDB }, /* EURO SIGN */
1315     { 0x2122, 0xAA }, /* TRADE MARK SIGN */
1316     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
1317     { 0x2206, 0xC6 }, /* INCREMENT */
1318     { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
1319     { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
1320     { 0x221A, 0xC3 }, /* SQUARE ROOT */
1321     { 0x221E, 0xB0 }, /* INFINITY */
1322     { 0x222B, 0xBA }, /* INTEGRAL */
1323     { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
1324     { 0x2260, 0xAD }, /* NOT EQUAL TO */
1325     { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
1326     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
1327     { 0x25CA, 0xD7 }, /* LOZENGE */
1328     { 0xF8FF, 0xF0 }, /* Apple logo */
1329     { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
1330     { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
1331 };
1332
1333 static const FcCharMap AppleRoman = {
1334     AppleRomanEnt,
1335     sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
1336 };
1337
1338 static const FcCharEnt AdobeSymbolEnt[] = {
1339     { 0x0020, 0x20 }, /* SPACE  # space */
1340     { 0x0021, 0x21 }, /* EXCLAMATION MARK       # exclam */
1341     { 0x0023, 0x23 }, /* NUMBER SIGN    # numbersign */
1342     { 0x0025, 0x25 }, /* PERCENT SIGN   # percent */
1343     { 0x0026, 0x26 }, /* AMPERSAND      # ampersand */
1344     { 0x0028, 0x28 }, /* LEFT PARENTHESIS       # parenleft */
1345     { 0x0029, 0x29 }, /* RIGHT PARENTHESIS      # parenright */
1346     { 0x002B, 0x2B }, /* PLUS SIGN      # plus */
1347     { 0x002C, 0x2C }, /* COMMA  # comma */
1348     { 0x002E, 0x2E }, /* FULL STOP      # period */
1349     { 0x002F, 0x2F }, /* SOLIDUS        # slash */
1350     { 0x0030, 0x30 }, /* DIGIT ZERO     # zero */
1351     { 0x0031, 0x31 }, /* DIGIT ONE      # one */
1352     { 0x0032, 0x32 }, /* DIGIT TWO      # two */
1353     { 0x0033, 0x33 }, /* DIGIT THREE    # three */
1354     { 0x0034, 0x34 }, /* DIGIT FOUR     # four */
1355     { 0x0035, 0x35 }, /* DIGIT FIVE     # five */
1356     { 0x0036, 0x36 }, /* DIGIT SIX      # six */
1357     { 0x0037, 0x37 }, /* DIGIT SEVEN    # seven */
1358     { 0x0038, 0x38 }, /* DIGIT EIGHT    # eight */
1359     { 0x0039, 0x39 }, /* DIGIT NINE     # nine */
1360     { 0x003A, 0x3A }, /* COLON  # colon */
1361     { 0x003B, 0x3B }, /* SEMICOLON      # semicolon */
1362     { 0x003C, 0x3C }, /* LESS-THAN SIGN # less */
1363     { 0x003D, 0x3D }, /* EQUALS SIGN    # equal */
1364     { 0x003E, 0x3E }, /* GREATER-THAN SIGN      # greater */
1365     { 0x003F, 0x3F }, /* QUESTION MARK  # question */
1366     { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET    # bracketleft */
1367     { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET   # bracketright */
1368     { 0x005F, 0x5F }, /* LOW LINE       # underscore */
1369     { 0x007B, 0x7B }, /* LEFT CURLY BRACKET     # braceleft */
1370     { 0x007C, 0x7C }, /* VERTICAL LINE  # bar */
1371     { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET    # braceright */
1372     { 0x00A0, 0x20 }, /* NO-BREAK SPACE # space */
1373     { 0x00AC, 0xD8 }, /* NOT SIGN       # logicalnot */
1374     { 0x00B0, 0xB0 }, /* DEGREE SIGN    # degree */
1375     { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN        # plusminus */
1376     { 0x00B5, 0x6D }, /* MICRO SIGN     # mu */
1377     { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN    # multiply */
1378     { 0x00F7, 0xB8 }, /* DIVISION SIGN  # divide */
1379     { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK # florin */
1380     { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA     # Alpha */
1381     { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA      # Beta */
1382     { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA     # Gamma */
1383     { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA     # Delta */
1384     { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON   # Epsilon */
1385     { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA      # Zeta */
1386     { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA       # Eta */
1387     { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA     # Theta */
1388     { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA      # Iota */
1389     { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA     # Kappa */
1390     { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA     # Lambda */
1391     { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU        # Mu */
1392     { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU        # Nu */
1393     { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI        # Xi */
1394     { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON   # Omicron */
1395     { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI        # Pi */
1396     { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO       # Rho */
1397     { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA     # Sigma */
1398     { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU       # Tau */
1399     { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON   # Upsilon */
1400     { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI       # Phi */
1401     { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI       # Chi */
1402     { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI       # Psi */
1403     { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA     # Omega */
1404     { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA       # alpha */
1405     { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA        # beta */
1406     { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA       # gamma */
1407     { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA       # delta */
1408     { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON     # epsilon */
1409     { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA        # zeta */
1410     { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA # eta */
1411     { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA       # theta */
1412     { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA        # iota */
1413     { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA       # kappa */
1414     { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA       # lambda */
1415     { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU  # mu */
1416     { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU  # nu */
1417     { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI  # xi */
1418     { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON     # omicron */
1419     { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI  # pi */
1420     { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO # rho */
1421     { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA # sigma1 */
1422     { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA       # sigma */
1423     { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU # tau */
1424     { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON     # upsilon */
1425     { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI # phi */
1426     { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI # chi */
1427     { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI # psi */
1428     { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA       # omega */
1429     { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL     # theta1 */
1430     { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 */
1431     { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL       # phi1 */
1432     { 0x03D6, 0x76 }, /* GREEK PI SYMBOL        # omega1 */
1433     { 0x2022, 0xB7 }, /* BULLET # bullet */
1434     { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS    # ellipsis */
1435     { 0x2032, 0xA2 }, /* PRIME  # minute */
1436     { 0x2033, 0xB2 }, /* DOUBLE PRIME   # second */
1437     { 0x2044, 0xA4 }, /* FRACTION SLASH # fraction */
1438     { 0x20AC, 0xA0 }, /* EURO SIGN      # Euro */
1439     { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I # Ifraktur */
1440     { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P       # weierstrass */
1441     { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R # Rfraktur */
1442     { 0x2126, 0x57 }, /* OHM SIGN       # Omega */
1443     { 0x2135, 0xC0 }, /* ALEF SYMBOL    # aleph */
1444     { 0x2190, 0xAC }, /* LEFTWARDS ARROW        # arrowleft */
1445     { 0x2191, 0xAD }, /* UPWARDS ARROW  # arrowup */
1446     { 0x2192, 0xAE }, /* RIGHTWARDS ARROW       # arrowright */
1447     { 0x2193, 0xAF }, /* DOWNWARDS ARROW        # arrowdown */
1448     { 0x2194, 0xAB }, /* LEFT RIGHT ARROW       # arrowboth */
1449     { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS  # carriagereturn */
1450     { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW # arrowdblleft */
1451     { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW   # arrowdblup */
1452     { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW        # arrowdblright */
1453     { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW # arrowdbldown */
1454     { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW        # arrowdblboth */
1455     { 0x2200, 0x22 }, /* FOR ALL        # universal */
1456     { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL   # partialdiff */
1457     { 0x2203, 0x24 }, /* THERE EXISTS   # existential */
1458     { 0x2205, 0xC6 }, /* EMPTY SET      # emptyset */
1459     { 0x2206, 0x44 }, /* INCREMENT      # Delta */
1460     { 0x2207, 0xD1 }, /* NABLA  # gradient */
1461     { 0x2208, 0xCE }, /* ELEMENT OF     # element */
1462     { 0x2209, 0xCF }, /* NOT AN ELEMENT OF      # notelement */
1463     { 0x220B, 0x27 }, /* CONTAINS AS MEMBER     # suchthat */
1464     { 0x220F, 0xD5 }, /* N-ARY PRODUCT  # product */
1465     { 0x2211, 0xE5 }, /* N-ARY SUMMATION        # summation */
1466     { 0x2212, 0x2D }, /* MINUS SIGN     # minus */
1467     { 0x2215, 0xA4 }, /* DIVISION SLASH # fraction */
1468     { 0x2217, 0x2A }, /* ASTERISK OPERATOR      # asteriskmath */
1469     { 0x221A, 0xD6 }, /* SQUARE ROOT    # radical */
1470     { 0x221D, 0xB5 }, /* PROPORTIONAL TO        # proportional */
1471     { 0x221E, 0xA5 }, /* INFINITY       # infinity */
1472     { 0x2220, 0xD0 }, /* ANGLE  # angle */
1473     { 0x2227, 0xD9 }, /* LOGICAL AND    # logicaland */
1474     { 0x2228, 0xDA }, /* LOGICAL OR     # logicalor */
1475     { 0x2229, 0xC7 }, /* INTERSECTION   # intersection */
1476     { 0x222A, 0xC8 }, /* UNION  # union */
1477     { 0x222B, 0xF2 }, /* INTEGRAL       # integral */
1478     { 0x2234, 0x5C }, /* THEREFORE      # therefore */
1479     { 0x223C, 0x7E }, /* TILDE OPERATOR # similar */
1480     { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO # congruent */
1481     { 0x2248, 0xBB }, /* ALMOST EQUAL TO        # approxequal */
1482     { 0x2260, 0xB9 }, /* NOT EQUAL TO   # notequal */
1483     { 0x2261, 0xBA }, /* IDENTICAL TO   # equivalence */
1484     { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO  # lessequal */
1485     { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO       # greaterequal */
1486     { 0x2282, 0xCC }, /* SUBSET OF      # propersubset */
1487     { 0x2283, 0xC9 }, /* SUPERSET OF    # propersuperset */
1488     { 0x2284, 0xCB }, /* NOT A SUBSET OF        # notsubset */
1489     { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO  # reflexsubset */
1490     { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO        # reflexsuperset */
1491     { 0x2295, 0xC5 }, /* CIRCLED PLUS   # circleplus */
1492     { 0x2297, 0xC4 }, /* CIRCLED TIMES  # circlemultiply */
1493     { 0x22A5, 0x5E }, /* UP TACK        # perpendicular */
1494     { 0x22C5, 0xD7 }, /* DOT OPERATOR   # dotmath */
1495     { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL      # integraltp */
1496     { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL   # integralbt */
1497     { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET    # angleleft */
1498     { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET   # angleright */
1499     { 0x25CA, 0xE0 }, /* LOZENGE        # lozenge */
1500     { 0x2660, 0xAA }, /* BLACK SPADE SUIT       # spade */
1501     { 0x2663, 0xA7 }, /* BLACK CLUB SUIT        # club */
1502     { 0x2665, 0xA9 }, /* BLACK HEART SUIT       # heart */
1503     { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT     # diamond */
1504     { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF   # copyrightserif (CUS) */
1505     { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF  # registerserif (CUS) */
1506     { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF  # trademarkserif (CUS) */
1507     { 0xF8E5, 0x60 }, /* RADICAL EXTENDER       # radicalex (CUS) */
1508     { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER        # arrowvertex (CUS) */
1509     { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER      # arrowhorizex (CUS) */
1510     { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF     # registersans (CUS) */
1511     { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF      # copyrightsans (CUS) */
1512     { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF     # trademarksans (CUS) */
1513     { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP # parenlefttp (CUS) */
1514     { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER    # parenleftex (CUS) */
1515     { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM      # parenleftbt (CUS) */
1516     { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP        # bracketlefttp (CUS) */
1517     { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER   # bracketleftex (CUS) */
1518     { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM     # bracketleftbt (CUS) */
1519     { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP # bracelefttp (CUS) */
1520     { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID # braceleftmid (CUS) */
1521     { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM      # braceleftbt (CUS) */
1522     { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER # braceex (CUS) */
1523     { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER      # integralex (CUS) */
1524     { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP        # parenrighttp (CUS) */
1525     { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER   # parenrightex (CUS) */
1526     { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM     # parenrightbt (CUS) */
1527     { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP       # bracketrighttp (CUS) */
1528     { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER  # bracketrightex (CUS) */
1529     { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM    # bracketrightbt (CUS) */
1530     { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP        # bracerighttp (CUS) */
1531     { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID        # bracerightmid (CUS) */
1532     { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM     # bracerightbt (CUS) */
1533 };
1534
1535 static const FcCharMap AdobeSymbol = {
1536     AdobeSymbolEnt,
1537     sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
1538 };
1539     
1540 static const FcFontDecode fcFontDecoders[] = {
1541     { ft_encoding_unicode,      0,              (1 << 21) - 1 },
1542     { ft_encoding_symbol,       &AdobeSymbol,   (1 << 16) - 1 },
1543     { ft_encoding_apple_roman,  &AppleRoman,    (1 << 16) - 1 },
1544 };
1545
1546 #define NUM_DECODE  (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
1547
1548 FcChar32
1549 FcFreeTypeUcs4ToPrivate (FcChar32 ucs4, const FcCharMap *map)
1550 {
1551     int         low, high, mid;
1552     FcChar16    bmp;
1553
1554     low = 0;
1555     high = map->nent - 1;
1556     if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
1557         return ~0;
1558     while (low <= high)
1559     {
1560         mid = (high + low) >> 1;
1561         bmp = map->ent[mid].bmp;
1562         if (ucs4 == bmp)
1563             return (FT_ULong) map->ent[mid].encode;
1564         if (ucs4 < bmp)
1565             high = mid - 1;
1566         else
1567             low = mid + 1;
1568     }
1569     return ~0;
1570 }
1571
1572 FcChar32
1573 FcFreeTypePrivateToUcs4 (FcChar32 private, const FcCharMap *map)
1574 {
1575     int     i;
1576
1577     for (i = 0; i < map->nent; i++)
1578         if (map->ent[i].encode == private)
1579             return (FcChar32) map->ent[i].bmp;
1580     return ~0;
1581 }
1582
1583 const FcCharMap *
1584 FcFreeTypeGetPrivateMap (FT_Encoding encoding)
1585 {
1586     int i;
1587
1588     for (i = 0; i < NUM_DECODE; i++)
1589         if (fcFontDecoders[i].encoding == encoding)
1590             return fcFontDecoders[i].map;
1591     return 0;
1592 }
1593
1594 #include "../fc-glyphname/fcglyphname.h"
1595
1596 static FcChar32
1597 FcHashGlyphName (const FcChar8 *name)
1598 {
1599     FcChar32    h = 0;
1600     FcChar8     c;
1601
1602     while ((c = *name++))
1603     {
1604         h = ((h << 1) | (h >> 31)) ^ c;
1605     }
1606     return h;
1607 }
1608
1609 /*
1610  * Use Type1 glyph names for fonts which have reliable names
1611  * and which export an Adobe Custom mapping
1612  */
1613 static FcBool
1614 FcFreeTypeUseNames (FT_Face face)
1615 {
1616     FT_Int  map;
1617     
1618     if (!FT_Has_PS_Glyph_Names (face))
1619         return FcFalse;
1620     for (map = 0; map < face->num_charmaps; map++)
1621         if (face->charmaps[map]->encoding == ft_encoding_adobe_custom)
1622             return FcTrue;
1623     return FcFalse;
1624 }
1625
1626 static FcChar8 *
1627 FcUcs4ToGlyphName (FcChar32 ucs4)
1628 {
1629     int         i = (int) (ucs4 % FC_GLYPHNAME_HASH);
1630     int         r = 0;
1631     FcGlyphName *gn;
1632
1633     while ((gn = ucs_to_name[i]))
1634     {
1635         if (gn->ucs == ucs4)
1636             return gn->name;
1637         if (!r) 
1638         {
1639             r = (int) (ucs4 % FC_GLYPHNAME_REHASH);
1640             if (!r)
1641                 r = 1;
1642         }
1643         i += r;
1644         if (i >= FC_GLYPHNAME_HASH)
1645             i -= FC_GLYPHNAME_HASH;
1646     }
1647     return 0;
1648 }
1649
1650 static FcChar32
1651 FcGlyphNameToUcs4 (FcChar8 *name)
1652 {
1653     FcChar32    h = FcHashGlyphName (name);
1654     int         i = (int) (h % FC_GLYPHNAME_HASH);
1655     int         r = 0;
1656     FcGlyphName *gn;
1657
1658     while ((gn = name_to_ucs[i]))
1659     {
1660         if (!strcmp ((char *) name, (char *) gn->name))
1661             return gn->ucs;
1662         if (!r) 
1663         {
1664             r = (int) (h % FC_GLYPHNAME_REHASH);
1665             if (!r)
1666                 r = 1;
1667         }
1668         i += r;
1669         if (i >= FC_GLYPHNAME_HASH)
1670             i -= FC_GLYPHNAME_HASH;
1671     }
1672     return 0xffff;
1673 }
1674
1675 /*
1676  * Search through a font for a glyph by name.  This is
1677  * currently a linear search as there doesn't appear to be
1678  * any defined order within the font
1679  */
1680 static FT_UInt
1681 FcFreeTypeGlyphNameIndex (FT_Face face, FcChar8 *name)
1682 {
1683     FT_UInt gindex;
1684     FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
1685
1686     for (gindex = 0; gindex < face->num_glyphs; gindex++)
1687     {
1688         if (FT_Get_Glyph_Name (face, gindex, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
1689             if (!strcmp ((char *) name, (char *) name_buf))
1690                 return gindex;
1691     }
1692     return 0;
1693 }
1694
1695 /*
1696  * Map a UCS4 glyph to a glyph index.  Use all available encoding
1697  * tables to try and find one that works.  This information is expected
1698  * to be cached by higher levels, so performance isn't critical
1699  */
1700
1701 FT_UInt
1702 FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
1703 {
1704     int             initial, offset, decode;
1705     FT_UInt         glyphindex;
1706     FcChar32        charcode;
1707
1708     initial = 0;
1709     /*
1710      * Find the current encoding
1711      */
1712     if (face->charmap)
1713     {
1714         for (; initial < NUM_DECODE; initial++)
1715             if (fcFontDecoders[initial].encoding == face->charmap->encoding)
1716                 break;
1717         if (initial == NUM_DECODE)
1718             initial = 0;
1719     }
1720     /*
1721      * Check each encoding for the glyph, starting with the current one
1722      */
1723     for (offset = 0; offset < NUM_DECODE; offset++)
1724     {
1725         decode = (initial + offset) % NUM_DECODE;
1726         if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
1727             if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
1728                 continue;
1729         if (fcFontDecoders[decode].map)
1730         {
1731             charcode = FcFreeTypeUcs4ToPrivate (ucs4, fcFontDecoders[decode].map);
1732             if (charcode == ~0)
1733                 continue;
1734         }
1735         else
1736             charcode = ucs4;
1737         glyphindex = FT_Get_Char_Index (face, (FT_ULong) charcode);
1738         if (glyphindex)
1739             return glyphindex;
1740     }
1741     /*
1742      * Check postscript name table if present
1743      */
1744     if (FcFreeTypeUseNames (face))
1745     {
1746         FcChar8 *name = FcUcs4ToGlyphName (ucs4);
1747         if (name)
1748         {
1749             glyphindex = FcFreeTypeGlyphNameIndex (face, name);
1750             if (glyphindex)
1751                 return glyphindex;
1752         }
1753     }
1754     return 0;
1755 }
1756
1757 static FcBool
1758 FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, 
1759                       FT_UInt glyph, FcBlanks *blanks,
1760                       FT_Pos *advance)
1761 {
1762     FT_Int          load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
1763     FT_GlyphSlot    slot;
1764     
1765     /*
1766      * When using scalable fonts, only report those glyphs
1767      * which can be scaled; otherwise those fonts will
1768      * only be available at some sizes, and never when
1769      * transformed.  Avoid this by simply reporting bitmap-only
1770      * glyphs as missing
1771      */
1772     if (face->face_flags & FT_FACE_FLAG_SCALABLE)
1773         load_flags |= FT_LOAD_NO_BITMAP;
1774     
1775     if (FT_Load_Glyph (face, glyph, load_flags))
1776         return FcFalse;
1777     
1778     slot = face->glyph;
1779     if (!glyph)
1780         return FcFalse;
1781     
1782     *advance = slot->metrics.horiAdvance;
1783
1784     switch (slot->format) {
1785     case ft_glyph_format_bitmap:
1786         /*
1787          * Bitmaps are assumed to be reasonable; if
1788          * this proves to be a rash assumption, this
1789          * code can be easily modified
1790          */
1791         return FcTrue;
1792     case ft_glyph_format_outline:
1793         /*
1794          * Glyphs with contours are always OK
1795          */
1796         if (slot->outline.n_contours != 0)
1797             return FcTrue;
1798         /*
1799          * Glyphs with no contours are only OK if
1800          * they're members of the Blanks set specified
1801          * in the configuration.  If blanks isn't set,
1802          * then allow any glyph to be blank
1803          */
1804         if (!blanks || FcBlanksIsMember (blanks, ucs4))
1805             return FcTrue;
1806         /* fall through ... */
1807     default:
1808         break;
1809     }
1810     return FcFalse;
1811 }
1812
1813 FcCharSet *
1814 FcFreeTypeCharSetAndSpacing (FT_Face face, FcBlanks *blanks, int *spacing)
1815 {
1816     FcChar32        page, off, max, ucs4;
1817 #ifdef CHECK
1818     FcChar32        font_max = 0;
1819 #endif
1820     FcCharSet       *fcs;
1821     FcCharLeaf      *leaf;
1822     const FcCharMap *map;
1823     int             o;
1824     int             i;
1825     FT_UInt         glyph;
1826     FT_Pos          advance, all_advance = 0;
1827     FcBool          has_advance = FcFalse, fixed_advance = FcTrue;
1828
1829     fcs = FcCharSetCreate ();
1830     if (!fcs)
1831         goto bail0;
1832     
1833 #ifdef CHECK
1834     printf ("Family %s style %s\n", face->family_name, face->style_name);
1835 #endif
1836     for (o = 0; o < NUM_DECODE; o++)
1837     {
1838         if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
1839             continue;
1840         map = fcFontDecoders[o].map;
1841         if (map)
1842         {
1843             /*
1844              * Non-Unicode tables are easy; there's a list of all possible
1845              * characters
1846              */
1847             for (i = 0; i < map->nent; i++)
1848             {
1849                 ucs4 = map->ent[i].bmp;
1850                 glyph = FT_Get_Char_Index (face, map->ent[i].encode);
1851                 if (glyph && 
1852                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
1853                 {
1854                     if (!has_advance)
1855                     {
1856                         has_advance = FcTrue;
1857                         all_advance = advance;
1858                     }
1859                     else if (advance != all_advance)
1860                         fixed_advance = FcFalse;
1861                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
1862                     if (!leaf)
1863                         goto bail1;
1864                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
1865 #ifdef CHECK
1866                     if (ucs4 > font_max)
1867                         font_max = ucs4;
1868 #endif
1869                 }
1870             }
1871         }
1872         else
1873         {
1874             FT_UInt gindex;
1875           
1876             max = fcFontDecoders[o].max;
1877             /*
1878              * Find the first encoded character in the font
1879              */
1880             if (FT_Get_Char_Index (face, 0))
1881             {
1882                 ucs4 = 0;
1883                 gindex = 1;
1884             }
1885             else
1886             {
1887                 ucs4 = FT_Get_Next_Char (face, 0, &gindex);
1888                 if (!ucs4)
1889                     gindex = 0;
1890             }
1891
1892             while (gindex)
1893             {
1894                 page = ucs4 >> 8;
1895                 leaf = 0;
1896                 while ((ucs4 >> 8) == page)
1897                 {
1898                     glyph = FT_Get_Char_Index (face, ucs4);
1899                     if (glyph && FcFreeTypeCheckGlyph (face, ucs4, 
1900                                                        glyph, blanks, &advance))
1901                     {
1902                         if (!has_advance)
1903                         {
1904                             has_advance = FcTrue;
1905                             all_advance = advance;
1906                         }
1907                         else if (advance != all_advance)
1908                             fixed_advance = FcFalse;
1909                         if (!leaf)
1910                         {
1911                             leaf = FcCharSetFindLeafCreate (fcs, ucs4);
1912                             if (!leaf)
1913                                 goto bail1;
1914                         }
1915                         off = ucs4 & 0xff;
1916                         leaf->map[off >> 5] |= (1 << (off & 0x1f));
1917 #ifdef CHECK
1918                         if (ucs4 > font_max)
1919                             font_max = ucs4;
1920 #endif
1921                     }
1922                     ucs4++;
1923                 }
1924                 ucs4 = FT_Get_Next_Char (face, ucs4 - 1, &gindex);
1925                 if (!ucs4)
1926                     gindex = 0;
1927             }
1928 #ifdef CHECK
1929             for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
1930             {
1931                 FcBool      FT_Has, FC_Has;
1932
1933                 FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
1934                 FC_Has = FcCharSetHasChar (fcs, ucs4);
1935                 if (FT_Has != FC_Has)
1936                 {
1937                     printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
1938                 }
1939             }
1940 #endif
1941         }
1942     }
1943     /*
1944      * Add mapping from PS glyph names if available
1945      */
1946     if (FcFreeTypeUseNames (face))
1947     {
1948         FcChar8 name_buf[FC_GLYPHNAME_MAXLEN + 2];
1949
1950         for (glyph = 0; glyph < face->num_glyphs; glyph++)
1951         {
1952             if (FT_Get_Glyph_Name (face, glyph, name_buf, FC_GLYPHNAME_MAXLEN+1) == 0)
1953             {
1954                 ucs4 = FcGlyphNameToUcs4 (name_buf);
1955                 if (ucs4 != 0xffff && 
1956                     FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
1957                 {
1958                     if (!has_advance)
1959                     {
1960                         has_advance = FcTrue;
1961                         all_advance = advance;
1962                     }
1963                     else if (advance != all_advance)
1964                         fixed_advance = FcFalse;
1965                     leaf = FcCharSetFindLeafCreate (fcs, ucs4);
1966                     if (!leaf)
1967                         goto bail1;
1968                     leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
1969 #ifdef CHECK
1970                     if (ucs4 > font_max)
1971                         font_max = ucs4;
1972 #endif
1973                 }
1974             }
1975         }
1976     }
1977 #ifdef CHECK
1978     printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
1979     for (ucs4 = 0; ucs4 <= font_max; ucs4++)
1980     {
1981         FcBool  has_char = (glyph = FcFreeTypeCharIndex (face, ucs4)) != 0;
1982         FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
1983
1984         if (has_char && !has_bit)
1985         {
1986             if (!FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks, &advance))
1987                 printf ("Bitmap missing broken char 0x%x\n", ucs4);
1988             else
1989                 printf ("Bitmap missing char 0x%x\n", ucs4);
1990         }
1991         else if (!has_char && has_bit)
1992             printf ("Bitmap extra char 0x%x\n", ucs4);
1993     }
1994 #endif
1995     if (fixed_advance)
1996         *spacing = FC_MONO;
1997     else
1998         *spacing = FC_PROPORTIONAL;
1999     return fcs;
2000 bail1:
2001     FcCharSetDestroy (fcs);
2002 bail0:
2003     return 0;
2004 }
2005
2006 FcCharSet *
2007 FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
2008 {
2009     int spacing;
2010
2011     return FcFreeTypeCharSetAndSpacing (face, blanks, &spacing);
2012 }