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