// MLFLink.cpp : Implementation of CMLFLink #include "private.h" #include "mlmain.h" #include "codepage.h" #ifdef UNIX inline WORD READWINTELWORD(WORD w) { return ( w << 8 | w >> 8 ); } inline DWORD READWINTELDWORD(DWORD dw) { return READWINTELWORD( (WORD)(dw >> 16 )) | ((DWORD)READWINTELWORD( dw & 0xffff)) << 16; } #else #define READWINTELWORD #define READWINTELDWORD #endif IMLangFontLink *g_pMLFLink = NULL; CMLFLink::CCodePagesCache* CMLFLink::m_pCodePagesCache = NULL; CMLFLink::CFontMappingCache* CMLFLink::m_pFontMappingCache = NULL; CMLFLink2::CFontMappingCache2* CMLFLink2::m_pFontMappingCache2 = NULL; // Strings to identify regular font const char szRegular[] = "Regular"; const char szNormal[] = "Normal"; // font table FONTINFO *g_pfont_table = NULL; // Unicode range table for non Windows code page code points // Data is provided by NT international group. URANGEFONT g_urange_table[] = { {0x0108, 0x010B, 0}, {0x0114, 0x0115, 0}, {0x011C, 0x011D, 0}, {0x0120, 0x0121, 0}, {0x0124, 0x0125, 0}, {0x0128, 0x0129, 0}, {0x012C, 0x012D, 0}, {0x0134, 0x0135, 0}, {0x014E, 0x014F, 0}, {0x015C, 0x015D, 0}, {0x0168, 0x0169, 0}, {0x016C, 0x016D, 0}, {0x0174, 0x0177, 0}, {0x017F, 0x0191, 0}, {0x0193, 0x019F, 0}, {0x01A2, 0x01AE, 0}, {0x01B1, 0x01CD, 0}, {0x01CF, 0x01CF, 0}, {0x01D1, 0x01D1, 0}, {0x01D3, 0x01D3, 0}, {0x01D5, 0x01D5, 0}, {0x01D7, 0x01D7, 0}, {0x01D9, 0x01D9, 0}, {0x01DB, 0x01DB, 0}, {0x01DD, 0x01F5, 0}, {0x01FA, 0x0217, 0}, {0x0250, 0x0250, 0}, {0x0252, 0x0260, 0}, {0x0262, 0x02A8, 0}, {0x02B0, 0x02C5, 0}, {0x02C8, 0x02C8, 0}, {0x02CC, 0x02CC, 0}, {0x02CE, 0x02CF, 0}, {0x02D1, 0x02D7, 0}, {0x02DE, 0x02DE, 0}, {0x02E0, 0x02E9, 0}, {0x0302, 0x0302, 0}, {0x0304, 0x0308, 0}, {0x030A, 0x0322, 0}, {0x0324, 0x0345, 0}, {0x0360, 0x0361, 0}, {0x0374, 0x0375, 0}, {0x037A, 0x037A, 0}, {0x037E, 0x037E, 0}, {0x0387, 0x0387, 0}, {0x03D0, 0x03D6, 0}, {0x03DA, 0x03DA, 0}, {0x03DC, 0x03DC, 0}, {0x03DE, 0x03DE, 0}, {0x03E0, 0x03E0, 0}, {0x03E2, 0x03F3, 0}, {0x0460, 0x0486, 0}, {0x0492, 0x04C4, 0}, {0x04C7, 0x04C8, 0}, {0x04CB, 0x04CC, 0}, {0x04D0, 0x04EB, 0}, {0x04EE, 0x04F5, 0}, {0x04F8, 0x04F9, 0}, {0x0531, 0x0556, 0}, {0x0559, 0x055F, 0}, {0x0561, 0x0587, 0}, {0x0589, 0x0589, 0}, {0x0591, 0x05A1, 0}, {0x05A3, 0x05AF, 0}, {0x05C4, 0x05C4, 0}, {0x0660, 0x066D, 0}, {0x0670, 0x067D, 0}, {0x067F, 0x0685, 0}, {0x0687, 0x0697, 0}, {0x0699, 0x06AE, 0}, {0x06B0, 0x06B7, 0}, {0x06BA, 0x06BE, 0}, {0x06C0, 0x06CE, 0}, {0x06D0, 0x06ED, 0}, {0x06F0, 0x06F9, 0}, {0x0901, 0x0903, 0}, {0x0905, 0x0939, 0}, {0x093C, 0x094D, 0}, {0x0950, 0x0954, 0}, {0x0958, 0x0970, 0}, {0x0981, 0x0983, 0}, {0x0985, 0x098C, 0}, {0x098F, 0x0990, 0}, {0x0993, 0x09A8, 0}, {0x09AA, 0x09B0, 0}, {0x09B2, 0x09B2, 0}, {0x09B6, 0x09B9, 0}, {0x09BC, 0x09BC, 0}, {0x09BE, 0x09C4, 0}, {0x09C7, 0x09C8, 0}, {0x09CB, 0x09CD, 0}, {0x09D7, 0x09D7, 0}, {0x09DC, 0x09DD, 0}, {0x09DF, 0x09E3, 0}, {0x09E6, 0x09FA, 0}, {0x0A02, 0x0A02, 0}, {0x0A05, 0x0A0A, 0}, {0x0A0F, 0x0A10, 0}, {0x0A13, 0x0A28, 0}, {0x0A2A, 0x0A30, 0}, {0x0A32, 0x0A33, 0}, {0x0A35, 0x0A36, 0}, {0x0A38, 0x0A39, 0}, {0x0A3C, 0x0A3C, 0}, {0x0A3E, 0x0A42, 0}, {0x0A47, 0x0A48, 0}, {0x0A4B, 0x0A4D, 0}, {0x0A59, 0x0A5C, 0}, {0x0A5E, 0x0A5E, 0}, {0x0A66, 0x0A74, 0}, {0x0A81, 0x0A83, 0}, {0x0A85, 0x0A8B, 0}, {0x0A8D, 0x0A8D, 0}, {0x0A8F, 0x0A91, 0}, {0x0A93, 0x0AA8, 0}, {0x0AAA, 0x0AB0, 0}, {0x0AB2, 0x0AB3, 0}, {0x0AB5, 0x0AB9, 0}, {0x0ABC, 0x0AC5, 0}, {0x0AC7, 0x0AC9, 0}, {0x0ACB, 0x0ACD, 0}, {0x0AD0, 0x0AD0, 0}, {0x0AE0, 0x0AE0, 0}, {0x0AE6, 0x0AEF, 0}, {0x0B01, 0x0B03, 0}, {0x0B05, 0x0B0C, 0}, {0x0B0F, 0x0B10, 0}, {0x0B13, 0x0B28, 0}, {0x0B2A, 0x0B30, 0}, {0x0B32, 0x0B33, 0}, {0x0B36, 0x0B39, 0}, {0x0B3C, 0x0B43, 0}, {0x0B47, 0x0B48, 0}, {0x0B4B, 0x0B4D, 0}, {0x0B56, 0x0B57, 0}, {0x0B5C, 0x0B5D, 0}, {0x0B5F, 0x0B61, 0}, {0x0B66, 0x0B70, 0}, {0x0B82, 0x0B83, 0}, {0x0B85, 0x0B8A, 0}, {0x0B8E, 0x0B90, 0}, {0x0B92, 0x0B95, 0}, {0x0B99, 0x0B9A, 0}, {0x0B9C, 0x0B9C, 0}, {0x0B9E, 0x0B9F, 0}, {0x0BA3, 0x0BA4, 0}, {0x0BA8, 0x0BAA, 0}, {0x0BAE, 0x0BB5, 0}, {0x0BB7, 0x0BB9, 0}, {0x0BBE, 0x0BC2, 0}, {0x0BC6, 0x0BC8, 0}, {0x0BCA, 0x0BCD, 0}, {0x0BD7, 0x0BD7, 0}, {0x0BE7, 0x0BF2, 0}, {0x0C01, 0x0C03, 0}, {0x0C05, 0x0C0C, 0}, {0x0C0E, 0x0C10, 0}, {0x0C12, 0x0C28, 0}, {0x0C2A, 0x0C33, 0}, {0x0C35, 0x0C39, 0}, {0x0C3E, 0x0C44, 0}, {0x0C46, 0x0C48, 0}, {0x0C4A, 0x0C4D, 0}, {0x0C55, 0x0C56, 0}, {0x0C60, 0x0C61, 0}, {0x0C66, 0x0C6F, 0}, {0x0C82, 0x0C83, 0}, {0x0C85, 0x0C8C, 0}, {0x0C8E, 0x0C90, 0}, {0x0C92, 0x0CA8, 0}, {0x0CAA, 0x0CB3, 0}, {0x0CB5, 0x0CB9, 0}, {0x0CBE, 0x0CC4, 0}, {0x0CC6, 0x0CC8, 0}, {0x0CCA, 0x0CCD, 0}, {0x0CD5, 0x0CD6, 0}, {0x0CDE, 0x0CDE, 0}, {0x0CE0, 0x0CE1, 0}, {0x0CE6, 0x0CEF, 0}, {0x0D02, 0x0D03, 0}, {0x0D05, 0x0D0C, 0}, {0x0D0E, 0x0D10, 0}, {0x0D12, 0x0D28, 0}, {0x0D2A, 0x0D39, 0}, {0x0D3E, 0x0D43, 0}, {0x0D46, 0x0D48, 0}, {0x0D4A, 0x0D4D, 0}, {0x0D57, 0x0D57, 0}, {0x0D60, 0x0D61, 0}, {0x0D66, 0x0D6F, 0}, {0x0E81, 0x0E82, 0}, {0x0E84, 0x0E84, 0}, {0x0E87, 0x0E88, 0}, {0x0E8A, 0x0E8A, 0}, {0x0E8D, 0x0E8D, 0}, {0x0E94, 0x0E97, 0}, {0x0E99, 0x0E9F, 0}, {0x0EA1, 0x0EA3, 0}, {0x0EA5, 0x0EA5, 0}, {0x0EA7, 0x0EA7, 0}, {0x0EAA, 0x0EAB, 0}, {0x0EAD, 0x0EB9, 0}, {0x0EBB, 0x0EBD, 0}, {0x0EC0, 0x0EC4, 0}, {0x0EC6, 0x0EC6, 0}, {0x0EC8, 0x0ECD, 0}, {0x0ED0, 0x0ED9, 0}, {0x0EDC, 0x0EDD, 0}, {0x0F00, 0x0F47, 0}, {0x0F49, 0x0F69, 0}, {0x0F71, 0x0F8B, 0}, {0x0F90, 0x0F95, 0}, {0x0F97, 0x0F97, 0}, {0x0F99, 0x0FAD, 0}, {0x0FB1, 0x0FB7, 0}, {0x0FB9, 0x0FB9, 0}, {0x10A0, 0x10C5, 0}, {0x10D0, 0x10F6, 0}, {0x10FB, 0x10FB, 0}, {0x1100, 0x1159, 0}, {0x115F, 0x11A2, 0}, {0x11A8, 0x11F9, 0}, {0x1E00, 0x1E9B, 0}, {0x1EA0, 0x1EF9, 0}, {0x1F00, 0x1F15, 0}, {0x1F18, 0x1F1D, 0}, {0x1F20, 0x1F45, 0}, {0x1F48, 0x1F4D, 0}, {0x1F50, 0x1F57, 0}, {0x1F59, 0x1F59, 0}, {0x1F5B, 0x1F5B, 0}, {0x1F5D, 0x1F5D, 0}, {0x1F5F, 0x1F7D, 0}, {0x1F80, 0x1FB4, 0}, {0x1FB6, 0x1FC4, 0}, {0x1FC6, 0x1FD3, 0}, {0x1FD6, 0x1FDB, 0}, {0x1FDD, 0x1FEF, 0}, {0x1FF2, 0x1FF4, 0}, {0x1FF6, 0x1FFE, 0}, {0x2000, 0x200B, 0}, {0x2011, 0x2012, 0}, {0x2017, 0x2017, 0}, {0x201B, 0x201B, 0}, {0x201F, 0x201F, 0}, {0x2023, 0x2024, 0}, {0x2028, 0x202E, 0}, {0x2031, 0x2031, 0}, {0x2034, 0x2034, 0}, {0x2036, 0x2038, 0}, {0x203C, 0x2046, 0}, {0x206A, 0x2070, 0}, {0x2075, 0x207E, 0}, {0x2080, 0x2080, 0}, {0x2085, 0x208E, 0}, {0x20A0, 0x20A9, 0}, {0x20D0, 0x20E1, 0}, {0x2100, 0x2102, 0}, {0x2104, 0x2104, 0}, {0x2106, 0x2108, 0}, {0x210A, 0x2112, 0}, {0x2114, 0x2115, 0}, {0x2117, 0x2120, 0}, {0x2123, 0x2125, 0}, {0x2127, 0x212A, 0}, {0x212C, 0x2138, 0}, {0x2155, 0x215A, 0}, {0x215F, 0x215F, 0}, {0x216C, 0x216F, 0}, {0x217A, 0x2182, 0}, {0x219A, 0x21D1, 0}, {0x21D3, 0x21D3, 0}, {0x21D5, 0x21EA, 0}, {0x2201, 0x2201, 0}, {0x2204, 0x2206, 0}, {0x2209, 0x220A, 0}, {0x220C, 0x220E, 0}, {0x2210, 0x2210, 0}, {0x2212, 0x2214, 0}, {0x2216, 0x2219, 0}, {0x221B, 0x221C, 0}, {0x2221, 0x2222, 0}, {0x2224, 0x2224, 0}, {0x2226, 0x2226, 0}, {0x222D, 0x222D, 0}, {0x222F, 0x2233, 0}, {0x2238, 0x223B, 0}, {0x223E, 0x2247, 0}, {0x2249, 0x224B, 0}, {0x224D, 0x2251, 0}, {0x2253, 0x225F, 0}, {0x2262, 0x2263, 0}, {0x2268, 0x2269, 0}, {0x226C, 0x226D, 0}, {0x2270, 0x2281, 0}, {0x2284, 0x2285, 0}, {0x2288, 0x2294, 0}, {0x2296, 0x2298, 0}, {0x229A, 0x22A4, 0}, {0x22A6, 0x22BE, 0}, {0x22C0, 0x22F1, 0}, {0x2300, 0x2300, 0}, {0x2302, 0x2311, 0}, {0x2313, 0x237A, 0}, {0x2400, 0x2424, 0}, {0x2440, 0x244A, 0}, {0x24B6, 0x24CF, 0}, {0x24EA, 0x24EA, 0}, {0x254C, 0x254F, 0}, {0x2575, 0x2580, 0}, {0x2590, 0x2591, 0}, {0x25A2, 0x25A2, 0}, {0x25AA, 0x25B1, 0}, {0x25B4, 0x25B5, 0}, {0x25B8, 0x25BB, 0}, {0x25BE, 0x25BF, 0}, {0x25C2, 0x25C5, 0}, {0x25C9, 0x25CA, 0}, {0x25CC, 0x25CD, 0}, {0x25D2, 0x25E1, 0}, {0x25E6, 0x25EE, 0}, {0x2600, 0x2604, 0}, {0x2607, 0x2608, 0}, {0x260A, 0x260D, 0}, {0x2610, 0x2613, 0}, {0x261A, 0x261B, 0}, {0x261D, 0x261D, 0}, {0x261F, 0x263F, 0}, {0x2641, 0x2641, 0}, {0x2643, 0x265F, 0}, {0x2662, 0x2662, 0}, {0x2666, 0x2666, 0}, {0x266B, 0x266B, 0}, {0x266E, 0x266E, 0}, {0x2701, 0x2704, 0}, {0x2706, 0x2709, 0}, {0x270C, 0x2727, 0}, {0x2729, 0x274B, 0}, {0x274D, 0x274D, 0}, {0x274F, 0x2752, 0}, {0x2756, 0x2756, 0}, {0x2758, 0x275E, 0}, {0x2761, 0x2767, 0}, {0x2776, 0x2794, 0}, {0x2798, 0x27AF, 0}, {0x27B1, 0x27BE, 0}, {0x3004, 0x3004, 0}, {0x3018, 0x301C, 0}, {0x3020, 0x3020, 0}, {0x302A, 0x3037, 0}, {0x303F, 0x303F, 0}, {0x3094, 0x3094, 0}, {0x3099, 0x309A, 0}, {0x30F7, 0x30FA, 0}, {0x312A, 0x312C, 0}, {0x3190, 0x319F, 0}, {0x322A, 0x3230, 0}, {0x3233, 0x3238, 0}, {0x323A, 0x3243, 0}, {0x3280, 0x32A2, 0}, {0x32A9, 0x32B0, 0}, {0x32C0, 0x32CB, 0}, {0x32D0, 0x32FE, 0}, {0x3300, 0x3302, 0}, {0x3304, 0x330C, 0}, {0x330E, 0x3313, 0}, {0x3315, 0x3317, 0}, {0x3319, 0x3321, 0}, {0x3324, 0x3325, 0}, {0x3328, 0x332A, 0}, {0x332C, 0x3335, 0}, {0x3337, 0x333A, 0}, {0x333C, 0x3348, 0}, {0x334B, 0x334C, 0}, {0x334E, 0x3350, 0}, {0x3352, 0x3356, 0}, {0x3358, 0x3376, 0}, {0x337F, 0x337F, 0}, {0x3385, 0x3387, 0}, {0x33CB, 0x33CC, 0}, {0x33D4, 0x33D4, 0}, {0x33D7, 0x33D7, 0}, {0x33D9, 0x33DA, 0}, {0x33E0, 0x33FE, 0}, {0xFB00, 0xFB06, 0}, {0xFB13, 0xFB17, 0}, {0xFB1E, 0xFB36, 0}, {0xFB38, 0xFB3C, 0}, {0xFB3E, 0xFB3E, 0}, {0xFB40, 0xFB41, 0}, {0xFB43, 0xFB44, 0}, {0xFB46, 0xFBB1, 0}, {0xFBD3, 0xFD3F, 0}, {0xFD50, 0xFD8F, 0}, {0xFD92, 0xFDC7, 0}, {0xFDF0, 0xFDFB, 0}, {0xFE20, 0xFE23, 0}, {0xFE32, 0xFE32, 0}, {0xFE58, 0xFE58, 0}, {0xFE70, 0xFE72, 0}, {0xFE74, 0xFE74, 0}, {0xFE76, 0xFEFC, 0}, {0xFEFF, 0xFEFF, 0}, {0xFFA0, 0xFFBE, 0}, {0xFFC2, 0xFFC7, 0}, {0xFFCA, 0xFFCF, 0}, {0xFFD2, 0xFFD7, 0}, {0xFFDA, 0xFFDC, 0}, {0xFFE8, 0xFFEE, 0}, {0xFFFD, 0xFFFD, 0} }; const struct { int nCharSet; UINT uCodePage; DWORD dwCodePages; SCRIPT_ID sid[3]; } g_CharSetTransTable[] = { ANSI_CHARSET, 1252, FS_LATIN1, sidAsciiLatin, sidLatin, sidDefault, EASTEUROPE_CHARSET, 1250, FS_LATIN2, sidAsciiLatin, sidLatin, sidDefault, RUSSIAN_CHARSET, 1251, FS_CYRILLIC, sidCyrillic, sidDefault, sidDefault, GREEK_CHARSET, 1253, FS_GREEK, sidGreek, sidDefault, sidDefault, TURKISH_CHARSET, 1254, FS_TURKISH, sidAsciiLatin, sidLatin, sidDefault, HEBREW_CHARSET, 1255, FS_HEBREW, sidHebrew, sidDefault, sidDefault, ARABIC_CHARSET, 1256, FS_ARABIC, sidArabic, sidDefault, sidDefault, BALTIC_CHARSET, 1257, FS_BALTIC, sidAsciiLatin, sidLatin, sidDefault, VIETNAMESE_CHARSET, 1258, FS_VIETNAMESE, sidAsciiLatin, sidLatin, sidDefault, THAI_CHARSET, 874, FS_THAI , sidThai, sidDefault, sidDefault, SHIFTJIS_CHARSET, 932, FS_JISJAPAN, sidKana, sidDefault, sidDefault, //sidKana, sidHan, sidDefault, GB2312_CHARSET, 936, FS_CHINESESIMP,sidHan, sidDefault, sidDefault, //sidKana, sidHan, sidBopomofo, HANGEUL_CHARSET, 949, FS_WANSUNG, sidHangul, sidDefault, sidDefault, //sidHangul, sidKana, sidHan, CHINESEBIG5_CHARSET, 950, FS_CHINESETRAD, sidBopomofo, sidDefault, sidDefault, //sidKana, sidHan, sidBopomofo, JOHAB_CHARSET, 1361, FS_JOHAB, sidHangul, sidDefault, sidDefault, DEFAULT_CHARSET, 0, 0, sidDefault, sidDefault, sidDefault, }; // // Extended code page table // const struct { int nCharSet; UINT uCodePage; DWORD dwCodePages; } g_CharSetTransTableExt[] = { ANSI_CHARSET, 28591, FS_MLANG_28591, EASTEUROPE_CHARSET, 28592, FS_MLANG_28592, RUSSIAN_CHARSET, 28595, FS_MLANG_28595, GREEK_CHARSET, 28597, FS_MLANG_28597, TURKISH_CHARSET, 28593, FS_MLANG_28593, HEBREW_CHARSET, 28598, FS_MLANG_28598, HEBREW_CHARSET, 38598, FS_MLANG_38598, ARABIC_CHARSET, 28596, FS_MLANG_28596, BALTIC_CHARSET, 28594, FS_MLANG_28594, VIETNAMESE_CHARSET, 28599, FS_MLANG_28599, THAI_CHARSET, 28605, FS_MLANG_28605, ANSI_CHARSET, 20127, FS_MLANG_20127, ANSI_CHARSET, 50220, FS_MLANG_50220, ANSI_CHARSET, 51932, FS_MLANG_51932, ANSI_CHARSET, 51949, FS_MLANG_51949, ANSI_CHARSET, 50225, FS_MLANG_50225, ANSI_CHARSET, 52936, FS_MLANG_52936, ANSI_CHARSET, 65000, FS_MLANG_65000, ANSI_CHARSET, 65001, FS_MLANG_65001, ANSI_CHARSET, 1200, FS_MLANG_1200, ANSI_CHARSET, 20866, FS_MLANG_20866, ANSI_CHARSET, 21866, FS_MLANG_21866, ANSI_CHARSET, 50221, FS_MLANG_50221, ANSI_CHARSET, 50222, FS_MLANG_50222, DEFAULT_CHARSET, 0, 0, }; // Primary chars for scripts // Pre-sorted by Unicode characters to speed up CMAP search. const struct { WCHAR wch; //Can be extended to a character list SCRIPT_ID sid; } g_wCharToScript[] = { 0x0531, sidArmenian, 0x0710, sidSyriac, 0x0780, sidThaana, 0x0905, sidDevanagari, 0x0985, sidBengali, 0x0a05, sidGurmukhi, 0x0a85, sidGujarati, 0x0b05, sidOriya, 0x0b85, sidTamil, 0x0c05, sidTelugu, 0x0c85, sidKannada, 0x0d05, sidMalayalam, 0x0d85, sidSinhala, 0x0e81, sidLao, 0x0f40, sidTibetan, 0x10a0, sidGeorgian, 0x10d0, sidGeorgian, 0x1300, sidEthiopic, 0x1401, sidCanSyllabic, 0x13a0, sidCherokee, 0xa000, sidYi, 0x1680, sidOgham, 0x16a0, sidRunic, 0x1700, sidBurmese, 0x1780, sidKhmer, 0x2800, sidBraille, // 0x0020, sidUserDefined }; // Script tables ported from Trident static SCRIPT_ID s_asidUnicodeSubRangeScriptMapping[] = { sidAsciiLatin, sidLatin, sidLatin, sidLatin, // 128-131 sidLatin, sidLatin, 0, sidGreek, // 132-135 sidGreek, sidCyrillic, sidArmenian, sidHebrew, // 136-139 sidHebrew, sidArabic, sidArabic, sidDevanagari, // 140-143 sidBengali, sidGurmukhi, sidGujarati, sidOriya, // 144-147 sidTamil, sidTelugu, sidKannada, sidMalayalam, // 148-151 sidThai, sidLao, sidGeorgian, sidGeorgian, // 152-155 sidHangul, sidLatin, sidGreek, 0, // 156-159 0, 0, 0, 0, // 160-163 0, 0, 0, 0, // 164-167 0, 0, 0, 0, // 168-171 0, 0, 0, 0, // 172-175 sidHan, sidKana, sidKana, sidBopomofo, // 176-179 sidHangul, 0, 0, 0, // 180-183 sidHangul, sidHangul, sidHangul, sidHan, // 184-187 0, sidHan, 0, 0, // 188-191 0, 0, 0, 0, // 192-195 0, 0, sidHangul, 0, // 196-199 }; // Script table (raw data from MichelSu) // Rendered by script ID const SCRIPT ScriptTable[] = { {sidDefault, IDS_SIDDEFAULT, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_SYSTEM}, // 0 {sidMerge, IDS_SIDMERGE, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_SYSTEM}, // 1 {sidAsciiSym, IDS_SIDASCIISYM, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_SYSTEM}, // 2 {sidAsciiLatin, IDS_SIDASCIILATIN, 1252, 0, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 3 {sidLatin, IDS_SIDLATIN, 1252, 0, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_HIDE}, // 4 {sidGreek, IDS_SIDGREEK, 1253, 0x03AC, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 5 {sidCyrillic, IDS_SIDCYRILLIC, 1251, 0x0401, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 6 {sidArmenian, IDS_SIDARMENIAN, 0, 0x0531, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 7 /**/{sidHebrew, IDS_SIDHEBREW, 1255, 0x05D4, IDS_FONT_HEBREW_FIXED, IDS_FONT_HEBREW_PROP, SCRIPTCONTF_SCRIPT_USER}, // 8 {sidArabic, IDS_SIDARABIC, 1256, 0x0627, IDS_FONT_ARABIC_FIXED, IDS_FONT_ARABIC_PROP, SCRIPTCONTF_SCRIPT_USER}, // 9 {sidDevanagari, IDS_SIDDEVANAGARI, 0, 0x0905, IDS_FONT_DEVANAGARI_FIXED,IDS_FONT_DEVANAGARI_PROP, SCRIPTCONTF_SCRIPT_USER}, // 10 {sidBengali, IDS_SIDBENGALI, 0, 0x0985, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 11 {sidGurmukhi, IDS_SIDGURMUKHI, 0, 0x0A05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 12 {sidGujarati, IDS_SIDGUJARATI, 0, 0x0A85, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 13 {sidOriya, IDS_SIDORIYA, 0, 0x0B05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 14 {sidTamil, IDS_SIDTAMIL, 0, 0x0B85, IDS_FONT_TAMIL_FIXED, IDS_FONT_TAMIL_PROP, SCRIPTCONTF_SCRIPT_USER}, // 15 {sidTelugu, IDS_SIDTELUGU, 0, 0x0C05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 16 {sidKannada, IDS_SIDKANNADA, 0, 0x0C85, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 17 {sidMalayalam, IDS_SIDMALAYALAM, 0, 0x0D05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 18 {sidThai, IDS_SIDTHAI, 874, 0x0E01, IDS_FONT_THAI_FIXED2, IDS_FONT_THAI_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 19 {sidLao, IDS_SIDLAO, 0, 0x0E81, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 20 {sidTibetan, IDS_SIDTIBETAN, 0, 0x0F40, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 21 {sidGeorgian, IDS_SIDGEORGIAN, 0, 0x10D0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 22 {sidHangul, IDS_SIDHANGUL, 949, 0, IDS_FONT_KOREAN_FIXED, IDS_FONT_KOREAN_PROP, SCRIPTCONTF_SCRIPT_USER}, // 23 {sidKana, IDS_SIDKANA, 932, 0, IDS_FONT_JAPANESE_FIXED, IDS_FONT_JAPANESE_PROP, SCRIPTCONTF_SCRIPT_USER}, // 24 {sidBopomofo, IDS_SIDBOPOMOFO, 950, 0, IDS_FONT_TAIWAN_FIXED, IDS_FONT_TAIWAN_PROP, SCRIPTCONTF_SCRIPT_USER}, // 25 {sidHan, IDS_SIDHAN, 936, 0, IDS_FONT_CHINESE_FIXED, IDS_FONT_CHINESE_PROP, SCRIPTCONTF_SCRIPT_USER}, // 26 {sidEthiopic, IDS_SIDETHIOPIC, 0, 0x1300, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 27 {sidCanSyllabic,IDS_SIDCANSYLLABIC, 0, 0x1401, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 28 {sidCherokee, IDS_SIDCHEROKEE, 0, 0x13A0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 29 {sidYi, IDS_SIDYI, 0, 0xA000, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 30 {sidBraille, IDS_SIDBRAILLE, 0, 0x2800, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 31 {sidRunic, IDS_SIDRUNIC, 0, 0x16A0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 32 {sidOgham, IDS_SIDOGHAM, 0, 0x1680, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 33 {sidSinhala, IDS_SIDSINHALA, 0, 0x0D85, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 34 {sidSyriac, IDS_SIDSYRIAC, 0, 0x0710, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 35 {sidBurmese, IDS_SIDBURMESE, 0, 0x1700, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 36 {sidKhmer, IDS_SIDKHMER, 0, 0x1780, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 37 {sidThaana, IDS_SIDTHAANA, 0, 0x0780, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 38 {sidMongolian, IDS_SIDMONGOLIAN, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 39 {sidUserDefined,IDS_SIDUSERDEFINED, 0, 0x0020, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 40 }; UINT g_cScript = ARRAYSIZE(ScriptTable); ///////////////////////////////////////////////////////////////////////////// // CMLFLink Free Global Objects void CMLangFontLink_FreeGlobalObjects() { if (g_pMLFLink) g_pMLFLink->Release(); if (CMLFLink::m_pCodePagesCache) delete CMLFLink::m_pCodePagesCache; if (CMLFLink::m_pFontMappingCache) delete CMLFLink::m_pFontMappingCache; if (CMLFLink2::m_pFontMappingCache2) delete CMLFLink2::m_pFontMappingCache2; } ///////////////////////////////////////////////////////////////////////////// // CMLFLink CMLFLink::CMLFLink() { DllAddRef(); EnterCriticalSection(&g_cs); if (!m_pCodePagesCache) m_pCodePagesCache = new CCodePagesCache; if (!m_pFontMappingCache) m_pFontMappingCache = new CFontMappingCache; LeaveCriticalSection(&g_cs); m_pFlinkTable = NULL; } STDMETHODIMP CMLFLink::GetCharCodePages(WCHAR chSrc, DWORD* pdwCodePages) { return ::GetCharCodePagesEx(chSrc, pdwCodePages, CPBITS_WINDOWS); } ///////////////////////////////////////////////////////////////////////////// // CMLFLink : IMLangCodePages HRESULT GetCharCodePagesEx(WCHAR chSrc, DWORD* pdwCodePages, DWORD dwFlags) { ASSERT_WRITE_PTR_OR_NULL(pdwCodePages); HRESULT hr = S_OK; int nLen; int iCmd = 0; int nPickOffset; int nBitOffset = 0; int nBitCount = 32; DWORD dwDiff = 0xffffffff; DWORD dwOr = 0; DWORD dwCodePages; DWORD adwBitsMap[32]; const CCodePagesHeader* pHeader; const WORD* pwTable; int nBlock; int nEndLen; const BYTE* pbBlock; BYTE *pBuffer = NULL; if (!CMLFLink::m_pCodePagesCache) CMLFLink::m_pCodePagesCache = new CMLFLink::CCodePagesCache; if (CMLFLink::m_pCodePagesCache) hr = CMLFLink::m_pCodePagesCache->Load(); else { hr = E_FAIL; } if (SUCCEEDED(hr)) { pBuffer = CMLFLink::m_pCodePagesCache->GetCodePageBits(dwFlags & CPBITS_WINDOWS? FALSE:TRUE); pHeader = (CCodePagesHeader*) pBuffer; pwTable = (WORD*)(pBuffer + READWINTELDWORD(pHeader->m_dwTableOffset)); nBlock = chSrc / READWINTELDWORD(pHeader->m_dwBlockSize); nEndLen = chSrc % READWINTELDWORD(pHeader->m_dwBlockSize); pbBlock = pBuffer + READWINTELWORD(pwTable[nBlock]); } for (int nDoneLen = 0; SUCCEEDED(hr) && nDoneLen < (int)READWINTELDWORD(pHeader->m_dwBlockSize); nDoneLen += nLen) { BYTE bCmd = pbBlock[--iCmd]; if (bCmd < pHeader->m_abCmdCode[1]) { // Flat nLen = bCmd + 1; nPickOffset = nBitOffset + nBitCount * (nEndLen - nDoneLen); nBitOffset += nBitCount * nLen; } else if (bCmd < pHeader->m_abCmdCode[2]) { // Pack nLen = bCmd - pHeader->m_abCmdCode[1] + 2; nPickOffset = nBitOffset; nBitOffset += nBitCount; } else if (bCmd < pHeader->m_abCmdCode[4]) { // Diff & Or nLen = 0; DWORD dw = pbBlock[--iCmd]; dw <<= 8; dw |= pbBlock[--iCmd]; dw <<= 8; dw |= pbBlock[--iCmd]; dw <<= 8; dw |= pbBlock[--iCmd]; if (bCmd < pHeader->m_abCmdCode[3]) { // Diff dwDiff = dw; DWORD dwShift = 1; nBitCount = 0; for (int nBit = 0; nBit < 32; nBit++) { if (dwDiff & (1 << nBit)) { adwBitsMap[nBit] = dwShift; dwShift <<= 1; nBitCount++; } else { adwBitsMap[nBit] = 0; } } } else { // Or dwOr = dw; } } else { // Big Pack nLen = (bCmd - pHeader->m_abCmdCode[4]) * 0x100 + pbBlock[--iCmd] + pHeader->m_abCmdCode[2] - pHeader->m_abCmdCode[1] + 1 + 1; nPickOffset = nBitOffset; nBitOffset += nBitCount; } if (nEndLen < nDoneLen + nLen) break; } if (SUCCEEDED(hr) && nDoneLen < (int)READWINTELDWORD(pHeader->m_dwBlockSize)) { const BYTE* const pbBuf = &pbBlock[nPickOffset / 8]; DWORD dwCompBits = pbBuf[0] | (DWORD(pbBuf[1]) << 8) | (DWORD(pbBuf[2]) << 16) | (DWORD(pbBuf[3]) << 24); dwCompBits >>= nPickOffset % 8; if (nBitOffset % 8) dwCompBits |= pbBuf[4] << (32 - nBitOffset % 8); if (nBitCount < 32) { dwCompBits &= (1 << nBitCount) - 1; dwCodePages = 0; for (int nBit = 0; nBit < 32; nBit++) { if (dwCompBits & adwBitsMap[nBit]) dwCodePages |= (1 << nBit); } } else { dwCodePages = dwCompBits; } dwCodePages |= dwOr; } else { hr = E_FAIL; // Probably Code Pages data is broken. } if (pdwCodePages) { if (SUCCEEDED(hr)) { if (dwFlags & CPBITS_WINDOWS) { // 04/07/00 WEIWU // Need to match latest NLS file (Currently W2K RTM) if we're in strict mode for outbound encoding detection // For backward compatibilities reasons, we don't want to change our raw Windows CP data. // We patch up major differences between Win95/NT4 NLS files and current NLS files here // For non-Windows CP data, we'll modify them directly since it doesn't affect text rendering if (dwFlags & CPBITS_STRICT) { // Add Euro support for 936,950, 949 if we're in strict mode if (chSrc == 0x20AC) { dwCodePages |= FS_WANSUNG|FS_CHINESESIMP|FS_CHINESETRAD; } else if (chSrc == 0x00AE) { dwCodePages |= FS_WANSUNG; } // Clear K1_HANJA bits if we're in strict mode dwCodePages &= ~FS_MLANG_K1HANJA; } else { // We introduce this new internal charset bit, FS_MLANG_K1HANJA, to support Korean K1 Hanja // K1 Hanja is defined in KSC 5657-1991, it contains non-cp949 DBCS characters // Currenly, Korean fonts shipped with NT5 and Win98 support K1 Hanja glyphs // and we don't want to switch font to other DBCS fonts in this case. if (dwCodePages & FS_MLANG_K1HANJA) { // Assume Korean font supports K1_HANJA on Win98 and NT5 if (g_bIsNT5 || (g_bIsWin98 && CP_KOR_5601 == g_uACP)) dwCodePages |= FS_WANSUNG; dwCodePages &= ~FS_MLANG_K1HANJA; } } } *pdwCodePages = dwCodePages; } else { *pdwCodePages = 0; } } return hr; } HRESULT GetStrCodePagesEx(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages, DWORD dwFlags) { ASSERT_READ_BLOCK(pszSrc, cchSrc); ASSERT_WRITE_PTR_OR_NULL(pdwCodePages); ASSERT_WRITE_PTR_OR_NULL(pcchCodePages); HRESULT hr = S_OK; long cchCodePages = 0; DWORD dwStrCodePages = (DWORD)~0; BOOL fInit = FALSE; BOOL fNoPri = FALSE; if (!pszSrc || cchSrc <= 0) // We can't make dwStrCodePages when cchSrc is zero hr = E_INVALIDARG; while (SUCCEEDED(hr) && cchSrc > 0) { DWORD dwCharCodePages; if (SUCCEEDED(hr = GetCharCodePagesEx(*pszSrc, &dwCharCodePages, dwFlags))) { if (!fInit) { fInit = TRUE; fNoPri = !(dwPriorityCodePages & dwCharCodePages); } else if (fNoPri != !(dwPriorityCodePages & dwCharCodePages)) { break; } if (!fNoPri) dwPriorityCodePages &= dwCharCodePages; if (dwCharCodePages & dwStrCodePages) dwStrCodePages &= dwCharCodePages; // Don't break if dwCharCodePages is zero and we're not in strict mode else if (dwCharCodePages || dwFlags & CPBITS_STRICT) break; pszSrc++; cchSrc--; cchCodePages++; } } // Codepage bits defines don't take full 32 bits. // If no bits are flipped, we don't have any candidate code pages, we should clear the bits if (dwStrCodePages == (DWORD)~0) dwStrCodePages = 0; if (SUCCEEDED(hr)) { if (pcchCodePages) *pcchCodePages = cchCodePages; if (pdwCodePages) *pdwCodePages = dwStrCodePages; } else { if (pcchCodePages) *pcchCodePages = 0; if (pdwCodePages) *pdwCodePages = 0; } return hr; } STDMETHODIMP CMLFLink::GetStrCodePages(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages) { return ::GetStrCodePagesEx(pszSrc, cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages, CPBITS_WINDOWS); } HRESULT CodePageToCodePagesEx(UINT uCodePage, DWORD* pdwCodePages, DWORD* pdwCodePagesExt) { ASSERT_WRITE_PTR_OR_NULL(pdwCodePages); int iCharSet; if (pdwCodePages) *pdwCodePages = 0; if (pdwCodePagesExt) *pdwCodePagesExt = 0; for (iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++) { if (uCodePage == g_CharSetTransTable[iCharSet].uCodePage) { if (pdwCodePages) *pdwCodePages = g_CharSetTransTable[iCharSet].dwCodePages; return S_OK; } } for (iCharSet = 0; g_CharSetTransTableExt[iCharSet].uCodePage; iCharSet++) { if (uCodePage == g_CharSetTransTableExt[iCharSet].uCodePage) { if (pdwCodePages) *pdwCodePagesExt = g_CharSetTransTableExt[iCharSet].dwCodePages; return S_OK; } } return E_FAIL; // Unknown code page } STDMETHODIMP CMLFLink::CodePageToCodePages(UINT uCodePage, DWORD* pdwCodePages) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(pdwCodePages); for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++) { if (uCodePage == g_CharSetTransTable[iCharSet].uCodePage) { if (pdwCodePages) *pdwCodePages = g_CharSetTransTable[iCharSet].dwCodePages; return S_OK; } } if (pdwCodePages) *pdwCodePages = 0; return E_FAIL; // Unknown code page } STDMETHODIMP CMLFLink::CodePagesToCodePage(DWORD dwCodePages, UINT uDefaultCodePage, UINT* puCodePage) { return ::CodePagesToCodePageEx(dwCodePages, uDefaultCodePage, puCodePage, 0); } HRESULT CodePagesToCodePageEx(DWORD dwCodePages, UINT uDefaultCodePage, UINT* puCodePage, BOOL bCodePagesExt) { ASSERT_WRITE_PTR_OR_NULL(puCodePage); HRESULT hr = E_FAIL; // Unknown code pages DWORD dwDefaultCodePages; if (uDefaultCodePage && SUCCEEDED(hr = CodePageToCodePagesEx(uDefaultCodePage, &dwDefaultCodePages, NULL)) && (dwDefaultCodePages & dwCodePages)) { hr = S_OK; } else { if (bCodePagesExt) { for (int iCharSet = 0; g_CharSetTransTableExt[iCharSet].dwCodePages; iCharSet++) { if (dwCodePages & g_CharSetTransTableExt[iCharSet].dwCodePages) { uDefaultCodePage = g_CharSetTransTableExt[iCharSet].uCodePage; hr = S_OK; break; } } } else { for (int iCharSet = 0; g_CharSetTransTable[iCharSet].dwCodePages; iCharSet++) { if (dwCodePages & g_CharSetTransTable[iCharSet].dwCodePages) { uDefaultCodePage = g_CharSetTransTable[iCharSet].uCodePage; hr = S_OK; break; } } } } if (puCodePage) { if (SUCCEEDED(hr)) *puCodePage = uDefaultCodePage; else *puCodePage = 0; } return hr; } #define REGSTR_PATH_FONTLINK TSZMICROSOFTPATH TEXT("\\Windows NT\\CurrentVersion\\FontLink\\SystemLink") void CMLFLink::FreeFlinkTable(void) { if (m_pFlinkTable) { for (UINT i=0; i= MAX_FONTLINK_BUFFER_SIZE) { break; } } dwValue = LF_FACESIZE; dwData = MAX_FONTLINK_BUFFER_SIZE; dwType = REG_MULTI_SZ; dwOffset = dwOffset2 = 0; dwIndex++; } m_uiFLinkFontNum = ulFLinkFonts; hr = S_OK; TABLE_DONE: if (hKey) RegCloseKey(hKey); if (hKeyFont) RegCloseKey(hKeyFont); if (tmpFontTable) LocalFree(tmpFontTable); if ((hr != S_OK) && m_pFlinkTable) FreeFlinkTable(); return hr; } HRESULT CMLFLink::GetNT5FLinkFontCodePages(HDC hDC, LOGFONTW* plfEnum, DWORD * lpdwCodePages) { HRESULT hr = S_OK; UINT i; if (!EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0)) return E_FAIL; if (NULL == m_pFlinkTable) CreateNT5FontLinkTable(); if (m_pFlinkTable) { for (i=0; ilfFaceName, m_pFlinkTable[i].szFaceName, LF_FACESIZE)) { DWORD dwOffset=0; // Internal buffer, we're sure it'll end while(TRUE) { MLStrCpyNW(plfEnum->lfFaceName, &m_pFlinkTable[i].pmszFaceName[dwOffset], LF_FACESIZE); EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0); dwOffset += lstrlenW(&m_pFlinkTable[i].pmszFaceName[dwOffset])+1; // End of multiple string ? if (m_pFlinkTable[i].pmszFaceName[dwOffset] == 0) break; } break; } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // CMLFLink : IMLangFontLink // 1/29/99 - Change HR return // Now, we always return S_OK unless system error, caller will // check code pages bits in dwCodePages for font code page coverage STDMETHODIMP CMLFLink::GetFontCodePages(HDC hDC, HFONT hFont, DWORD* pdwCodePages) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(pdwCodePages); HRESULT hr = S_OK; LOGFONT lfFont; DWORD dwCodePages = 0; if (!::GetObject(hFont, sizeof(lfFont), &lfFont)) hr = E_FAIL; // Invalid hFont if (SUCCEEDED(hr)) { LOGFONT lfEnum; // Enumerates all character sets of given font's facename // Then, combines them in dwCodePages ::memset(&lfEnum, 0, sizeof(lfEnum)); lfEnum.lfCharSet = DEFAULT_CHARSET; _tcsncpy(lfEnum.lfFaceName, lfFont.lfFaceName, ARRAYSIZE(lfEnum.lfFaceName)); if (g_bIsNT5) { LOGFONTW lfEnumW = {0}; lfEnumW.lfCharSet = DEFAULT_CHARSET; if (MultiByteToWideChar(g_uACP, 0, lfFont.lfFaceName, LF_FACESIZE, lfEnumW.lfFaceName, LF_FACESIZE)) hr = GetNT5FLinkFontCodePages(hDC, &lfEnumW, &dwCodePages); else if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0)) hr = E_FAIL; // Invalid hDC } else { if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0)) hr = E_FAIL; // Invalid hDC } } //############################ //###### MingLiU HACK ###### //## Fix the bogus font !!! ## //############################ if (SUCCEEDED(hr) && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, _T("MingLiU"), -1) == 2) { dwCodePages &= ~FS_LATIN1; // Actually it doesn't have the characters of ANSI_CHARSET. } //############################ // We should use following logic to replace above hack code // But, there is another DBCS<->Western font size mapping issue, we should disable this code until that issue is resolved, #if 0 // If font claims FE and 1252 and 1250, believe it can do 1252. // If font claims FE and 1252 and not 1250, don't believe it can do 1252. // This lets full Unicode fonts pass but blocks bad FE fonts. if (SUCCEEDED(hr) && (dwCodePages & (FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD)) && (dwCodePages & FS_LATIN1) && !(dwCodePages & FS_LATIN2)) { dwCodePages &= ~FS_LATIN1; } #endif #ifdef UNICODE #define PRC_DEFAULT_GUI_FONT L"\x5b8b\x4f53" #else #define PRC_DEFAULT_GUI_FONT "\xcb\xce\xcc\xe5" #endif // PRC Win95 DEFAULT_GUI_FONT HACK !!! if (SUCCEEDED(hr) && lfFont.lfCharSet == ANSI_CHARSET && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, PRC_DEFAULT_GUI_FONT, -1) == 2) { dwCodePages &= ~FS_CHINESESIMP; // Actually it doesn't have the characters of GB2321_CHARSET. } if (pdwCodePages) { if (SUCCEEDED(hr)) *pdwCodePages = dwCodePages; else *pdwCodePages = 0; } return hr; } int CALLBACK CMLFLink::GetFontCodePagesEnumFontProc(const LOGFONT* plf, const TEXTMETRIC*, DWORD FontType, LPARAM lParam) { for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++) { if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet) { if ((FontType == TRUETYPE_FONTTYPE) || (g_CharSetTransTable[iCharSet].uCodePage == g_uACP)) { *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages; break; } } } return TRUE; } int CALLBACK CMLFLink::GetFontCodePagesEnumFontProcW(const LOGFONTW* plf, const TEXTMETRICW*, DWORD FontType, LPARAM lParam) { for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++) { if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet) { if ((FontType == TRUETYPE_FONTTYPE) || (g_CharSetTransTable[iCharSet].uCodePage == g_uACP)) { *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages; break; } } } return TRUE; } STDMETHODIMP CMLFLink::MapFont(HDC hDC, DWORD dwCodePages, HFONT hSrcFont, HFONT* phDestFont) { ASSERT_THIS; ASSERT_WRITE_PTR_OR_NULL(phDestFont); HRESULT hr = S_OK; CFontMappingInfo fm; // To accelerate internal subroutine calls fm.hDC = hDC; // Font mapping cache works only for Display BOOL fDisplay = (::GetDeviceCaps(hDC, TECHNOLOGY) == DT_RASDISPLAY); dwCodePages &= ~FS_SYMBOL; // We don't map symbol font. if (!::GetObject(hSrcFont, sizeof(fm.lfSrcFont), &fm.lfSrcFont)) hr = E_FAIL; // Invalid hSrcFont // Do two things at same time // (1) Find given font in the font mapping cache // (2) Build m_auCodePage[] and m_adwCodePages[] if (SUCCEEDED(hr)) { if (fDisplay) { BYTE nCharSet = fm.lfSrcFont.lfCharSet; fm.lfSrcFont.lfCharSet = DEFAULT_CHARSET; EnumFontFamiliesEx(hDC, &fm.lfSrcFont, (FONTENUMPROC)VerifyFontSizeEnumFontProc, (LPARAM)&fm.lfSrcFont, 0); fm.lfSrcFont.lfCharSet = nCharSet; } hr = S_FALSE; // hr == S_FALSE means that we didn't find the font in the cache for (int n = 0; n < 32 && dwCodePages; n++) { hr = CodePagesToCodePage(dwCodePages, 0, &fm.auCodePage[n]); // Pick one of CodePages if (SUCCEEDED(hr)) hr = CodePageToCodePages(fm.auCodePage[n], &fm.adwCodePages[n]); if (SUCCEEDED(hr)) { if (fDisplay && m_pFontMappingCache) hr = m_pFontMappingCache->FindEntry(fm.auCodePage[n], fm.lfSrcFont, &fm.hDestFont); else hr = S_FALSE; } if (hr != S_FALSE) break; dwCodePages &= ~fm.adwCodePages[n]; } fm.auCodePage[n] = NULL; // End mark fm.adwCodePages[n] = 0; } if (hr == S_FALSE) // Not exist in cache { hr = MapFontCodePages(fm, GetFaceNameRegistry); if (hr == MLSTR_E_FACEMAPPINGFAILURE) hr = MapFontCodePages(fm, GetFaceNameGDI); // Handle font link failure case for NT5 if (hr == MLSTR_E_FACEMAPPINGFAILURE && g_bIsNT5) hr = MapFontCodePages(fm, GetFaceNameMIME); if (SUCCEEDED(hr) && fDisplay && m_pFontMappingCache) hr = m_pFontMappingCache->AddEntry(fm.auCodePage[fm.iCP], fm.lfSrcFont, fm.hDestFont); } if (phDestFont) { if (SUCCEEDED(hr)) { *phDestFont = fm.hDestFont; fm.hDestFont = NULL; // Avoid being deleted it in destructor } else { *phDestFont = NULL; } } return hr; } STDMETHODIMP CMLFLink::ReleaseFont(HFONT hFont) { ASSERT_THIS; HRESULT hr = S_OK; if (!m_pFontMappingCache || FAILED(hr = m_pFontMappingCache->UnlockEntry(hFont))) { // For non display DC if (::DeleteObject(hFont)) hr = S_OK; else hr = E_FAIL; // Invalid hFont } return hr; } STDMETHODIMP CMLFLink::ResetFontMapping(void) { ASSERT_THIS; HRESULT hr = S_OK; if (m_pFontMappingCache) hr = m_pFontMappingCache->FlushEntries(); return hr; } STDMETHODIMP CMLFLink2::ResetFontMapping(void) { ASSERT_THIS; HRESULT hr = S_OK; if (m_pIMLFLnk) hr = m_pIMLFLnk->ResetFontMapping(); if (m_pFontMappingCache2) hr = (S_OK == m_pFontMappingCache2->EnsureFontTable(FALSE)? hr : E_FAIL); return hr; } HRESULT CMLFLink::MapFontCodePages(CFontMappingInfo& fm, PFNGETFACENAME pfnGetFaceName) { HRESULT hr = MLSTR_E_FACEMAPPINGFAILURE; for (fm.iCP = 0; fm.auCodePage[fm.iCP]; fm.iCP++) { fm.lfDestFont.lfCharSet = DEFAULT_CHARSET; hr = (this->*pfnGetFaceName)(fm); if (SUCCEEDED(hr)) { LOGFONT lf = {0}; // If face name is from registry or MIMEDB, we set charset to codepage charset. if (fm.lfDestFont.lfCharSet == DEFAULT_CHARSET) { for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++) { if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage) { fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet; break; } } } lf.lfCharSet = DEFAULT_CHARSET; MLStrCpyN(lf.lfFaceName, fm.szFaceName, LF_FACESIZE); // Retrieve LOGFONT from gotten facename fm.lfDestFont.lfFaceName[0] = _T('\0'); if (!::EnumFontFamiliesEx(fm.hDC, &lf, MapFontEnumFontProc, (LPARAM)&fm.lfDestFont, 0)) hr = E_FAIL; // Invalid hDC else if (fm.lfDestFont.lfFaceName[0] == _T('\0')) hr = MLSTR_E_FACEMAPPINGFAILURE; } if (SUCCEEDED(hr)) { fm.lfDestFont.lfHeight = fm.lfSrcFont.lfHeight; fm.lfDestFont.lfWidth = fm.lfSrcFont.lfWidth; fm.lfDestFont.lfEscapement = fm.lfSrcFont.lfEscapement; fm.lfDestFont.lfOrientation = fm.lfSrcFont.lfOrientation; fm.lfDestFont.lfWeight = fm.lfSrcFont.lfWeight; fm.lfDestFont.lfItalic = fm.lfSrcFont.lfItalic; fm.lfDestFont.lfUnderline = fm.lfSrcFont.lfUnderline; fm.lfDestFont.lfStrikeOut = fm.lfSrcFont.lfStrikeOut; HRESULT hrTemp = VerifyFaceMap(fm); if (hrTemp == MLSTR_E_FACEMAPPINGFAILURE && fm.lfDestFont.lfWidth) { fm.lfDestFont.lfWidth = 0; // To recover non-scalable font hr = VerifyFaceMap(fm); } else { hr = hrTemp; } } if (hr != MLSTR_E_FACEMAPPINGFAILURE) break; } return hr; } int CALLBACK CMLFLink::MapFontEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD, LPARAM lParam) { LOGFONT* plfDestFont = (LOGFONT*)lParam; if (!plfDestFont->lfFaceName[0] ) { if (plfDestFont->lfCharSet != DEFAULT_CHARSET) { if (plfDestFont->lfCharSet == plfFont->lfCharSet) *plfDestFont = *plfFont; } else *plfDestFont = *plfFont; } return TRUE; } HRESULT CMLFLink::GetFaceNameRegistry(CFontMappingInfo& fm) { static const TCHAR szRootKey[] = _T("Software\\Microsoft\\Internet Explorer"); static const TCHAR szIntlKey[] = _T("International\\%d"); static const TCHAR szPropFontName[] = _T("IEPropFontName"); static const TCHAR szFixedFontName[] = _T("IEFixedFontName"); HRESULT hr = S_OK; HKEY hKeyRoot; if (::RegOpenKeyEx(HKEY_CURRENT_USER, szRootKey, 0, KEY_READ, &hKeyRoot) == ERROR_SUCCESS) { TCHAR szCodePageKey[ARRAYSIZE(szIntlKey) + 10]; HKEY hKeySub; ::wsprintf(szCodePageKey, szIntlKey, fm.auCodePage[fm.iCP]); if (::RegOpenKeyEx(hKeyRoot, szCodePageKey, 0, KEY_READ, &hKeySub) == ERROR_SUCCESS) { const TCHAR* pszFontNameValue; DWORD dwType; DWORD dwSize = sizeof(fm.szFaceName); if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH) pszFontNameValue = szFixedFontName; else pszFontNameValue = szPropFontName; if (::RegQueryValueEx(hKeySub, pszFontNameValue, 0, &dwType, (LPBYTE)fm.szFaceName, &dwSize) != ERROR_SUCCESS) hr = MLSTR_E_FACEMAPPINGFAILURE; if (::RegCloseKey(hKeySub) != ERROR_SUCCESS && SUCCEEDED(hr)) hr = MLSTR_E_FACEMAPPINGFAILURE; } else { hr = MLSTR_E_FACEMAPPINGFAILURE; } if (::RegCloseKey(hKeyRoot) != ERROR_SUCCESS && SUCCEEDED(hr)) hr = MLSTR_E_FACEMAPPINGFAILURE; } else { hr = MLSTR_E_FACEMAPPINGFAILURE; } return hr; } HRESULT CMLFLink::GetFaceNameGDI(CFontMappingInfo& fm) { HRESULT hr = S_OK; for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++) { if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage) break; } if (g_CharSetTransTable[iCharSet].uCodePage) { ::memset(&fm.lfDestFont, 0, sizeof(fm.lfDestFont)); // Specify font weight as NORMAL to avoid NT GDI font mapping bugs fm.lfDestFont.lfWeight = FW_NORMAL; fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet; hr = GetFaceNameRealizeFont(fm); } else { hr = E_FAIL; // Unknown code page } if (SUCCEEDED(hr)) { // Height, CharSet, Pitch and Family fm.lfDestFont.lfHeight = fm.lfSrcFont.lfHeight; fm.lfDestFont.lfPitchAndFamily = fm.lfSrcFont.lfPitchAndFamily; hr = GetFaceNameRealizeFont(fm); if (FAILED(hr)) { // CharSet, Pitch and Family fm.lfDestFont.lfHeight = 0; hr = GetFaceNameRealizeFont(fm); } if (FAILED(hr)) { // CharSet and Pitch fm.lfDestFont.lfPitchAndFamily &= 0x03; // Pitch Mask hr = GetFaceNameRealizeFont(fm); } if (FAILED(hr)) { // CharSet only fm.lfDestFont.lfPitchAndFamily = 0; hr = GetFaceNameRealizeFont(fm); } } return hr; } HRESULT CMLFLink::GetFaceNameMIME(CFontMappingInfo& fm) { HRESULT hr = E_FAIL; MIMECPINFO cpInfo; if (fm.auCodePage[fm.iCP] == 936) { MLStrCpyN(fm.szFaceName, TEXT("SimSun"), LF_FACESIZE); return S_OK; } if (!g_pMimeDatabase) BuildGlobalObjects(); if (NULL != g_pMimeDatabase) { if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(fm.auCodePage[fm.iCP], 0x409, &cpInfo))) { TCHAR szFontFaceName[LF_FACESIZE]; szFontFaceName[0] = 0; if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH && cpInfo.wszFixedWidthFont[0]) { #ifdef UNICODE MLStrCpyNW(szFontFaceName, cpInfo.wszFixedWidthFont, LF_FACESIZE); #else WideCharToMultiByte(CP_ACP, 0, cpInfo.wszFixedWidthFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL); #endif } else if (cpInfo.wszProportionalFont[0]) { #ifdef UNICODE MLStrCpyNW(szFontFaceName, cpInfo.wszProportionalFont, LF_FACESIZE); #else WideCharToMultiByte(CP_ACP, 0, cpInfo.wszProportionalFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL); #endif } if (szFontFaceName[0]) { MLStrCpyN(fm.szFaceName, szFontFaceName, LF_FACESIZE); hr = S_OK; } } else hr = MLSTR_E_FACEMAPPINGFAILURE; } return hr; } HRESULT CMLFLink::GetFaceNameRealizeFont(CFontMappingInfo& fm) { HRESULT hr = S_OK; HFONT hFont = NULL; HFONT hOldFont; DWORD dwFontCodePages; // First let's get a facename based on the given lfDestFont // Then verify if the font of the found facename has the code pages we want. hFont = ::CreateFontIndirect(&fm.lfDestFont); if (!hFont) hr = E_FAIL; // Out of memory or GDI resource if (SUCCEEDED(hr)) { hOldFont = (HFONT)::SelectObject(fm.hDC, hFont); if (!hOldFont) hr = E_FAIL; // Out of memory or GDI resource } if (SUCCEEDED(hr)) { if (!::GetTextFace(fm.hDC, ARRAYSIZE(fm.szFaceName), fm.szFaceName)) hr = E_FAIL; // Out of memory or GDI resource if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr)) hr = E_FAIL; // Out of memory or GDI resource } if (hFont) ::DeleteObject(hFont); if (SUCCEEDED(hr)) { LOGFONT lfTemp; lfTemp = fm.lfDestFont; _tcsncpy(lfTemp.lfFaceName, fm.szFaceName, ARRAYSIZE(lfTemp.lfFaceName)); hFont = ::CreateFontIndirect(&lfTemp); if (!hFont) hr = E_FAIL; // Out of memory or GDI resource if (SUCCEEDED(hr = GetFontCodePages(fm.hDC, hFont, &dwFontCodePages)) && !(dwFontCodePages & fm.adwCodePages[fm.iCP])) hr = MLSTR_E_FACEMAPPINGFAILURE; if (hFont) ::DeleteObject(hFont); } return hr; } HRESULT CMLFLink::VerifyFaceMap(CFontMappingInfo& fm) { HRESULT hr = S_OK; HFONT hOldFont; if (fm.hDestFont) ::DeleteObject(fm.hDestFont); fm.hDestFont = ::CreateFontIndirect(&fm.lfDestFont); if (!fm.hDestFont) hr = E_FAIL; // Out of memory or GDI resource if (SUCCEEDED(hr)) { hOldFont = (HFONT)::SelectObject(fm.hDC, fm.hDestFont); if (!hOldFont) hr = E_FAIL; // Out of memory or GDI resource } if (SUCCEEDED(hr)) { TCHAR szFaceName[LF_FACESIZE]; if (!::GetTextFace(fm.hDC, ARRAYSIZE(szFaceName), szFaceName)) hr = E_FAIL; // Out of memory or GDI resource if (SUCCEEDED(hr)) { int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, fm.lfDestFont.lfFaceName, -1, szFaceName, -1); if (!nRet) hr = E_FAIL; // Unexpected error else if (nRet != 2) // Not Equal hr = MLSTR_E_FACEMAPPINGFAILURE; } if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr)) hr = E_FAIL; // Out of memory or GDI resource } return hr; } ///////////////////////////////////////////////////////////////////////////// // CMLFLink::CFontMappingCache CMLFLink::CFontMappingCache::CFontMappingCache(void) : m_pEntries(NULL), m_pFree(NULL), m_cEntries(0) { ::InitializeCriticalSection(&m_cs); } CMLFLink::CFontMappingCache::~CFontMappingCache(void) { FlushEntries(); DeleteCriticalSection(&m_cs); } HRESULT CMLFLink::CFontMappingCache::FindEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT* phDestFont) { HRESULT hr = S_FALSE; ::EnterCriticalSection(&m_cs); if (m_pEntries) { CFontMappingCacheEntry* pEntry = m_pEntries; while ((pEntry = pEntry->m_pPrev) != m_pEntries) { if (uCodePage == pEntry->m_uSrcCodePage && lfSrcFont.lfPitchAndFamily == pEntry->m_bSrcPitchAndFamily && lfSrcFont.lfHeight == pEntry->m_lSrcHeight && lfSrcFont.lfWidth == pEntry->m_lSrcWidth && lfSrcFont.lfEscapement == pEntry->m_lSrcEscapement && lfSrcFont.lfOrientation == pEntry->m_lSrcOrientation && lfSrcFont.lfWeight == pEntry->m_lSrcWeight && lfSrcFont.lfItalic == pEntry->m_bSrcItalic && lfSrcFont.lfUnderline == pEntry->m_bSrcUnderline && lfSrcFont.lfStrikeOut == pEntry->m_bSrcStrikeOut) { int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfSrcFont.lfFaceName, -1, pEntry->m_szSrcFaceName, -1); if (!nRet) { hr = E_FAIL; // Unexpected error break; } else if (nRet == 2) // Equal { if (phDestFont) *phDestFont = pEntry->m_hDestFont; pEntry->m_nLockCount++; hr = S_OK; break; } } } } ::LeaveCriticalSection(&m_cs); if (phDestFont && hr != S_OK) *phDestFont = NULL; return hr; } HRESULT CMLFLink::CFontMappingCache::UnlockEntry(HFONT hDestFont) { HRESULT hr = E_FAIL; // hDestFont is not found in the cache ::EnterCriticalSection(&m_cs); if (m_pEntries) { CFontMappingCacheEntry* pEntry = m_pEntries; while ((pEntry = pEntry->m_pPrev) != m_pEntries) { if (hDestFont == pEntry->m_hDestFont) { if (pEntry->m_nLockCount - 1 >= 0) { pEntry->m_nLockCount--; hr = S_OK; } break; } } } ::LeaveCriticalSection(&m_cs); return hr; } HRESULT CMLFLink::CFontMappingCache::AddEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT hDestFont) { HRESULT hr = S_OK; ::EnterCriticalSection(&m_cs); if (!m_pEntries) // Need to allocate all the entries { CFontMappingCacheEntry* pEntries; pEntries = new CFontMappingCacheEntry[NUMFONTMAPENTRIES + 1]; // +1 for sentinel if (pEntries) { // Init sentinel pEntries[0].m_pPrev = &pEntries[0]; pEntries[0].m_pNext = &pEntries[0]; // Init free entries for (int n = 0; n < NUMFONTMAPENTRIES; n++) { const nEnt = n + 1; // + 1 for sentinel if (n < NUMFONTMAPENTRIES - 1) pEntries[nEnt].m_pNext = &pEntries[nEnt + 1]; else pEntries[nEnt].m_pNext = NULL; } m_pEntries = &pEntries[0]; m_pFree = &pEntries[1]; } else { hr = E_OUTOFMEMORY; } } if (SUCCEEDED(hr) && !m_pFree) // Need to delete oldest entry { CFontMappingCacheEntry* pOldestEntry = m_pEntries->m_pPrev; while (pOldestEntry->m_nLockCount > 0 && pOldestEntry != m_pEntries) // Entry is locked pOldestEntry = pOldestEntry->m_pPrev; if (pOldestEntry != m_pEntries) { if (pOldestEntry->m_hDestFont) ::DeleteObject(pOldestEntry->m_hDestFont); // Delete it from m_pEntries list pOldestEntry->m_pPrev->m_pNext = pOldestEntry->m_pNext; pOldestEntry->m_pNext->m_pPrev = pOldestEntry->m_pPrev; // Insert it into m_pFree list pOldestEntry->m_pNext = m_pFree; m_pFree = pOldestEntry; } else // No entry available { hr = E_FAIL; // Out of cache entries } } if (SUCCEEDED(hr)) // Create new entry and fill it { CFontMappingCacheEntry* pNewEntry; // Delete it from m_pFree list pNewEntry = m_pFree; // shouldn't be NULL m_pFree = pNewEntry->m_pNext; // Insert it into m_pEntries list pNewEntry->m_pNext = m_pEntries->m_pNext; pNewEntry->m_pPrev = m_pEntries; m_pEntries->m_pNext->m_pPrev = pNewEntry; m_pEntries->m_pNext = pNewEntry; // Fill it pNewEntry->m_nLockCount = 1; pNewEntry->m_uSrcCodePage = uCodePage; pNewEntry->m_lSrcHeight = lfSrcFont.lfHeight; pNewEntry->m_lSrcWidth = lfSrcFont.lfWidth; pNewEntry->m_lSrcEscapement = lfSrcFont.lfEscapement; pNewEntry->m_lSrcOrientation = lfSrcFont.lfOrientation; pNewEntry->m_lSrcWeight = lfSrcFont.lfWeight; pNewEntry->m_bSrcItalic = lfSrcFont.lfItalic; pNewEntry->m_bSrcUnderline = lfSrcFont.lfUnderline; pNewEntry->m_bSrcStrikeOut = lfSrcFont.lfStrikeOut; pNewEntry->m_bSrcPitchAndFamily = lfSrcFont.lfPitchAndFamily; _tcsncpy(pNewEntry->m_szSrcFaceName, lfSrcFont.lfFaceName, ARRAYSIZE(pNewEntry->m_szSrcFaceName)); pNewEntry->m_hDestFont = hDestFont; } ::LeaveCriticalSection(&m_cs); return hr; } HRESULT CMLFLink::CFontMappingCache::FlushEntries(void) { ::EnterCriticalSection(&m_cs); if (m_pEntries) { CFontMappingCacheEntry* pEntry = m_pEntries; while ((pEntry = pEntry->m_pPrev) != m_pEntries) { if (pEntry->m_hDestFont) ::DeleteObject(pEntry->m_hDestFont); } delete[] m_pEntries; m_pEntries = NULL; m_cEntries = 0; } ::LeaveCriticalSection(&m_cs); return S_OK; } ///////////////////////////////////////////////////////////////////////////// // CMLFLink::CCodePagesCache CMLFLink::CCodePagesCache::CCodePagesCache(void) : m_pbBuf(NULL),m_pbBufExt(NULL) { ::InitializeCriticalSection(&m_cs); } CMLFLink::CCodePagesCache::~CCodePagesCache(void) { DeleteCriticalSection(&m_cs); } HRESULT CMLFLink::CCodePagesCache::RealLoad(void) { HRESULT hr = S_OK; ::EnterCriticalSection(&m_cs); if (!m_pbBuf && !m_pbBufExt) { HRSRC hrCodePages; HGLOBAL hgCodePages; HRSRC hrCodePagesExt; HGLOBAL hgCodePagesExt; if (SUCCEEDED(hr)) { hrCodePages = ::FindResource(g_hInst, MAKEINTRESOURCE(IDR_CODEPAGES), _T("CODEPAGES")); hrCodePagesExt = ::FindResource(g_hInst, MAKEINTRESOURCE(IDR_CODEPAGESEXT), _T("CODEPAGESEXT")); if (!hrCodePages || !hrCodePagesExt) hr = E_FAIL; // Build error? } if (SUCCEEDED(hr)) { hgCodePages = ::LoadResource(g_hInst, hrCodePages); hgCodePagesExt = ::LoadResource(g_hInst, hrCodePagesExt); if (!hgCodePages && !hgCodePagesExt) hr = E_FAIL; // Unexpected error } if (SUCCEEDED(hr)) { m_pbBuf = (BYTE*)::LockResource(hgCodePages); m_pbBufExt = (BYTE*)::LockResource(hgCodePagesExt); if (!m_pbBuf || !m_pbBufExt) hr = E_FAIL; // Unexpected error } } ::LeaveCriticalSection(&m_cs); return hr; } extern "C" HRESULT GetGlobalFontLinkObject(IMLangFontLink **ppMLFontLink) { HRESULT hr = E_INVALIDARG; if (NULL != ppMLFontLink) { if (NULL == g_pMLFLink) { EnterCriticalSection(&g_cs); if (NULL == g_pMLFLink) CComCreator< CComPolyObject< CMLFLink > >::CreateInstance(NULL, IID_IMLangFontLink, (void **)&g_pMLFLink); LeaveCriticalSection(&g_cs); } *ppMLFontLink = g_pMLFLink; if (g_pMLFLink) { g_pMLFLink->AddRef(); hr = S_OK; } else hr = E_FAIL; } return hr; } HRESULT CMLFLink2::CFontMappingCache2::MapFontFromCMAP(HDC hDC, WCHAR wchar, HFONT hSrcFont, HFONT *phDestFont) { BOOL bFont = FALSE; HRESULT hr = E_FAIL; int i,j,k; LOGFONT LogFont; if (!phDestFont) return E_INVALIDARG; if (!GetObject(hSrcFont, sizeof(LOGFONT), &LogFont)) return hr; if (!g_pfont_table || !g_pfont_table[0].szFaceName[0]) { if (FAILED(LoadFontDataFile())) { return hr; } } i=0; j=ARRAYSIZE(g_urange_table); k = j/2; while (i<=j) { if (wchar >= g_urange_table[k].wcFrom && wchar <= g_urange_table[k].wcTo) break; else if (wchar < g_urange_table[k].wcFrom) { j = k -1; } else { i = k + 1; } k = (i+j)/2; } if (i<=j && g_urange_table[k].nFonts) { TCHAR szFaceName[LF_FACESIZE]; GetTextFace(hDC, LF_FACESIZE, szFaceName); // Check if it supports the character for (i=0; i= g_urange_table[k].nFonts) { i = fetchCharSet((BYTE *) &(LogFont.lfCharSet), k); } MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE); } if (i < g_urange_table[k].nFonts) { MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE); } bFont = TRUE; } if (bFont && (*phDestFont = CreateFontIndirect(&LogFont))) { hr = S_OK; } else { *phDestFont = NULL; } return hr; } HRESULT CMLFLink2::CFontMappingCache2::UnicodeRanges( LPTSTR szFont, UINT *puiRanges, UNICODERANGE* pURanges ) { HRESULT hr = E_FAIL; UINT nURange = 0; DWORD cmap = 0; DWORD name = 0; HANDLE hTTF; TCHAR szFontPath[MAX_PATH]; static TCHAR s_szFontDir[MAX_PATH] = {0}; HANDLE hTTFMap; DWORD dwFileSize; LPVOID lpvFile = NULL; LPBYTE lp, lp1, lp2, lpMax = NULL; DWORD Num; WORD i, j, Len; if (!szFont[0]) return hr; if (!s_szFontDir[0]) { MLGetWindowsDirectory(s_szFontDir, MAX_PATH); MLPathCombine(s_szFontDir, s_szFontDir, FONT_FOLDER); } MLPathCombine(szFontPath, s_szFontDir, szFont); hTTF = CreateFile( szFontPath, // pointer to name of the file GENERIC_READ, // access (read-write) mode FILE_SHARE_READ, // share mode NULL, // pointer to security attributes OPEN_EXISTING, // how to create FILE_ATTRIBUTE_NORMAL, // file attributes NULL); // handle to file with attributes to copy; if (INVALID_HANDLE_VALUE == hTTF) return hr; dwFileSize = GetFileSize(hTTF, NULL); hTTFMap = CreateFileMapping( hTTF, NULL, PAGE_READONLY, 0, dwFileSize, NULL ); if(hTTFMap == NULL) { goto CloseHandle0; } lpvFile = MapViewOfFile( hTTFMap, FILE_MAP_READ, 0, 0, 0 ); if(lpvFile == NULL) { goto CloseHandle; } lp = (LPBYTE)lpvFile; // The maximum boundary we can go lpMax = (LPBYTE)lpvFile + dwFileSize; // Font table name uses ASCII if(strncmp(((TTC_HEAD*)lp)->TTCTag, "ttcf", 4) == 0) // TTC format { lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1); // points to first TTF } Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables); // Number of Tables lp += sizeof(TTF_HEAD); if (lp+Num*sizeof(TABLE_DIR) >= lpMax) // Not a valid TrueType file if table size >= TTF file size goto CloseHandle; for(i = 0; i < Num ; i++) // go thru all tables to find cmap and name { if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0) { cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset); if (name) break; } else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0) { name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset); if (cmap) break; } lp += sizeof(TABLE_DIR); } if((!cmap) || (!name)) // Can't find cmap or name { goto CloseHandle; } // Read thru all name records // to see if font subfamily name is "Regular" lp = (LPBYTE)lpvFile + name; // point to name table Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec); // # of name record if (lp + sizeof(NAME_TABLE)*Num >= lpMax) goto CloseHandle; lp1 = lp + sizeof(NAME_TABLE); // point to name record for(i = 0; i < Num; i++) { if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID)) { lp2 = lp + // point to string store TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) + TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset); // Invalid TTF file if (lp2 >= lpMax) break; Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length); if(((MICROSOFT_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) && (UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))) || ((APPLE_UNICODE_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) && (APPLE_UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding)))) { Len >>= 1; const char *pStr = szRegular; if (Len == sizeof(szNormal) -1) pStr = szNormal; else if (Len != sizeof(szRegular)-1) { lp1 += sizeof(NAME_RECORD); continue; } while(--Len > 0) { if(*(lp2+(Len<<1)+1) != pStr[Len]) break; } if (!Len) break; else { lp1 += sizeof(NAME_RECORD); continue; } } else { if(strncmp((char*)lp2, szRegular, sizeof(szRegular)-1) != 0 && strncmp((char*)lp2, szNormal, sizeof(szNormal)-1) != 0) { lp1 += sizeof(NAME_RECORD); continue; } else break; } } lp1 += sizeof(NAME_RECORD); } // If no regular font, exit if (i == Num) goto CloseHandle; // all non-regular fonts have already been eliminated lp1 = (LPBYTE)lpvFile + cmap; // point to cmap table if (lp1 + sizeof(CMAP_TABLE)*Num >= lpMax) goto CloseHandle; Num = TWO_BYTE_NUM(((CMAP_HEAD*)lp1)->NumTables); lp1 += sizeof(CMAP_HEAD); while(Num >0) { if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM && (TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING || TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_SYMBOL_INDEXING)) { lp = (LPBYTE)lpvFile + cmap + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset); if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR) { break; } } Num--; lp1 += sizeof(CMAP_TABLE); } if(Num == 0) // can't find Platform:3/Encoding:1 (Unicode) goto CloseHandle; Num = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2); lp2 = lp + sizeof(CMAP_FORMAT); // lp2 -> first WCHAR of wcTo lp1 = lp2 + Num + 2; // lp1 -> first WCHAR of wcFrom if (lp1 + Num >= lpMax) goto CloseHandle; Num /= 2; if (pURanges == NULL) { *puiRanges = Num; } else { if (Num > *puiRanges) Num = *puiRanges; else *puiRanges = Num; for(i=0, j=0; i < Num; i++, j++, j++) { pURanges[i].wcFrom = TWO_BYTE_NUM((lp1+j)); pURanges[i].wcTo = TWO_BYTE_NUM((lp2+j)); } } hr = S_OK; CloseHandle: UnmapViewOfFile(lpvFile); CloseHandle0: CloseHandle(hTTFMap); CloseHandle(hTTF); return hr; } int CMLFLink2::CFontMappingCache2::fetchCharSet(BYTE *pCharset, int iURange) { int i,j; //Check if current charset valid for the font for (i=0; iTTCTag, "ttcf", 4) == 0) // TTC format { lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1); // points to first TTF } Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables); // Number of Tables { // if SearchRange != (Maximum power of 2 <= Num)*16, // then this is not a TTF file DWORD wTmp = 1; while(wTmp <= Num) { wTmp <<= 1; } wTmp <<= 3; // (wTmp/2)*16 if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->SearchRange)) { goto CloseHandle00; } // if RangeShift != (Num*16) - SearchRange, // then this is not a TTF file wTmp = (Num<<4) - wTmp; if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->RangeShift)) { goto CloseHandle00; } } lp += sizeof(TTF_HEAD); for(i = 0; i < (int)Num; i++) // go thru all tables to find cmap and name { if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0) { cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset); if (name && os2) break; } else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0) { name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset); if (cmap && os2) break; } else if(strncmp( ((TABLE_DIR*)lp)->Tag, "OS/2", 4) == 0) { os2 = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset); if (cmap && name) break; } lp += sizeof(TABLE_DIR); } if((!cmap) || (!name) || (!os2)) // Can't find cmap or name { goto CloseHandle00; } // Read thru all name records // to see if font subfamily name is "Regular" lp = (LPBYTE)lpvFile + name; // point to name table Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec); // # of name record lp1 = lp + sizeof(NAME_TABLE); // point to name record for(i = 0; i < (int)Num; i++) { if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID)) { lp2 = lp + // point to string store TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) + TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset); Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length); if(UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding)) { Len >>= 1; while(--Len > 0) { if(*(lp2+(Len<<1)+1) != szRegular[Len]) goto CloseHandle00; } break; } else { if(strncmp((char*)lp2, szRegular, Len) != 0) goto CloseHandle00; else break; } } lp1 += sizeof(NAME_RECORD); } // all non-regular fonts have already been eliminated lp1 = (LPBYTE)lpvFile + cmap; // point to cmap table Num = TWO_BYTE_NUM(((CMAP_HEAD*)lp)->NumTables); lp1 += sizeof(CMAP_HEAD); while(Num >0) { if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM && TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING) { lp = (LPBYTE)lpvFile + cmap + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset); if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR) { break; } } Num--; lp1 += sizeof(CMAP_TABLE); } if(Num == 0) // can't find Platform:3/Encoding:1 (Unicode) goto CloseHandle00; Num = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2) ; m = ARRAYSIZE(g_urange_table); lp2 = lp + sizeof(CMAP_FORMAT); // lp2 -> first WCHAR of wcTo lp1 = lp2 + Num + 2; // lp1 -> first WCHAR of wcFrom // Fast parse !!! while (--m) { // URANGE binary search i=0; j= (int) Num - 2; k=j/2; while (i<=j) { if (k % 2) k++; if (g_urange_table[m].wcFrom >= TWO_BYTE_NUM((lp1+k)) && g_urange_table[m].wcTo <= TWO_BYTE_NUM((lp2+k))) { EnterCriticalSection(&g_cs); if (!g_urange_table[m].pFontIndex) g_urange_table[m].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)* MAX_FONT_INDEX); if (!g_urange_table[m].pFontIndex) { goto CloseHandle00; } if (g_urange_table[m].nFonts >= MAX_FONT_INDEX) { break; } g_urange_table[m].pFontIndex[g_urange_table[m].nFonts] = iFontIndex; g_urange_table[m].nFonts++; // Fill in font code page signature g_pfont_table[iFontIndex].dwCodePages[0] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE)); g_pfont_table[iFontIndex].dwCodePages[1] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE+1)); LeaveCriticalSection(&g_cs); break; } else { if (g_urange_table[m].wcFrom < TWO_BYTE_NUM((lp1+k))) { j = k-2; } else { i = k+2; } k = (i+j)/2; } } } bRet = TRUE; CloseHandle00: UnmapViewOfFile(lpvFile); CloseHandle01: CloseHandle(hTTF); CloseHandle(hTTFMap); return bRet; } HRESULT GetRegFontKey(HKEY *phKey, DWORD *pdwValues) { HRESULT hr = E_FAIL; if (ERROR_SUCCESS == (g_bIsNT? RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEYNT, 0, KEY_READ, phKey): RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEY95, 0, KEY_READ, phKey))) { if (ERROR_SUCCESS == RegQueryInfoKey(*phKey, NULL, NULL, 0, NULL, NULL, NULL, pdwValues, NULL, NULL, NULL, NULL)) { hr = S_OK; } } return hr; } BOOL CMLFLink2::CFontMappingCache2::GetFontURangeBits(TCHAR *szFontFile, DWORD * pdwURange) { // We can make use of font Unicode range signature if needed. return TRUE; } BOOL CMLFLink2::CFontMappingCache2::SetFontScripts(void) { LOGFONT lf; int i,j; HWND hWnd = GetTopWindow(GetDesktopWindow()); HDC hDC = GetDC(hWnd); if (!g_pfont_table) return FALSE; // Process code page based scripts (g_CharSetTransTable.sid) for (i = 0; g_CharSetTransTable[i].nCharSet != DEFAULT_CHARSET; i++) { j = 0; ZeroMemory(&lf, sizeof(lf)); lf.lfCharSet = (BYTE)g_CharSetTransTable[i].nCharSet; while (g_CharSetTransTable[i].sid[j] != sidDefault) { EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)SetFontScriptsEnumFontProc, (LPARAM)g_CharSetTransTable[i].sid[j], 0); j++; } } if (hDC) ReleaseDC(hWnd, hDC); // Process Unicode subrange based scripts (not implemented) // Skip this part since we need to access font CMAP anyway // Process char based scripts (g_wCharToScript) for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++) { UINT uiRanges = 0; UNICODERANGE* pURanges = NULL; SCRIPT_IDS scripts; if (SUCCEEDED(m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges))) { if (uiRanges) { int l, m, n; pURanges = (UNICODERANGE *)LocalAlloc(LPTR, sizeof(UNICODERANGE) * uiRanges); if (!pURanges) return FALSE; m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges); for (j=0; j< ARRAYSIZE(g_wCharToScript); j++) { l = 0; m = uiRanges; n = m/2; while (l <= m) { if ((g_wCharToScript[j].wch >= pURanges[n].wcFrom) && (g_wCharToScript[j].wch <= pURanges[n].wcTo)) { scripts = 1; scripts <<= g_wCharToScript[j].sid; g_pfont_table[i].scripts |= scripts; break; } else { if (g_wCharToScript[j].wch < pURanges[n].wcFrom) m = n-1; else l = n+1; n = (m+l)/2; } } } LocalFree(pURanges); pURanges = NULL; } } // sidUserDefined should contain all valid regular TrueType fonts if (!MLStrStr(g_pfont_table[i].szFaceName, TEXT("Bold")) && !MLStrStr(g_pfont_table[i].szFaceName, TEXT("Italic"))) { scripts = 1; scripts <<= sidUserDefined; g_pfont_table[i].scripts |= scripts; } } //GetFontScriptFromCMAP(szFont, &(g_pfont_table[i].scripts)); return TRUE; } BOOL CMLFLink2::CFontMappingCache2::IsFontUpdated(void) { HKEY hkey; DWORD dwFonts = 0; BOOL bRet = FALSE; if (g_pfont_table) { if (S_OK == GetRegFontKey(&hkey, &dwFonts)) { if (g_pfont_table[0].dwCodePages[1] != dwFonts) bRet = TRUE; RegCloseKey(hkey); } } else { // font table not created yet, need to update bRet = TRUE; } return bRet; } // Make sure we have font data table available and it is updated HRESULT CMLFLink2::CFontMappingCache2::EnsureFontTable(BOOL bUpdateURangeTable) { BOOL bRet; if (IsFontUpdated()) { // Need to guard the whole font creation procedure by critical sections EnterCriticalSection(&g_cs); if (IsFontUpdated()) { if (g_pfont_table) { if (g_pfont_table[0].szFaceName[0]) { bUpdateURangeTable = TRUE; } if (g_pfont_table) { LocalFree(g_pfont_table); g_pfont_table = NULL; } } bRet = SetFontTable(); if (!bRet) return E_OUTOFMEMORY; } LeaveCriticalSection(&g_cs); } if (bUpdateURangeTable) { EnterCriticalSection(&g_cs); for (int i = 0; i < ARRAYSIZE(g_urange_table); i++) { if (g_urange_table[i].nFonts) { LocalFree(g_urange_table[i].pFontIndex); g_urange_table[i].pFontIndex = NULL; g_urange_table[i].nFonts = 0; } } LeaveCriticalSection(&g_cs); if (S_OK != SetFontUnicodeRanges()) return E_OUTOFMEMORY; SaveFontDataFile(); } // All tables created successfully return S_OK; } #ifdef UNIX typedef struct tagTable_info{ int count; int table_size; } Table_info; int UnixGetAllFontsProc(ENUMLOGFONTEX* plfFont, NEWTEXTMETRICEX* lpntm, int iFontType, LPARAM lParam) { LOGFONT *lplf; int *pcount = &((Table_info*)lParam)->count; int *ptable_size = &((Table_info*)lParam)->table_size; lplf = &(plfFont->elfLogFont); // We don't use non TrueType fonts if (iFontType == DEVICE_FONTTYPE || iFontType == RASTER_FONTTYPE) return 1; // keep going but don't use this font // We don't use the SYMBOL, Mac Charset fonts if(lplf->lfCharSet == SYMBOL_CHARSET || lplf->lfCharSet == MAC_CHARSET) return 1; // We don't handle vertical fonts if (TEXT('@') == lplf->lfFaceName[0]) return 1; // Now update the font-table // Does UNIX use TTF? // if (FontType == TRUETYPE_FONTTYPE) { CopyMemory(&g_pfont_table[*pcount].lf, lplf, sizeof(LOGFONT)); MLStrCpyN(g_pfont_table[*pcount].szFaceName, lplf->lfFaceName, LF_FACESIZE); (*pcount)++; } if (*pcount >= *ptable_size) { FONTINFO * pfont_table = NULL; *ptable_size += FONT_TABLE_INIT_SIZE; pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, sizeof(FONTINFO) * *ptable_size, LMEM_MOVEABLE | LMEM_ZEROINIT); if (NULL == pfont_table) { return 0; // Stop enum. } else { g_pfont_table = pfont_table; } } return 1; // Keep enum. } #endif BOOL CMLFLink2::CFontMappingCache2::SetFontTable(void) { BOOL bRet = TRUE; TCHAR szFaceName[MAX_PATH]; DWORD dwValue; TCHAR szFontFile[MAX_FONT_FILE_NAME]; DWORD dwData; DWORD dwType = REG_SZ; DWORD dwFonts; int i, table_size = FONT_TABLE_INIT_SIZE; LPTSTR pNewFaceName = NULL; HKEY hkey = NULL; static int count; HDC hDC = NULL; HWND hWnd = NULL; count = 1; if (!g_pfont_table) { g_pfont_table = (FONTINFO *)LocalAlloc(LPTR, sizeof(FONTINFO) * FONT_TABLE_INIT_SIZE); if (!g_pfont_table) { bRet = FALSE; goto SETFONT_DONE; } } else { goto SETFONT_DONE; } #ifndef UNIX if (S_OK != GetRegFontKey(&hkey, &dwFonts)) { bRet = FALSE; goto SETFONT_DONE; } hWnd = GetTopWindow(GetDesktopWindow()); hDC = GetDC(hWnd); for (i=0; ;i++) { dwValue = sizeof(szFaceName); dwData = sizeof(szFontFile); if (ERROR_NO_MORE_ITEMS == RegEnumValue( hkey, i, szFaceName, &dwValue, NULL, &dwType, (LPBYTE)szFontFile, &dwData )) { break; } DWORD dwOffset = 0; FIND_NEXT_FACENAME: pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT(" & ")); if (pNewFaceName) { *pNewFaceName = 0; // Skip " & ", look for next font face name pNewFaceName+=3; } else { pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT("(TrueType)")); if(pNewFaceName) { // Ignor the space between face name and "(TrueTye)" signature if ((pNewFaceName > szFaceName) && (*(pNewFaceName-1) == 0x20)) pNewFaceName--; *pNewFaceName = 0; } } if (pNewFaceName && !EnumFontFamilies(hDC, &szFaceName[dwOffset], MapFontExEnumFontProc, (LPARAM)&count)) //TrueType font { int nSize; LPTSTR pFontFile; if (count >= table_size) { FONTINFO * _pfont_table = NULL; table_size += FONT_TABLE_INIT_SIZE; _pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, sizeof(FONTINFO) * table_size, LMEM_MOVEABLE | LMEM_ZEROINIT); if (NULL == _pfont_table) { bRet = FALSE; goto SETFONT_DONE; } else { g_pfont_table = _pfont_table; } } nSize = lstrlen(szFontFile); if (!MLStrCmpNI(&szFontFile[nSize-3], "fot", 3)) MLStrCpyN(&szFontFile[nSize-3], "ttf", 3); // // Trim off path // // #335900, some third party apps write font file names to registry directly // and the names they used could have redundant font path // pFontFile = szFontFile; while (nSize) { // Font file name contains only ASCII characters, // So, we can safely trim the path by backward searching '\' if (szFontFile[nSize] == TEXT('\\')) { pFontFile = &szFontFile[nSize]; pFontFile++; break; } nSize--; } GetFontURangeBits(szFontFile, &(g_pfont_table[count-1].dwUniSubRanges[0])); MLStrCpyN(g_pfont_table[count-1].szFaceName, &szFaceName[dwOffset], LF_FACESIZE); MLStrCpyN(g_pfont_table[count-1].szFileName, pFontFile, LF_FACESIZE); } if (pNewFaceName && (*pNewFaceName)) { dwOffset = (DWORD)(pNewFaceName - &szFaceName[0]); goto FIND_NEXT_FACENAME; } } #else // For UNIX, we don't have registry font information, // Let's create font table through EnumFontFamiliesEx. Table_info table_info; table_info.count = 1; table_info.table_size = table_size; int iRet; LOGFONT lf; lf.lfCharSet = DEFAULT_CHARSET; // give me all fonts lf.lfFaceName[0] = _T('\0'); lf.lfPitchAndFamily = 0; hWnd = GetTopWindow(GetDesktopWindow()); hDC = GetDC(hWnd); iRet = EnumFontFamiliesEx(hDC, // Enum all fonts &lf, (FONTENUMPROC)UnixGetAllFontsProc, (LPARAM)&table_info, 0); count = table_info.count; if (iRet == 0) // abort { bRet = FALSE; goto SETFONT_DONE; } #endif // UNIX // Release un-used memory g_pfont_table = (FONTINFO *)LocalReAlloc(g_pfont_table, (count)*sizeof(FONTINFO), LMEM_MOVEABLE); // Save TrueType font number g_pfont_table[0].dwCodePages[0] = count-1; #ifndef UNIX // Unix doesn't have this number. // Save total font number for font change verification g_pfont_table[0].dwCodePages[1] = dwFonts; RegCloseKey(hkey); #endif if (count > 1) SetFontScripts(); SETFONT_DONE: if (hDC) ReleaseDC(hWnd, hDC); if (count <= 1) { if (g_pfont_table) { LocalFree(g_pfont_table); g_pfont_table = NULL; } bRet = FALSE; } return bRet; } HRESULT CMLFLink2::CFontMappingCache2::SaveFontDataFile(void) { FONTDATAHEADER fileHeader; HRESULT hr = E_FAIL; int *pTmpBuf = NULL; HANDLE hFile = NULL; int i, j, Count = 0; DWORD dwSize; FONTDATATABLE fontInfoTable, fontIndexTable; hFile = CreateFile( szFontDataFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); if (hFile == INVALID_HANDLE_VALUE) { goto SAVE_FONT_DATA_DONE; } for (i = 0; i < ARRAYSIZE(g_urange_table); i++) { Count += (g_urange_table[i].nFonts+1); } // Create file header lstrcpyA(fileHeader.FileSig, FONT_DATA_SIGNATURE); fileHeader.dwVersion = 0x00010000; // Use file size as CheckSum fileHeader.dwCheckSum = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1)+Count*sizeof(int)+ + sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM; fileHeader.nTable = FONTDATATABLENUM; pTmpBuf = (int *)LocalAlloc(LPTR, Count*sizeof(int)); if (!pTmpBuf) goto SAVE_FONT_DATA_DONE; // Get font index data for (i = 0; i < ARRAYSIZE(g_urange_table); i++) { *pTmpBuf++ = g_urange_table[i].nFonts; if (g_urange_table[i].nFonts) { for (j = 0; j< g_urange_table[i].nFonts; j++) { *pTmpBuf++ = *(g_urange_table[i].pFontIndex+j); } } } pTmpBuf -= Count; // Create Dir tables lstrcpyA(fontInfoTable.szName, "fnt"); fontInfoTable.dwOffset = sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM; fontInfoTable.dwSize = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1); lstrcpyA(fontIndexTable.szName, "idx"); fontIndexTable.dwOffset = fontInfoTable.dwSize+fontInfoTable.dwOffset; fontIndexTable.dwSize = Count*sizeof(int); if (WriteFile(hFile, &fileHeader, sizeof(FONTDATAHEADER), &dwSize, NULL) && WriteFile(hFile, &fontInfoTable, sizeof(FONTDATATABLE), &dwSize, NULL) && WriteFile(hFile, &fontIndexTable, sizeof(FONTDATATABLE), &dwSize, NULL) && WriteFile(hFile, g_pfont_table, fontInfoTable.dwSize, &dwSize, NULL) && WriteFile(hFile, pTmpBuf, fontIndexTable.dwSize, &dwSize, NULL)) { hr = S_OK; } SAVE_FONT_DATA_DONE: if (hFile) CloseHandle(hFile); if (pTmpBuf) LocalFree(pTmpBuf); return hr; } HRESULT CMLFLink2::CFontMappingCache2::LoadFontDataFile(void) { HANDLE hFontData = NULL; HANDLE hFileMap = NULL; LPVOID lpvFile = NULL; int * lp; HRESULT hr = E_FAIL; DWORD dwFileSize; int i, j; HKEY hKey = NULL; DWORD nFonts; FONTDATAHEADER *pHeader; FONTDATATABLE *pfTable; hFontData = CreateFile(szFontDataFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFontData == INVALID_HANDLE_VALUE) return EnsureFontTable(TRUE); dwFileSize = GetFileSize(hFontData, NULL); hFileMap = CreateFileMapping( hFontData, NULL, PAGE_READONLY, 0, dwFileSize, NULL ); if(hFileMap == NULL) { goto Load_File_Done; } lpvFile = MapViewOfFile( hFileMap, FILE_MAP_READ, 0, 0, 0 ); if (lpvFile == NULL) { goto Load_File_Done; } pHeader = (FONTDATAHEADER *)lpvFile; // Check mlang font cache file by signature and checksum if (lstrcmpA(pHeader->FileSig, FONT_DATA_SIGNATURE) || pHeader->dwCheckSum != dwFileSize) { goto Load_File_Done; } if (S_OK != GetRegFontKey(&hKey, &nFonts)) { goto Load_File_Done; } pfTable = (FONTDATATABLE *) ((LPBYTE)lpvFile + sizeof(FONTDATAHEADER)); // Check if there is any font change (no guarantee, but works in most cases) if (nFonts != ((FONTINFO*)((LPBYTE)lpvFile + pfTable[0].dwOffset))->dwCodePages[1]) { // If there is a change in system font number, we reload everything UnmapViewOfFile(lpvFile); CloseHandle(hFileMap); CloseHandle(hFontData); RegCloseKey(hKey); return EnsureFontTable(TRUE); } EnterCriticalSection(&g_cs); // Reset cache information if (g_pfont_table) { LocalFree(g_pfont_table); g_pfont_table = NULL; for (i = 0; i < ARRAYSIZE(g_urange_table); i++) { if (g_urange_table[i].nFonts) { LocalFree(g_urange_table[i].pFontIndex); g_urange_table[i].pFontIndex = NULL; g_urange_table[i].nFonts = 0; } } } if(!(g_pfont_table = (FONTINFO *) (LocalAlloc(LPTR, pfTable[0].dwSize)))) { hr = E_OUTOFMEMORY; goto Load_File_Done; } CopyMemory(g_pfont_table, (LPBYTE)lpvFile + pfTable[0].dwOffset, pfTable[0].dwSize); lp = (int *)((LPBYTE)lpvFile + pfTable[1].dwOffset); for (i = 0; i < ARRAYSIZE(g_urange_table); i++) { if (g_urange_table[i].nFonts = *lp++) { //g_urange_table[i].nFonts = *lp++; g_urange_table[i].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)*g_urange_table[i].nFonts); for (j = 0; j< g_urange_table[i].nFonts; j++) { g_urange_table[i].pFontIndex[j] = *lp++; } } } LeaveCriticalSection(&g_cs); hr = S_OK; Load_File_Done: if (lpvFile) UnmapViewOfFile(lpvFile); if (hFileMap) CloseHandle(hFileMap); if (hFontData) CloseHandle(hFontData); if (hKey) RegCloseKey(hKey); return hr; } HRESULT CMLFLink2::CFontMappingCache2::SetFontUnicodeRanges(void) { TCHAR szFontPath[MAX_PATH]; TCHAR szFont[MAX_PATH]; HRESULT hr = S_OK; int i; EnterCriticalSection(&g_cs); g_pfont_table[0].szFaceName[0] = 1; LeaveCriticalSection(&g_cs); MLGetWindowsDirectory(szFontPath, MAX_PATH); MLPathCombine(szFontPath, szFontPath, FONT_FOLDER); for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++) { MLPathCombine(szFont, szFontPath, g_pfont_table[i].szFileName); GetNonCpFontUnicodeRanges(szFont, i); } // Release un-used memory for (i=0; i< ARRAYSIZE(g_urange_table); i++) { if (g_urange_table[i].nFonts) g_urange_table[i].pFontIndex = (int *)LocalReAlloc(g_urange_table[i].pFontIndex, g_urange_table[i].nFonts*sizeof(int), LMEM_MOVEABLE); } return hr; } STDMETHODIMP CMLFLink2::GetStrCodePages(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages) { ASSERT_THIS; ASSERT_READ_BLOCK(pszSrc, cchSrc); ASSERT_WRITE_PTR_OR_NULL(pdwCodePages); ASSERT_WRITE_PTR_OR_NULL(pcchCodePages); HRESULT hr = S_OK; long cchCodePages = 0; DWORD dwStrCodePages = (DWORD)~0; BOOL fInit = FALSE; BOOL fNoPri = FALSE; if (!pszSrc || cchSrc <= 0) // We can't make dwStrCodePages when cchSrc is zero hr = E_INVALIDARG; if (!m_pIMLFLnk) return E_OUTOFMEMORY; while (SUCCEEDED(hr) && cchSrc > 0) { DWORD dwCharCodePages; if (SUCCEEDED(hr = m_pIMLFLnk->GetCharCodePages(*pszSrc, &dwCharCodePages))) { if (!fInit) { fInit = TRUE; fNoPri = !(dwPriorityCodePages & dwCharCodePages); } else if (fNoPri != !(dwPriorityCodePages & dwCharCodePages)) { break; } if (!fNoPri) dwPriorityCodePages &= dwCharCodePages; if (dwCharCodePages && (dwCharCodePages & dwStrCodePages)) dwStrCodePages &= dwCharCodePages; else break; pszSrc++; cchSrc--; cchCodePages++; } } if (SUCCEEDED(hr)) { if (!cchCodePages) { dwStrCodePages = 0; cchCodePages++; } if (pcchCodePages) *pcchCodePages = cchCodePages; if (pdwCodePages) *pdwCodePages = dwStrCodePages; } else { if (pcchCodePages) *pcchCodePages = 0; if (pdwCodePages) *pdwCodePages = 0; } return hr; } STDMETHODIMP CMLFLink2::MapFont(HDC hDC, DWORD dwCodePages, WCHAR wchar, HFONT* phDestFont) { HFONT hSrcFont = NULL; if (NULL == (hSrcFont = (HFONT) GetCurrentObject(hDC, OBJ_FONT))) return E_FAIL; if (dwCodePages) { if (m_pIMLFLnk) return m_pIMLFLnk->MapFont(hDC, dwCodePages, hSrcFont, phDestFont); return E_OUTOFMEMORY; } else { if (!m_pFontMappingCache2) m_pFontMappingCache2 = new CFontMappingCache2; if (m_pFontMappingCache2) return m_pFontMappingCache2->MapFontFromCMAP(hDC, wchar, hSrcFont, phDestFont); else return E_OUTOFMEMORY; } } STDMETHODIMP CMLFLink2::GetFontUnicodeRanges(HDC hDC, UINT *puiRanges, UNICODERANGE* pURanges) { int i; LOGFONT lf; HRESULT hr = E_FAIL; HFONT hFont = NULL; if (!puiRanges) return E_INVALIDARG; if (!m_pFontMappingCache2) m_pFontMappingCache2 = new CFontMappingCache2; if (!m_pFontMappingCache2) return E_OUTOFMEMORY; if (!(hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT))) return hr; if (FAILED(m_pFontMappingCache2->EnsureFontTable(FALSE))) return hr; if (!GetObject(hFont, sizeof(LOGFONT), &lf)) return hr; for (i=1; i<= (int) g_pfont_table[0].dwCodePages[0]; i++) { if (!lstrcmp(lf.lfFaceName, g_pfont_table[i].szFaceName)) break; } if (i > (int) g_pfont_table[0].dwCodePages[0]) return hr; return m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, puiRanges, pURanges); } STDMETHODIMP CMLFLink2::GetScriptFontInfo(SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts, SCRIPTFONTINFO* pScriptFont) { HRESULT hr = E_FAIL; UINT uiNum; BYTE bPitch = dwFlags & SCRIPTCONTF_FIXED_FONT? FIXED_PITCH:VARIABLE_PITCH; if (!m_pFontMappingCache2) m_pFontMappingCache2 = new CFontMappingCache2; if (m_pFontMappingCache2) m_pFontMappingCache2->EnsureFontTable(FALSE); if (!g_pfont_table) return hr; if (!pScriptFont) { uiNum = g_pfont_table[0].dwCodePages[0]; } else { uiNum = *puiFonts; } *puiFonts = 0; // Binary search font table to match script id. for (UINT i=1; i<= g_pfont_table[0].dwCodePages[0]; i++) { // Check font pitch if (!(g_pfont_table[i].lf.lfPitchAndFamily & bPitch)) continue; // Get sid bit mask SCRIPT_IDS sids = 1; sids <<= sid; if (sids & g_pfont_table[i].scripts) { // Bail out is required number reached if (*puiFonts >= uiNum) { break; } if (pScriptFont) { MultiByteToWideChar(CP_ACP, 0, g_pfont_table[i].szFaceName, -1, (pScriptFont + *puiFonts)->wszFont, MAX_MIMEFACE_NAME); (pScriptFont + *puiFonts)->scripts = g_pfont_table[i].scripts; } (*puiFonts)++; } } return S_OK; } // Map Windows code page to script id // if multiple script id exist, we'll return the default one STDMETHODIMP CMLFLink2::CodePageToScriptID(UINT uiCodePage, SCRIPT_ID *pSid) { MIMECPINFO cpInfo; HRESULT hr = E_FAIL; if (!pSid) return E_INVALIDARG; if (NULL != g_pMimeDatabase) { if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo))) { if (cpInfo.uiFamilyCodePage == CP_USER_DEFINED) { *pSid = sidUserDefined; hr = S_OK; } else for (int i = 0; g_CharSetTransTable[i].uCodePage; i++) { if (cpInfo.uiFamilyCodePage == g_CharSetTransTable[i].uCodePage) { *pSid = g_CharSetTransTable[i].sid[0]; hr = S_OK; break; } } } } return hr; } CMLFLink2::CFontMappingCache2::CFontMappingCache2(void) { GetSystemDirectory(szFontDataFilePath, MAX_PATH); MLPathCombine(szFontDataFilePath, szFontDataFilePath, FONT_DATA_FILE_NAME); } CMLFLink2::CFontMappingCache2::~CFontMappingCache2(void) { EnterCriticalSection(&g_cs); if (g_pfont_table) { LocalFree(g_pfont_table); g_pfont_table = NULL; } for (int i=0; i< ARRAYSIZE(g_urange_table); i++) { if (g_urange_table[i].nFonts) { LocalFree(g_urange_table[i].pFontIndex); g_urange_table[i].nFonts = 0; } } LeaveCriticalSection(&g_cs); } int CALLBACK CMLFLink2::CFontMappingCache2::MapFontExEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam) { if (FontType == TRUETYPE_FONTTYPE && plfFont->lfFaceName[0] != TEXT('@') ) { CopyMemory(&g_pfont_table[*(int *)lParam].lf, plfFont, sizeof(LOGFONT)); (*(int *)lParam)++; return 0; } return 1; } int CALLBACK CMLFLink2::CFontMappingCache2::SetFontScriptsEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam) { if (FontType == TRUETYPE_FONTTYPE) { if (g_pfont_table) { for (int i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++) if (!MLStrCmpNI(plfFont->lfFaceName, g_pfont_table[i].szFaceName, LF_FACESIZE)) { SCRIPT_IDS scripts = 1; scripts <<= lParam; g_pfont_table[i].scripts |= scripts; break; } if (i > (int)g_pfont_table[0].dwCodePages[0] && plfFont->lfFaceName[0] != TEXT('@')) // GDI font not in current font table? { FONTINFO * pfont_table = NULL; pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, sizeof(FONTINFO) * (g_pfont_table[0].dwCodePages[0]+2), LMEM_MOVEABLE | LMEM_ZEROINIT); if (NULL != pfont_table) { g_pfont_table = pfont_table; g_pfont_table[0].dwCodePages[0]++; MLStrCpyN(g_pfont_table[i].szFaceName, (char *)plfFont->lfFaceName, LF_FACESIZE); CopyMemory(&g_pfont_table[i].lf, plfFont, sizeof(LOGFONT)); SCRIPT_IDS scripts = 1; scripts <<= lParam; g_pfont_table[i].scripts |= scripts; } } } } return 1; } int CALLBACK CMLFLink::VerifyFontSizeEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC* ptm, DWORD FontType, LPARAM lParam) { LOGFONT* plfSrcFont = (LOGFONT*)lParam; if (FontType != TRUETYPE_FONTTYPE) { LONG lHeight = ptm->tmInternalLeading - ptm->tmHeight; // Match source font's lfHeight to physical bitmap font's lfHeight if (lHeight < 0 && plfSrcFont->lfHeight < 0 && lHeight < plfSrcFont->lfHeight) { plfSrcFont->lfHeight = lHeight ; } } return 0; }