2 * $XFree86: xc/lib/fontconfig/src/fcfreetype.c,v 1.11 2002/08/31 22:17:32 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
;
132 const FcChar8
*exclusiveLang
= 0;
134 FT_UInt snamei
, snamec
;
135 FcBool family_allocated
= FcFalse
;
136 FcBool style_allocated
= FcFalse
;
140 if (FT_Init_FreeType (&ftLibrary
))
143 if (FT_New_Face (ftLibrary
, (char *) file
, id
, &face
))
146 *count
= face
->num_faces
;
148 pat
= FcPatternCreate ();
152 if (!FcPatternAddBool (pat
, FC_OUTLINE
,
153 (face
->face_flags
& FT_FACE_FLAG_SCALABLE
) != 0))
156 if (!FcPatternAddBool (pat
, FC_SCALABLE
,
157 (face
->face_flags
& FT_FACE_FLAG_SCALABLE
) != 0))
161 slant
= FC_SLANT_ROMAN
;
162 if (face
->style_flags
& FT_STYLE_FLAG_ITALIC
)
163 slant
= FC_SLANT_ITALIC
;
165 if (!FcPatternAddInteger (pat
, FC_SLANT
, slant
))
168 weight
= FC_WEIGHT_MEDIUM
;
169 if (face
->style_flags
& FT_STYLE_FLAG_BOLD
)
170 weight
= FC_WEIGHT_BOLD
;
172 if (!FcPatternAddInteger (pat
, FC_WEIGHT
, weight
))
176 * Grub through the name table looking for family
177 * and style names. FreeType makes quite a hash
182 snamec
= FT_Get_Sfnt_Name_Count (face
);
183 for (snamei
= 0; snamei
< snamec
; snamei
++)
195 const FcCharMap
*map
;
198 FcNameEncodingAppleRoman
,
203 if (FT_Get_Sfnt_Name (face
, snamei
, &sname
) != 0)
207 * Look for Unicode strings
209 switch (sname
.platform_id
) {
210 case TT_PLATFORM_APPLE_UNICODE
:
212 * All APPLE_UNICODE encodings are Utf16 BE
214 * Because there's no language id for Unicode,
215 * assume it's English
217 prio
|= FC_NAME_PRIO_LANG_ENGLISH
;
218 prio
|= FC_NAME_PRIO_ENC_UNICODE
;
219 encoding
= FcNameEncodingUtf16
;
221 case TT_PLATFORM_MACINTOSH
:
222 switch (sname
.encoding_id
) {
223 case TT_MAC_ID_ROMAN
:
224 encoding
= FcNameEncodingAppleRoman
;
229 switch (sname
.language_id
) {
230 case TT_MAC_LANGID_ENGLISH
:
231 prio
|= FC_NAME_PRIO_LANG_ENGLISH
;
235 * Sometimes Microsoft language ids
236 * end up in the macintosh table. This
237 * is often accompanied by data in
238 * some mystic encoding. Ignore these names
240 if (sname
.language_id
>= 0x100)
245 case TT_PLATFORM_MICROSOFT
:
246 switch (sname
.encoding_id
) {
247 case TT_MS_ID_UNICODE_CS
:
248 encoding
= FcNameEncodingUtf16
;
249 prio
|= FC_NAME_PRIO_ENC_UNICODE
;
254 switch (sname
.language_id
& 0xff) {
256 prio
|= FC_NAME_PRIO_LANG_ENGLISH
;
262 case TT_PLATFORM_ISO
:
263 switch (sname
.encoding_id
) {
264 case TT_ISO_ID_10646
:
265 encoding
= FcNameEncodingUtf16
;
266 prio
|= FC_NAME_PRIO_ENC_UNICODE
;
268 case TT_ISO_ID_7BIT_ASCII
:
269 case TT_ISO_ID_8859_1
:
270 encoding
= FcNameEncodingLatin1
;
281 * Look for family and style names
283 switch (sname
.name_id
) {
284 case TT_NAME_ID_FONT_FAMILY
:
285 prio
|= FC_NAME_PRIO_NAME_FAMILY
;
287 case TT_NAME_ID_PS_NAME
:
288 prio
|= FC_NAME_PRIO_NAME_PS
;
290 case TT_NAME_ID_FONT_SUBFAMILY
:
296 src
= (FcChar8
*) sname
.string
;
297 src_len
= sname
.string_len
;
300 case FcNameEncodingUtf16
:
302 * Convert Utf16 to Utf8
305 if (!FcUtf16Len (src
, FcEndianBig
, src_len
, &len
, &wchar
))
309 * Allocate plenty of space. Freed below
311 utf8
= malloc (len
* FC_UTF8_MAX_LEN
+ 1);
317 while ((ilen
= FcUtf16ToUcs4 (src
, FcEndianBig
, &ucs4
, src_len
)) > 0)
321 olen
= FcUcs4ToUtf8 (ucs4
, u8
);
326 case FcNameEncodingLatin1
:
328 * Convert Latin1 to Utf8. Freed below
330 utf8
= malloc (src_len
* 2 + 1);
339 olen
= FcUcs4ToUtf8 (ucs4
, u8
);
344 case FcNameEncodingAppleRoman
:
346 * Convert AppleRoman to Utf8
348 map
= FcFreeTypeGetPrivateMap (ft_encoding_apple_roman
);
353 utf8
= malloc (src_len
* 3 + 1);
360 ucs4
= FcFreeTypePrivateToUcs4 (*src
++, map
);
362 olen
= FcUcs4ToUtf8 (ucs4
, u8
);
370 if ((prio
& FC_NAME_PRIO_LANG
) == FC_NAME_PRIO_LANG_NONE
)
371 if (FcUtf8IsLatin (utf8
, strlen ((char *) utf8
)))
372 prio
|= FC_NAME_PRIO_LANG_LATIN
;
374 if (FcDebug () & FC_DBG_SCANV
)
375 printf ("\nfound name (name %d platform %d encoding %d language 0x%x prio 0x%x) %s\n",
376 sname
.name_id
, sname
.platform_id
,
377 sname
.encoding_id
, sname
.language_id
,
380 switch (sname
.name_id
) {
381 case TT_NAME_ID_FONT_FAMILY
:
382 case TT_NAME_ID_PS_NAME
:
383 if (!family
|| prio
> family_prio
)
389 family_allocated
= FcTrue
;
393 case TT_NAME_ID_FONT_SUBFAMILY
:
394 if (!style
|| prio
> style_prio
)
400 style_allocated
= FcTrue
;
410 family
= (FcChar8
*) face
->family_name
;
413 style
= (FcChar8
*) face
->style_name
;
417 FcChar8
*start
, *end
;
419 start
= (FcChar8
*) strrchr ((char *) file
, '/');
423 start
= (FcChar8
*) file
;
424 end
= (FcChar8
*) strrchr ((char *) start
, '.');
426 end
= start
+ strlen ((char *) start
);
428 family
= malloc (end
- start
+ 1);
429 strncpy ((char *) family
, (char *) start
, end
- start
);
430 family
[end
- start
] = '\0';
431 family_allocated
= FcTrue
;
434 if (FcDebug() & FC_DBG_SCAN
)
435 printf ("\"%s\" \"%s\" ", family
, style
? style
: (FcChar8
*) "<none>");
437 if (!FcPatternAddString (pat
, FC_FAMILY
, family
))
439 if (family_allocated
)
446 if (family_allocated
)
451 if (!FcPatternAddString (pat
, FC_STYLE
, style
))
461 if (!FcPatternAddString (pat
, FC_FILE
, file
))
464 if (!FcPatternAddInteger (pat
, FC_INDEX
, id
))
467 if (!FcPatternAddString (pat
, FC_SOURCE
, (FcChar8
*) "FreeType"))
471 if ((face
->face_flags
& FT_FACE_FLAG_FIXED_WIDTH
) != 0)
472 if (!FcPatternAddInteger (pat
, FC_SPACING
, FC_MONO
))
477 * Find the font revision (if available)
479 head
= (TT_Header
*) FT_Get_Sfnt_Table (face
, ft_sfnt_head
);
482 if (!FcPatternAddInteger (pat
, FC_FONTVERSION
, head
->Font_Revision
))
487 if (!FcPatternAddInteger (pat
, FC_FONTVERSION
, 0))
492 * Get the OS/2 table and poke about
494 os2
= (TT_OS2
*) FT_Get_Sfnt_Table (face
, ft_sfnt_os2
);
495 if (os2
&& os2
->version
>= 0x0001 && os2
->version
!= 0xffff)
497 for (i
= 0; i
< NUM_CODE_PAGE_RANGE
; i
++)
501 if (FcCodePageRange
[i
].bit
< 32)
503 bits
= os2
->ulCodePageRange1
;
504 bit
= FcCodePageRange
[i
].bit
;
508 bits
= os2
->ulCodePageRange2
;
509 bit
= FcCodePageRange
[i
].bit
- 32;
511 if (bits
& (1 << bit
))
514 * If the font advertises support for multiple
515 * "exclusive" languages, then include support
516 * for any language found to have coverage
523 exclusiveLang
= FcCodePageRange
[i
].lang
;
529 * Compute the unicode coverage for the font
531 cs
= FcFreeTypeCharSet (face
, blanks
);
536 * Skip over PCF fonts that have no encoded characters; they're
537 * usually just Unicode fonts transcoded to some legacy encoding
539 if (FcCharSetCount (cs
) == 0)
541 if (!strcmp(FT_MODULE_CLASS(&face
->driver
->root
)->module_name
, "pcf"))
545 if (!FcPatternAddCharSet (pat
, FC_CHARSET
, cs
))
548 ls
= FcFreeTypeLangSet (cs
, exclusiveLang
);
552 if (!FcPatternAddLangSet (pat
, FC_LANG
, ls
))
556 * Drop our reference to the charset
558 FcCharSetDestroy (cs
);
560 if (!(face
->face_flags
& FT_FACE_FLAG_SCALABLE
))
562 for (i
= 0; i
< face
->num_fixed_sizes
; i
++)
563 if (!FcPatternAddDouble (pat
, FC_PIXEL_SIZE
,
564 (double) face
->available_sizes
[i
].height
))
566 if (!FcPatternAddBool (pat
, FC_ANTIALIAS
, FcFalse
))
571 FT_Done_FreeType (ftLibrary
);
575 FcCharSetDestroy (cs
);
577 FcPatternDestroy (pat
);
581 FT_Done_FreeType (ftLibrary
);