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
);