|
|
// 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<m_uiFLinkFontNum; i++) if (m_pFlinkTable[i].pmszFaceName) LocalFree(m_pFlinkTable[i].pmszFaceName); LocalFree(m_pFlinkTable); m_pFlinkTable = NULL; m_uiFLinkFontNum = 0; } }
#define MAX_FONTLINK_BUFFER_SIZE 1024
HRESULT CMLFLink::CreateNT5FontLinkTable(void) { HKEY hKey = NULL; HKEY hKeyFont = NULL; ULONG ulFonts = 0; ULONG ulFLinkFonts = 0; DWORD dwIndex = 0; WCHAR szFaceName[MAX_PATH]; LPWSTR pNewFaceName = NULL; DWORD dwOffset = 0; DWORD dwOffset2 = 0; DWORD dwValue; DWORD dwData; WCHAR szFontFile[LF_FACESIZE]; DWORD dwType; WCHAR szFlinkFont[MAX_FONTLINK_BUFFER_SIZE];
// Internal temperate data
struct tagFontTable { WCHAR szFontFile[LF_FACESIZE]; WCHAR szFaceName[LF_FACESIZE]; }* tmpFontTable = NULL;
HRESULT hr;
// Open system font and fontlink key
if ((ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_FONTLINK, 0, KEY_READ, &hKey)) || (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEYNT, 0, KEY_READ, &hKeyFont))) { hr = E_FAIL; goto TABLE_DONE; }
// Get number of items
if ((ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, NULL, 0, NULL, NULL, NULL, &ulFLinkFonts, NULL, NULL, NULL, NULL) || 0 == ulFLinkFonts) || (ERROR_SUCCESS != RegQueryInfoKey(hKeyFont, NULL, NULL, 0, NULL, NULL, NULL, &ulFonts, NULL, NULL, NULL, NULL) || 0 == ulFonts)) { hr = E_FAIL; goto TABLE_DONE; }
tmpFontTable = (struct tagFontTable *)LocalAlloc(LPTR, sizeof(struct tagFontTable)*ulFonts);
if (NULL == tmpFontTable) { hr = E_OUTOFMEMORY; goto TABLE_DONE; }
dwValue = dwData = LF_FACESIZE; dwType = REG_SZ; dwIndex = 0; ulFonts = 0;
while (ERROR_NO_MORE_ITEMS != RegEnumValueW( hKeyFont, dwIndex++, szFaceName, &dwValue, NULL, &dwType, (LPBYTE)szFontFile, &dwData )) { // TTF fonts only, TTC fonts already have face name under fontlink
if (pNewFaceName = wcsstr(szFaceName, L" & ")) break; pNewFaceName = wcsstr(szFaceName, L" (TrueType)"); if(pNewFaceName) { *pNewFaceName = 0; MLStrCpyNW(tmpFontTable[ulFonts].szFaceName, szFaceName, LF_FACESIZE); MLStrCpyNW(tmpFontTable[ulFonts++].szFontFile, szFontFile, LF_FACESIZE); }
dwValue = dwData = LF_FACESIZE; dwType = REG_SZ; }
m_pFlinkTable = (PFLINKFONT) LocalAlloc(LPTR, sizeof(FLINKFONT)*ulFLinkFonts); if (NULL == m_pFlinkTable) { hr = E_OUTOFMEMORY; goto TABLE_DONE; }
dwValue = LF_FACESIZE; dwData = MAX_FONTLINK_BUFFER_SIZE; dwType = REG_MULTI_SZ;
dwIndex = 0;
while (ERROR_NO_MORE_ITEMS != RegEnumValueW( hKey, dwIndex, m_pFlinkTable[dwIndex].szFaceName, &dwValue, NULL, &dwType, (LPBYTE)szFlinkFont, &dwData )) { m_pFlinkTable[dwIndex].pmszFaceName = (LPWSTR) LocalAlloc(LPTR, MAX_FONTLINK_BUFFER_SIZE); if (!m_pFlinkTable[dwIndex].pmszFaceName) { hr = E_OUTOFMEMORY; goto TABLE_DONE; } while (TRUE) { pNewFaceName = wcsstr(&szFlinkFont[dwOffset], L","); if (pNewFaceName) // TTC font, get face name from registry
{ MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), ++pNewFaceName, LF_FACESIZE); dwOffset2 += lstrlenW(pNewFaceName)+1; } else // TTF font, search font table for face name
{ if (szFlinkFont[dwOffset]) for (UINT i=0; i<ulFonts; i++) { if (!MLStrCmpNIW(&szFlinkFont[dwOffset], tmpFontTable[i].szFontFile, LF_FACESIZE)) { MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), tmpFontTable[i].szFaceName, LF_FACESIZE); dwOffset2 += lstrlenW(tmpFontTable[i].szFaceName)+1; break; } } else // End of multiple string, break out
break; }
dwOffset += lstrlenW(&szFlinkFont[dwOffset])+1;
// Prevent infinitive loop, shouldn't happen
if (dwOffset >= 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; i<m_uiFLinkFontNum;i++) { if (!MLStrCmpNIW(plfEnum->lfFaceName, 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++) { if (!MLStrCmpI(szFaceName,g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName)) break; }
// Current font doesn't support this character
if (i == g_urange_table[k].nFonts) { for (i=0; i<g_urange_table[k].nFonts; i++) { if (LogFont.lfCharSet == g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfCharSet) break; }
// No font available for current CharSet, then return the first one in the list
if (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; i<g_urange_table[iURange].nFonts; i++) { for (j=0;(j<32) && g_CharSetTransTable[j].uCodePage;j++) { if (g_pfont_table[*(g_urange_table[iURange].pFontIndex+i)].dwCodePages[0] & g_CharSetTransTable[j].dwCodePages) if (*pCharset == g_CharSetTransTable[j].nCharSet) return i; } }
//If invalid, fetch first valid one.
for (i=0;(i<32) && g_CharSetTransTable[i].uCodePage;i++) { if (g_pfont_table[*(g_urange_table[iURange].pFontIndex)].dwCodePages[0] & g_CharSetTransTable[i].dwCodePages) { *pCharset = (BYTE)g_CharSetTransTable[i].nCharSet; break; } }
return 0; }
BOOL CMLFLink2::CFontMappingCache2::GetNonCpFontUnicodeRanges(TCHAR *szFontName, int iFontIndex) { LONG nURange = 0; DWORD cmap = 0; DWORD name = 0; DWORD os2 = 0;
HANDLE hTTFMap; DWORD dwFileSize; LPVOID lpvFile; LPBYTE lp, lp1, lp2; DWORD Num; int i, j, k, m; WORD Len; HANDLE hTTF; BOOL bRet = FALSE;
hTTF = CreateFile( szFontName, // 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 (hTTF == INVALID_HANDLE_VALUE) return FALSE;
dwFileSize = GetFileSize(hTTF, NULL);
hTTFMap = CreateFileMapping( hTTF, NULL, PAGE_READONLY, 0, dwFileSize, NULL );
if(hTTFMap == NULL) { goto CloseHandle01; }
lpvFile = MapViewOfFile( hTTFMap, FILE_MAP_READ, 0, 0, 0 );
if(lpvFile == NULL) { goto CloseHandle00; }
lp = (LPBYTE)lpvFile;
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
{ // 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; }
|