windows-nt/Source/XPSP1/NT/shell/ext/mlang/mlflink.cpp
2020-09-26 16:20:57 +08:00

3875 lines
111 KiB
C++

// 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;
}