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