mlflink.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 106k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. // MLFLink.cpp : Implementation of CMLFLink
  2. #include "private.h"
  3. #include "mlmain.h"
  4. #include "codepage.h"
  5. #ifdef UNIX
  6. inline WORD READWINTELWORD(WORD w)
  7. {
  8.   return ( w << 8 | w >> 8 );
  9. }
  10. inline DWORD READWINTELDWORD(DWORD dw)
  11. {
  12.   return READWINTELWORD( (WORD)(dw >> 16 )) | ((DWORD)READWINTELWORD( dw & 0xffff)) << 16;
  13. }
  14. #else
  15. #define READWINTELWORD
  16. #define READWINTELDWORD
  17. #endif
  18. IMLangFontLink *g_pMLFLink = NULL;
  19. CMLFLink::CCodePagesCache* CMLFLink::m_pCodePagesCache = NULL;
  20. CMLFLink::CFontMappingCache* CMLFLink::m_pFontMappingCache = NULL;
  21. CMLFLink2::CFontMappingCache2* CMLFLink2::m_pFontMappingCache2 = NULL;
  22. // Strings to identify regular font
  23. const char szRegular[]    = "Regular";
  24. const char szNormal[]     = "Normal";
  25. // font table
  26. FONTINFO *g_pfont_table = NULL;
  27. // Unicode range table for non Windows code page code points
  28. // Data is provided by NT international group.
  29. URANGEFONT g_urange_table[] = {
  30. {0x0108, 0x010B, 0},
  31. {0x0114, 0x0115, 0},
  32. {0x011C, 0x011D, 0},
  33. {0x0120, 0x0121, 0},
  34. {0x0124, 0x0125, 0},
  35. {0x0128, 0x0129, 0},
  36. {0x012C, 0x012D, 0},
  37. {0x0134, 0x0135, 0},
  38. {0x014E, 0x014F, 0},
  39. {0x015C, 0x015D, 0},
  40. {0x0168, 0x0169, 0},
  41. {0x016C, 0x016D, 0},
  42. {0x0174, 0x0177, 0},
  43. {0x017F, 0x0191, 0},
  44. {0x0193, 0x019F, 0},
  45. {0x01A2, 0x01AE, 0},
  46. {0x01B1, 0x01CD, 0},
  47. {0x01CF, 0x01CF, 0},
  48. {0x01D1, 0x01D1, 0},
  49. {0x01D3, 0x01D3, 0},
  50. {0x01D5, 0x01D5, 0},
  51. {0x01D7, 0x01D7, 0},
  52. {0x01D9, 0x01D9, 0},
  53. {0x01DB, 0x01DB, 0},
  54. {0x01DD, 0x01F5, 0},
  55. {0x01FA, 0x0217, 0},
  56. {0x0250, 0x0250, 0},
  57. {0x0252, 0x0260, 0},
  58. {0x0262, 0x02A8, 0},
  59. {0x02B0, 0x02C5, 0},
  60. {0x02C8, 0x02C8, 0},
  61. {0x02CC, 0x02CC, 0},
  62. {0x02CE, 0x02CF, 0},
  63. {0x02D1, 0x02D7, 0},
  64. {0x02DE, 0x02DE, 0},
  65. {0x02E0, 0x02E9, 0},
  66. {0x0302, 0x0302, 0},
  67. {0x0304, 0x0308, 0},
  68. {0x030A, 0x0322, 0},
  69. {0x0324, 0x0345, 0},
  70. {0x0360, 0x0361, 0},
  71. {0x0374, 0x0375, 0},
  72. {0x037A, 0x037A, 0},
  73. {0x037E, 0x037E, 0},
  74. {0x0387, 0x0387, 0},
  75. {0x03D0, 0x03D6, 0},
  76. {0x03DA, 0x03DA, 0},
  77. {0x03DC, 0x03DC, 0},
  78. {0x03DE, 0x03DE, 0},
  79. {0x03E0, 0x03E0, 0},
  80. {0x03E2, 0x03F3, 0},
  81. {0x0460, 0x0486, 0},
  82. {0x0492, 0x04C4, 0},
  83. {0x04C7, 0x04C8, 0},
  84. {0x04CB, 0x04CC, 0},
  85. {0x04D0, 0x04EB, 0},
  86. {0x04EE, 0x04F5, 0},
  87. {0x04F8, 0x04F9, 0},
  88. {0x0531, 0x0556, 0},
  89. {0x0559, 0x055F, 0},
  90. {0x0561, 0x0587, 0},
  91. {0x0589, 0x0589, 0},
  92. {0x0591, 0x05A1, 0},
  93. {0x05A3, 0x05AF, 0},
  94. {0x05C4, 0x05C4, 0},
  95. {0x0660, 0x066D, 0},
  96. {0x0670, 0x067D, 0},
  97. {0x067F, 0x0685, 0},
  98. {0x0687, 0x0697, 0},
  99. {0x0699, 0x06AE, 0},
  100. {0x06B0, 0x06B7, 0},
  101. {0x06BA, 0x06BE, 0},
  102. {0x06C0, 0x06CE, 0},
  103. {0x06D0, 0x06ED, 0},
  104. {0x06F0, 0x06F9, 0},
  105. {0x0901, 0x0903, 0},
  106. {0x0905, 0x0939, 0},
  107. {0x093C, 0x094D, 0},
  108. {0x0950, 0x0954, 0},
  109. {0x0958, 0x0970, 0},
  110. {0x0981, 0x0983, 0},
  111. {0x0985, 0x098C, 0},
  112. {0x098F, 0x0990, 0},
  113. {0x0993, 0x09A8, 0},
  114. {0x09AA, 0x09B0, 0},
  115. {0x09B2, 0x09B2, 0},
  116. {0x09B6, 0x09B9, 0},
  117. {0x09BC, 0x09BC, 0},
  118. {0x09BE, 0x09C4, 0},
  119. {0x09C7, 0x09C8, 0},
  120. {0x09CB, 0x09CD, 0},
  121. {0x09D7, 0x09D7, 0},
  122. {0x09DC, 0x09DD, 0},
  123. {0x09DF, 0x09E3, 0},
  124. {0x09E6, 0x09FA, 0},
  125. {0x0A02, 0x0A02, 0},
  126. {0x0A05, 0x0A0A, 0},
  127. {0x0A0F, 0x0A10, 0},
  128. {0x0A13, 0x0A28, 0},
  129. {0x0A2A, 0x0A30, 0},
  130. {0x0A32, 0x0A33, 0},
  131. {0x0A35, 0x0A36, 0},
  132. {0x0A38, 0x0A39, 0},
  133. {0x0A3C, 0x0A3C, 0},
  134. {0x0A3E, 0x0A42, 0},
  135. {0x0A47, 0x0A48, 0},
  136. {0x0A4B, 0x0A4D, 0},
  137. {0x0A59, 0x0A5C, 0},
  138. {0x0A5E, 0x0A5E, 0},
  139. {0x0A66, 0x0A74, 0},
  140. {0x0A81, 0x0A83, 0},
  141. {0x0A85, 0x0A8B, 0},
  142. {0x0A8D, 0x0A8D, 0},
  143. {0x0A8F, 0x0A91, 0},
  144. {0x0A93, 0x0AA8, 0},
  145. {0x0AAA, 0x0AB0, 0},
  146. {0x0AB2, 0x0AB3, 0},
  147. {0x0AB5, 0x0AB9, 0},
  148. {0x0ABC, 0x0AC5, 0},
  149. {0x0AC7, 0x0AC9, 0},
  150. {0x0ACB, 0x0ACD, 0},
  151. {0x0AD0, 0x0AD0, 0},
  152. {0x0AE0, 0x0AE0, 0},
  153. {0x0AE6, 0x0AEF, 0},
  154. {0x0B01, 0x0B03, 0},
  155. {0x0B05, 0x0B0C, 0},
  156. {0x0B0F, 0x0B10, 0},
  157. {0x0B13, 0x0B28, 0},
  158. {0x0B2A, 0x0B30, 0},
  159. {0x0B32, 0x0B33, 0},
  160. {0x0B36, 0x0B39, 0},
  161. {0x0B3C, 0x0B43, 0},
  162. {0x0B47, 0x0B48, 0},
  163. {0x0B4B, 0x0B4D, 0},
  164. {0x0B56, 0x0B57, 0},
  165. {0x0B5C, 0x0B5D, 0},
  166. {0x0B5F, 0x0B61, 0},
  167. {0x0B66, 0x0B70, 0},
  168. {0x0B82, 0x0B83, 0},
  169. {0x0B85, 0x0B8A, 0},
  170. {0x0B8E, 0x0B90, 0},
  171. {0x0B92, 0x0B95, 0},
  172. {0x0B99, 0x0B9A, 0},
  173. {0x0B9C, 0x0B9C, 0},
  174. {0x0B9E, 0x0B9F, 0},
  175. {0x0BA3, 0x0BA4, 0},
  176. {0x0BA8, 0x0BAA, 0},
  177. {0x0BAE, 0x0BB5, 0},
  178. {0x0BB7, 0x0BB9, 0},
  179. {0x0BBE, 0x0BC2, 0},
  180. {0x0BC6, 0x0BC8, 0},
  181. {0x0BCA, 0x0BCD, 0},
  182. {0x0BD7, 0x0BD7, 0},
  183. {0x0BE7, 0x0BF2, 0},
  184. {0x0C01, 0x0C03, 0},
  185. {0x0C05, 0x0C0C, 0},
  186. {0x0C0E, 0x0C10, 0},
  187. {0x0C12, 0x0C28, 0},
  188. {0x0C2A, 0x0C33, 0},
  189. {0x0C35, 0x0C39, 0},
  190. {0x0C3E, 0x0C44, 0},
  191. {0x0C46, 0x0C48, 0},
  192. {0x0C4A, 0x0C4D, 0},
  193. {0x0C55, 0x0C56, 0},
  194. {0x0C60, 0x0C61, 0},
  195. {0x0C66, 0x0C6F, 0},
  196. {0x0C82, 0x0C83, 0},
  197. {0x0C85, 0x0C8C, 0},
  198. {0x0C8E, 0x0C90, 0},
  199. {0x0C92, 0x0CA8, 0},
  200. {0x0CAA, 0x0CB3, 0},
  201. {0x0CB5, 0x0CB9, 0},
  202. {0x0CBE, 0x0CC4, 0},
  203. {0x0CC6, 0x0CC8, 0},
  204. {0x0CCA, 0x0CCD, 0},
  205. {0x0CD5, 0x0CD6, 0},
  206. {0x0CDE, 0x0CDE, 0},
  207. {0x0CE0, 0x0CE1, 0},
  208. {0x0CE6, 0x0CEF, 0},
  209. {0x0D02, 0x0D03, 0},
  210. {0x0D05, 0x0D0C, 0},
  211. {0x0D0E, 0x0D10, 0},
  212. {0x0D12, 0x0D28, 0},
  213. {0x0D2A, 0x0D39, 0},
  214. {0x0D3E, 0x0D43, 0},
  215. {0x0D46, 0x0D48, 0},
  216. {0x0D4A, 0x0D4D, 0},
  217. {0x0D57, 0x0D57, 0},
  218. {0x0D60, 0x0D61, 0},
  219. {0x0D66, 0x0D6F, 0},
  220. {0x0E81, 0x0E82, 0},
  221. {0x0E84, 0x0E84, 0},
  222. {0x0E87, 0x0E88, 0},
  223. {0x0E8A, 0x0E8A, 0},
  224. {0x0E8D, 0x0E8D, 0},
  225. {0x0E94, 0x0E97, 0},
  226. {0x0E99, 0x0E9F, 0},
  227. {0x0EA1, 0x0EA3, 0},
  228. {0x0EA5, 0x0EA5, 0},
  229. {0x0EA7, 0x0EA7, 0},
  230. {0x0EAA, 0x0EAB, 0},
  231. {0x0EAD, 0x0EB9, 0},
  232. {0x0EBB, 0x0EBD, 0},
  233. {0x0EC0, 0x0EC4, 0},
  234. {0x0EC6, 0x0EC6, 0},
  235. {0x0EC8, 0x0ECD, 0},
  236. {0x0ED0, 0x0ED9, 0},
  237. {0x0EDC, 0x0EDD, 0},
  238. {0x0F00, 0x0F47, 0},
  239. {0x0F49, 0x0F69, 0},
  240. {0x0F71, 0x0F8B, 0},
  241. {0x0F90, 0x0F95, 0},
  242. {0x0F97, 0x0F97, 0},
  243. {0x0F99, 0x0FAD, 0},
  244. {0x0FB1, 0x0FB7, 0},
  245. {0x0FB9, 0x0FB9, 0},
  246. {0x10A0, 0x10C5, 0},
  247. {0x10D0, 0x10F6, 0},
  248. {0x10FB, 0x10FB, 0},
  249. {0x1100, 0x1159, 0},
  250. {0x115F, 0x11A2, 0},
  251. {0x11A8, 0x11F9, 0},
  252. {0x1E00, 0x1E9B, 0},
  253. {0x1EA0, 0x1EF9, 0},
  254. {0x1F00, 0x1F15, 0},
  255. {0x1F18, 0x1F1D, 0},
  256. {0x1F20, 0x1F45, 0},
  257. {0x1F48, 0x1F4D, 0},
  258. {0x1F50, 0x1F57, 0},
  259. {0x1F59, 0x1F59, 0},
  260. {0x1F5B, 0x1F5B, 0},
  261. {0x1F5D, 0x1F5D, 0},
  262. {0x1F5F, 0x1F7D, 0},
  263. {0x1F80, 0x1FB4, 0},
  264. {0x1FB6, 0x1FC4, 0},
  265. {0x1FC6, 0x1FD3, 0},
  266. {0x1FD6, 0x1FDB, 0},
  267. {0x1FDD, 0x1FEF, 0},
  268. {0x1FF2, 0x1FF4, 0},
  269. {0x1FF6, 0x1FFE, 0},
  270. {0x2000, 0x200B, 0},
  271. {0x2011, 0x2012, 0},
  272. {0x2017, 0x2017, 0},
  273. {0x201B, 0x201B, 0},
  274. {0x201F, 0x201F, 0},
  275. {0x2023, 0x2024, 0},
  276. {0x2028, 0x202E, 0},
  277. {0x2031, 0x2031, 0},
  278. {0x2034, 0x2034, 0},
  279. {0x2036, 0x2038, 0},
  280. {0x203C, 0x2046, 0},
  281. {0x206A, 0x2070, 0},
  282. {0x2075, 0x207E, 0},
  283. {0x2080, 0x2080, 0},
  284. {0x2085, 0x208E, 0},
  285. {0x20A0, 0x20A9, 0},
  286. {0x20D0, 0x20E1, 0},
  287. {0x2100, 0x2102, 0},
  288. {0x2104, 0x2104, 0},
  289. {0x2106, 0x2108, 0},
  290. {0x210A, 0x2112, 0},
  291. {0x2114, 0x2115, 0},
  292. {0x2117, 0x2120, 0},
  293. {0x2123, 0x2125, 0},
  294. {0x2127, 0x212A, 0},
  295. {0x212C, 0x2138, 0},
  296. {0x2155, 0x215A, 0},
  297. {0x215F, 0x215F, 0},
  298. {0x216C, 0x216F, 0},
  299. {0x217A, 0x2182, 0},
  300. {0x219A, 0x21D1, 0},
  301. {0x21D3, 0x21D3, 0},
  302. {0x21D5, 0x21EA, 0},
  303. {0x2201, 0x2201, 0},
  304. {0x2204, 0x2206, 0},
  305. {0x2209, 0x220A, 0},
  306. {0x220C, 0x220E, 0},
  307. {0x2210, 0x2210, 0},
  308. {0x2212, 0x2214, 0},
  309. {0x2216, 0x2219, 0},
  310. {0x221B, 0x221C, 0},
  311. {0x2221, 0x2222, 0},
  312. {0x2224, 0x2224, 0},
  313. {0x2226, 0x2226, 0},
  314. {0x222D, 0x222D, 0},
  315. {0x222F, 0x2233, 0},
  316. {0x2238, 0x223B, 0},
  317. {0x223E, 0x2247, 0},
  318. {0x2249, 0x224B, 0},
  319. {0x224D, 0x2251, 0},
  320. {0x2253, 0x225F, 0},
  321. {0x2262, 0x2263, 0},
  322. {0x2268, 0x2269, 0},
  323. {0x226C, 0x226D, 0},
  324. {0x2270, 0x2281, 0},
  325. {0x2284, 0x2285, 0},
  326. {0x2288, 0x2294, 0},
  327. {0x2296, 0x2298, 0},
  328. {0x229A, 0x22A4, 0},
  329. {0x22A6, 0x22BE, 0},
  330. {0x22C0, 0x22F1, 0},
  331. {0x2300, 0x2300, 0},
  332. {0x2302, 0x2311, 0},
  333. {0x2313, 0x237A, 0},
  334. {0x2400, 0x2424, 0},
  335. {0x2440, 0x244A, 0},
  336. {0x24B6, 0x24CF, 0},
  337. {0x24EA, 0x24EA, 0},
  338. {0x254C, 0x254F, 0},
  339. {0x2575, 0x2580, 0},
  340. {0x2590, 0x2591, 0},
  341. {0x25A2, 0x25A2, 0},
  342. {0x25AA, 0x25B1, 0},
  343. {0x25B4, 0x25B5, 0},
  344. {0x25B8, 0x25BB, 0},
  345. {0x25BE, 0x25BF, 0},
  346. {0x25C2, 0x25C5, 0},
  347. {0x25C9, 0x25CA, 0},
  348. {0x25CC, 0x25CD, 0},
  349. {0x25D2, 0x25E1, 0},
  350. {0x25E6, 0x25EE, 0},
  351. {0x2600, 0x2604, 0},
  352. {0x2607, 0x2608, 0},
  353. {0x260A, 0x260D, 0},
  354. {0x2610, 0x2613, 0},
  355. {0x261A, 0x261B, 0},
  356. {0x261D, 0x261D, 0},
  357. {0x261F, 0x263F, 0},
  358. {0x2641, 0x2641, 0},
  359. {0x2643, 0x265F, 0},
  360. {0x2662, 0x2662, 0},
  361. {0x2666, 0x2666, 0},
  362. {0x266B, 0x266B, 0},
  363. {0x266E, 0x266E, 0},
  364. {0x2701, 0x2704, 0},
  365. {0x2706, 0x2709, 0},
  366. {0x270C, 0x2727, 0},
  367. {0x2729, 0x274B, 0},
  368. {0x274D, 0x274D, 0},
  369. {0x274F, 0x2752, 0},
  370. {0x2756, 0x2756, 0},
  371. {0x2758, 0x275E, 0},
  372. {0x2761, 0x2767, 0},
  373. {0x2776, 0x2794, 0},
  374. {0x2798, 0x27AF, 0},
  375. {0x27B1, 0x27BE, 0},
  376. {0x3004, 0x3004, 0},
  377. {0x3018, 0x301C, 0},
  378. {0x3020, 0x3020, 0},
  379. {0x302A, 0x3037, 0},
  380. {0x303F, 0x303F, 0},
  381. {0x3094, 0x3094, 0},
  382. {0x3099, 0x309A, 0},
  383. {0x30F7, 0x30FA, 0},
  384. {0x312A, 0x312C, 0},
  385. {0x3190, 0x319F, 0},
  386. {0x322A, 0x3230, 0},
  387. {0x3233, 0x3238, 0},
  388. {0x323A, 0x3243, 0},
  389. {0x3280, 0x32A2, 0},
  390. {0x32A9, 0x32B0, 0},
  391. {0x32C0, 0x32CB, 0},
  392. {0x32D0, 0x32FE, 0},
  393. {0x3300, 0x3302, 0},
  394. {0x3304, 0x330C, 0},
  395. {0x330E, 0x3313, 0},
  396. {0x3315, 0x3317, 0},
  397. {0x3319, 0x3321, 0},
  398. {0x3324, 0x3325, 0},
  399. {0x3328, 0x332A, 0},
  400. {0x332C, 0x3335, 0},
  401. {0x3337, 0x333A, 0},
  402. {0x333C, 0x3348, 0},
  403. {0x334B, 0x334C, 0},
  404. {0x334E, 0x3350, 0},
  405. {0x3352, 0x3356, 0},
  406. {0x3358, 0x3376, 0},
  407. {0x337F, 0x337F, 0},
  408. {0x3385, 0x3387, 0},
  409. {0x33CB, 0x33CC, 0},
  410. {0x33D4, 0x33D4, 0},
  411. {0x33D7, 0x33D7, 0},
  412. {0x33D9, 0x33DA, 0},
  413. {0x33E0, 0x33FE, 0},
  414. {0xFB00, 0xFB06, 0},
  415. {0xFB13, 0xFB17, 0},
  416. {0xFB1E, 0xFB36, 0},
  417. {0xFB38, 0xFB3C, 0},
  418. {0xFB3E, 0xFB3E, 0},
  419. {0xFB40, 0xFB41, 0},
  420. {0xFB43, 0xFB44, 0},
  421. {0xFB46, 0xFBB1, 0},
  422. {0xFBD3, 0xFD3F, 0},
  423. {0xFD50, 0xFD8F, 0},
  424. {0xFD92, 0xFDC7, 0},
  425. {0xFDF0, 0xFDFB, 0},
  426. {0xFE20, 0xFE23, 0},
  427. {0xFE32, 0xFE32, 0},
  428. {0xFE58, 0xFE58, 0},
  429. {0xFE70, 0xFE72, 0},
  430. {0xFE74, 0xFE74, 0},
  431. {0xFE76, 0xFEFC, 0},
  432. {0xFEFF, 0xFEFF, 0},
  433. {0xFFA0, 0xFFBE, 0},
  434. {0xFFC2, 0xFFC7, 0},
  435. {0xFFCA, 0xFFCF, 0},
  436. {0xFFD2, 0xFFD7, 0},
  437. {0xFFDA, 0xFFDC, 0},
  438. {0xFFE8, 0xFFEE, 0},
  439. {0xFFFD, 0xFFFD, 0}
  440. };
  441. const struct {
  442.     int         nCharSet;
  443.     UINT        uCodePage;
  444.     DWORD       dwCodePages;
  445.     SCRIPT_ID   sid[3];
  446. } g_CharSetTransTable[] = 
  447. {
  448.     ANSI_CHARSET,        1252, FS_LATIN1,   sidAsciiLatin,  sidLatin,   sidDefault,  
  449.     EASTEUROPE_CHARSET,  1250, FS_LATIN2,   sidAsciiLatin,  sidLatin,   sidDefault,  
  450.     RUSSIAN_CHARSET,     1251, FS_CYRILLIC, sidCyrillic,    sidDefault, sidDefault,
  451.     GREEK_CHARSET,       1253, FS_GREEK,    sidGreek,       sidDefault, sidDefault,
  452.     TURKISH_CHARSET,     1254, FS_TURKISH,  sidAsciiLatin,  sidLatin,   sidDefault,
  453.     HEBREW_CHARSET,      1255, FS_HEBREW,   sidHebrew,      sidDefault, sidDefault,
  454.     ARABIC_CHARSET,      1256, FS_ARABIC,   sidArabic,      sidDefault, sidDefault,
  455.     BALTIC_CHARSET,      1257, FS_BALTIC,   sidAsciiLatin,  sidLatin,   sidDefault,
  456.     VIETNAMESE_CHARSET,  1258, FS_VIETNAMESE, sidAsciiLatin,  sidLatin, sidDefault,
  457.     THAI_CHARSET,         874, FS_THAI ,    sidThai,        sidDefault, sidDefault,
  458.     SHIFTJIS_CHARSET,     932, FS_JISJAPAN, sidKana,        sidDefault, sidDefault, //sidKana,        sidHan,     sidDefault,
  459.     GB2312_CHARSET,       936, FS_CHINESESIMP,sidHan,       sidDefault, sidDefault, //sidKana,     sidHan,     sidBopomofo,
  460.     HANGEUL_CHARSET,      949, FS_WANSUNG,  sidHangul,      sidDefault, sidDefault, //sidHangul,   sidKana,    sidHan,
  461.     CHINESEBIG5_CHARSET,  950, FS_CHINESETRAD, sidBopomofo, sidDefault, sidDefault, //sidKana,     sidHan,     sidBopomofo,     
  462.     JOHAB_CHARSET,       1361, FS_JOHAB,    sidDefault,     sidDefault, sidDefault,
  463.     DEFAULT_CHARSET,        0, 0,           sidDefault,     sidDefault, sidDefault,
  464. };
  465. // Primary chars for scripts
  466. // Pre-sorted by Unicode characters to speed up CMAP search.
  467. const struct {
  468.     WCHAR       wch;    //Can be extended to a character list
  469.     SCRIPT_ID   sid;
  470. } g_wCharToScript[] =
  471. {
  472.         0x0531, sidArmenian,
  473.         0x0710, sidSyriac,
  474.         0x0780, sidThaana,
  475.         0x0905, sidDevanagari,
  476.         0x0985, sidBengali,
  477.         0x0a05, sidGurmukhi,
  478.         0x0a85, sidGujarati,
  479.         0x0b05, sidOriya,
  480.         0x0b85, sidTamil,
  481.         0x0c05, sidTelugu,
  482.         0x0c85, sidKannada,
  483.         0x0d05, sidMalayalam,
  484.         0x0d85, sidSinhala,
  485.         0x0e81, sidLao,
  486.         0x0f40, sidTibetan,
  487.         0x10a0, sidGeorgian,
  488.         0x1300, sidEthiopic,
  489.         0x1401, sidCanSyllabic,
  490.         0x13a0, sidCherokee,
  491.         0xa000, sidYi,
  492.         0x1680, sidOgham,
  493.         0x16a0, sidRunic,
  494.         0x1700, sidBurmese,
  495.         0x1780, sidKhmer,
  496.         0x2800, sidBraille,
  497. //      0x0020, sidUserDefined
  498.     };
  499. // Script tables ported from Trident
  500. static SCRIPT_ID s_asidUnicodeSubRangeScriptMapping[] =
  501. {
  502.     sidAsciiLatin, sidLatin,      sidLatin,      sidLatin,        // 128-131
  503.     sidLatin,      sidLatin,      0,             sidGreek,        // 132-135
  504.     sidGreek,      sidCyrillic,   sidArmenian,   sidHebrew,       // 136-139
  505.     sidHebrew,     sidArabic,     sidArabic,     sidDevanagari,   // 140-143
  506.     sidBengali,    sidGurmukhi,   sidGujarati,   sidOriya,        // 144-147
  507.     sidTamil,      sidTelugu,     sidKannada,    sidMalayalam,    // 148-151
  508.     sidThai,       sidLao,        sidGeorgian,   sidGeorgian,     // 152-155
  509.     sidHangul,     sidLatin,      sidGreek,      0,               // 156-159
  510.     0,             0,             0,             0,               // 160-163
  511.     0,             0,             0,             0,               // 164-167
  512.     0,             0,             0,             0,               // 168-171
  513.     0,             0,             0,             0,               // 172-175
  514.     sidHan,        sidKana,       sidKana,       sidBopomofo,     // 176-179
  515.     sidHangul,     0,             0,             0,               // 180-183
  516.     sidHangul,     sidHangul,     sidHangul,     sidHan,          // 184-187
  517.     0,             sidHan,        0,             0,               // 188-191
  518.     0,             0,             0,             0,               // 192-195
  519.     0,             0,             sidHangul,     0,               // 196-199
  520. };
  521. // Script table (raw data from MichelSu)
  522. // Rendered by script ID
  523. const SCRIPT ScriptTable[] = 
  524. {
  525.     {sidDefault,    IDS_SIDDEFAULT,     0,  0,  0,  0, SCRIPTCONTF_SCRIPT_SYSTEM},      // 0
  526.     {sidMerge,      IDS_SIDMERGE,       0,  0,  0,  0, SCRIPTCONTF_SCRIPT_SYSTEM},      // 1
  527.     {sidAsciiSym,   IDS_SIDASCIISYM,    0,  0,  0,  0, SCRIPTCONTF_SCRIPT_SYSTEM},      // 2
  528.     {sidAsciiLatin, IDS_SIDASCIILATIN,  1252, 0,      IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER},  // 3
  529.     {sidLatin,      IDS_SIDLATIN,       1252, 0,      IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_HIDE},  // 4
  530.     {sidGreek,      IDS_SIDGREEK,       1253, 0x03AC, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER},  // 5
  531.     {sidCyrillic,   IDS_SIDCYRILLIC,    1251, 0x0401, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER},  // 6
  532.     {sidArmenian,   IDS_SIDARMENIAN,    0,    0x0531, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 7
  533. /**/{sidHebrew,     IDS_SIDHEBREW,      1255, 0x05D4, IDS_FONT_HEBREW_FIXED,  IDS_FONT_HEBREW_PROP, SCRIPTCONTF_SCRIPT_USER},    // 8
  534.     {sidArabic,     IDS_SIDARABIC,      1256, 0x0627, IDS_FONT_ARABIC_FIXED,  IDS_FONT_ARABIC_PROP, SCRIPTCONTF_SCRIPT_USER},    // 9
  535.     {sidDevanagari, IDS_SIDDEVANAGARI,  0,    0x0905, IDS_FONT_DEVANAGARI_FIXED,IDS_FONT_DEVANAGARI_PROP, SCRIPTCONTF_SCRIPT_USER}, // 10
  536.     {sidBengali,    IDS_SIDBENGALI,     0,    0x0985, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 11
  537.     {sidGurmukhi,   IDS_SIDGURMUKHI,    0,    0x0A05, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 12
  538.     {sidGujarati,   IDS_SIDGUJARATI,    0,    0x0A85, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 13
  539.     {sidOriya,      IDS_SIDORIYA,       0,    0x0B05, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 14
  540.     {sidTamil,      IDS_SIDTAMIL,       0,    0x0B85, IDS_FONT_TAMIL_FIXED, IDS_FONT_TAMIL_PROP, SCRIPTCONTF_SCRIPT_USER},       // 15
  541.     {sidTelugu,     IDS_SIDTELUGU,      0,    0x0C05, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 16
  542.     {sidKannada,    IDS_SIDKANNADA,     0,    0x0C85, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 17
  543.     {sidMalayalam,  IDS_SIDMALAYALAM,   0,    0x0D05, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 18
  544.     {sidThai,       IDS_SIDTHAI,        874,  0x0E01, IDS_FONT_THAI_FIXED, IDS_FONT_THAI_PROP, SCRIPTCONTF_SCRIPT_USER},         // 19
  545.     {sidLao,        IDS_SIDLAO,         0,    0x0E81, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 20
  546.     {sidTibetan,    IDS_SIDTIBETAN,     0,    0x0F40, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 21
  547.     {sidGeorgian,   IDS_SIDGEORGIAN,    0,    0x10A0, 0, 0, SCRIPTCONTF_SCRIPT_USER},                                            // 22
  548.     {sidHangul,     IDS_SIDHANGUL,      949,  0,      IDS_FONT_KOREAN_FIXED,   IDS_FONT_KOREAN_PROP, SCRIPTCONTF_SCRIPT_USER},   // 23
  549.     {sidKana,       IDS_SIDKANA,        932,  0,      IDS_FONT_JAPANESE_FIXED, IDS_FONT_JAPANESE_PROP, SCRIPTCONTF_SCRIPT_USER}, // 24
  550.     {sidBopomofo,   IDS_SIDBOPOMOFO,    950,  0,      IDS_FONT_TAIWAN_FIXED,   IDS_FONT_TAIWAN_PROP, SCRIPTCONTF_SCRIPT_USER},   // 25
  551.     {sidHan,        IDS_SIDHAN,         936,  0,      IDS_FONT_CHINESE_FIXED,  IDS_FONT_CHINESE_PROP, SCRIPTCONTF_SCRIPT_USER},  // 26
  552.     {sidEthiopic,   IDS_SIDETHIOPIC,    0,    0x1300, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 27
  553.     {sidCanSyllabic,IDS_SIDCANSYLLABIC, 0,    0x1401, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 28
  554.     {sidCherokee,   IDS_SIDCHEROKEE,    0,    0x13A0, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 29
  555.     {sidYi,         IDS_SIDYI,          0,    0xA000, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 30
  556.     {sidBraille,    IDS_SIDBRAILLE,     0,    0x2800, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 31
  557.     {sidRunic,      IDS_SIDRUNIC,       0,    0x16A0, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 32
  558.     {sidOgham,      IDS_SIDOGHAM,       0,    0x1680, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 33
  559.     {sidSinhala,    IDS_SIDSINHALA,     0,    0x0D85, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 34
  560.     {sidSyriac,     IDS_SIDSYRIAC,      0,    0x0710, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 35
  561.     {sidBurmese,    IDS_SIDBURMESE,     0,    0x1700, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 36
  562.     {sidKhmer,      IDS_SIDKHMER,       0,    0x1780, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 37
  563.     {sidThaana,     IDS_SIDTHAANA,      0,    0x0780, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 38
  564.     {sidMongolian,  IDS_SIDMONGOLIAN,   0,    0,      0, 0, SCRIPTCONTF_SCRIPT_USER},      // 39
  565.     {sidUserDefined,IDS_SIDUSERDEFINED, 0,    0x0020, 0, 0, SCRIPTCONTF_SCRIPT_USER},      // 40
  566. };
  567. UINT g_cScript = ARRAYSIZE(ScriptTable);
  568. /////////////////////////////////////////////////////////////////////////////
  569. // CMLFLink Free Global Objects
  570. void CMLangFontLink_FreeGlobalObjects()
  571. {
  572.     if (g_pMLFLink)
  573.         g_pMLFLink->Release();
  574.     if (CMLFLink::m_pCodePagesCache)
  575.         delete CMLFLink::m_pCodePagesCache;
  576.     if (CMLFLink::m_pFontMappingCache)
  577.         delete CMLFLink::m_pFontMappingCache;
  578.     if (CMLFLink2::m_pFontMappingCache2)
  579.         delete CMLFLink2::m_pFontMappingCache2;
  580. }
  581. /////////////////////////////////////////////////////////////////////////////
  582. // CMLFLink
  583. CMLFLink::CMLFLink()
  584. {
  585.     EnterCriticalSection(&g_cs);
  586.     if (!m_pCodePagesCache)
  587.         m_pCodePagesCache = new CCodePagesCache;
  588.     if (!m_pFontMappingCache)
  589.         m_pFontMappingCache = new CFontMappingCache;
  590.     LeaveCriticalSection(&g_cs);
  591.     m_pFlinkTable = NULL;
  592. }
  593. /////////////////////////////////////////////////////////////////////////////
  594. // CMLFLink : IMLangCodePages
  595. STDMETHODIMP CMLFLink::GetCharCodePages(WCHAR chSrc, DWORD* pdwCodePages)
  596. {
  597.     ASSERT_THIS;
  598.     ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  599.     HRESULT hr = S_OK;
  600.     int nLen;
  601.     int iCmd = 0;
  602.     int nPickOffset;
  603.     int nBitOffset = 0;
  604.     int nBitCount = 32;
  605.     DWORD dwDiff = 0xffffffff;
  606.     DWORD dwOr = 0;
  607.     DWORD dwCodePages;
  608.     DWORD adwBitsMap[32];
  609.     const CCodePagesHeader* pHeader;
  610.     const WORD* pwTable;
  611.     int nBlock;
  612.     int nEndLen;
  613.     const BYTE* pbBlock;
  614.     if (m_pCodePagesCache)
  615.         hr = m_pCodePagesCache->Load();
  616.     else
  617.         hr = E_FAIL;
  618.     if (SUCCEEDED(hr))
  619.     {
  620.         pHeader = (CCodePagesHeader*)(BYTE*)*m_pCodePagesCache;
  621.         pwTable = (WORD*)(*m_pCodePagesCache + READWINTELDWORD(pHeader->m_dwTableOffset));
  622.         nBlock = chSrc / READWINTELDWORD(pHeader->m_dwBlockSize);
  623.         nEndLen = chSrc % READWINTELDWORD(pHeader->m_dwBlockSize);
  624.         pbBlock = *m_pCodePagesCache + READWINTELWORD(pwTable[nBlock]);
  625.     }
  626.     for (int nDoneLen = 0; SUCCEEDED(hr) && nDoneLen < (int)READWINTELDWORD(pHeader->m_dwBlockSize); nDoneLen += nLen)
  627.     {
  628.         BYTE bCmd = pbBlock[--iCmd];
  629.         if (bCmd < pHeader->m_abCmdCode[1])
  630.         {
  631.             // Flat
  632.             nLen = bCmd + 1;
  633.             nPickOffset = nBitOffset + nBitCount * (nEndLen - nDoneLen);
  634.             nBitOffset += nBitCount * nLen;
  635.         }
  636.         else if (bCmd < pHeader->m_abCmdCode[2])
  637.         {
  638.             // Pack
  639.             nLen = bCmd - pHeader->m_abCmdCode[1] + 2;
  640.             nPickOffset = nBitOffset;
  641.             nBitOffset += nBitCount;
  642.         }
  643.         else if (bCmd < pHeader->m_abCmdCode[4])
  644.         {
  645.             // Diff & Or
  646.             nLen = 0;
  647.             DWORD dw = pbBlock[--iCmd];
  648.             dw <<= 8;
  649.             dw |= pbBlock[--iCmd];
  650.             dw <<= 8;
  651.             dw |= pbBlock[--iCmd];
  652.             dw <<= 8;
  653.             dw |= pbBlock[--iCmd];
  654.             if (bCmd < pHeader->m_abCmdCode[3])
  655.             {
  656.                 // Diff
  657.                 dwDiff = dw;
  658.                 DWORD dwShift = 1;
  659.                 nBitCount = 0;
  660.                 for (int nBit = 0; nBit < 32; nBit++)
  661.                 {
  662.                     if (dwDiff & (1 << nBit))
  663.                     {
  664.                         adwBitsMap[nBit] = dwShift;
  665.                         dwShift <<= 1;
  666.                         nBitCount++;
  667.                     }
  668.                     else
  669.                     {
  670.                         adwBitsMap[nBit] = 0;
  671.                     }
  672.                 }
  673.             }
  674.             else
  675.             {
  676.                 // Or
  677.                 dwOr = dw;
  678.             }
  679.         }
  680.         else
  681.         {
  682.             // Big Pack
  683.             nLen = (bCmd - pHeader->m_abCmdCode[4]) * 0x100 + pbBlock[--iCmd] + pHeader->m_abCmdCode[2] - pHeader->m_abCmdCode[1] + 1 + 1;
  684.             nPickOffset = nBitOffset;
  685.             nBitOffset += nBitCount;
  686.         }
  687.         if (nEndLen < nDoneLen + nLen)
  688.             break;
  689.     }
  690.     if (SUCCEEDED(hr) &&
  691.         nDoneLen < (int)READWINTELDWORD(pHeader->m_dwBlockSize))
  692.     {
  693.         const BYTE* const pbBuf = &pbBlock[nPickOffset / 8];
  694.         DWORD dwCompBits = pbBuf[0] | (DWORD(pbBuf[1]) << 8) | (DWORD(pbBuf[2]) << 16) | (DWORD(pbBuf[3]) << 24);
  695.         dwCompBits >>= nPickOffset % 8;
  696.         if (nBitOffset % 8)
  697.             dwCompBits |= pbBuf[4] << (32 - nBitOffset % 8);
  698.         if (nBitCount < 32)
  699.         {
  700.             dwCompBits &= (1 << nBitCount) - 1;
  701.             dwCodePages = 0;
  702.             for (int nBit = 0; nBit < 32; nBit++)
  703.             {
  704.                 if (dwCompBits & adwBitsMap[nBit])
  705.                     dwCodePages |= (1 << nBit);
  706.             }
  707.         }
  708.         else
  709.         {
  710.             dwCodePages = dwCompBits;
  711.         }
  712.         dwCodePages |= dwOr;
  713.     }
  714.     else
  715.     {
  716.         hr = E_FAIL; // Probably Code Pages data is broken.
  717.     }
  718.     if (pdwCodePages)
  719.     {
  720.         if (SUCCEEDED(hr))
  721.         {
  722.             // We invent this new internal charset bit, FS_MLANG_K1HANJA, to support Korean K1 Hanja
  723.             // K1 Hanja is defined in KSC 5657-1991, it contains non-cp949 DBCS characters
  724.             // Currenly, Korean fonts shipped with NT5 and Win98 support K1 Hanja glyphs 
  725.             // and we don't want to switch font to other DBCS fonts in this case.
  726.             if (dwCodePages & FS_MLANG_K1HANJA)
  727.             {
  728.                 // Assume Korean font supports K1_HANJA on Win98 and NT5 
  729.                 if (g_bIsNT5 || (g_bIsWin98 && CP_KOR_5601 == GetACP()))
  730.                     dwCodePages |= FS_WANSUNG;
  731.                 dwCodePages &= ~FS_MLANG_K1HANJA;
  732.             }            
  733.             *pdwCodePages = dwCodePages;
  734.         }
  735.         else
  736.             *pdwCodePages = 0;
  737.     }
  738.     return hr;
  739. }   
  740. STDMETHODIMP CMLFLink::GetStrCodePages(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages)
  741. {
  742.     ASSERT_THIS;
  743.     ASSERT_READ_BLOCK(pszSrc, cchSrc);
  744.     ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  745.     ASSERT_WRITE_PTR_OR_NULL(pcchCodePages);
  746.     HRESULT hr = S_OK;
  747.     long cchCodePages = 0;
  748.     DWORD dwStrCodePages = (DWORD)~0;
  749.     BOOL fInit = FALSE;
  750.     BOOL fNoPri = FALSE;
  751.     if (!pszSrc || cchSrc <= 0) // We can't make dwStrCodePages when cchSrc is zero
  752.         hr = E_INVALIDARG;
  753.     while (SUCCEEDED(hr) && cchSrc > 0)
  754.     {
  755.         DWORD dwCharCodePages;
  756.         if (SUCCEEDED(hr = GetCharCodePages(*pszSrc, &dwCharCodePages)))
  757.         {
  758.             if (!fInit)
  759.             {
  760.                 fInit = TRUE;
  761.                 fNoPri = !(dwPriorityCodePages & dwCharCodePages);
  762.             }
  763.             else if (fNoPri != !(dwPriorityCodePages & dwCharCodePages))
  764.             {
  765.                 break;
  766.             }
  767.             if (!fNoPri)
  768.                 dwPriorityCodePages &= dwCharCodePages;
  769.             if (dwCharCodePages && (dwCharCodePages & dwStrCodePages))
  770.                 dwStrCodePages &= dwCharCodePages;
  771.             else if (dwCharCodePages) // Don't break if dwCharCodePages is zero
  772.                      break;
  773.             pszSrc++;
  774.             cchSrc--;
  775.             cchCodePages++;
  776.         }
  777.     }
  778.     if (SUCCEEDED(hr))
  779.     {
  780.         if (pcchCodePages)
  781.             *pcchCodePages = cchCodePages;
  782.         if (pdwCodePages)
  783.             *pdwCodePages = dwStrCodePages;
  784.     }
  785.     else
  786.     {
  787.         if (pcchCodePages)
  788.             *pcchCodePages = 0;
  789.         if (pdwCodePages)
  790.             *pdwCodePages = 0;
  791.     }
  792.     return hr;
  793. }
  794. STDMETHODIMP CMLFLink::CodePageToCodePages(UINT uCodePage, DWORD* pdwCodePages)
  795. {
  796.     ASSERT_THIS;
  797.     ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  798.     for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  799.     {
  800.         if (uCodePage == g_CharSetTransTable[iCharSet].uCodePage)
  801.         {
  802.             if (pdwCodePages)
  803.                 *pdwCodePages = g_CharSetTransTable[iCharSet].dwCodePages;
  804.             return S_OK;
  805.         }
  806.     }
  807.     if (pdwCodePages)
  808.         *pdwCodePages = 0;
  809.     return E_FAIL; // Unknown code page
  810. }
  811. STDMETHODIMP CMLFLink::CodePagesToCodePage(DWORD dwCodePages, UINT uDefaultCodePage, UINT* puCodePage)
  812. {
  813.     ASSERT_THIS;
  814.     ASSERT_WRITE_PTR_OR_NULL(puCodePage);
  815.     HRESULT hr = E_FAIL; // Unknown code pages
  816.     DWORD dwDefaultCodePages;
  817.     if (uDefaultCodePage &&
  818.         SUCCEEDED(hr = CodePageToCodePages(uDefaultCodePage, &dwDefaultCodePages)) &&
  819.         (dwDefaultCodePages & dwCodePages))
  820.     {
  821.         hr = S_OK;
  822.     }
  823.     else
  824.     {
  825.         for (int iCharSet = 0; g_CharSetTransTable[iCharSet].dwCodePages; iCharSet++)
  826.         {
  827.             if (dwCodePages & g_CharSetTransTable[iCharSet].dwCodePages)
  828.             {
  829.                 uDefaultCodePage = g_CharSetTransTable[iCharSet].uCodePage;
  830.                 hr = S_OK;
  831.                 break;
  832.             }
  833.         }
  834.     }
  835.     if (puCodePage)
  836.     {
  837.         if (SUCCEEDED(hr))
  838.             *puCodePage = uDefaultCodePage;
  839.         else
  840.             *puCodePage = 0;
  841.     }
  842.     return hr;
  843. }
  844. #define REGSTR_PATH_FONTLINK TSZMICROSOFTPATH TEXT("\Windows NT\CurrentVersion\FontLink\SystemLink")
  845. void CMLFLink::FreeFlinkTable(void)
  846. {
  847.     if (m_pFlinkTable)
  848.     {
  849.         for (UINT i=0; i<m_uiFLinkFontNum; i++)
  850.             if (m_pFlinkTable[i].pmszFaceName)
  851.                 LocalFree(m_pFlinkTable[i].pmszFaceName);
  852.         LocalFree(m_pFlinkTable);
  853.         m_pFlinkTable = NULL;
  854.         m_uiFLinkFontNum = 0;
  855.     }
  856. }
  857. #define MAX_FONTLINK_BUFFER_SIZE    1024
  858. HRESULT CMLFLink::CreateNT5FontLinkTable(void)
  859. {
  860.     HKEY    hKey = NULL;
  861.     HKEY    hKeyFont = NULL;
  862.     ULONG   ulFonts = 0;
  863.     ULONG   ulFLinkFonts = 0;
  864.     DWORD   dwIndex = 0;
  865.     WCHAR   szFaceName[MAX_PATH];
  866.     LPWSTR  pNewFaceName = NULL;
  867.     DWORD   dwOffset = 0;
  868.     DWORD   dwOffset2 = 0;
  869.     DWORD   dwValue;
  870.     DWORD   dwData;
  871.     WCHAR   szFontFile[LF_FACESIZE];
  872.     DWORD   dwType;
  873.     WCHAR   szFlinkFont[MAX_FONTLINK_BUFFER_SIZE];
  874.     
  875.     // Internal temperate data
  876.     struct tagFontTable
  877.     {
  878.         WCHAR szFontFile[LF_FACESIZE];
  879.         WCHAR szFaceName[LF_FACESIZE];
  880.     }* tmpFontTable = NULL;
  881.     HRESULT hr;
  882.     // Open system font and fontlink key
  883.     if ((ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_FONTLINK, 0, KEY_READ, &hKey)) ||
  884.         (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEYNT, 0, KEY_READ, &hKeyFont)))
  885.     {
  886.         hr = E_FAIL;
  887.         goto TABLE_DONE;
  888.     }
  889.     // Get number of items
  890.     if ((ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, NULL, 0, NULL, 
  891.          NULL, NULL, &ulFLinkFonts, NULL, NULL, NULL, NULL) || 0 == ulFLinkFonts) ||            
  892.         (ERROR_SUCCESS != RegQueryInfoKey(hKeyFont, NULL, NULL, 0, NULL, 
  893.             NULL, NULL, &ulFonts, NULL, NULL, NULL, NULL) || 0 == ulFonts))
  894.     {
  895.         hr = E_FAIL;
  896.         goto TABLE_DONE;
  897.     }
  898.     tmpFontTable = (struct tagFontTable *)LocalAlloc(LPTR, sizeof(struct tagFontTable)*ulFonts);
  899.     if (NULL == tmpFontTable)
  900.     {
  901.         hr = E_OUTOFMEMORY;
  902.         goto TABLE_DONE;
  903.     }
  904.     dwValue = dwData = LF_FACESIZE;
  905.     dwType = REG_SZ;
  906.     dwIndex = 0;
  907.     ulFonts = 0;    
  908.     while (ERROR_NO_MORE_ITEMS != RegEnumValueW(
  909.                       hKeyFont,
  910.                       dwIndex++,
  911.                       szFaceName,
  912.                       &dwValue,
  913.                       NULL,
  914.                       &dwType,
  915.                       (LPBYTE)szFontFile,
  916.                       &dwData ))
  917.     {
  918.         //  TTF fonts only, TTC fonts already have face name under fontlink
  919.         if (pNewFaceName = wcsstr(szFaceName, L" & "))
  920.             break;
  921.         pNewFaceName = wcsstr(szFaceName, L" (TrueType)");
  922.         if(pNewFaceName)
  923.         {
  924.            *pNewFaceName = 0;
  925.            MLStrCpyNW(tmpFontTable[ulFonts].szFaceName, szFaceName, LF_FACESIZE);
  926.            MLStrCpyNW(tmpFontTable[ulFonts++].szFontFile, szFontFile, LF_FACESIZE);
  927.         }
  928.         dwValue = dwData = LF_FACESIZE;
  929.         dwType = REG_SZ;
  930.     }
  931.     
  932.     m_pFlinkTable = (PFLINKFONT) LocalAlloc(LPTR, sizeof(FLINKFONT)*ulFLinkFonts);
  933.     if (NULL == m_pFlinkTable)
  934.     {
  935.         hr = E_OUTOFMEMORY;
  936.         goto TABLE_DONE;
  937.     }
  938.     dwValue = LF_FACESIZE;
  939.     dwData = MAX_FONTLINK_BUFFER_SIZE;
  940.     dwType = REG_MULTI_SZ;
  941.     dwIndex = 0;
  942.     while (ERROR_NO_MORE_ITEMS != RegEnumValueW(
  943.                       hKey,
  944.                       dwIndex,
  945.                       m_pFlinkTable[dwIndex].szFaceName,
  946.                       &dwValue,
  947.                       NULL,
  948.                       &dwType,
  949.                       (LPBYTE)szFlinkFont,
  950.                       &dwData ))
  951.     {
  952.         m_pFlinkTable[dwIndex].pmszFaceName = (LPWSTR) LocalAlloc(LPTR, MAX_FONTLINK_BUFFER_SIZE); 
  953.         if (!m_pFlinkTable[dwIndex].pmszFaceName)
  954.         {
  955.             hr = E_OUTOFMEMORY;
  956.             goto TABLE_DONE;
  957.         }
  958.         while (TRUE)
  959.         {
  960.             pNewFaceName = wcsstr(&szFlinkFont[dwOffset], L",");
  961.             
  962.             if (pNewFaceName)   // TTC font, get face name from registry
  963.             {
  964.                 MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), ++pNewFaceName, LF_FACESIZE);
  965.                 dwOffset2 += lstrlenW(pNewFaceName)+1;
  966.             }
  967.             else                // TTF font, search font table for face name            
  968.             {
  969.                 if (szFlinkFont[dwOffset])
  970.                     for (UINT i=0; i<ulFonts; i++)
  971.                     {
  972.                         if (!MLStrCmpNIW(&szFlinkFont[dwOffset], tmpFontTable[i].szFontFile, LF_FACESIZE))
  973.                         {
  974.                             MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), tmpFontTable[i].szFaceName, LF_FACESIZE);
  975.                             dwOffset2 += lstrlenW(tmpFontTable[i].szFaceName)+1;
  976.                             break;
  977.                         }
  978.                     }
  979.                 else            // End of multiple string, break out                    
  980.                     break;
  981.             }
  982.             dwOffset += lstrlenW(&szFlinkFont[dwOffset])+1;
  983.             // Prevent infinitive loop, shouldn't happen
  984.             if (dwOffset >= MAX_FONTLINK_BUFFER_SIZE) 
  985.             {
  986.                 break;
  987.             }
  988.         }
  989.         dwValue = LF_FACESIZE;
  990.         dwData = MAX_FONTLINK_BUFFER_SIZE;
  991.         dwType = REG_MULTI_SZ;
  992.         dwOffset = dwOffset2 = 0;
  993.         dwIndex++;
  994.     }
  995.     m_uiFLinkFontNum = ulFLinkFonts;
  996.     hr = S_OK;
  997. TABLE_DONE:
  998.     if (hKey)
  999.         RegCloseKey(hKey);
  1000.     if (hKeyFont)
  1001.         RegCloseKey(hKeyFont);
  1002.     if (tmpFontTable)
  1003.         LocalFree(tmpFontTable);
  1004.     if ((hr != S_OK) && m_pFlinkTable)
  1005.         FreeFlinkTable();
  1006.     return hr;
  1007. }
  1008. HRESULT CMLFLink::GetNT5FLinkFontCodePages(HDC hDC, LOGFONTW* plfEnum, DWORD * lpdwCodePages)
  1009. {
  1010.     HRESULT hr = S_OK;
  1011.     UINT    i;
  1012.     if (!EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0))
  1013.         return E_FAIL;
  1014.     if (NULL == m_pFlinkTable)
  1015.         CreateNT5FontLinkTable();
  1016.     if (m_pFlinkTable)
  1017.     {
  1018.         for (i=0; i<m_uiFLinkFontNum;i++)
  1019.         {
  1020.             if (!MLStrCmpNIW(plfEnum->lfFaceName, m_pFlinkTable[i].szFaceName, LF_FACESIZE))
  1021.             {
  1022.                 DWORD dwOffset=0;
  1023.                 // Internal buffer, we're sure it'll end
  1024.                 while(TRUE)
  1025.                 {
  1026.                     MLStrCpyNW(plfEnum->lfFaceName, &m_pFlinkTable[i].pmszFaceName[dwOffset], LF_FACESIZE);
  1027.                     EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0);
  1028.                     dwOffset += lstrlenW(&m_pFlinkTable[i].pmszFaceName[dwOffset])+1;
  1029.                     // End of multiple string ?
  1030.                     if (m_pFlinkTable[i].pmszFaceName[dwOffset] == 0)
  1031.                         break;                        
  1032.                 }
  1033.                 break;
  1034.             }
  1035.         }
  1036.     }
  1037.     return hr;
  1038. }
  1039. /////////////////////////////////////////////////////////////////////////////
  1040. // CMLFLink : IMLangFontLink
  1041. // 1/29/99 - Change HR return
  1042. //        Now, we always return S_OK unless system error, caller will
  1043. //        check code pages bits in dwCodePages for font code page coverage
  1044. STDMETHODIMP CMLFLink::GetFontCodePages(HDC hDC, HFONT hFont, DWORD* pdwCodePages)
  1045. {
  1046.     ASSERT_THIS;
  1047.     ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  1048.     HRESULT hr = S_OK;
  1049.     LOGFONT lfFont;
  1050.     DWORD dwCodePages = 0;
  1051.     if (!::GetObject(hFont, sizeof(lfFont), &lfFont))
  1052.         hr = E_FAIL; // Invalid hFont
  1053.     if (SUCCEEDED(hr))
  1054.     {
  1055.         LOGFONT lfEnum;
  1056.         // Enumerates all character sets of given font's facename
  1057.         // Then, combines them in dwCodePages
  1058.         ::memset(&lfEnum, 0, sizeof(lfEnum));
  1059.         lfEnum.lfCharSet = DEFAULT_CHARSET;
  1060.         _tcsncpy(lfEnum.lfFaceName, lfFont.lfFaceName, ARRAYSIZE(lfEnum.lfFaceName));
  1061.         if (g_bIsNT5)
  1062.         {
  1063.             LOGFONTW lfEnumW = {0};
  1064.             lfEnumW.lfCharSet = DEFAULT_CHARSET;
  1065.             if (MultiByteToWideChar(GetACP(), 0, lfFont.lfFaceName, LF_FACESIZE, lfEnumW.lfFaceName, LF_FACESIZE))
  1066.                 hr = GetNT5FLinkFontCodePages(hDC, &lfEnumW, &dwCodePages);
  1067.             else
  1068.                 if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0))
  1069.                     hr = E_FAIL; // Invalid hDC
  1070.         }
  1071.         else
  1072.         {
  1073.             if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0))
  1074.                 hr = E_FAIL; // Invalid hDC
  1075.         }
  1076.     }
  1077. //############################
  1078. //######  MingLiU HACK  ######
  1079. //## Fix the bogus font !!! ##
  1080. //############################
  1081.     if (SUCCEEDED(hr) && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, _T("MingLiU"), -1) == 2)
  1082.     {
  1083.         dwCodePages &= ~FS_LATIN1; // Actually it doesn't have the characters of ANSI_CHARSET.
  1084.     }
  1085. //############################
  1086. #ifdef UNICODE
  1087. #define PRC_DEFAULT_GUI_FONT L"x5b8bx4f53"
  1088. #else
  1089. #define PRC_DEFAULT_GUI_FONT "xcbxcexccxe5"
  1090. #endif
  1091.     // PRC Win95 DEFAULT_GUI_FONT HACK !!!
  1092.     if (SUCCEEDED(hr) && lfFont.lfCharSet == ANSI_CHARSET && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, PRC_DEFAULT_GUI_FONT, -1) == 2)
  1093.     {
  1094.         dwCodePages &= ~FS_CHINESESIMP; // Actually it doesn't have the characters of GB2321_CHARSET.
  1095.     }
  1096.     if (pdwCodePages)
  1097.     {
  1098.         if (SUCCEEDED(hr))
  1099.             *pdwCodePages = dwCodePages;
  1100.         else
  1101.             *pdwCodePages = 0;
  1102.     }
  1103.     return hr;
  1104. }
  1105. int CALLBACK CMLFLink::GetFontCodePagesEnumFontProc(const LOGFONT* plf, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  1106. {
  1107.     for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++)
  1108.     {
  1109.         if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet)
  1110.         {
  1111.             if ((FontType == TRUETYPE_FONTTYPE) || 
  1112.                 (g_CharSetTransTable[iCharSet].uCodePage == GetACP()))
  1113.             {
  1114.                 *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages;
  1115.                 break;
  1116.             }
  1117.         }
  1118.     }
  1119.     return TRUE;
  1120. }
  1121. int CALLBACK CMLFLink::GetFontCodePagesEnumFontProcW(const LOGFONTW* plf, const TEXTMETRICW*, DWORD FontType, LPARAM lParam)
  1122. {
  1123.     for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++)
  1124.     {
  1125.         if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet)
  1126.         {
  1127.             if ((FontType == TRUETYPE_FONTTYPE) || 
  1128.                 (g_CharSetTransTable[iCharSet].uCodePage == GetACP()))
  1129.             {
  1130.                 *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages;
  1131.                 break;
  1132.             }
  1133.         }
  1134.     }
  1135.     return TRUE;
  1136. }
  1137. STDMETHODIMP CMLFLink::MapFont(HDC hDC, DWORD dwCodePages, HFONT hSrcFont, HFONT* phDestFont)
  1138. {
  1139.     ASSERT_THIS;
  1140.     ASSERT_WRITE_PTR_OR_NULL(phDestFont);
  1141.     HRESULT hr = S_OK;
  1142.     CFontMappingInfo fm; // To accelerate internal subroutine calls
  1143.     fm.hDC = hDC;
  1144.     // Font mapping cache works only for Display
  1145.     BOOL fDisplay = (::GetDeviceCaps(hDC, TECHNOLOGY) == DT_RASDISPLAY);
  1146.     dwCodePages &= ~FS_SYMBOL; // We don't map symbol font.
  1147.     if (!::GetObject(hSrcFont, sizeof(fm.lfSrcFont), &fm.lfSrcFont))
  1148.         hr = E_FAIL; // Invalid hSrcFont
  1149.     if (fDisplay)
  1150.         EnumFontFamiliesEx(hDC, &fm.lfSrcFont, (FONTENUMPROC)VerifyFontSizeEnumFontProc, (LPARAM)&fm.lfSrcFont, 0);
  1151.     // Do two things at same time
  1152.     // (1) Find given font in the font mapping cache
  1153.     // (2) Build m_auCodePage[] and m_adwCodePages[]
  1154.     if (SUCCEEDED(hr))
  1155.     {
  1156.         hr = S_FALSE; // hr == S_FALSE means that we didn't find the font in the cache
  1157.         for (int n = 0; n < 32 && dwCodePages; n++)
  1158.         {
  1159.             hr = CodePagesToCodePage(dwCodePages, 0, &fm.auCodePage[n]); // Pick one of CodePages
  1160.             if (SUCCEEDED(hr))
  1161.                 hr = CodePageToCodePages(fm.auCodePage[n], &fm.adwCodePages[n]);
  1162.             if (SUCCEEDED(hr))
  1163.             {
  1164.                 if (fDisplay && m_pFontMappingCache)
  1165.                     hr = m_pFontMappingCache->FindEntry(fm.auCodePage[n], fm.lfSrcFont, &fm.hDestFont);
  1166.                 else
  1167.                     hr = S_FALSE;
  1168.             }
  1169.             if (hr != S_FALSE)
  1170.                 break;
  1171.             dwCodePages &= ~fm.adwCodePages[n];
  1172.         }
  1173.         fm.auCodePage[n] = NULL; // End mark
  1174.         fm.adwCodePages[n] = 0;
  1175.     }
  1176.     if (hr == S_FALSE) // Not exist in cache
  1177.     {
  1178.         hr = MapFontCodePages(fm, GetFaceNameRegistry);
  1179.         if (hr == MLSTR_E_FACEMAPPINGFAILURE)
  1180.             hr = MapFontCodePages(fm, GetFaceNameGDI);
  1181.         // Handle font link failure case for NT5
  1182.         if (hr == MLSTR_E_FACEMAPPINGFAILURE && g_bIsNT5)
  1183.             hr = MapFontCodePages(fm, GetFaceNameMIME);
  1184.         if (SUCCEEDED(hr) && fDisplay && m_pFontMappingCache)
  1185.             hr = m_pFontMappingCache->AddEntry(fm.auCodePage[fm.iCP], fm.lfSrcFont, fm.hDestFont);
  1186.     }
  1187.     if (phDestFont)
  1188.     {
  1189.         if (SUCCEEDED(hr))
  1190.         {            
  1191.             *phDestFont = fm.hDestFont;
  1192.             fm.hDestFont = NULL; // Avoid being deleted it in destructor
  1193.         }
  1194.         else
  1195.         {
  1196.             *phDestFont = NULL;
  1197.         }
  1198.     }
  1199.     return hr;
  1200. }
  1201. STDMETHODIMP CMLFLink::ReleaseFont(HFONT hFont)
  1202. {
  1203.     ASSERT_THIS;
  1204.     HRESULT hr = S_OK;
  1205.     if (!m_pFontMappingCache || FAILED(hr = m_pFontMappingCache->UnlockEntry(hFont)))
  1206.     {
  1207.         // For non display DC
  1208.         if (::DeleteObject(hFont))
  1209.             hr = S_OK;
  1210.         else
  1211.             hr = E_FAIL; // Invalid hFont
  1212.     }
  1213.     return hr;
  1214. }
  1215. STDMETHODIMP CMLFLink::ResetFontMapping(void)
  1216. {
  1217.     ASSERT_THIS;
  1218.     HRESULT hr = S_OK;
  1219.     if (m_pFontMappingCache)
  1220.         hr =  m_pFontMappingCache->FlushEntries();
  1221.     return hr;
  1222. }
  1223. STDMETHODIMP CMLFLink2::ResetFontMapping(void)
  1224. {
  1225.     ASSERT_THIS;
  1226.     HRESULT hr = S_OK;
  1227.     if (m_pIMLFLnk)
  1228.         hr =  m_pIMLFLnk->ResetFontMapping();
  1229.     if (m_pFontMappingCache2)
  1230.         hr = (S_OK == m_pFontMappingCache2->EnsureFontTable(FALSE)? hr : E_FAIL);
  1231.     return hr;
  1232. }
  1233. HRESULT CMLFLink::MapFontCodePages(CFontMappingInfo& fm, PFNGETFACENAME pfnGetFaceName)
  1234. {
  1235.     HRESULT hr = MLSTR_E_FACEMAPPINGFAILURE;    
  1236.     for (fm.iCP = 0; fm.auCodePage[fm.iCP]; fm.iCP++)
  1237.     {
  1238.         fm.lfDestFont.lfCharSet = DEFAULT_CHARSET;
  1239.         hr = (this->*pfnGetFaceName)(fm);
  1240.         if (SUCCEEDED(hr))
  1241.         {
  1242.             LOGFONT lf = {0};
  1243.             // If face name is from registry or MIMEDB, we set charset to codepage charset.
  1244.             if (fm.lfDestFont.lfCharSet == DEFAULT_CHARSET)
  1245.             {
  1246.                 for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  1247.                 {
  1248.                     if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage)
  1249.                     {
  1250.                         fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet;
  1251.                         break;
  1252.                     }
  1253.                 }
  1254.             }
  1255.             lf.lfCharSet = DEFAULT_CHARSET;
  1256.             MLStrCpyN(lf.lfFaceName, fm.szFaceName, LF_FACESIZE);
  1257.             // Retrieve LOGFONT from gotten facename
  1258.             fm.lfDestFont.lfFaceName[0] = _T('');
  1259.             if (!::EnumFontFamiliesEx(fm.hDC, &lf, MapFontEnumFontProc, (LPARAM)&fm.lfDestFont, 0))
  1260.                 hr = E_FAIL; // Invalid hDC
  1261.             else if (fm.lfDestFont.lfFaceName[0] == _T(''))
  1262.                 hr = MLSTR_E_FACEMAPPINGFAILURE;
  1263.         }
  1264.         if (SUCCEEDED(hr))
  1265.         {
  1266.             fm.lfDestFont.lfHeight      = fm.lfSrcFont.lfHeight;
  1267.             fm.lfDestFont.lfWidth       = fm.lfSrcFont.lfWidth;
  1268.             fm.lfDestFont.lfEscapement  = fm.lfSrcFont.lfEscapement;
  1269.             fm.lfDestFont.lfOrientation = fm.lfSrcFont.lfOrientation;
  1270.             fm.lfDestFont.lfWeight      = fm.lfSrcFont.lfWeight;
  1271.             fm.lfDestFont.lfItalic      = fm.lfSrcFont.lfItalic;
  1272.             fm.lfDestFont.lfUnderline   = fm.lfSrcFont.lfUnderline;
  1273.             fm.lfDestFont.lfStrikeOut   = fm.lfSrcFont.lfStrikeOut;
  1274.             HRESULT hrTemp = VerifyFaceMap(fm);
  1275.             if (hrTemp == MLSTR_E_FACEMAPPINGFAILURE && fm.lfDestFont.lfWidth)
  1276.             {
  1277.                 fm.lfDestFont.lfWidth = 0; // To recover non-scalable font
  1278.                 hr = VerifyFaceMap(fm);
  1279.             }
  1280.             else
  1281.             {
  1282.                 hr = hrTemp;
  1283.             }
  1284.         }
  1285.         if (hr != MLSTR_E_FACEMAPPINGFAILURE)
  1286.             break;
  1287.     }
  1288.     return hr;
  1289. }
  1290.     
  1291. int CALLBACK CMLFLink::MapFontEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD, LPARAM lParam)
  1292. {
  1293.     LOGFONT* plfDestFont = (LOGFONT*)lParam;
  1294.     
  1295.     if (!plfDestFont->lfFaceName[0] )
  1296.     {
  1297.         if (plfDestFont->lfCharSet != DEFAULT_CHARSET)
  1298.         {
  1299.             if (plfDestFont->lfCharSet == plfFont->lfCharSet)
  1300.                 *plfDestFont = *plfFont;
  1301.         }
  1302.         else
  1303.               *plfDestFont = *plfFont;
  1304.     }
  1305.     return TRUE;
  1306. }
  1307. HRESULT CMLFLink::GetFaceNameRegistry(CFontMappingInfo& fm)
  1308. {
  1309.     static const TCHAR szRootKey[]       = _T("Software\Microsoft\Internet Explorer");
  1310.     static const TCHAR szIntlKey[]       = _T("International\%d");
  1311.     static const TCHAR szPropFontName[]  = _T("IEPropFontName");
  1312.     static const TCHAR szFixedFontName[] = _T("IEFixedFontName");
  1313.     HRESULT hr = S_OK;
  1314.     HKEY hKeyRoot;
  1315.     if (::RegOpenKeyEx(HKEY_CURRENT_USER, szRootKey, 0, KEY_READ, &hKeyRoot) == ERROR_SUCCESS)
  1316.     {
  1317.         TCHAR szCodePageKey[ARRAYSIZE(szIntlKey) + 10];
  1318.         HKEY hKeySub;
  1319.         ::wsprintf(szCodePageKey, szIntlKey, fm.auCodePage[fm.iCP]);
  1320.         if (::RegOpenKeyEx(hKeyRoot, szCodePageKey, 0, KEY_READ, &hKeySub) == ERROR_SUCCESS)
  1321.         {
  1322.             const TCHAR* pszFontNameValue;
  1323.             DWORD dwType;
  1324.             DWORD dwSize = sizeof(fm.szFaceName);
  1325.             if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH)
  1326.                 pszFontNameValue = szFixedFontName;
  1327.             else
  1328.                 pszFontNameValue = szPropFontName;
  1329.             if (::RegQueryValueEx(hKeySub, pszFontNameValue, 0, &dwType, (LPBYTE)fm.szFaceName, &dwSize) != ERROR_SUCCESS)
  1330.                 hr = MLSTR_E_FACEMAPPINGFAILURE;
  1331.             if (::RegCloseKey(hKeySub) != ERROR_SUCCESS && SUCCEEDED(hr))
  1332.                 hr = MLSTR_E_FACEMAPPINGFAILURE;
  1333.         }
  1334.         else
  1335.         {
  1336.             hr = MLSTR_E_FACEMAPPINGFAILURE;
  1337.         }
  1338.         if (::RegCloseKey(hKeyRoot) != ERROR_SUCCESS && SUCCEEDED(hr))
  1339.             hr = MLSTR_E_FACEMAPPINGFAILURE;
  1340.     }
  1341.     else
  1342.     {
  1343.         hr = MLSTR_E_FACEMAPPINGFAILURE;
  1344.     }
  1345.     return hr;
  1346. }
  1347. HRESULT CMLFLink::GetFaceNameGDI(CFontMappingInfo& fm)
  1348. {
  1349.     HRESULT hr = S_OK;
  1350.     for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  1351.     {
  1352.         if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage)
  1353.             break;
  1354.     }
  1355.     if (g_CharSetTransTable[iCharSet].uCodePage)
  1356.     {
  1357.         ::memset(&fm.lfDestFont, 0, sizeof(fm.lfDestFont));
  1358.         // Specify font weight as NORMAL to avoid NT GDI font mapping bugs
  1359.         fm.lfDestFont.lfWeight = FW_NORMAL;
  1360.         fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet;
  1361.         hr = GetFaceNameRealizeFont(fm);
  1362.     }
  1363.     else
  1364.     {
  1365.         hr = E_FAIL; // Unknown code page
  1366.     }
  1367.     if (SUCCEEDED(hr))
  1368.     {
  1369.         // Height, CharSet, Pitch and Family
  1370.         fm.lfDestFont.lfHeight = fm.lfSrcFont.lfHeight;
  1371.         fm.lfDestFont.lfPitchAndFamily = fm.lfSrcFont.lfPitchAndFamily;
  1372.         hr = GetFaceNameRealizeFont(fm);
  1373.         if (FAILED(hr))
  1374.         {
  1375.             // CharSet, Pitch and Family
  1376.             fm.lfDestFont.lfHeight = 0;
  1377.             hr = GetFaceNameRealizeFont(fm);
  1378.         }
  1379.         if (FAILED(hr))
  1380.         {
  1381.             // CharSet and Pitch
  1382.             fm.lfDestFont.lfPitchAndFamily &= 0x03; // Pitch Mask
  1383.             hr = GetFaceNameRealizeFont(fm);
  1384.         }
  1385.         if (FAILED(hr))
  1386.         {
  1387.             // CharSet only
  1388.             fm.lfDestFont.lfPitchAndFamily = 0;
  1389.             hr = GetFaceNameRealizeFont(fm);
  1390.         }
  1391.     }
  1392.     return hr;
  1393. }
  1394. extern void BuildGlobalObjects(void);
  1395. HRESULT CMLFLink::GetFaceNameMIME(CFontMappingInfo& fm)
  1396. {
  1397.     HRESULT hr = E_FAIL;
  1398.     MIMECPINFO cpInfo;    
  1399.     if (fm.auCodePage[fm.iCP] == 936)
  1400.     {
  1401.         MLStrCpyN(fm.szFaceName, TEXT("SimSun"), LF_FACESIZE);
  1402.         return S_OK;
  1403.     }
  1404.     if (!g_pMimeDatabase)
  1405.         BuildGlobalObjects();
  1406.     if (NULL != g_pMimeDatabase)
  1407.     {
  1408.         if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(fm.auCodePage[fm.iCP], 0x409, &cpInfo)))
  1409.         {
  1410.             TCHAR szFontFaceName[LF_FACESIZE];
  1411.             szFontFaceName[0] = 0;
  1412.             if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH && cpInfo.wszFixedWidthFont[0])
  1413.             {
  1414. #ifdef UNICODE
  1415.                 MLStrCpyNW(szFontFaceName, cpInfo.wszFixedWidthFont, LF_FACESIZE);
  1416. #else
  1417.                 WideCharToMultiByte(CP_ACP, 0, cpInfo.wszFixedWidthFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL);
  1418. #endif
  1419.             }
  1420.             else
  1421.                 if (cpInfo.wszProportionalFont[0])
  1422.                 {
  1423. #ifdef UNICODE
  1424.                     MLStrCpyNW(szFontFaceName, cpInfo.wszProportionalFont, LF_FACESIZE);
  1425. #else
  1426.                     WideCharToMultiByte(CP_ACP, 0, cpInfo.wszProportionalFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL);
  1427. #endif
  1428.                 }
  1429.             if (szFontFaceName[0])
  1430.             {
  1431.                 MLStrCpyN(fm.szFaceName, szFontFaceName, LF_FACESIZE);
  1432.                 hr = S_OK;
  1433.             }
  1434.         }
  1435.         else
  1436.             hr = MLSTR_E_FACEMAPPINGFAILURE;
  1437.     }
  1438.     return hr;
  1439. }
  1440. HRESULT CMLFLink::GetFaceNameRealizeFont(CFontMappingInfo& fm)
  1441. {
  1442.     HRESULT hr = S_OK;
  1443.     HFONT hFont = NULL;
  1444.     HFONT hOldFont;
  1445.     DWORD dwFontCodePages;
  1446.     // First let's get a facename based on the given lfDestFont
  1447.     // Then verify if the font of the found facename has the code pages we want.
  1448.     hFont = ::CreateFontIndirect(&fm.lfDestFont);
  1449.     if (!hFont)
  1450.         hr = E_FAIL; // Out of memory or GDI resource
  1451.     if (SUCCEEDED(hr))
  1452.     {
  1453.         hOldFont = (HFONT)::SelectObject(fm.hDC, hFont);
  1454.         if (!hOldFont)
  1455.             hr = E_FAIL; // Out of memory or GDI resource
  1456.     }
  1457.     if (SUCCEEDED(hr))
  1458.     {
  1459.         if (!::GetTextFace(fm.hDC, ARRAYSIZE(fm.szFaceName), fm.szFaceName))
  1460.             hr = E_FAIL; // Out of memory or GDI resource
  1461.         if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr))
  1462.             hr = E_FAIL; // Out of memory or GDI resource
  1463.     }
  1464.     if (hFont)
  1465.         ::DeleteObject(hFont);
  1466.     if (SUCCEEDED(hr))
  1467.     {
  1468.         LOGFONT lfTemp;
  1469.         lfTemp = fm.lfDestFont;
  1470.         _tcsncpy(lfTemp.lfFaceName, fm.szFaceName, ARRAYSIZE(lfTemp.lfFaceName));
  1471.         hFont = ::CreateFontIndirect(&lfTemp);
  1472.         if (!hFont)
  1473.             hr = E_FAIL; // Out of memory or GDI resource
  1474.         if (SUCCEEDED(hr = GetFontCodePages(fm.hDC, hFont, &dwFontCodePages)) && !(dwFontCodePages & fm.adwCodePages[fm.iCP]))
  1475.                 hr = MLSTR_E_FACEMAPPINGFAILURE;
  1476.         if (hFont)
  1477.             ::DeleteObject(hFont);
  1478.     }
  1479.     return hr;
  1480. }
  1481. HRESULT CMLFLink::VerifyFaceMap(CFontMappingInfo& fm)
  1482. {
  1483.     HRESULT hr = S_OK;
  1484.     HFONT hOldFont;
  1485.     if (fm.hDestFont)
  1486.         ::DeleteObject(fm.hDestFont);
  1487.     fm.hDestFont = ::CreateFontIndirect(&fm.lfDestFont);
  1488.     if (!fm.hDestFont)
  1489.         hr = E_FAIL; // Out of memory or GDI resource
  1490.     if (SUCCEEDED(hr))
  1491.     {
  1492.         hOldFont = (HFONT)::SelectObject(fm.hDC, fm.hDestFont);
  1493.         if (!hOldFont)
  1494.             hr = E_FAIL; // Out of memory or GDI resource
  1495.     }
  1496.     if (SUCCEEDED(hr))
  1497.     {
  1498.         TCHAR szFaceName[LF_FACESIZE];
  1499.         if (!::GetTextFace(fm.hDC, ARRAYSIZE(szFaceName), szFaceName))
  1500.             hr = E_FAIL; // Out of memory or GDI resource
  1501.         if (SUCCEEDED(hr))
  1502.         {
  1503.             int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, fm.lfDestFont.lfFaceName, -1, szFaceName, -1);
  1504.             if (!nRet)
  1505.                 hr = E_FAIL; // Unexpected error
  1506.             else if (nRet != 2) // Not Equal
  1507.                 hr = MLSTR_E_FACEMAPPINGFAILURE;
  1508.         }
  1509.         if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr))
  1510.             hr = E_FAIL; // Out of memory or GDI resource
  1511.     }
  1512.     return hr;
  1513. }
  1514. /////////////////////////////////////////////////////////////////////////////
  1515. // CMLFLink::CFontMappingCache
  1516. CMLFLink::CFontMappingCache::CFontMappingCache(void) :
  1517.     m_pEntries(NULL),
  1518.     m_pFree(NULL),
  1519.     m_cEntries(0)
  1520. {
  1521.     ::InitializeCriticalSection(&m_cs);
  1522. }
  1523. CMLFLink::CFontMappingCache::~CFontMappingCache(void)
  1524. {
  1525.     FlushEntries();
  1526.     DeleteCriticalSection(&m_cs);
  1527. }
  1528. HRESULT CMLFLink::CFontMappingCache::FindEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT* phDestFont)
  1529. {
  1530.     HRESULT hr = S_FALSE;
  1531.     ::EnterCriticalSection(&m_cs);
  1532.     if (m_pEntries)
  1533.     {
  1534.         CFontMappingCacheEntry* pEntry = m_pEntries;
  1535.         while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1536.         {
  1537.             if (uCodePage == pEntry->m_uSrcCodePage &&
  1538.                 lfSrcFont.lfPitchAndFamily == pEntry->m_bSrcPitchAndFamily &&
  1539.                 lfSrcFont.lfHeight == pEntry->m_lSrcHeight &&
  1540.                 lfSrcFont.lfWidth == pEntry->m_lSrcWidth &&
  1541.                 lfSrcFont.lfEscapement == pEntry->m_lSrcEscapement &&
  1542.                 lfSrcFont.lfOrientation == pEntry->m_lSrcOrientation &&
  1543.                 lfSrcFont.lfWeight == pEntry->m_lSrcWeight &&
  1544.                 lfSrcFont.lfItalic == pEntry->m_bSrcItalic &&
  1545.                 lfSrcFont.lfUnderline == pEntry->m_bSrcUnderline &&
  1546.                 lfSrcFont.lfStrikeOut == pEntry->m_bSrcStrikeOut)
  1547.             {
  1548.                 int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfSrcFont.lfFaceName, -1, pEntry->m_szSrcFaceName, -1);
  1549.                 if (!nRet)
  1550.                 {
  1551.                     hr = E_FAIL; // Unexpected error
  1552.                     break;
  1553.                 }
  1554.                 else if (nRet == 2) // Equal
  1555.                 {
  1556.                     if (phDestFont)
  1557.                         *phDestFont = pEntry->m_hDestFont;
  1558.                     pEntry->m_nLockCount++;
  1559.                     hr = S_OK;
  1560.                     break;
  1561.                 }
  1562.             }
  1563.         }
  1564.     }
  1565.     ::LeaveCriticalSection(&m_cs);
  1566.     if (phDestFont && hr != S_OK)
  1567.         *phDestFont = NULL;
  1568.     return hr;
  1569. }
  1570. HRESULT CMLFLink::CFontMappingCache::UnlockEntry(HFONT hDestFont)
  1571. {
  1572.     HRESULT hr = E_FAIL; // hDestFont is not found in the cache
  1573.     ::EnterCriticalSection(&m_cs);
  1574.     if (m_pEntries)
  1575.     {
  1576.         CFontMappingCacheEntry* pEntry = m_pEntries;
  1577.         while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1578.         {
  1579.             if (hDestFont == pEntry->m_hDestFont)
  1580.             {
  1581.                 if (pEntry->m_nLockCount - 1 >= 0)
  1582.                 {
  1583.                     pEntry->m_nLockCount--;
  1584.                     hr = S_OK;
  1585.                 }
  1586.                 break;
  1587.             }
  1588.         }
  1589.     }
  1590.     ::LeaveCriticalSection(&m_cs);
  1591.     return hr;
  1592. }
  1593. HRESULT CMLFLink::CFontMappingCache::AddEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT hDestFont)
  1594. {
  1595.     HRESULT hr = S_OK;
  1596.     ::EnterCriticalSection(&m_cs);
  1597.     if (!m_pEntries) // Need to allocate all the entries
  1598.     {
  1599.         CFontMappingCacheEntry* pEntries;
  1600.         pEntries = new CFontMappingCacheEntry[NUMFONTMAPENTRIES + 1]; // +1 for sentinel
  1601.         if (pEntries)
  1602.         {
  1603.             // Init sentinel
  1604.             pEntries[0].m_pPrev = &pEntries[0];
  1605.             pEntries[0].m_pNext = &pEntries[0];
  1606.             // Init free entries
  1607.             for (int n = 0; n < NUMFONTMAPENTRIES; n++)
  1608.             {
  1609.                 const nEnt = n + 1; // + 1 for sentinel
  1610.                 if (n < NUMFONTMAPENTRIES - 1)
  1611.                     pEntries[nEnt].m_pNext = &pEntries[nEnt + 1];
  1612.                 else
  1613.                     pEntries[nEnt].m_pNext = NULL;
  1614.             }
  1615.             m_pEntries = &pEntries[0];
  1616.             m_pFree = &pEntries[1];
  1617.         }
  1618.         else
  1619.         {
  1620.             hr = E_OUTOFMEMORY;
  1621.         }
  1622.     }
  1623.     if (SUCCEEDED(hr) && !m_pFree) // Need to delete oldest entry
  1624.     {
  1625.         CFontMappingCacheEntry* pOldestEntry = m_pEntries->m_pPrev;
  1626.         while (pOldestEntry->m_nLockCount > 0 && pOldestEntry != m_pEntries) // Entry is locked
  1627.             pOldestEntry = pOldestEntry->m_pPrev;
  1628.         if (pOldestEntry != m_pEntries)
  1629.         {
  1630.             if (pOldestEntry->m_hDestFont)
  1631.                 ::DeleteObject(pOldestEntry->m_hDestFont);
  1632.             // Delete it from m_pEntries list
  1633.             pOldestEntry->m_pPrev->m_pNext = pOldestEntry->m_pNext;
  1634.             pOldestEntry->m_pNext->m_pPrev = pOldestEntry->m_pPrev;
  1635.             // Insert it into m_pFree list
  1636.             pOldestEntry->m_pNext = m_pFree;
  1637.             m_pFree = pOldestEntry;
  1638.         }
  1639.         else // No entry available
  1640.         {
  1641.             hr = E_FAIL; // Out of cache entries
  1642.         }
  1643.     }
  1644.     if (SUCCEEDED(hr)) // Create new entry and fill it
  1645.     {
  1646.         CFontMappingCacheEntry* pNewEntry;
  1647.         // Delete it from m_pFree list
  1648.         pNewEntry = m_pFree; // shouldn't be NULL
  1649.         m_pFree = pNewEntry->m_pNext;
  1650.         // Insert it into m_pEntries list
  1651.         pNewEntry->m_pNext = m_pEntries->m_pNext;
  1652.         pNewEntry->m_pPrev = m_pEntries;
  1653.         m_pEntries->m_pNext->m_pPrev = pNewEntry;
  1654.         m_pEntries->m_pNext = pNewEntry;
  1655.         // Fill it
  1656.         pNewEntry->m_nLockCount = 1;
  1657.         pNewEntry->m_uSrcCodePage = uCodePage;
  1658.         pNewEntry->m_lSrcHeight = lfSrcFont.lfHeight;
  1659.         pNewEntry->m_lSrcWidth = lfSrcFont.lfWidth;
  1660.         pNewEntry->m_lSrcEscapement = lfSrcFont.lfEscapement;
  1661.         pNewEntry->m_lSrcOrientation = lfSrcFont.lfOrientation;
  1662.         pNewEntry->m_lSrcWeight = lfSrcFont.lfWeight;
  1663.         pNewEntry->m_bSrcItalic = lfSrcFont.lfItalic;
  1664.         pNewEntry->m_bSrcUnderline = lfSrcFont.lfUnderline;
  1665.         pNewEntry->m_bSrcStrikeOut = lfSrcFont.lfStrikeOut;
  1666.         pNewEntry->m_bSrcPitchAndFamily = lfSrcFont.lfPitchAndFamily;
  1667.         _tcsncpy(pNewEntry->m_szSrcFaceName, lfSrcFont.lfFaceName, ARRAYSIZE(pNewEntry->m_szSrcFaceName));
  1668.         pNewEntry->m_hDestFont = hDestFont;
  1669.     }
  1670.     ::LeaveCriticalSection(&m_cs);
  1671.     return hr;
  1672. }
  1673. HRESULT CMLFLink::CFontMappingCache::FlushEntries(void)
  1674. {
  1675.     ::EnterCriticalSection(&m_cs);
  1676.     if (m_pEntries)
  1677.     {
  1678.         CFontMappingCacheEntry* pEntry = m_pEntries;
  1679.         while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1680.         {
  1681.             if (pEntry->m_hDestFont)
  1682.                 ::DeleteObject(pEntry->m_hDestFont);
  1683.         }
  1684.         delete[] m_pEntries;
  1685.         m_pEntries = NULL;
  1686.         m_cEntries = 0;
  1687.     }
  1688.     ::LeaveCriticalSection(&m_cs);
  1689.     return S_OK;
  1690. }
  1691. /////////////////////////////////////////////////////////////////////////////
  1692. // CMLFLink::CCodePagesCache
  1693. CMLFLink::CCodePagesCache::CCodePagesCache(void) :
  1694.     m_pbBuf(NULL)
  1695. {
  1696.     ::InitializeCriticalSection(&m_cs);
  1697. }
  1698. CMLFLink::CCodePagesCache::~CCodePagesCache(void)
  1699. {
  1700.     DeleteCriticalSection(&m_cs);
  1701. }
  1702. HRESULT CMLFLink::CCodePagesCache::RealLoad(void)
  1703. {
  1704.     HRESULT hr = S_OK;
  1705.     ::EnterCriticalSection(&m_cs);
  1706.     if (!m_pbBuf)
  1707.     {
  1708.         HRSRC hrCodePages;
  1709.         HGLOBAL hgCodePages;
  1710.         if (SUCCEEDED(hr))
  1711.         {
  1712.             hrCodePages = ::FindResource(g_hInst, MAKEINTRESOURCE(IDR_CODEPAGES), _T("CODEPAGES"));
  1713.             if (!hrCodePages)
  1714.                 hr = E_FAIL; // Build error?
  1715.         }
  1716.         if (SUCCEEDED(hr))
  1717.         {
  1718.             hgCodePages = ::LoadResource(g_hInst, hrCodePages);
  1719.             if (!hgCodePages)
  1720.                 hr = E_FAIL; // Unexpected error
  1721.         }
  1722.         if (SUCCEEDED(hr))
  1723.         {
  1724.             m_pbBuf = (BYTE*)::LockResource(hgCodePages);
  1725.             if (!m_pbBuf)
  1726.                 hr = E_FAIL; // Unexpected error
  1727.         }
  1728.     }
  1729.     ::LeaveCriticalSection(&m_cs);
  1730.     return hr;
  1731. }
  1732. extern "C" HRESULT GetGlobalFontLinkObject(IMLangFontLink **ppMLFontLink)
  1733. {
  1734.     HRESULT hr = E_INVALIDARG;
  1735.     if (NULL != ppMLFontLink)
  1736.     {
  1737.         if (NULL == g_pMLFLink)
  1738.         {
  1739.             EnterCriticalSection(&g_cs);
  1740.             if (NULL == g_pMLFLink)
  1741.                 CComCreator< CComPolyObject< CMLFLink > >::CreateInstance(NULL, IID_IMLangFontLink, (void **)&g_pMLFLink);
  1742.             LeaveCriticalSection(&g_cs);
  1743.         }
  1744.         *ppMLFontLink = g_pMLFLink;
  1745.         if (g_pMLFLink)
  1746.         {
  1747.             g_pMLFLink->AddRef();
  1748.             hr = S_OK;
  1749.         }
  1750.         else
  1751.             hr = E_FAIL;
  1752.     }
  1753.     return hr;
  1754. }
  1755. HRESULT CMLFLink2::CFontMappingCache2::MapFontFromCMAP(HDC hDC, WCHAR wchar, HFONT hSrcFont, HFONT *phDestFont)
  1756. {
  1757.     BOOL    bFont = FALSE;
  1758.     HRESULT hr = E_FAIL;
  1759.     int     i,j,k;
  1760.     LOGFONT LogFont;
  1761.     if (!phDestFont)
  1762.         return E_INVALIDARG;
  1763.     if (!GetObject(hSrcFont, sizeof(LOGFONT), &LogFont))
  1764.         return hr;
  1765.     if (!g_pfont_table || !g_pfont_table[0].szFaceName[0])
  1766.     {        
  1767.         if (FAILED(LoadFontDataFile()))
  1768.         {
  1769.             return hr;
  1770.         }
  1771.     }
  1772.     i=0;
  1773.     j=ARRAYSIZE(g_urange_table);
  1774.     k = j/2;
  1775.     while (i<=j)
  1776.     {
  1777.         if (wchar >= g_urange_table[k].wcFrom && wchar <= g_urange_table[k].wcTo)
  1778.            break;
  1779.         else
  1780.            if (wchar < g_urange_table[k].wcFrom)
  1781.            {
  1782.                j = k -1;
  1783.            }
  1784.            else
  1785.            {
  1786.                i = k + 1;
  1787.            }
  1788.            k = (i+j)/2;
  1789.     }
  1790.     if (i<=j && g_urange_table[k].nFonts)
  1791.     {
  1792.         TCHAR szFaceName[LF_FACESIZE];
  1793.         GetTextFace(hDC, LF_FACESIZE, szFaceName);
  1794.         // Check if it supports the character
  1795.         for (i=0; i<g_urange_table[k].nFonts; i++)
  1796.         {
  1797.             if (!MLStrCmpI(szFaceName,g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName))
  1798.                 break;
  1799.         }
  1800.         // Current font doesn't support this character
  1801.         if (i == g_urange_table[k].nFonts)
  1802.         {
  1803.             for (i=0; i<g_urange_table[k].nFonts; i++)
  1804.             {
  1805.                 if (LogFont.lfCharSet == g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfCharSet)
  1806.                     break;
  1807.             }
  1808.             // No font available for current CharSet, then return the first one in the list            
  1809.             if (i >= g_urange_table[k].nFonts)
  1810.             {
  1811.                 i = fetchCharSet((BYTE *) &(LogFont.lfCharSet), k);
  1812.             }
  1813.             MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE);
  1814.         }
  1815.         if (i < g_urange_table[k].nFonts)
  1816.         {
  1817.             MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE);
  1818.         }
  1819.         
  1820.         bFont = TRUE;
  1821.     } 
  1822.     if (bFont && (*phDestFont = CreateFontIndirect(&LogFont)))
  1823.     {
  1824.         hr = S_OK;       
  1825.     }
  1826.     else
  1827.     {
  1828.         *phDestFont = NULL;
  1829.     }
  1830.     return hr;
  1831. }
  1832. HRESULT CMLFLink2::CFontMappingCache2::UnicodeRanges(
  1833.     LPTSTR  szFont,
  1834.     UINT    *puiRanges, 
  1835.     UNICODERANGE* pURanges
  1836.     )
  1837. {
  1838.     HRESULT hr = E_FAIL;
  1839.     UINT    nURange = 0;
  1840.     DWORD   cmap    = 0;
  1841.     DWORD   name    = 0;
  1842.     HANDLE  hTTF;    
  1843.     TCHAR   szFontPath[MAX_PATH];
  1844.     static TCHAR s_szFontDir[MAX_PATH] = {0};
  1845.     HANDLE  hTTFMap;
  1846.     DWORD   dwFileSize;
  1847.     LPVOID  lpvFile;
  1848.     LPBYTE  lp, lp1, lp2;
  1849.     DWORD   Num;
  1850.     WORD    i, j, Len;
  1851.     if (!s_szFontDir[0])
  1852.     {
  1853.         MLGetWindowsDirectory(s_szFontDir, MAX_PATH);
  1854.         MLPathCombine(s_szFontDir, s_szFontDir, FONT_FOLDER);
  1855.     }
  1856.     MLPathCombine(szFontPath, s_szFontDir, szFont);
  1857.     hTTF = CreateFile(  szFontPath,             // pointer to name of the file
  1858.                         GENERIC_READ,           // access (read-write) mode
  1859.                         FILE_SHARE_READ,        // share mode
  1860.                         NULL,                   // pointer to security attributes
  1861.                         OPEN_EXISTING,          // how to create
  1862.                         FILE_ATTRIBUTE_NORMAL,  // file attributes
  1863.                         NULL);                  // handle to file with attributes to copy;
  1864.     if (INVALID_HANDLE_VALUE == hTTF)
  1865.         return hr;
  1866.     dwFileSize = GetFileSize(hTTF, NULL);
  1867.     hTTFMap = CreateFileMapping(
  1868.                   hTTF,
  1869.                   NULL,
  1870.                   PAGE_READONLY,
  1871.                   0,
  1872.                   dwFileSize,
  1873.                   NULL
  1874.               );
  1875.     if(hTTFMap == NULL)
  1876.     {
  1877.         goto CloseHandle0;
  1878.     }
  1879.     lpvFile = MapViewOfFile(
  1880.                   hTTFMap,
  1881.                   FILE_MAP_READ,
  1882.                   0,
  1883.                   0,
  1884.                   0
  1885.               );
  1886.     if(lpvFile == NULL)
  1887.     {
  1888.         goto CloseHandle;
  1889.     }
  1890.     lp = (LPBYTE)lpvFile;
  1891.     // Font table name uses ASCII
  1892.     if(strncmp(((TTC_HEAD*)lp)->TTCTag, "ttcf", 4) == 0)   // TTC format
  1893.     {
  1894.         lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1);  // points to first TTF
  1895.     }
  1896.     Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables);        // Number of Tables
  1897.     lp += sizeof(TTF_HEAD);
  1898.     for(i = 0; i < Num; i++)   // go thru all tables to find cmap and name
  1899.     {
  1900.         if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0)
  1901.         {
  1902.             cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  1903.             if (name) break;
  1904.         }
  1905.         else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0)
  1906.         {
  1907.             name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  1908.             if (cmap) break;
  1909.         }
  1910.         lp += sizeof(TABLE_DIR);
  1911.      }
  1912.     if((!cmap) || (!name))    // Can't find cmap or name
  1913.     {
  1914.         goto CloseHandle;
  1915.     }
  1916.     // Read thru all name records
  1917.     // to see if font subfamily name is "Regular"
  1918.     lp  = (LPBYTE)lpvFile + name;                   // point to name table
  1919.     Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec);  // # of name record
  1920.     lp1 = lp  + sizeof(NAME_TABLE);                 // point to name record
  1921.     for(i = 0; i < Num; i++)
  1922.     {
  1923.         if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID))
  1924.         {
  1925.             lp2 = lp +                              // point to string store
  1926.                   TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) +
  1927.                   TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset);
  1928.             Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length);
  1929.             if(((MICROSOFT_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) && 
  1930.                 (UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding)))  ||
  1931.                ((APPLE_UNICODE_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) && 
  1932.                 (APPLE_UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))))  
  1933.             {
  1934.                 Len >>= 1;
  1935.                 const char *pStr = szRegular;
  1936.                 if (Len == sizeof(szNormal) -1)
  1937.                     pStr = szNormal;
  1938.                 else 
  1939.                     if (Len != sizeof(szRegular)-1)
  1940.                     {
  1941.                         lp1 += sizeof(NAME_RECORD);
  1942.                         continue;
  1943.                     }
  1944.                 while(--Len > 0)
  1945.                 {
  1946.                     if(*(lp2+(Len<<1)+1) != pStr[Len])
  1947.                     break;
  1948.                 }
  1949.                 if (!Len)
  1950.                     break;
  1951.                 else
  1952.                 {
  1953.                     lp1 += sizeof(NAME_RECORD);
  1954.                     continue;
  1955.                 }
  1956.             }
  1957.             else
  1958.             {
  1959.                 if(strncmp((char*)lp2, szRegular, sizeof(szRegular)-1) != 0 && 
  1960.                    strncmp((char*)lp2, szNormal, sizeof(szNormal)-1) != 0)
  1961.                 {
  1962.                     lp1 += sizeof(NAME_RECORD);
  1963.                     continue;
  1964.                 }
  1965.                 else
  1966.                     break;
  1967.             }
  1968.         }
  1969.         lp1 += sizeof(NAME_RECORD);
  1970.     }
  1971.     // If no regular font, exit
  1972.     if (i == Num)
  1973.         goto CloseHandle;
  1974.     // all non-regular fonts have already been eliminated
  1975.     lp1  = (LPBYTE)lpvFile + cmap;                     // point to cmap table
  1976.     Num  = TWO_BYTE_NUM(((CMAP_HEAD*)lp1)->NumTables);
  1977.     lp1 += sizeof(CMAP_HEAD);
  1978.     while(Num >0)
  1979.     {
  1980.         if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM && 
  1981.            (TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING ||
  1982.            TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_SYMBOL_INDEXING))
  1983.         {
  1984.             lp = (LPBYTE)lpvFile
  1985.                  + cmap
  1986.                  + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset);
  1987.             if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR)
  1988.             {
  1989.                 break;
  1990.             }
  1991.         }
  1992.         Num--;
  1993.         lp1 += sizeof(CMAP_TABLE);
  1994.     }
  1995.     if(Num == 0)                            // can't find Platform:3/Encoding:1 (Unicode)
  1996.         goto CloseHandle;
  1997.     Num  = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2);
  1998.     lp2  = lp  + sizeof(CMAP_FORMAT);       // lp2 -> first WCHAR of wcTo
  1999.     lp1  = lp2 + Num + 2;                   // lp1 -> first WCHAR of wcFrom
  2000.     Num /= 2;
  2001.     if (pURanges == NULL)
  2002.     {
  2003.         *puiRanges = Num;
  2004.     }
  2005.     else
  2006.     {
  2007.         if (Num > *puiRanges)
  2008.             Num = *puiRanges;
  2009.         else
  2010.             *puiRanges = Num;
  2011.         for(i=0, j=0; i < Num; i++, j++, j++)
  2012.         {
  2013.             pURanges[i].wcFrom = TWO_BYTE_NUM((lp1+j));
  2014.             pURanges[i].wcTo   = TWO_BYTE_NUM((lp2+j));
  2015.         }
  2016.     }
  2017.     hr = S_OK;
  2018. CloseHandle:
  2019.     UnmapViewOfFile(lpvFile);
  2020. CloseHandle0:
  2021.     CloseHandle(hTTFMap);
  2022.     CloseHandle(hTTF);
  2023.     return hr;
  2024. }
  2025. int CMLFLink2::CFontMappingCache2::fetchCharSet(BYTE *pCharset, int iURange)
  2026. {
  2027.     int i,j;
  2028.     //Check if current charset valid for the font
  2029.     for (i=0; i<g_urange_table[iURange].nFonts; i++)
  2030.     {
  2031.         for (j=0;(j<32) && g_CharSetTransTable[j].uCodePage;j++)
  2032.         {
  2033.             if (g_pfont_table[*(g_urange_table[iURange].pFontIndex+i)].dwCodePages[0] & g_CharSetTransTable[j].dwCodePages)
  2034.                 if (*pCharset == g_CharSetTransTable[j].nCharSet)
  2035.                     return i;
  2036.         }
  2037.     }
  2038.     //If invalid, fetch first valid one.
  2039.     for (i=0;(i<32) && g_CharSetTransTable[i].uCodePage;i++)
  2040.     {
  2041.         if (g_pfont_table[*(g_urange_table[iURange].pFontIndex)].dwCodePages[0] & g_CharSetTransTable[i].dwCodePages)
  2042.         {
  2043.            *pCharset = (BYTE)g_CharSetTransTable[i].nCharSet;
  2044.            break;
  2045.         }
  2046.     }
  2047.     return 0;
  2048. }
  2049. BOOL CMLFLink2::CFontMappingCache2::GetNonCpFontUnicodeRanges(TCHAR *szFontName, int iFontIndex)
  2050. {
  2051.     LONG    nURange = 0;
  2052.     DWORD   cmap    = 0;
  2053.     DWORD   name    = 0;
  2054.     DWORD   os2     = 0;
  2055.     HANDLE  hTTFMap;
  2056.     DWORD   dwFileSize;
  2057.     LPVOID  lpvFile;
  2058.     LPBYTE  lp, lp1, lp2;
  2059.     DWORD   Num;
  2060.     int     i, j, k, m;
  2061.     WORD    Len;
  2062.     HANDLE  hTTF;
  2063.     BOOL    bRet = FALSE;
  2064.     hTTF = CreateFile(  szFontName,             // pointer to name of the file
  2065.                         GENERIC_READ,           // access (read-write) mode
  2066.                         FILE_SHARE_READ,        // share mode
  2067.                         NULL,                   // pointer to security attributes
  2068.                         OPEN_EXISTING,          // how to create
  2069.                         FILE_ATTRIBUTE_NORMAL,  // file attributes
  2070.                         NULL);                  // handle to file with attributes to copy;
  2071.     if (hTTF == INVALID_HANDLE_VALUE)
  2072.         return FALSE;
  2073.     dwFileSize = GetFileSize(hTTF, NULL);
  2074.     hTTFMap = CreateFileMapping(
  2075.                   hTTF,
  2076.                   NULL,
  2077.                   PAGE_READONLY,
  2078.                   0,
  2079.                   dwFileSize,
  2080.                   NULL
  2081.               );
  2082.     if(hTTFMap == NULL)
  2083.     {
  2084.         goto CloseHandle01;
  2085.     }
  2086.     lpvFile = MapViewOfFile(
  2087.                   hTTFMap,
  2088.                   FILE_MAP_READ,
  2089.                   0,
  2090.                   0,
  2091.                   0
  2092.               );
  2093.     if(lpvFile == NULL)
  2094.     {
  2095.         goto CloseHandle00;
  2096.     }
  2097.     lp = (LPBYTE)lpvFile;
  2098.     if(strncmp(((TTC_HEAD*)lp)->TTCTag, "ttcf", 4) == 0)   // TTC format
  2099.     {
  2100.         lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1);  // points to first TTF
  2101.     }
  2102.     Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables);        // Number of Tables
  2103.     {
  2104.       // if SearchRange != (Maximum power of 2 <= Num)*16,
  2105.       // then this is not a TTF file
  2106.       DWORD  wTmp = 1;
  2107.       while(wTmp <= Num)
  2108.       {
  2109.         wTmp <<= 1;
  2110.       }
  2111.       wTmp <<= 3;          // (wTmp/2)*16
  2112.       if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->SearchRange))
  2113.       {
  2114.         goto CloseHandle00;
  2115.       }
  2116.       // if RangeShift != (Num*16) - SearchRange,
  2117.       // then this is not a TTF file
  2118.       wTmp = (Num<<4) - wTmp;
  2119.       if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->RangeShift))
  2120.       {
  2121.         goto CloseHandle00;
  2122.       }
  2123.     }
  2124.     lp += sizeof(TTF_HEAD);
  2125.     for(i = 0; i < (int)Num; i++)   // go thru all tables to find cmap and name
  2126.     {
  2127.         if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0)
  2128.         {
  2129.             cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2130.             if (name && os2) break;
  2131.         }
  2132.         else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0)
  2133.         {
  2134.             name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2135.             if (cmap && os2) break;
  2136.         }
  2137.         else if(strncmp( ((TABLE_DIR*)lp)->Tag, "OS/2", 4) == 0)
  2138.         {
  2139.             os2 = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2140.             if (cmap && name) break;
  2141.         }
  2142.         lp += sizeof(TABLE_DIR);
  2143.      }
  2144.     if((!cmap) || (!name) || (!os2))    // Can't find cmap or name
  2145.     {
  2146.         goto CloseHandle00;
  2147.     }
  2148.     // Read thru all name records
  2149.     // to see if font subfamily name is "Regular"
  2150.     lp  = (LPBYTE)lpvFile + name;                   // point to name table
  2151.     Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec);  // # of name record
  2152.     lp1 = lp  + sizeof(NAME_TABLE);                 // point to name record
  2153.     for(i = 0; i < (int)Num; i++)
  2154.     {
  2155.         if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID))
  2156.         {
  2157.             lp2 = lp +                              // point to string store
  2158.                   TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) +
  2159.                   TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset);
  2160.             Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length);
  2161.             if(UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))
  2162.             {
  2163.                 Len >>= 1;
  2164.                 while(--Len > 0)
  2165.                 {
  2166.                     if(*(lp2+(Len<<1)+1) != szRegular[Len])
  2167.                     goto CloseHandle00;
  2168.                 }
  2169.                 break;
  2170.             }
  2171.             else
  2172.             {
  2173.                 if(strncmp((char*)lp2, szRegular, Len) != 0)
  2174.                     goto CloseHandle00;
  2175.                 else
  2176.                     break;
  2177.             }
  2178.         } 
  2179.         lp1 += sizeof(NAME_RECORD);
  2180.     }
  2181.     // all non-regular fonts have already been eliminated
  2182.     lp1  = (LPBYTE)lpvFile + cmap;                     // point to cmap table
  2183.     Num  = TWO_BYTE_NUM(((CMAP_HEAD*)lp)->NumTables);
  2184.     lp1 += sizeof(CMAP_HEAD);
  2185.     while(Num >0)
  2186.     {
  2187.         if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM && 
  2188.            TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING)
  2189.         {
  2190.             lp = (LPBYTE)lpvFile
  2191.                  + cmap
  2192.                  + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset);
  2193.             if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR)
  2194.             {
  2195.                 break;
  2196.             }
  2197.         }
  2198.         Num--;
  2199.         lp1 += sizeof(CMAP_TABLE);
  2200.     }
  2201.     if(Num == 0)                   // can't find Platform:3/Encoding:1 (Unicode)
  2202.         goto CloseHandle00;
  2203.     Num  = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2) ;
  2204.     m = ARRAYSIZE(g_urange_table);
  2205.     lp2  = lp  + sizeof(CMAP_FORMAT);     // lp2 -> first WCHAR of wcTo
  2206.     lp1  = lp2 + Num + 2;                 // lp1 -> first WCHAR of wcFrom
  2207.     // Fast parse !!!
  2208.     while (--m)
  2209.     {
  2210.         // URANGE binary search
  2211.         i=0;
  2212.         j= (int) Num - 2;
  2213.         k=j/2;
  2214.         while (i<=j)
  2215.         {
  2216.             if (k % 2) 
  2217.                 k++;
  2218.             if (g_urange_table[m].wcFrom >= TWO_BYTE_NUM((lp1+k)) && g_urange_table[m].wcTo <= TWO_BYTE_NUM((lp2+k)))
  2219.             {
  2220.                 EnterCriticalSection(&g_cs);
  2221.                 if (!g_urange_table[m].pFontIndex)
  2222.                     g_urange_table[m].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)* MAX_FONT_INDEX);
  2223.                 if (!g_urange_table[m].pFontIndex)
  2224.                 {
  2225.                     goto CloseHandle00;
  2226.                 }
  2227.                 if (g_urange_table[m].nFonts >= MAX_FONT_INDEX)
  2228.                 {
  2229.                     break;
  2230.                 }
  2231.                 g_urange_table[m].pFontIndex[g_urange_table[m].nFonts] = iFontIndex;
  2232.                 g_urange_table[m].nFonts++;
  2233.                 // Fill in font code page signature
  2234.                 g_pfont_table[iFontIndex].dwCodePages[0] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE));
  2235.                 g_pfont_table[iFontIndex].dwCodePages[1] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE+1));                
  2236.                 LeaveCriticalSection(&g_cs);
  2237.                 break;
  2238.             }
  2239.             else
  2240.             {
  2241.                 if (g_urange_table[m].wcFrom < TWO_BYTE_NUM((lp1+k)))
  2242.                 {
  2243.                     j = k-2;
  2244.                 }
  2245.                 else
  2246.                 {
  2247.                     i = k+2;
  2248.                 }
  2249.                 k = (i+j)/2;
  2250.             }
  2251.         }
  2252.     }
  2253.     
  2254.     bRet = TRUE;
  2255. CloseHandle00:
  2256.     UnmapViewOfFile(lpvFile);
  2257. CloseHandle01:
  2258.     CloseHandle(hTTF);
  2259.     CloseHandle(hTTFMap);
  2260.     return bRet;
  2261. }
  2262. HRESULT GetRegFontKey(HKEY *phKey, DWORD *pdwValues)
  2263. {
  2264.     HRESULT hr = E_FAIL;
  2265.     if (ERROR_SUCCESS == (g_bIsNT? 
  2266.         RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEYNT, 0, KEY_READ, phKey):
  2267.         RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEY95, 0, KEY_READ, phKey)))
  2268.     {
  2269.         if (ERROR_SUCCESS == RegQueryInfoKey(*phKey, NULL, NULL, 0, NULL, 
  2270.             NULL, NULL, pdwValues, NULL, NULL, NULL, NULL))
  2271.         {
  2272.             hr = S_OK;
  2273.         }        
  2274.     }
  2275.     return hr;
  2276. }
  2277. BOOL CMLFLink2::CFontMappingCache2::GetFontURangeBits(TCHAR *szFontFile, DWORD * pdwURange)
  2278. {
  2279.     // We can make use of font Unicode range signature if needed.
  2280.     return TRUE;    
  2281. }
  2282. BOOL CMLFLink2::CFontMappingCache2::SetFontScripts(void)
  2283. {
  2284.     LOGFONT lf;
  2285.     int     i,j;
  2286.     HWND    hWnd = GetTopWindow(GetDesktopWindow());
  2287.     HDC     hDC = GetDC(hWnd);
  2288.     if (!g_pfont_table)
  2289.         return FALSE;
  2290.     // Process code page based scripts (g_CharSetTransTable.sid)
  2291.     for (i = 0; g_CharSetTransTable[i].nCharSet != DEFAULT_CHARSET; i++)
  2292.     {
  2293.         j = 0;
  2294.         ZeroMemory(&lf, sizeof(lf));
  2295.         lf.lfCharSet = (BYTE)g_CharSetTransTable[i].nCharSet;
  2296.         while (g_CharSetTransTable[i].sid[j] != sidDefault)
  2297.         {
  2298.             EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)SetFontScriptsEnumFontProc, (LPARAM)g_CharSetTransTable[i].sid[j], 0);
  2299.             j++;
  2300.         }
  2301.     }
  2302.     if (hDC)
  2303.         ReleaseDC(hWnd, hDC);
  2304.     // Process Unicode subrange based scripts (not implemented)
  2305.     // Skip this part since we need to access font CMAP anyway
  2306.     // Process char based scripts (g_wCharToScript)
  2307.     for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  2308.     {
  2309.         UINT uiRanges = 0;
  2310.         UNICODERANGE* pURanges = NULL;
  2311.         SCRIPT_IDS  scripts;
  2312.         if (SUCCEEDED(m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges)))
  2313.         {
  2314.             if (uiRanges)
  2315.             {
  2316.                 int         l, m, n;                
  2317.                 pURanges = (UNICODERANGE *)LocalAlloc(LPTR, sizeof(UNICODERANGE) * uiRanges);
  2318.                 if (!pURanges)
  2319.                     return E_OUTOFMEMORY;
  2320.                 m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges);
  2321.                 for (j=0; j< ARRAYSIZE(g_wCharToScript); j++)
  2322.                 {
  2323.                     l = 0;
  2324.                     m = uiRanges;
  2325.                     n = m/2;
  2326.                     while (l <= m)
  2327.                     {
  2328.                         if ((g_wCharToScript[j].wch >= pURanges[n].wcFrom) && (g_wCharToScript[j].wch <= pURanges[n].wcTo))
  2329.                         {
  2330.                             scripts = 1;
  2331.                             scripts <<= g_wCharToScript[j].sid;
  2332.                             g_pfont_table[i].scripts |= scripts;
  2333.                             break;
  2334.                         }
  2335.                         else
  2336.                         {
  2337.                             if (g_wCharToScript[j].wch < pURanges[n].wcFrom)
  2338.                                 m = n-1;
  2339.                             else
  2340.                                 l = n+1;
  2341.                             n = (m+l)/2;
  2342.                         }
  2343.                     }
  2344.                 }
  2345.                 LocalFree(pURanges);
  2346.                 pURanges = NULL;
  2347.             }
  2348.         }
  2349.         // sidUserDefined should contain all valid regular TrueType fonts
  2350.         if (!MLStrStr(g_pfont_table[i].szFaceName, TEXT("Bold")) && !MLStrStr(g_pfont_table[i].szFaceName, TEXT("Italic")))
  2351.         {
  2352.             scripts = 1;
  2353.             scripts <<= sidUserDefined;
  2354.             g_pfont_table[i].scripts |= scripts;
  2355.         }
  2356.     }
  2357.     //GetFontScriptFromCMAP(szFont, &(g_pfont_table[i].scripts));
  2358.     return TRUE;
  2359. }
  2360. BOOL CMLFLink2::CFontMappingCache2::IsFontUpdated(void)
  2361. {
  2362.     HKEY    hkey;
  2363.     DWORD   dwFonts = 0;
  2364.     BOOL    bRet = FALSE;
  2365.     if (g_pfont_table)
  2366.     {
  2367.         if (S_OK == GetRegFontKey(&hkey, &dwFonts))
  2368.         {
  2369.             if (g_pfont_table[0].dwCodePages[1] != dwFonts)
  2370.                 bRet = TRUE;
  2371.             RegCloseKey(hkey);
  2372.         }
  2373.     }
  2374.     else
  2375.     {
  2376.         // font table not created yet, need to update
  2377.         bRet = TRUE;
  2378.     }
  2379.     return bRet;
  2380. }
  2381.     
  2382. // Make sure we have font data table available and it is updated
  2383. HRESULT CMLFLink2::CFontMappingCache2::EnsureFontTable(BOOL bUpdateURangeTable)    
  2384. {
  2385.     if (IsFontUpdated())
  2386.     {
  2387.         if (g_pfont_table)
  2388.         {
  2389.             if (g_pfont_table[0].szFaceName[0])
  2390.             {
  2391.                 bUpdateURangeTable = TRUE;
  2392.             }
  2393.             LocalFree(g_pfont_table);
  2394.             g_pfont_table = NULL;
  2395.         }
  2396.         if (!SetFontTable())
  2397.             return E_OUTOFMEMORY;
  2398.         if (bUpdateURangeTable)
  2399.         {
  2400.             for (int i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2401.             {
  2402.                 if (g_urange_table[i].nFonts)
  2403.                 {
  2404.                     LocalFree(g_urange_table[i].pFontIndex);
  2405.                     g_urange_table[i].pFontIndex = NULL;
  2406.                     g_urange_table[i].nFonts = 0;
  2407.                 }            
  2408.             }
  2409.             if (S_OK != SetFontUnicodeRanges())
  2410.                 return E_OUTOFMEMORY;
  2411.             SaveFontDataFile();
  2412.         }
  2413.     }
  2414.     // All tables created successfully
  2415.     return S_OK;
  2416. }
  2417. #ifdef UNIX
  2418. typedef struct tagTable_info{
  2419.     int count;
  2420.     int table_size;
  2421.     } Table_info;
  2422. int UnixGetAllFontsProc(ENUMLOGFONTEX* plfFont, NEWTEXTMETRICEX* lpntm, int iFontType, LPARAM lParam)
  2423. {
  2424.     LOGFONT *lplf;
  2425.     int *pcount = &((Table_info*)lParam)->count;
  2426.     int *ptable_size = &((Table_info*)lParam)->table_size;
  2427.     lplf = &(plfFont->elfLogFont);
  2428.     // We don't use non TrueType fonts
  2429.     if (iFontType == DEVICE_FONTTYPE || iFontType == RASTER_FONTTYPE)
  2430.         return 1;   // keep going but don't use this font
  2431.     // We don't use the SYMBOL, Mac Charset fonts
  2432.     if(lplf->lfCharSet == SYMBOL_CHARSET || lplf->lfCharSet == MAC_CHARSET)
  2433.         return 1;
  2434.     // We don't handle vertical fonts
  2435.     if (TEXT('@') == lplf->lfFaceName[0])
  2436.         return 1;
  2437.     // Now update the font-table
  2438.     // Does UNIX use TTF? // if (FontType == TRUETYPE_FONTTYPE)
  2439.     {
  2440.         CopyMemory(&g_pfont_table[*pcount].lf, lplf, sizeof(LOGFONT));
  2441.         MLStrCpyN(g_pfont_table[*pcount].szFaceName, lplf->lfFaceName, LF_FACESIZE);
  2442.         (*pcount)++;
  2443.     }
  2444.     if (*pcount >= *ptable_size)
  2445.     {
  2446.         FONTINFO * pfont_table = NULL;
  2447.         *ptable_size += FONT_TABLE_INIT_SIZE;
  2448.         pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, 
  2449.                                         sizeof(FONTINFO) * *ptable_size,
  2450.                                         LMEM_MOVEABLE | LMEM_ZEROINIT);
  2451.         if (NULL == pfont_table)
  2452.         {
  2453.             return 0; // Stop enum. 
  2454.         }
  2455.         else
  2456.         {
  2457.             g_pfont_table = pfont_table;
  2458.         }
  2459.     }
  2460.  
  2461.     return 1;       // Keep enum. 
  2462. }
  2463. #endif
  2464. BOOL CMLFLink2::CFontMappingCache2::SetFontTable(void)
  2465. {
  2466.     BOOL    bRet = TRUE;
  2467.     TCHAR   szFaceName[MAX_PATH];
  2468.     DWORD   dwValue;
  2469.     TCHAR   szFontFile[MAX_FONT_FILE_NAME];
  2470.     DWORD   dwData;
  2471.     DWORD   dwType = REG_SZ;
  2472.     DWORD   dwFonts;
  2473.     int     i, table_size = FONT_TABLE_INIT_SIZE;
  2474.     LPTSTR  pNewFaceName = NULL;
  2475.     HKEY    hkey = NULL;
  2476.     static int count;
  2477.     HDC     hDC = NULL;
  2478.     HWND    hWnd = NULL;
  2479.     
  2480.     if (!g_pfont_table)
  2481.     {
  2482.         EnterCriticalSection(&g_cs);
  2483.         g_pfont_table = (FONTINFO *)LocalAlloc(LPTR, sizeof(FONTINFO) * FONT_TABLE_INIT_SIZE);
  2484.         LeaveCriticalSection(&g_cs);
  2485.         if (!g_pfont_table)
  2486.         {
  2487.             bRet = FALSE;
  2488.             goto SETFONT_DONE;
  2489.         }        
  2490.     }
  2491.     else
  2492.     {
  2493.         return TRUE;
  2494.     }
  2495.     
  2496. #ifndef UNIX
  2497.     if (S_OK != GetRegFontKey(&hkey, &dwFonts))
  2498.     {
  2499.         return FALSE;
  2500.     }    
  2501.     count = 1;
  2502.     hWnd = GetTopWindow(GetDesktopWindow());
  2503.     hDC = GetDC(hWnd);
  2504.     for (i=0; ;i++)
  2505.     {
  2506.         dwValue = sizeof(szFaceName);
  2507.         dwData  = sizeof(szFontFile);
  2508.         if (ERROR_NO_MORE_ITEMS == RegEnumValue(
  2509.                       hkey,
  2510.                       i,
  2511.                       szFaceName,
  2512.                       &dwValue,
  2513.                       NULL,
  2514.                       &dwType,
  2515.                       (LPBYTE)szFontFile,
  2516.                       &dwData ))
  2517.         {
  2518.             break;
  2519.         }
  2520.         DWORD dwOffset = 0;
  2521. FIND_NEXT_FACENAME:
  2522.         
  2523.         pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT(" & "));
  2524.         if (pNewFaceName)
  2525.         {
  2526.            *pNewFaceName = 0;
  2527.            // Skip " & ", look for next font face name
  2528.            pNewFaceName+=3;
  2529.         }
  2530.         else
  2531.         {
  2532.             pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT("(TrueType)"));
  2533.             if(pNewFaceName)
  2534.             {
  2535.                 // Ignor the space between face name and "(TrueTye)" signature
  2536.                 if ((pNewFaceName > szFaceName) && (*(pNewFaceName-1) == 0x20))
  2537.                     pNewFaceName--;
  2538.                 *pNewFaceName = 0;
  2539.             }
  2540.         }
  2541.         EnterCriticalSection(&g_cs);
  2542.         if (pNewFaceName && !EnumFontFamilies(hDC, &szFaceName[dwOffset], MapFontExEnumFontProc, (LPARAM)&count))   //TrueType font
  2543.         {
  2544.             if (count >= table_size)
  2545.             {
  2546.                 FONTINFO * _pfont_table = NULL;
  2547.                 table_size += FONT_TABLE_INIT_SIZE;
  2548.                 _pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, sizeof(FONTINFO) * table_size,
  2549.                                     LMEM_MOVEABLE | LMEM_ZEROINIT);
  2550.                 if (NULL == _pfont_table)
  2551.                 {
  2552.                     bRet = FALSE;
  2553.                     goto SETFONT_DONE;
  2554.                 }
  2555.                 else
  2556.                 {
  2557.                     g_pfont_table = _pfont_table;
  2558.                 }
  2559.             }
  2560.             GetFontURangeBits(szFontFile, &(g_pfont_table[count-1].dwUniSubRanges[0]));
  2561.             MLStrCpyN(g_pfont_table[count-1].szFaceName, &szFaceName[dwOffset], LF_FACESIZE);
  2562.             MLStrCpyN(g_pfont_table[count-1].szFileName, szFontFile, LF_FACESIZE);
  2563.         }
  2564.         LeaveCriticalSection(&g_cs);
  2565.         if (pNewFaceName && (*pNewFaceName))
  2566.         {
  2567.             dwOffset = (DWORD)(pNewFaceName - &szFaceName[0]);
  2568.             goto FIND_NEXT_FACENAME;
  2569.         }
  2570.     }
  2571. #else
  2572.     // For UNIX, we don't have registry font information,
  2573.     // Let's create font table through EnumFontFamiliesEx.
  2574.     Table_info table_info;
  2575.     table_info.count = 1;
  2576.     table_info.table_size = table_size;
  2577.     int iRet;
  2578.     LOGFONT lf;
  2579.     lf.lfCharSet = DEFAULT_CHARSET; // give me all fonts
  2580.     lf.lfFaceName[0] = _T('');
  2581.     lf.lfPitchAndFamily = 0;
  2582.         
  2583.     hWnd = GetTopWindow(GetDesktopWindow());
  2584.     hDC = GetDC(hWnd);
  2585.     EnterCriticalSection(&g_cs);
  2586.     iRet = EnumFontFamiliesEx(hDC, // Enum all fonts
  2587.                      &lf,
  2588.                      (FONTENUMPROC)UnixGetAllFontsProc,
  2589.                      (LPARAM)&table_info,
  2590.                      0);
  2591.     LeaveCriticalSection(&g_cs);
  2592.     count = table_info.count;
  2593.     if (iRet == 0) // abort
  2594.     {
  2595.         bRet = FALSE;
  2596.         goto SETFONT_DONE;    
  2597.     }
  2598. #endif // UNIX
  2599.     // Release un-used memory
  2600.     g_pfont_table = (FONTINFO *)LocalReAlloc(g_pfont_table, (count)*sizeof(FONTINFO), LMEM_MOVEABLE);
  2601.     // Save TrueType font number
  2602.     g_pfont_table[0].dwCodePages[0] = count-1;
  2603. #ifndef UNIX
  2604.     // Unix doesn't have this number.
  2605.     // Save total font number for font change verification 
  2606.     g_pfont_table[0].dwCodePages[1] = dwFonts;
  2607.     RegCloseKey(hkey);
  2608. #endif
  2609.     if (count > 1)
  2610.         SetFontScripts();
  2611. SETFONT_DONE:    
  2612.     if (hDC)
  2613.         ReleaseDC(hWnd, hDC);
  2614.     if (count <= 1)
  2615.     {
  2616.         if (g_pfont_table)
  2617.             LocalFree(g_pfont_table);
  2618.         bRet = FALSE;
  2619.     }
  2620.     return bRet;
  2621. }
  2622. HRESULT CMLFLink2::CFontMappingCache2::SaveFontDataFile(void)
  2623. {
  2624.     FONTDATAHEADER fileHeader;
  2625.     HRESULT hr = E_FAIL;
  2626.     int     *pTmpBuf = NULL;
  2627.     HANDLE  hFile = NULL;
  2628.     int     i, j, Count = 0;
  2629.     DWORD   dwSize;
  2630.     FONTDATATABLE fontInfoTable, fontIndexTable;
  2631.     hFile = CreateFile( szFontDataFilePath,         
  2632.                         GENERIC_WRITE,          
  2633.                         0,                      
  2634.                         NULL,                   
  2635.                         CREATE_ALWAYS,          
  2636.                         FILE_ATTRIBUTE_HIDDEN,
  2637.                         NULL);                 
  2638.     if (hFile == INVALID_HANDLE_VALUE)
  2639.     {
  2640.         goto SAVE_FONT_DATA_DONE;
  2641.     }
  2642.     for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2643.     {
  2644.         Count += (g_urange_table[i].nFonts+1);
  2645.     }
  2646.     // Create file header
  2647.     lstrcpyA(fileHeader.FileSig, FONT_DATA_SIGNATURE);
  2648.     fileHeader.dwVersion = 0x00010000;
  2649.     // Use file size as CheckSum
  2650.     fileHeader.dwCheckSum = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1)+Count*sizeof(int)+
  2651.          + sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM;
  2652.     fileHeader.nTable = FONTDATATABLENUM;
  2653.     pTmpBuf = (int *)LocalAlloc(LPTR, Count*sizeof(int));
  2654.     // Get font index data
  2655.     for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2656.     {
  2657.         *pTmpBuf++ = g_urange_table[i].nFonts;
  2658.         if (g_urange_table[i].nFonts)
  2659.         {
  2660.             for (j = 0; j< g_urange_table[i].nFonts; j++)
  2661.             {
  2662.                 *pTmpBuf++ = *(g_urange_table[i].pFontIndex+j);
  2663.             }
  2664.         }
  2665.     }
  2666.     pTmpBuf -= Count;
  2667.     // Create Dir tables
  2668.     lstrcpyA(fontInfoTable.szName, "fnt");
  2669.     fontInfoTable.dwOffset = sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM;
  2670.     fontInfoTable.dwSize = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1);
  2671.     lstrcpyA(fontIndexTable.szName, "idx");
  2672.     fontIndexTable.dwOffset = fontInfoTable.dwSize+fontInfoTable.dwOffset;
  2673.     fontIndexTable.dwSize = Count*sizeof(int);
  2674.     if (WriteFile(hFile, &fileHeader, sizeof(FONTDATAHEADER), &dwSize, NULL) &&
  2675.         WriteFile(hFile, &fontInfoTable, sizeof(FONTDATATABLE), &dwSize, NULL) &&
  2676.         WriteFile(hFile, &fontIndexTable, sizeof(FONTDATATABLE), &dwSize, NULL) &&
  2677.         WriteFile(hFile, g_pfont_table, fontInfoTable.dwSize, &dwSize, NULL) &&
  2678.         WriteFile(hFile, pTmpBuf, fontIndexTable.dwSize, &dwSize, NULL))
  2679.     {
  2680.         hr = S_OK;
  2681.     }
  2682. SAVE_FONT_DATA_DONE:
  2683.     if (hFile)
  2684.         CloseHandle(hFile);
  2685.     if (pTmpBuf)
  2686.         LocalFree(pTmpBuf);
  2687.     return hr;
  2688. }
  2689. HRESULT CMLFLink2::CFontMappingCache2::LoadFontDataFile(void)
  2690. {
  2691.     HANDLE  hFontData = NULL;
  2692.     HANDLE  hFileMap = NULL;
  2693.     LPVOID  lpvFile;
  2694.     int *   lp;
  2695.     HRESULT hr = E_FAIL;
  2696.     DWORD   dwFileSize;
  2697.     int     i, j;
  2698.     HKEY    hKey = NULL;
  2699.     DWORD   nFonts;
  2700.     FONTDATAHEADER *pHeader;
  2701.     FONTDATATABLE *pfTable;
  2702.     hFontData = CreateFile(szFontDataFilePath,  
  2703.                         GENERIC_READ,           
  2704.                         FILE_SHARE_READ,        
  2705.                         NULL,                   
  2706.                         OPEN_EXISTING,          
  2707.                         FILE_ATTRIBUTE_NORMAL,  
  2708.                         NULL);                  
  2709.     if (hFontData == INVALID_HANDLE_VALUE)
  2710.         return EnsureFontTable(TRUE);
  2711.     dwFileSize = GetFileSize(hFontData, NULL);
  2712.     hFileMap = CreateFileMapping(
  2713.                   hFontData,
  2714.                   NULL,
  2715.                   PAGE_READONLY,
  2716.                   0,
  2717.                   dwFileSize,
  2718.                   NULL
  2719.               );
  2720.     if(hFileMap == NULL)
  2721.     {
  2722.         goto Load_File_Done;
  2723.     }
  2724.     lpvFile = MapViewOfFile(
  2725.                   hFileMap,
  2726.                   FILE_MAP_READ,
  2727.                   0,
  2728.                   0,
  2729.                   0
  2730.               );
  2731.     if (lpvFile == NULL)
  2732.     {        
  2733.         goto Load_File_Done;
  2734.     }
  2735.     pHeader = (FONTDATAHEADER *)lpvFile;
  2736.     // Check mlang font cache file by signature and checksum
  2737.     if (lstrcmpA(pHeader->FileSig, FONT_DATA_SIGNATURE) || pHeader->dwCheckSum != dwFileSize)
  2738.     {
  2739.         goto Load_File_Done;
  2740.     }
  2741.     if (S_OK != GetRegFontKey(&hKey, &nFonts))
  2742.     {
  2743.         goto Load_File_Done;
  2744.     }
  2745.     pfTable = (FONTDATATABLE *) ((LPBYTE)lpvFile + sizeof(FONTDATAHEADER));
  2746.     //!BUGBUG, Check if there is any font change (no guarantee, but works in most cases)
  2747.     if (nFonts != ((FONTINFO*)((LPBYTE)lpvFile + pfTable[0].dwOffset))->dwCodePages[1])
  2748.     {
  2749.         // If there is a change in system font number, we reload everything
  2750.         UnmapViewOfFile(lpvFile);
  2751.         CloseHandle(hFileMap);
  2752.         CloseHandle(hFontData);
  2753.         RegCloseKey(hKey);
  2754.         return EnsureFontTable(TRUE);
  2755.     }
  2756.     EnterCriticalSection(&g_cs);
  2757.     // Reset cache information
  2758.     if (g_pfont_table)
  2759.     {
  2760.         
  2761.         LocalFree(g_pfont_table);
  2762.         g_pfont_table = NULL;
  2763.         for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2764.         {
  2765.             if (g_urange_table[i].nFonts)
  2766.             {
  2767.                 LocalFree(g_urange_table[i].pFontIndex);
  2768.                 g_urange_table[i].pFontIndex = NULL;
  2769.                 g_urange_table[i].nFonts = 0;
  2770.             }
  2771.         }        
  2772.     }
  2773.     if(!(g_pfont_table = (FONTINFO *) (LocalAlloc(LPTR, pfTable[0].dwSize))))
  2774.     {
  2775.         hr = E_OUTOFMEMORY;
  2776.         goto Load_File_Done;
  2777.     }
  2778.     CopyMemory(g_pfont_table, (LPBYTE)lpvFile + pfTable[0].dwOffset, pfTable[0].dwSize);
  2779.     lp = (int *)((LPBYTE)lpvFile + pfTable[1].dwOffset);
  2780.     for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2781.     {
  2782.         if (g_urange_table[i].nFonts = *lp++)
  2783.         {
  2784.             //g_urange_table[i].nFonts = *lp++;
  2785.             g_urange_table[i].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)*g_urange_table[i].nFonts);
  2786.             for (j = 0; j<  g_urange_table[i].nFonts; j++)
  2787.             {
  2788.                 g_urange_table[i].pFontIndex[j] = *lp++;
  2789.             }
  2790.         }
  2791.     }
  2792.     LeaveCriticalSection(&g_cs);
  2793.     hr = S_OK;
  2794. Load_File_Done:
  2795.     if (lpvFile)
  2796.         UnmapViewOfFile(lpvFile);
  2797.     if (hFileMap)
  2798.         CloseHandle(hFileMap);
  2799.     if (hFontData)
  2800.         CloseHandle(hFontData);
  2801.     if (hKey)
  2802.         RegCloseKey(hKey);
  2803.     return hr;
  2804. }
  2805. HRESULT CMLFLink2::CFontMappingCache2::SetFontUnicodeRanges(void)
  2806. {
  2807.     TCHAR   szFontPath[MAX_PATH];
  2808.     TCHAR   szFont[MAX_PATH];
  2809.     HRESULT hr = S_OK;
  2810.     int     i;
  2811.     
  2812.     EnterCriticalSection(&g_cs);
  2813.     g_pfont_table[0].szFaceName[0] = 1;
  2814.     LeaveCriticalSection(&g_cs);
  2815.     
  2816.     MLGetWindowsDirectory(szFontPath, MAX_PATH);
  2817.     MLPathCombine(szFontPath, szFontPath, FONT_FOLDER);
  2818.     for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  2819.     {
  2820.         MLPathCombine(szFont, szFontPath, g_pfont_table[i].szFileName);
  2821.         GetNonCpFontUnicodeRanges(szFont, i);
  2822.     }
  2823.     // Release un-used memory
  2824.     for (i=0; i< ARRAYSIZE(g_urange_table); i++)
  2825.     {
  2826.         if (g_urange_table[i].nFonts)
  2827.             g_urange_table[i].pFontIndex = (int *)LocalReAlloc(g_urange_table[i].pFontIndex, g_urange_table[i].nFonts*sizeof(int), LMEM_MOVEABLE);
  2828.     }
  2829.     return hr;
  2830. }
  2831. STDMETHODIMP CMLFLink2::GetStrCodePages(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages)
  2832. {
  2833.     ASSERT_THIS;
  2834.     ASSERT_READ_BLOCK(pszSrc, cchSrc);
  2835.     ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  2836.     ASSERT_WRITE_PTR_OR_NULL(pcchCodePages);
  2837.     HRESULT hr = S_OK;
  2838.     long cchCodePages = 0;
  2839.     DWORD dwStrCodePages = (DWORD)~0;
  2840.     BOOL fInit = FALSE;
  2841.     BOOL fNoPri = FALSE;
  2842.     if (!pszSrc || cchSrc <= 0) // We can't make dwStrCodePages when cchSrc is zero
  2843.         hr = E_INVALIDARG;
  2844.     if (!m_pIMLFLnk)
  2845.         return E_OUTOFMEMORY;
  2846.     while (SUCCEEDED(hr) && cchSrc > 0)
  2847.     {
  2848.         DWORD dwCharCodePages;
  2849.         if (SUCCEEDED(hr = m_pIMLFLnk->GetCharCodePages(*pszSrc, &dwCharCodePages)))
  2850.         {
  2851.             if (!fInit)
  2852.             {
  2853.                 fInit = TRUE;
  2854.                 fNoPri = !(dwPriorityCodePages & dwCharCodePages);
  2855.             }
  2856.             else if (fNoPri != !(dwPriorityCodePages & dwCharCodePages))
  2857.             {
  2858.                 break;
  2859.             }
  2860.             if (!fNoPri)
  2861.                 dwPriorityCodePages &= dwCharCodePages;
  2862.             if (dwCharCodePages && (dwCharCodePages & dwStrCodePages))
  2863.                 dwStrCodePages &= dwCharCodePages;
  2864.             else
  2865.                 break;
  2866.             pszSrc++;
  2867.             cchSrc--;
  2868.             cchCodePages++;
  2869.         }
  2870.     }
  2871.     if (SUCCEEDED(hr))
  2872.     {
  2873.         if (!cchCodePages)
  2874.         {
  2875.             dwStrCodePages = 0;
  2876.             cchCodePages++;
  2877.         }
  2878.         if (pcchCodePages)
  2879.             *pcchCodePages = cchCodePages;
  2880.         if (pdwCodePages)
  2881.             *pdwCodePages = dwStrCodePages;
  2882.     }
  2883.     else
  2884.     {
  2885.         if (pcchCodePages)
  2886.             *pcchCodePages = 0;
  2887.         if (pdwCodePages)
  2888.             *pdwCodePages = 0;
  2889.     }
  2890.     return hr;
  2891. }
  2892. STDMETHODIMP CMLFLink2::MapFont(HDC hDC, DWORD dwCodePages, WCHAR wchar, HFONT* phDestFont)
  2893. {
  2894.     HFONT hSrcFont = NULL;
  2895.     if (NULL == (hSrcFont = (HFONT) GetCurrentObject(hDC, OBJ_FONT)))
  2896.         return E_FAIL;
  2897.     if (dwCodePages)
  2898.     {
  2899.         if (m_pIMLFLnk)
  2900.             return m_pIMLFLnk->MapFont(hDC, dwCodePages, hSrcFont, phDestFont);
  2901.         return E_OUTOFMEMORY;
  2902.     }
  2903.     else
  2904.     {
  2905.         if (!m_pFontMappingCache2)
  2906.             m_pFontMappingCache2 = new CFontMappingCache2;
  2907.         if (m_pFontMappingCache2)
  2908.             return m_pFontMappingCache2->MapFontFromCMAP(hDC, wchar, hSrcFont, phDestFont);
  2909.         else
  2910.             return E_OUTOFMEMORY;
  2911.     }
  2912. }
  2913. STDMETHODIMP CMLFLink2::GetFontUnicodeRanges(HDC hDC, UINT *puiRanges, UNICODERANGE* pURanges)
  2914. {
  2915.     int     i;
  2916.     LOGFONT lf;
  2917.     HRESULT hr = E_FAIL;
  2918.     HFONT   hFont = NULL;
  2919.     if (!puiRanges)
  2920.         return E_INVALIDARG;
  2921.     if (!m_pFontMappingCache2)
  2922.         m_pFontMappingCache2 = new CFontMappingCache2;
  2923.     if (!m_pFontMappingCache2)
  2924.         return E_OUTOFMEMORY;
  2925.     if (!(hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT)))
  2926.         return hr;
  2927.     if (FAILED(m_pFontMappingCache2->EnsureFontTable(FALSE)))
  2928.         return hr;
  2929.     if (!GetObject(hFont, sizeof(LOGFONT), &lf))
  2930.         return hr;
  2931.     for (i=1; i<= (int) g_pfont_table[0].dwCodePages[0]; i++)
  2932.     {
  2933.         if (!lstrcmp(lf.lfFaceName, g_pfont_table[i].szFaceName))
  2934.             break;
  2935.     }
  2936.     if (i > (int) g_pfont_table[0].dwCodePages[0])
  2937.         return hr;
  2938.     return m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, puiRanges, pURanges);
  2939. }
  2940. STDMETHODIMP CMLFLink2::GetScriptFontInfo(SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts, SCRIPTFONTINFO* pScriptFont)
  2941. {
  2942.     HRESULT hr = E_FAIL;
  2943.     UINT    uiNum;
  2944.     BYTE    bPitch = dwFlags & SCRIPTCONTF_FIXED_FONT? FIXED_PITCH:VARIABLE_PITCH;
  2945.     if (!m_pFontMappingCache2)
  2946.         m_pFontMappingCache2 = new CFontMappingCache2;
  2947.     if (m_pFontMappingCache2)
  2948.         m_pFontMappingCache2->EnsureFontTable(FALSE);
  2949.     if (!g_pfont_table)
  2950.         return hr;
  2951.     if (!pScriptFont)
  2952.     {
  2953.         uiNum = g_pfont_table[0].dwCodePages[0];
  2954.     }
  2955.     else
  2956.     {
  2957.         uiNum = *puiFonts;    
  2958.     }
  2959.     *puiFonts = 0;
  2960.     // Binary search font table to match script id.
  2961.     for (UINT i=1; i<= g_pfont_table[0].dwCodePages[0]; i++)
  2962.     {
  2963.         // Check font pitch
  2964.         if (!(g_pfont_table[i].lf.lfPitchAndFamily & bPitch))
  2965.             continue;
  2966.         // Get sid bit mask
  2967.         SCRIPT_IDS sids = 1;
  2968.         sids <<= sid;
  2969.         if (sids & g_pfont_table[i].scripts)
  2970.         {
  2971.             // Bail out is required number reached
  2972.             if (*puiFonts >= uiNum)
  2973.             {
  2974.                 break;
  2975.             }
  2976.             if (pScriptFont)
  2977.             {
  2978.                 MultiByteToWideChar(CP_ACP, 0, g_pfont_table[i].szFaceName, -1, (pScriptFont + *puiFonts)->wszFont, MAX_MIMEFACE_NAME);
  2979.                 (pScriptFont + *puiFonts)->scripts = g_pfont_table[i].scripts;
  2980.             }
  2981.             (*puiFonts)++;
  2982.         }
  2983.     }
  2984.     return S_OK;
  2985. }
  2986. // Map Windows code page to script id 
  2987. // if multiple script id exist, we'll return the default one
  2988. STDMETHODIMP CMLFLink2::CodePageToScriptID(UINT uiCodePage, SCRIPT_ID *pSid)
  2989. {
  2990.     MIMECPINFO  cpInfo;
  2991.     HRESULT     hr = E_FAIL;
  2992.     if (!pSid)
  2993.         return E_INVALIDARG;
  2994.     if (NULL != g_pMimeDatabase)
  2995.     {
  2996.         if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo)))
  2997.         {
  2998.             if (cpInfo.uiFamilyCodePage == CP_USER_DEFINED)
  2999.             {
  3000.                 *pSid = sidUserDefined;
  3001.                 hr = S_OK; 
  3002.             }
  3003.             else
  3004.                 for (int i = 0; g_CharSetTransTable[i].uCodePage; i++)
  3005.                 {
  3006.                     if (cpInfo.uiFamilyCodePage == g_CharSetTransTable[i].uCodePage)
  3007.                     {
  3008.                         *pSid = g_CharSetTransTable[i].sid[0];
  3009.                         hr = S_OK;
  3010.                         break;
  3011.                     }
  3012.                 }            
  3013.         }
  3014.     }
  3015.     return hr;
  3016. }
  3017.         
  3018. CMLFLink2::CFontMappingCache2::CFontMappingCache2(void)
  3019. {
  3020.     GetSystemDirectory(szFontDataFilePath, MAX_PATH);
  3021.     MLPathCombine(szFontDataFilePath, szFontDataFilePath, FONT_DATA_FILE_NAME);
  3022. }
  3023. CMLFLink2::CFontMappingCache2::~CFontMappingCache2(void)
  3024. {
  3025.     if (g_pfont_table) 
  3026.     {
  3027.         LocalFree(g_pfont_table); 
  3028.         g_pfont_table = NULL;
  3029.     }
  3030.     if (g_urange_table)
  3031.     {
  3032.         for (int i=0; i< ARRAYSIZE(g_urange_table); i++)
  3033.         if (g_urange_table[i].nFonts)
  3034.         {
  3035.             LocalFree(g_urange_table[i].pFontIndex);
  3036.         }
  3037.     }
  3038. }
  3039. int CALLBACK CMLFLink2::CFontMappingCache2::MapFontExEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  3040. {  
  3041.     if (FontType == TRUETYPE_FONTTYPE && plfFont->lfFaceName[0] != TEXT('@') )
  3042.     {
  3043.         CopyMemory(&g_pfont_table[*(int *)lParam].lf, plfFont, sizeof(LOGFONT));
  3044.         (*(int *)lParam)++;
  3045.         return 0;
  3046.     }
  3047.     return 1;
  3048. }
  3049. int CALLBACK CMLFLink2::CFontMappingCache2::SetFontScriptsEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  3050. {      
  3051.     if (FontType == TRUETYPE_FONTTYPE)
  3052.     {
  3053.         if (g_pfont_table)
  3054.         {
  3055.             for (int i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  3056.                 if (!MLStrCmpNI(plfFont->lfFaceName, g_pfont_table[i].szFaceName, LF_FACESIZE))
  3057.                 {
  3058.                     SCRIPT_IDS scripts = 1;
  3059.                     scripts <<= lParam;
  3060.                     g_pfont_table[i].scripts |= scripts;
  3061.                     break;
  3062.                 }
  3063.             if (i > (int)g_pfont_table[0].dwCodePages[0] && plfFont->lfFaceName[0] != TEXT('@'))        // GDI font not in current font table?
  3064.             {
  3065.                 FONTINFO * pfont_table = NULL;
  3066.                 pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, 
  3067.                                         sizeof(FONTINFO) * (g_pfont_table[0].dwCodePages[0]+2),
  3068.                                         LMEM_MOVEABLE | LMEM_ZEROINIT);
  3069.                 if (NULL != pfont_table)
  3070.                 {
  3071.                     g_pfont_table = pfont_table;
  3072.                     g_pfont_table[0].dwCodePages[0]++;
  3073.                     MLStrCpyN(g_pfont_table[i].szFaceName, (char *)plfFont->lfFaceName, LF_FACESIZE);
  3074.                     CopyMemory(&g_pfont_table[i].lf, plfFont, sizeof(LOGFONT));
  3075.                     SCRIPT_IDS scripts = 1;
  3076.                     scripts <<= lParam;
  3077.                     g_pfont_table[i].scripts |= scripts;                    
  3078.                 }
  3079.             }
  3080.         }
  3081.     }
  3082.     return 1;
  3083. }
  3084. int CALLBACK CMLFLink::VerifyFontSizeEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC* ptm, DWORD FontType, LPARAM lParam)
  3085. {
  3086.     LOGFONT* plfSrcFont = (LOGFONT*)lParam;
  3087.     if (FontType != TRUETYPE_FONTTYPE)
  3088.     {
  3089.         LONG lHeight = ptm->tmInternalLeading - ptm->tmHeight;
  3090.         // Match source font's lfHeight to physical bitmap font's lfHeight
  3091.         if (lHeight < 0 && plfSrcFont->lfHeight < 0 && lHeight < plfSrcFont->lfHeight)
  3092.         {
  3093.             plfSrcFont->lfHeight = lHeight ;
  3094.         }
  3095.     }
  3096.     return 0;
  3097. }
  3098.