2 * $XFree86: xc/lib/fontconfig/src/fcfreetype.c,v 1.9 2002/07/13 05:43:25 keithp Exp $
4 * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
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.
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.
29 #include <freetype/freetype.h>
30 #include <freetype/internal/ftobjs.h>
31 #include <freetype/tttables.h>
32 #include <freetype/ftsnames.h>
33 #include <freetype/ttnameid.h>
36 * Keep Han languages separated by eliminating languages
37 * that the codePageRange bits says aren't supported
43 } FcCodePageRange[] = {
44 { 17, (const FcChar8 *) "ja" },
45 { 18, (const FcChar8 *) "zh-cn" },
46 { 19, (const FcChar8 *) "ko" },
47 { 20, (const FcChar8 *) "zh-tw" },
50 #define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
53 FcFreeTypeIsExclusiveLang (const FcChar8 *lang)
57 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
59 if (FcLangCompare (lang, FcCodePageRange[i].lang) != FcLangDifferentLang)
65 #define FC_NAME_PRIO_LANG 0x0f00
66 #define FC_NAME_PRIO_LANG_ENGLISH 0x0200
67 #define FC_NAME_PRIO_LANG_LATIN 0x0100
68 #define FC_NAME_PRIO_LANG_NONE 0x0000
70 #define FC_NAME_PRIO_ENC 0x00f0
71 #define FC_NAME_PRIO_ENC_UNICODE 0x0010
72 #define FC_NAME_PRIO_ENC_NONE 0x0000
74 #define FC_NAME_PRIO_NAME 0x000f
75 #define FC_NAME_PRIO_NAME_FAMILY 0x0002
76 #define FC_NAME_PRIO_NAME_PS 0x0001
77 #define FC_NAME_PRIO_NAME_NONE 0x0000
80 FcUcs4IsLatin (FcChar32 ucs4)
82 FcChar32 page = ucs4 >> 8;
88 if (0x20 <= page && page <= 0x23)
98 FcUtf8IsLatin (FcChar8 *str, int len)
103 int clen = FcUtf8ToUcs4 (str, &ucs4, len);
106 if (!FcUcs4IsLatin (ucs4))
115 FcFreeTypeQuery (const FcChar8 *file,
127 FT_Library ftLibrary;
131 const FcChar8 *exclusiveLang = 0;
133 FT_UInt snamei, snamec;
134 FcBool family_allocated = FcFalse;
135 FcBool style_allocated = FcFalse;
139 if (FT_Init_FreeType (&ftLibrary))
142 if (FT_New_Face (ftLibrary, (char *) file, id, &face))
145 *count = face->num_faces;
147 pat = FcPatternCreate ();
151 if (!FcPatternAddBool (pat, FC_OUTLINE,
152 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
155 if (!FcPatternAddBool (pat, FC_SCALABLE,
156 (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
160 slant = FC_SLANT_ROMAN;
161 if (face->style_flags & FT_STYLE_FLAG_ITALIC)
162 slant = FC_SLANT_ITALIC;
164 if (!FcPatternAddInteger (pat, FC_SLANT, slant))
167 weight = FC_WEIGHT_MEDIUM;
168 if (face->style_flags & FT_STYLE_FLAG_BOLD)
169 weight = FC_WEIGHT_BOLD;
171 if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
175 * Grub through the name table looking for family
176 * and style names. FreeType makes quite a hash
181 snamec = FT_Get_Sfnt_Name_Count (face);
182 for (snamei = 0; snamei < snamec; snamei++)
194 const FcCharMap *map;
197 FcNameEncodingAppleRoman,
202 if (FT_Get_Sfnt_Name (face, snamei, &sname) != 0)
206 * Look for Unicode strings
208 switch (sname.platform_id) {
209 case TT_PLATFORM_APPLE_UNICODE:
211 * All APPLE_UNICODE encodings are Utf16 BE
213 * Because there's no language id for Unicode,
214 * assume it's English
216 prio |= FC_NAME_PRIO_LANG_ENGLISH;
217 prio |= FC_NAME_PRIO_ENC_UNICODE;
218 encoding = FcNameEncodingUtf16;
220 case TT_PLATFORM_MACINTOSH:
221 switch (sname.encoding_id) {
222 case TT_MAC_ID_ROMAN:
223 encoding = FcNameEncodingAppleRoman;
228 switch (sname.language_id) {
229 case TT_MAC_LANGID_ENGLISH:
230 prio |= FC_NAME_PRIO_LANG_ENGLISH;
234 * Sometimes Microsoft language ids
235 * end up in the macintosh table. This
236 * is often accompanied by data in
237 * some mystic encoding. Ignore these names
239 if (sname.language_id >= 0x100)
244 case TT_PLATFORM_MICROSOFT:
245 switch (sname.encoding_id) {
246 case TT_MS_ID_UNICODE_CS:
247 encoding = FcNameEncodingUtf16;
248 prio |= FC_NAME_PRIO_ENC_UNICODE;
253 switch (sname.language_id & 0xff) {
255 prio |= FC_NAME_PRIO_LANG_ENGLISH;
261 case TT_PLATFORM_ISO:
262 switch (sname.encoding_id) {
263 case TT_ISO_ID_10646:
264 encoding = FcNameEncodingUtf16;
265 prio |= FC_NAME_PRIO_ENC_UNICODE;
267 case TT_ISO_ID_7BIT_ASCII:
268 case TT_ISO_ID_8859_1:
269 encoding = FcNameEncodingLatin1;
280 * Look for family and style names
282 switch (sname.name_id) {
283 case TT_NAME_ID_FONT_FAMILY:
284 prio |= FC_NAME_PRIO_NAME_FAMILY;
286 case TT_NAME_ID_PS_NAME:
287 prio |= FC_NAME_PRIO_NAME_PS;
289 case TT_NAME_ID_FONT_SUBFAMILY:
295 src = (FcChar8 *) sname.string;
296 src_len = sname.string_len;
299 case FcNameEncodingUtf16:
301 * Convert Utf16 to Utf8
304 if (!FcUtf16Len (src, FcEndianBig, src_len, &len, &wchar))
308 * Allocate plenty of space
310 utf8 = malloc (len * FC_UTF8_MAX_LEN + 1);
316 while ((ilen = FcUtf16ToUcs4 (src, FcEndianBig, &ucs4, src_len)) > 0)
320 olen = FcUcs4ToUtf8 (ucs4, u8);
325 case FcNameEncodingLatin1:
327 * Convert Latin1 to Utf8
329 utf8 = malloc (src_len * 2 + 1);
338 olen = FcUcs4ToUtf8 (ucs4, u8);
343 case FcNameEncodingAppleRoman:
345 * Convert AppleRoman to Utf8
347 map = FcFreeTypeGetPrivateMap (ft_encoding_apple_roman);
351 utf8 = malloc (src_len * 3 + 1);
358 ucs4 = FcFreeTypePrivateToUcs4 (*src++, map);
360 olen = FcUcs4ToUtf8 (ucs4, u8);
368 if ((prio & FC_NAME_PRIO_LANG) == FC_NAME_PRIO_LANG_NONE)
369 if (FcUtf8IsLatin (utf8, strlen ((char *) utf8)))
370 prio |= FC_NAME_PRIO_LANG_LATIN;
372 if (FcDebug () & FC_DBG_SCANV)
373 printf ("\nfound name (name %d platform %d encoding %d language 0x%x prio 0x%x) %s\n",
374 sname.name_id, sname.platform_id,
375 sname.encoding_id, sname.language_id,
378 switch (sname.name_id) {
379 case TT_NAME_ID_FONT_FAMILY:
380 case TT_NAME_ID_PS_NAME:
381 if (!family || prio > family_prio)
387 family_allocated = FcTrue;
391 case TT_NAME_ID_FONT_SUBFAMILY:
392 if (!style || prio > style_prio)
398 style_allocated = FcTrue;
408 family = (FcChar8 *) face->family_name;
411 style = (FcChar8 *) face->style_name;
415 FcChar8 *start, *end;
417 start = (FcChar8 *) strrchr ((char *) file, '/');
421 start = (FcChar8 *) file;
422 end = (FcChar8 *) strrchr ((char *) start, '.');
424 end = start + strlen ((char *) start);
425 family = malloc (end - start + 1);
426 strncpy ((char *) family, (char *) start, end - start);
427 family[end - start] = '\0';
428 family_allocated = FcTrue;
431 if (FcDebug() & FC_DBG_SCAN)
432 printf ("\"%s\" \"%s\" ", family, style ? style : (FcChar8 *) "<none>");
434 if (!FcPatternAddString (pat, FC_FAMILY, family))
436 if (family_allocated)
443 if (family_allocated)
448 if (!FcPatternAddString (pat, FC_STYLE, style))
458 if (!FcPatternAddString (pat, FC_FILE, file))
461 if (!FcPatternAddInteger (pat, FC_INDEX, id))
464 if (!FcPatternAddString (pat, FC_SOURCE, (FcChar8 *) "FreeType"))
468 if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
469 if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
474 * Get the OS/2 table and poke about
476 os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
477 if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
479 for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
483 if (FcCodePageRange[i].bit < 32)
485 bits = os2->ulCodePageRange1;
486 bit = FcCodePageRange[i].bit;
490 bits = os2->ulCodePageRange2;
491 bit = FcCodePageRange[i].bit - 32;
493 if (bits & (1 << bit))
496 * If the font advertises support for multiple
497 * "exclusive" languages, then include support
498 * for any language found to have coverage
505 exclusiveLang = FcCodePageRange[i].lang;
511 * Compute the unicode coverage for the font
513 cs = FcFreeTypeCharSet (face, blanks);
518 * Skip over PCF fonts that have no encoded characters; they're
519 * usually just Unicode fonts transcoded to some legacy encoding
521 if (FcCharSetCount (cs) == 0)
523 if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
527 if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
530 ls = FcFreeTypeLangSet (cs, exclusiveLang);
534 if (!FcPatternAddLangSet (pat, FC_LANG, ls))
538 * Drop our reference to the charset
540 FcCharSetDestroy (cs);
542 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
544 for (i = 0; i < face->num_fixed_sizes; i++)
545 if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
546 (double) face->available_sizes[i].height))
548 if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
553 FT_Done_FreeType (ftLibrary);
557 FcCharSetDestroy (cs);
559 FcPatternDestroy (pat);
563 FT_Done_FreeType (ftLibrary);