2 * $XFree86: xc/lib/fontconfig/src/fcfreetype.c,v 1.8 2002/07/09 02:28:29 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
,
126 FT_Library ftLibrary
;
130 const FcChar8
*exclusiveLang
= 0;
132 FT_UInt snamei
, snamec
;
133 FcBool family_allocated
= FcFalse
;
134 FcBool style_allocated
= FcFalse
;
138 if (FT_Init_FreeType (&ftLibrary
))
141 if (FT_New_Face (ftLibrary
, (char *) file
, id
, &face
))
144 *count
= face
->num_faces
;
146 pat
= FcPatternCreate ();
150 if (!FcPatternAddBool (pat
, FC_OUTLINE
,
151 (face
->face_flags
& FT_FACE_FLAG_SCALABLE
) != 0))
154 if (!FcPatternAddBool (pat
, FC_SCALABLE
,
155 (face
->face_flags
& FT_FACE_FLAG_SCALABLE
) != 0))
159 slant
= FC_SLANT_ROMAN
;
160 if (face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
161 slant
= FC_SLANT_ITALIC
;
163 if (!FcPatternAddInteger (pat
, FC_SLANT
, slant
))
166 weight
= FC_WEIGHT_MEDIUM
;
167 if (face
->style_flags
& FT_STYLE_FLAG_BOLD
)
168 weight
= FC_WEIGHT_BOLD
;
170 if (!FcPatternAddInteger (pat
, FC_WEIGHT
, weight
))
174 * Grub through the name table looking for family
175 * and style names. FreeType makes quite a hash
180 snamec
= FT_Get_Sfnt_Name_Count (face
);
181 for (snamei
= 0; snamei
< snamec
; snamei
++)
193 const FcCharMap
*map
;
196 FcNameEncodingAppleRoman
,
201 if (FT_Get_Sfnt_Name (face
, snamei
, &sname
) != 0)
205 * Look for Unicode strings
207 switch (sname
.platform_id
) {
208 case TT_PLATFORM_APPLE_UNICODE
:
210 * All APPLE_UNICODE encodings are Utf16 BE
212 * Because there's no language id for Unicode,
213 * assume it's English
215 prio
|= FC_NAME_PRIO_LANG_ENGLISH
;
216 prio
|= FC_NAME_PRIO_ENC_UNICODE
;
217 encoding
= FcNameEncodingUtf16
;
219 case TT_PLATFORM_MACINTOSH
:
220 switch (sname
.encoding_id
) {
221 case TT_MAC_ID_ROMAN
:
222 encoding
= FcNameEncodingAppleRoman
;
227 switch (sname
.language_id
) {
228 case TT_MAC_LANGID_ENGLISH
:
229 prio
|= FC_NAME_PRIO_LANG_ENGLISH
;
233 * Sometimes Microsoft language ids
234 * end up in the macintosh table. This
235 * is often accompanied by data in
236 * some mystic encoding. Ignore these names
238 if (sname
.language_id
>= 0x100)
243 case TT_PLATFORM_MICROSOFT
:
244 switch (sname
.encoding_id
) {
245 case TT_MS_ID_UNICODE_CS
:
246 encoding
= FcNameEncodingUtf16
;
247 prio
|= FC_NAME_PRIO_ENC_UNICODE
;
252 switch (sname
.language_id
& 0xff) {
254 prio
|= FC_NAME_PRIO_LANG_ENGLISH
;
260 case TT_PLATFORM_ISO
:
261 switch (sname
.encoding_id
) {
262 case TT_ISO_ID_10646
:
263 encoding
= FcNameEncodingUtf16
;
264 prio
|= FC_NAME_PRIO_ENC_UNICODE
;
266 case TT_ISO_ID_7BIT_ASCII
:
267 case TT_ISO_ID_8859_1
:
268 encoding
= FcNameEncodingLatin1
;
279 * Look for family and style names
281 switch (sname
.name_id
) {
282 case TT_NAME_ID_FONT_FAMILY
:
283 prio
|= FC_NAME_PRIO_NAME_FAMILY
;
285 case TT_NAME_ID_PS_NAME
:
286 prio
|= FC_NAME_PRIO_NAME_PS
;
288 case TT_NAME_ID_FONT_SUBFAMILY
:
294 src
= (FcChar8
*) sname
.string
;
295 src_len
= sname
.string_len
;
298 case FcNameEncodingUtf16
:
300 * Convert Utf16 to Utf8
303 if (!FcUtf16Len (src
, FcEndianBig
, src_len
, &len
, &wchar
))
307 * Allocate plenty of space
309 utf8
= malloc (len
* FC_UTF8_MAX_LEN
+ 1);
315 while ((ilen
= FcUtf16ToUcs4 (src
, FcEndianBig
, &ucs4
, src_len
)) > 0)
319 olen
= FcUcs4ToUtf8 (ucs4
, u8
);
324 case FcNameEncodingLatin1
:
326 * Convert Latin1 to Utf8
328 utf8
= malloc (src_len
* 2 + 1);
337 olen
= FcUcs4ToUtf8 (ucs4
, u8
);
342 case FcNameEncodingAppleRoman
:
344 * Convert AppleRoman to Utf8
346 map
= FcFreeTypeGetPrivateMap (ft_encoding_apple_roman
);
350 utf8
= malloc (src_len
* 3 + 1);
357 ucs4
= FcFreeTypePrivateToUcs4 (*src
++, map
);
359 olen
= FcUcs4ToUtf8 (ucs4
, u8
);
367 if ((prio
& FC_NAME_PRIO_LANG
) == FC_NAME_PRIO_LANG_NONE
)
368 if (FcUtf8IsLatin (utf8
, strlen ((char *) utf8
)))
369 prio
|= FC_NAME_PRIO_LANG_LATIN
;
371 if (FcDebug () & FC_DBG_SCANV
)
372 printf ("\nfound name (name %d platform %d encoding %d language 0x%x prio 0x%x) %s\n",
373 sname
.name_id
, sname
.platform_id
,
374 sname
.encoding_id
, sname
.language_id
,
377 switch (sname
.name_id
) {
378 case TT_NAME_ID_FONT_FAMILY
:
379 case TT_NAME_ID_PS_NAME
:
380 if (!family
|| prio
> family_prio
)
386 family_allocated
= FcTrue
;
390 case TT_NAME_ID_FONT_SUBFAMILY
:
391 if (!style
|| prio
> style_prio
)
397 style_allocated
= FcTrue
;
407 family
= (FcChar8
*) face
->family_name
;
410 style
= (FcChar8
*) face
->style_name
;
414 FcChar8
*start
, *end
;
416 start
= (FcChar8
*) strrchr ((char *) file
, '/');
420 start
= (FcChar8
*) file
;
421 end
= (FcChar8
*) strrchr ((char *) start
, '.');
423 end
= start
+ strlen ((char *) start
);
424 family
= malloc (end
- start
+ 1);
425 strncpy ((char *) family
, (char *) start
, end
- start
);
426 family
[end
- start
] = '\0';
427 family_allocated
= FcTrue
;
430 if (FcDebug() & FC_DBG_SCAN
)
431 printf ("\"%s\" \"%s\" ", family
, style
? style
: (FcChar8
*) "<none>");
433 if (!FcPatternAddString (pat
, FC_FAMILY
, family
))
435 if (family_allocated
)
442 if (family_allocated
)
447 if (!FcPatternAddString (pat
, FC_STYLE
, style
))
457 if (!FcPatternAddString (pat
, FC_FILE
, file
))
460 if (!FcPatternAddInteger (pat
, FC_INDEX
, id
))
463 if (!FcPatternAddString (pat
, FC_SOURCE
, (FcChar8
*) "FreeType"))
467 if ((face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
) != 0)
468 if (!FcPatternAddInteger (pat
, FC_SPACING
, FC_MONO
))
473 * Get the OS/2 table and poke about
475 os2
= (TT_OS2
*) FT_Get_Sfnt_Table (face
, ft_sfnt_os2
);
476 if (os2
&& os2
->version
>= 0x0001 && os2
->version
!= 0xffff)
478 for (i
= 0; i
< NUM_CODE_PAGE_RANGE
; i
++)
482 if (FcCodePageRange
[i
].bit
< 32)
484 bits
= os2
->ulCodePageRange1
;
485 bit
= FcCodePageRange
[i
].bit
;
489 bits
= os2
->ulCodePageRange2
;
490 bit
= FcCodePageRange
[i
].bit
- 32;
492 if (bits
& (1 << bit
))
495 * If the font advertises support for multiple
496 * "exclusive" languages, then include support
497 * for any language found to have coverage
504 exclusiveLang
= FcCodePageRange
[i
].lang
;
510 * Compute the unicode coverage for the font
512 cs
= FcFreeTypeCharSet (face
, blanks
);
517 * Skip over PCF fonts that have no encoded characters; they're
518 * usually just Unicode fonts transcoded to some legacy encoding
520 if (FcCharSetCount (cs
) == 0)
522 if (!strcmp(FT_MODULE_CLASS(&face
->driver
->root
)->module_name
, "pcf"))
526 if (!FcPatternAddCharSet (pat
, FC_CHARSET
, cs
))
529 if (!FcFreeTypeSetLang (pat
, cs
, exclusiveLang
))
533 * Drop our reference to the charset
535 FcCharSetDestroy (cs
);
537 if (!(face
->face_flags
& FT_FACE_FLAG_SCALABLE
))
539 for (i
= 0; i
< face
->num_fixed_sizes
; i
++)
540 if (!FcPatternAddDouble (pat
, FC_PIXEL_SIZE
,
541 (double) face
->available_sizes
[i
].height
))
543 if (!FcPatternAddBool (pat
, FC_ANTIALIAS
, FcFalse
))
548 FT_Done_FreeType (ftLibrary
);
552 FcCharSetDestroy (cs
);
554 FcPatternDestroy (pat
);
558 FT_Done_FreeType (ftLibrary
);