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