/* * Copyright 2020 RĂ©mi Bernon for CodeWeavers * Copyright 2014 Aric Stewart for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #if 0 #pragma makedep unix #endif #include #include #include "windef.h" #include "winbase.h" #include "winnls.h" #include "wine/debug.h" #include "ntgdi_private.h" WINE_DEFAULT_DEBUG_CHANNEL(font); #define MS_OTTO_TAG MS_MAKE_TAG('O','T','T','O') #define MS_HEAD_TAG MS_MAKE_TAG('h','e','a','d') #define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a') #define MS_OS_2_TAG MS_MAKE_TAG('O','S','/','2') #define MS_EBSC_TAG MS_MAKE_TAG('E','B','S','C') #define MS_EBDT_TAG MS_MAKE_TAG('E','B','D','T') #define MS_CBDT_TAG MS_MAKE_TAG('C','B','D','T') #define MS_NAME_TAG MS_MAKE_TAG('n','a','m','e') #define MS_CFF__TAG MS_MAKE_TAG('C','F','F',' ') #ifdef WORDS_BIGENDIAN #define GET_BE_WORD(x) (x) #define GET_BE_DWORD(x) (x) #else #define GET_BE_WORD(x) RtlUshortByteSwap(x) #define GET_BE_DWORD(x) RtlUlongByteSwap(x) #endif #include "pshpack2.h" struct ttc_header_v1 { CHAR TTCTag[4]; DWORD Version; DWORD numFonts; DWORD OffsetTable[1]; }; struct ttc_sfnt_v1 { DWORD version; WORD numTables; WORD searchRange; WORD entrySelector; WORD rangeShift; }; struct tt_tablerecord { DWORD tag; DWORD checkSum; DWORD offset; DWORD length; }; struct tt_os2_v1 { USHORT version; SHORT xAvgCharWidth; USHORT usWeightClass; USHORT usWidthClass; SHORT fsType; SHORT ySubscriptXSize; SHORT ySubscriptYSize; SHORT ySubscriptXOffset; SHORT ySubscriptYOffset; SHORT ySuperscriptXSize; SHORT ySuperscriptYSize; SHORT ySuperscriptXOffset; SHORT ySuperscriptYOffset; SHORT yStrikeoutSize; SHORT yStrikeoutPosition; SHORT sFamilyClass; PANOSE panose; ULONG ulUnicodeRange1; ULONG ulUnicodeRange2; ULONG ulUnicodeRange3; ULONG ulUnicodeRange4; CHAR achVendID[4]; USHORT fsSelection; USHORT usFirstCharIndex; USHORT usLastCharIndex; /* According to the Apple spec, original version didn't have the below fields, * version numbers were taken from the OpenType spec. */ /* version 0 (TrueType 1.5) */ USHORT sTypoAscender; USHORT sTypoDescender; USHORT sTypoLineGap; USHORT usWinAscent; USHORT usWinDescent; /* version 1 (TrueType 1.66) */ ULONG ulCodePageRange1; ULONG ulCodePageRange2; }; struct tt_namerecord { WORD platformID; WORD encodingID; WORD languageID; WORD nameID; WORD length; WORD offset; }; struct tt_name_v0 { WORD format; WORD count; WORD stringOffset; struct tt_namerecord nameRecord[1]; }; struct tt_head { USHORT majorVersion; USHORT minorVersion; ULONG revision; ULONG checksumadj; ULONG magic; USHORT flags; USHORT unitsPerEm; ULONGLONG created; ULONGLONG modified; SHORT xMin; SHORT yMin; SHORT xMax; SHORT yMax; USHORT macStyle; USHORT lowestRecPPEM; SHORT direction_hint; SHORT index_format; SHORT glyphdata_format; }; #include "poppack.h" enum OPENTYPE_PLATFORM_ID { OPENTYPE_PLATFORM_UNICODE = 0, OPENTYPE_PLATFORM_MAC, OPENTYPE_PLATFORM_ISO, OPENTYPE_PLATFORM_WIN, OPENTYPE_PLATFORM_CUSTOM }; enum TT_NAME_WIN_ENCODING_ID { TT_NAME_WIN_ENCODING_SYMBOL = 0, TT_NAME_WIN_ENCODING_UNICODE_BMP, TT_NAME_WIN_ENCODING_SJIS, TT_NAME_WIN_ENCODING_PRC, TT_NAME_WIN_ENCODING_BIG5, TT_NAME_WIN_ENCODING_WANSUNG, TT_NAME_WIN_ENCODING_JOHAB, TT_NAME_WIN_ENCODING_RESERVED1, TT_NAME_WIN_ENCODING_RESERVED2, TT_NAME_WIN_ENCODING_RESERVED3, TT_NAME_WIN_ENCODING_UNICODE_FULL }; enum TT_NAME_UNICODE_ENCODING_ID { TT_NAME_UNICODE_ENCODING_1_0 = 0, TT_NAME_UNICODE_ENCODING_1_1, TT_NAME_UNICODE_ENCODING_ISO_10646, TT_NAME_UNICODE_ENCODING_2_0_BMP, TT_NAME_UNICODE_ENCODING_2_0_FULL, TT_NAME_UNICODE_ENCODING_VAR, TT_NAME_UNICODE_ENCODING_FULL, }; enum TT_NAME_MAC_ENCODING_ID { TT_NAME_MAC_ENCODING_ROMAN = 0, TT_NAME_MAC_ENCODING_JAPANESE, TT_NAME_MAC_ENCODING_TRAD_CHINESE, TT_NAME_MAC_ENCODING_KOREAN, TT_NAME_MAC_ENCODING_ARABIC, TT_NAME_MAC_ENCODING_HEBREW, TT_NAME_MAC_ENCODING_GREEK, TT_NAME_MAC_ENCODING_RUSSIAN, TT_NAME_MAC_ENCODING_RSYMBOL, TT_NAME_MAC_ENCODING_DEVANAGARI, TT_NAME_MAC_ENCODING_GURMUKHI, TT_NAME_MAC_ENCODING_GUJARATI, TT_NAME_MAC_ENCODING_ORIYA, TT_NAME_MAC_ENCODING_BENGALI, TT_NAME_MAC_ENCODING_TAMIL, TT_NAME_MAC_ENCODING_TELUGU, TT_NAME_MAC_ENCODING_KANNADA, TT_NAME_MAC_ENCODING_MALAYALAM, TT_NAME_MAC_ENCODING_SINHALESE, TT_NAME_MAC_ENCODING_BURMESE, TT_NAME_MAC_ENCODING_KHMER, TT_NAME_MAC_ENCODING_THAI, TT_NAME_MAC_ENCODING_LAOTIAN, TT_NAME_MAC_ENCODING_GEORGIAN, TT_NAME_MAC_ENCODING_ARMENIAN, TT_NAME_MAC_ENCODING_SIMPL_CHINESE, TT_NAME_MAC_ENCODING_TIBETAN, TT_NAME_MAC_ENCODING_MONGOLIAN, TT_NAME_MAC_ENCODING_GEEZ, TT_NAME_MAC_ENCODING_SLAVIC, TT_NAME_MAC_ENCODING_VIETNAMESE, TT_NAME_MAC_ENCODING_SINDHI, TT_NAME_MAC_ENCODING_UNINTERPRETED }; enum OPENTYPE_NAME_ID { OPENTYPE_NAME_COPYRIGHT_NOTICE = 0, OPENTYPE_NAME_FAMILY, OPENTYPE_NAME_SUBFAMILY, OPENTYPE_NAME_UNIQUE_IDENTIFIER, OPENTYPE_NAME_FULLNAME, OPENTYPE_NAME_VERSION_STRING, OPENTYPE_NAME_POSTSCRIPT, OPENTYPE_NAME_TRADEMARK, OPENTYPE_NAME_MANUFACTURER, OPENTYPE_NAME_DESIGNER, OPENTYPE_NAME_DESCRIPTION, OPENTYPE_NAME_VENDOR_URL, OPENTYPE_NAME_DESIGNER_URL, OPENTYPE_NAME_LICENSE_DESCRIPTION, OPENTYPE_NAME_LICENSE_INFO_URL, OPENTYPE_NAME_RESERVED_ID15, OPENTYPE_NAME_TYPOGRAPHIC_FAMILY, OPENTYPE_NAME_TYPOGRAPHIC_SUBFAMILY, OPENTYPE_NAME_COMPATIBLE_FULLNAME, OPENTYPE_NAME_SAMPLE_TEXT, OPENTYPE_NAME_POSTSCRIPT_CID, OPENTYPE_NAME_WWS_FAMILY, OPENTYPE_NAME_WWS_SUBFAMILY }; enum OS2_FSSELECTION { OS2_FSSELECTION_ITALIC = 1 << 0, OS2_FSSELECTION_UNDERSCORE = 1 << 1, OS2_FSSELECTION_NEGATIVE = 1 << 2, OS2_FSSELECTION_OUTLINED = 1 << 3, OS2_FSSELECTION_STRIKEOUT = 1 << 4, OS2_FSSELECTION_BOLD = 1 << 5, OS2_FSSELECTION_REGULAR = 1 << 6, OS2_FSSELECTION_USE_TYPO_METRICS = 1 << 7, OS2_FSSELECTION_WWS = 1 << 8, OS2_FSSELECTION_OBLIQUE = 1 << 9 }; static BOOL opentype_get_table_ptr( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, UINT32 table_tag, const void **table_ptr, UINT32 *table_size ) { const struct tt_tablerecord *table_record; UINT16 i, table_count; UINT32 offset, length; if (!ttc_sfnt_v1) return FALSE; table_record = (const struct tt_tablerecord *)(ttc_sfnt_v1 + 1); table_count = GET_BE_WORD( ttc_sfnt_v1->numTables ); for (i = 0; i < table_count; i++, table_record++) { if (table_record->tag != table_tag) continue; offset = GET_BE_DWORD( table_record->offset ); length = GET_BE_DWORD( table_record->length ); if (size < offset + length) return FALSE; if (table_size && length < *table_size) return FALSE; if (table_ptr) *table_ptr = (const char *)data + offset; if (table_size) *table_size = length; return TRUE; } return FALSE; } static BOOL opentype_get_tt_os2_v1( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, const struct tt_os2_v1 **tt_os2_v1 ) { UINT32 table_size = sizeof(**tt_os2_v1); return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_OS_2_TAG, (const void **)tt_os2_v1, &table_size ); } static BOOL opentype_get_tt_head( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, const struct tt_head **tt_head ) { UINT32 table_size = sizeof(**tt_head); return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_HEAD_TAG, (const void **)tt_head, &table_size ); } static UINT get_name_record_codepage( enum OPENTYPE_PLATFORM_ID platform, USHORT encoding ) { switch (platform) { case OPENTYPE_PLATFORM_UNICODE: return 0; case OPENTYPE_PLATFORM_MAC: switch (encoding) { case TT_NAME_MAC_ENCODING_ROMAN: return 10000; case TT_NAME_MAC_ENCODING_JAPANESE: return 10001; case TT_NAME_MAC_ENCODING_TRAD_CHINESE: return 10002; case TT_NAME_MAC_ENCODING_KOREAN: return 10003; case TT_NAME_MAC_ENCODING_ARABIC: return 10004; case TT_NAME_MAC_ENCODING_HEBREW: return 10005; case TT_NAME_MAC_ENCODING_GREEK: return 10006; case TT_NAME_MAC_ENCODING_RUSSIAN: return 10007; case TT_NAME_MAC_ENCODING_SIMPL_CHINESE: return 10008; case TT_NAME_MAC_ENCODING_THAI: return 10021; default: FIXME( "encoding %u not handled, platform %d.\n", encoding, platform ); break; } break; case OPENTYPE_PLATFORM_WIN: switch (encoding) { case TT_NAME_WIN_ENCODING_SYMBOL: case TT_NAME_WIN_ENCODING_UNICODE_BMP: case TT_NAME_WIN_ENCODING_UNICODE_FULL: return 0; case TT_NAME_WIN_ENCODING_SJIS: return 932; case TT_NAME_WIN_ENCODING_PRC: return 936; case TT_NAME_WIN_ENCODING_BIG5: return 950; case TT_NAME_WIN_ENCODING_WANSUNG: return 20949; case TT_NAME_WIN_ENCODING_JOHAB: return 1361; default: FIXME( "encoding %u not handled, platform %d.\n", encoding, platform ); break; } break; default: FIXME( "unknown platform %d\n", platform ); break; } return 0; } static const LANGID mac_langid_table[] = { MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT), MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT), MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT), MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT), MAKELANGID(LANG_SPANISH, SUBLANG_DEFAULT), MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT), MAKELANGID(LANG_PORTUGUESE, SUBLANG_DEFAULT), MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT), MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT), MAKELANGID(LANG_ICELANDIC, SUBLANG_DEFAULT), MAKELANGID(LANG_MALTESE, SUBLANG_DEFAULT), MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT), MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_CHINESE_TRADITIONAL, SUBLANG_DEFAULT), MAKELANGID(LANG_URDU, SUBLANG_DEFAULT), MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT), MAKELANGID(LANG_THAI, SUBLANG_DEFAULT), MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT), MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_ESTONIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_SAMI, SUBLANG_DEFAULT), MAKELANGID(LANG_FAEROESE, SUBLANG_DEFAULT), MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_CHINESE_SIMPLIFIED, SUBLANG_DEFAULT), MAKELANGID(LANG_DUTCH, SUBLANG_DUTCH_BELGIAN), MAKELANGID(LANG_IRISH, SUBLANG_DEFAULT), MAKELANGID(LANG_ALBANIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT), MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT), MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT), 0, MAKELANGID(LANG_SERBIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_MACEDONIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_BELARUSIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_UZBEK, SUBLANG_DEFAULT), MAKELANGID(LANG_KAZAK, SUBLANG_DEFAULT), MAKELANGID(LANG_AZERI, SUBLANG_AZERI_CYRILLIC), 0, MAKELANGID(LANG_ARMENIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_GEORGIAN, SUBLANG_DEFAULT), 0, MAKELANGID(LANG_KYRGYZ, SUBLANG_DEFAULT), MAKELANGID(LANG_TAJIK, SUBLANG_DEFAULT), MAKELANGID(LANG_TURKMEN, SUBLANG_DEFAULT), MAKELANGID(LANG_MONGOLIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_MONGOLIAN, SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA), MAKELANGID(LANG_PASHTO, SUBLANG_DEFAULT), 0, MAKELANGID(LANG_KASHMIRI, SUBLANG_DEFAULT), MAKELANGID(LANG_SINDHI, SUBLANG_DEFAULT), MAKELANGID(LANG_TIBETAN, SUBLANG_DEFAULT), MAKELANGID(LANG_NEPALI, SUBLANG_DEFAULT), MAKELANGID(LANG_SANSKRIT, SUBLANG_DEFAULT), MAKELANGID(LANG_MARATHI, SUBLANG_DEFAULT), MAKELANGID(LANG_BENGALI, SUBLANG_DEFAULT), MAKELANGID(LANG_ASSAMESE, SUBLANG_DEFAULT), MAKELANGID(LANG_GUJARATI, SUBLANG_DEFAULT), MAKELANGID(LANG_PUNJABI, SUBLANG_DEFAULT), MAKELANGID(LANG_ORIYA, SUBLANG_DEFAULT), MAKELANGID(LANG_MALAYALAM, SUBLANG_DEFAULT), MAKELANGID(LANG_KANNADA, SUBLANG_DEFAULT), MAKELANGID(LANG_TAMIL, SUBLANG_DEFAULT), MAKELANGID(LANG_TELUGU, SUBLANG_DEFAULT), MAKELANGID(LANG_SINHALESE, SUBLANG_DEFAULT), 0, MAKELANGID(LANG_KHMER, SUBLANG_DEFAULT), MAKELANGID(LANG_LAO, SUBLANG_DEFAULT), MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT), MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT), 0, MAKELANGID(LANG_MALAY, SUBLANG_DEFAULT), 0, MAKELANGID(LANG_AMHARIC, SUBLANG_DEFAULT), MAKELANGID(LANG_TIGRIGNA, SUBLANG_DEFAULT), 0, 0, MAKELANGID(LANG_SWAHILI, SUBLANG_DEFAULT), 0, 0, 0, MAKELANGID(LANG_MALAGASY, SUBLANG_DEFAULT), MAKELANGID(LANG_ESPERANTO, SUBLANG_DEFAULT), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MAKELANGID(LANG_WELSH, SUBLANG_DEFAULT), MAKELANGID(LANG_BASQUE, SUBLANG_DEFAULT), MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT), 0, MAKELANGID(LANG_QUECHUA, SUBLANG_DEFAULT), 0, 0, MAKELANGID(LANG_TATAR, SUBLANG_DEFAULT), MAKELANGID(LANG_UIGHUR, SUBLANG_DEFAULT), 0, 0, 0, MAKELANGID(LANG_GALICIAN, SUBLANG_DEFAULT), MAKELANGID(LANG_AFRIKAANS, SUBLANG_DEFAULT), MAKELANGID(LANG_BRETON, SUBLANG_DEFAULT), MAKELANGID(LANG_INUKTITUT, SUBLANG_DEFAULT), MAKELANGID(LANG_SCOTTISH_GAELIC, SUBLANG_DEFAULT), MAKELANGID(LANG_MANX_GAELIC, SUBLANG_DEFAULT), MAKELANGID(LANG_IRISH, SUBLANG_IRISH_IRELAND), 0, 0, MAKELANGID(LANG_GREENLANDIC, SUBLANG_DEFAULT), MAKELANGID(LANG_AZERI, SUBLANG_AZERI_LATIN), }; static LANGID get_name_record_langid( enum OPENTYPE_PLATFORM_ID platform, USHORT encoding, USHORT language ) { switch (platform) { case OPENTYPE_PLATFORM_WIN: return language; case OPENTYPE_PLATFORM_MAC: if (language < ARRAY_SIZE(mac_langid_table)) return mac_langid_table[language]; WARN( "invalid mac lang id %d\n", language ); break; case OPENTYPE_PLATFORM_UNICODE: switch (encoding) { case TT_NAME_UNICODE_ENCODING_1_0: case TT_NAME_UNICODE_ENCODING_ISO_10646: case TT_NAME_UNICODE_ENCODING_2_0_BMP: if (language < ARRAY_SIZE(mac_langid_table)) return mac_langid_table[language]; WARN( "invalid unicode lang id %d\n", language ); break; default: break; } break; default: FIXME( "unknown platform %d\n", platform ); break; } return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); } static BOOL opentype_enum_font_names( const struct tt_name_v0 *header, enum OPENTYPE_PLATFORM_ID platform, enum OPENTYPE_NAME_ID name, opentype_enum_names_cb callback, void *user ) { const char *name_data; USHORT i, name_count, encoding, language, length, offset; USHORT platform_id = GET_BE_WORD( platform ), name_id = GET_BE_WORD( name ); LANGID langid; BOOL ret = FALSE; switch (GET_BE_WORD( header->format )) { case 0: case 1: break; default: FIXME( "unsupported name format %d\n", GET_BE_WORD( header->format ) ); return FALSE; } name_data = (const char *)header + GET_BE_WORD( header->stringOffset ); name_count = GET_BE_WORD( header->count ); for (i = 0; i < name_count; i++) { const struct tt_namerecord *record = &header->nameRecord[i]; struct opentype_name opentype_name; if (record->nameID != name_id) continue; if (record->platformID != platform_id) continue; language = GET_BE_WORD( record->languageID ); if (language >= 0x8000) { FIXME( "handle name format 1\n" ); continue; } encoding = GET_BE_WORD( record->encodingID ); offset = GET_BE_WORD( record->offset ); length = GET_BE_WORD( record->length ); langid = get_name_record_langid( platform, encoding, language ); opentype_name.codepage = get_name_record_codepage( platform, encoding ); opentype_name.length = length; opentype_name.bytes = name_data + offset; if ((ret = callback( langid, &opentype_name, user ))) break; } return ret; } BOOL opentype_get_ttc_sfnt_v1( const void *data, size_t size, DWORD index, DWORD *count, const struct ttc_sfnt_v1 **ttc_sfnt_v1 ) { const struct ttc_header_v1 *ttc_header_v1 = data; const struct tt_os2_v1 *tt_os2_v1; UINT32 offset, fourcc; *ttc_sfnt_v1 = NULL; *count = 1; if (size < sizeof(fourcc)) return FALSE; memcpy( &fourcc, data, sizeof(fourcc) ); switch (fourcc) { default: WARN( "unsupported font format %x\n", fourcc ); return FALSE; case MS_TTCF_TAG: if (size < sizeof(ttc_header_v1)) return FALSE; if (index >= (*count = GET_BE_DWORD( ttc_header_v1->numFonts ))) return FALSE; offset = GET_BE_DWORD( ttc_header_v1->OffsetTable[index] ); break; case 0x00000100: case MS_OTTO_TAG: offset = 0; break; } if (size < offset + sizeof(**ttc_sfnt_v1)) return FALSE; *ttc_sfnt_v1 = (const struct ttc_sfnt_v1 *)((const char *)data + offset); if (!opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_HEAD_TAG, NULL, NULL )) { WARN( "unsupported sfnt font: missing head table.\n" ); return FALSE; } if (!opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_HHEA_TAG, NULL, NULL )) { WARN( "unsupported sfnt font: missing hhea table.\n" ); return FALSE; } if (!opentype_get_tt_os2_v1( data, size, *ttc_sfnt_v1, &tt_os2_v1 )) { WARN( "unsupported sfnt font: missing OS/2 table.\n" ); return FALSE; } /* Wine uses ttfs as an intermediate step in building its bitmap fonts; we don't want to load these. */ if (!memcmp( tt_os2_v1->achVendID, "Wine", sizeof(tt_os2_v1->achVendID) ) && opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_EBSC_TAG, NULL, NULL )) { TRACE( "ignoring wine bitmap-only sfnt font.\n" ); return FALSE; } if (opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_EBDT_TAG, NULL, NULL ) || opentype_get_table_ptr( data, size, *ttc_sfnt_v1, MS_CBDT_TAG, NULL, NULL )) { WARN( "unsupported sfnt font: embedded bitmap data.\n" ); return FALSE; } return TRUE; } BOOL opentype_get_tt_name_v0( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, const struct tt_name_v0 **tt_name_v0 ) { UINT32 table_size = sizeof(**tt_name_v0); return opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_NAME_TAG, (const void **)tt_name_v0, &table_size ); } BOOL opentype_enum_family_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) { if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_FAMILY, callback, user )) return TRUE; if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_FAMILY, callback, user )) return TRUE; if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_FAMILY, callback, user )) return TRUE; return FALSE; } BOOL opentype_enum_style_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) { if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_SUBFAMILY, callback, user )) return TRUE; if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_SUBFAMILY, callback, user )) return TRUE; if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_SUBFAMILY, callback, user )) return TRUE; return FALSE; } BOOL opentype_enum_full_names( const struct tt_name_v0 *header, opentype_enum_names_cb callback, void *user ) { if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_WIN, OPENTYPE_NAME_FULLNAME, callback, user )) return TRUE; if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_MAC, OPENTYPE_NAME_FULLNAME, callback, user )) return TRUE; if (opentype_enum_font_names( header, OPENTYPE_PLATFORM_UNICODE, OPENTYPE_NAME_FULLNAME, callback, user )) return TRUE; return FALSE; } BOOL opentype_get_properties( const void *data, size_t size, const struct ttc_sfnt_v1 *ttc_sfnt_v1, DWORD *version, FONTSIGNATURE *fs, DWORD *ntm_flags ) { const struct tt_os2_v1 *tt_os2_v1; const struct tt_head *tt_head; const void *cff_header; UINT32 table_size = 0; USHORT idx, selection; DWORD flags = 0; if (!opentype_get_tt_head( data, size, ttc_sfnt_v1, &tt_head )) return FALSE; if (!opentype_get_tt_os2_v1( data, size, ttc_sfnt_v1, &tt_os2_v1 )) return FALSE; *version = GET_BE_DWORD( tt_head->revision ); fs->fsUsb[0] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange1 ); fs->fsUsb[1] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange2 ); fs->fsUsb[2] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange3 ); fs->fsUsb[3] = GET_BE_DWORD( tt_os2_v1->ulUnicodeRange4 ); if (tt_os2_v1->version == 0) { idx = GET_BE_WORD( tt_os2_v1->usFirstCharIndex ); if (idx >= 0xf000 && idx < 0xf100) fs->fsCsb[0] = FS_SYMBOL; else fs->fsCsb[0] = FS_LATIN1; fs->fsCsb[1] = 0; } else { fs->fsCsb[0] = GET_BE_DWORD( tt_os2_v1->ulCodePageRange1 ); fs->fsCsb[1] = GET_BE_DWORD( tt_os2_v1->ulCodePageRange2 ); } selection = GET_BE_WORD( tt_os2_v1->fsSelection ); if (selection & OS2_FSSELECTION_ITALIC) flags |= NTM_ITALIC; if (selection & OS2_FSSELECTION_BOLD) flags |= NTM_BOLD; if (selection & OS2_FSSELECTION_REGULAR) flags |= NTM_REGULAR; if (flags == 0) flags = NTM_REGULAR; if (opentype_get_table_ptr( data, size, ttc_sfnt_v1, MS_CFF__TAG, &cff_header, &table_size )) flags |= NTM_PS_OPENTYPE; *ntm_flags = flags; return TRUE; }