Source code of Windows XP (NT5)

3874 lines
111 KiB

  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, sidHangul, sidDefault, sidDefault,
  463. DEFAULT_CHARSET, 0, 0, sidDefault, sidDefault, sidDefault,
  464. };
  465. //
  466. // Extended code page table
  467. //
  468. const struct {
  469. int nCharSet;
  470. UINT uCodePage;
  471. DWORD dwCodePages;
  472. } g_CharSetTransTableExt[] =
  473. {
  474. ANSI_CHARSET, 28591, FS_MLANG_28591,
  475. EASTEUROPE_CHARSET, 28592, FS_MLANG_28592,
  476. RUSSIAN_CHARSET, 28595, FS_MLANG_28595,
  477. GREEK_CHARSET, 28597, FS_MLANG_28597,
  478. TURKISH_CHARSET, 28593, FS_MLANG_28593,
  479. HEBREW_CHARSET, 28598, FS_MLANG_28598,
  480. HEBREW_CHARSET, 38598, FS_MLANG_38598,
  481. ARABIC_CHARSET, 28596, FS_MLANG_28596,
  482. BALTIC_CHARSET, 28594, FS_MLANG_28594,
  483. VIETNAMESE_CHARSET, 28599, FS_MLANG_28599,
  484. THAI_CHARSET, 28605, FS_MLANG_28605,
  485. ANSI_CHARSET, 20127, FS_MLANG_20127,
  486. ANSI_CHARSET, 50220, FS_MLANG_50220,
  487. ANSI_CHARSET, 51932, FS_MLANG_51932,
  488. ANSI_CHARSET, 51949, FS_MLANG_51949,
  489. ANSI_CHARSET, 50225, FS_MLANG_50225,
  490. ANSI_CHARSET, 52936, FS_MLANG_52936,
  491. ANSI_CHARSET, 65000, FS_MLANG_65000,
  492. ANSI_CHARSET, 65001, FS_MLANG_65001,
  493. ANSI_CHARSET, 1200, FS_MLANG_1200,
  494. ANSI_CHARSET, 20866, FS_MLANG_20866,
  495. ANSI_CHARSET, 21866, FS_MLANG_21866,
  496. ANSI_CHARSET, 50221, FS_MLANG_50221,
  497. ANSI_CHARSET, 50222, FS_MLANG_50222,
  498. DEFAULT_CHARSET, 0, 0,
  499. };
  500. // Primary chars for scripts
  501. // Pre-sorted by Unicode characters to speed up CMAP search.
  502. const struct {
  503. WCHAR wch; //Can be extended to a character list
  504. SCRIPT_ID sid;
  505. } g_wCharToScript[] =
  506. {
  507. 0x0531, sidArmenian,
  508. 0x0710, sidSyriac,
  509. 0x0780, sidThaana,
  510. 0x0905, sidDevanagari,
  511. 0x0985, sidBengali,
  512. 0x0a05, sidGurmukhi,
  513. 0x0a85, sidGujarati,
  514. 0x0b05, sidOriya,
  515. 0x0b85, sidTamil,
  516. 0x0c05, sidTelugu,
  517. 0x0c85, sidKannada,
  518. 0x0d05, sidMalayalam,
  519. 0x0d85, sidSinhala,
  520. 0x0e81, sidLao,
  521. 0x0f40, sidTibetan,
  522. 0x10a0, sidGeorgian,
  523. 0x10d0, sidGeorgian,
  524. 0x1300, sidEthiopic,
  525. 0x1401, sidCanSyllabic,
  526. 0x13a0, sidCherokee,
  527. 0xa000, sidYi,
  528. 0x1680, sidOgham,
  529. 0x16a0, sidRunic,
  530. 0x1700, sidBurmese,
  531. 0x1780, sidKhmer,
  532. 0x2800, sidBraille,
  533. // 0x0020, sidUserDefined
  534. };
  535. // Script tables ported from Trident
  536. static SCRIPT_ID s_asidUnicodeSubRangeScriptMapping[] =
  537. {
  538. sidAsciiLatin, sidLatin, sidLatin, sidLatin, // 128-131
  539. sidLatin, sidLatin, 0, sidGreek, // 132-135
  540. sidGreek, sidCyrillic, sidArmenian, sidHebrew, // 136-139
  541. sidHebrew, sidArabic, sidArabic, sidDevanagari, // 140-143
  542. sidBengali, sidGurmukhi, sidGujarati, sidOriya, // 144-147
  543. sidTamil, sidTelugu, sidKannada, sidMalayalam, // 148-151
  544. sidThai, sidLao, sidGeorgian, sidGeorgian, // 152-155
  545. sidHangul, sidLatin, sidGreek, 0, // 156-159
  546. 0, 0, 0, 0, // 160-163
  547. 0, 0, 0, 0, // 164-167
  548. 0, 0, 0, 0, // 168-171
  549. 0, 0, 0, 0, // 172-175
  550. sidHan, sidKana, sidKana, sidBopomofo, // 176-179
  551. sidHangul, 0, 0, 0, // 180-183
  552. sidHangul, sidHangul, sidHangul, sidHan, // 184-187
  553. 0, sidHan, 0, 0, // 188-191
  554. 0, 0, 0, 0, // 192-195
  555. 0, 0, sidHangul, 0, // 196-199
  556. };
  557. // Script table (raw data from MichelSu)
  558. // Rendered by script ID
  559. const SCRIPT ScriptTable[] =
  560. {
  561. {sidDefault, IDS_SIDDEFAULT, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_SYSTEM}, // 0
  562. {sidMerge, IDS_SIDMERGE, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_SYSTEM}, // 1
  563. {sidAsciiSym, IDS_SIDASCIISYM, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_SYSTEM}, // 2
  564. {sidAsciiLatin, IDS_SIDASCIILATIN, 1252, 0, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 3
  565. {sidLatin, IDS_SIDLATIN, 1252, 0, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_HIDE}, // 4
  566. {sidGreek, IDS_SIDGREEK, 1253, 0x03AC, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 5
  567. {sidCyrillic, IDS_SIDCYRILLIC, 1251, 0x0401, IDS_FONT_WESTERN_FIXED, IDS_FONT_WESTERN_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 6
  568. {sidArmenian, IDS_SIDARMENIAN, 0, 0x0531, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 7
  569. /**/{sidHebrew, IDS_SIDHEBREW, 1255, 0x05D4, IDS_FONT_HEBREW_FIXED, IDS_FONT_HEBREW_PROP, SCRIPTCONTF_SCRIPT_USER}, // 8
  570. {sidArabic, IDS_SIDARABIC, 1256, 0x0627, IDS_FONT_ARABIC_FIXED, IDS_FONT_ARABIC_PROP, SCRIPTCONTF_SCRIPT_USER}, // 9
  571. {sidDevanagari, IDS_SIDDEVANAGARI, 0, 0x0905, IDS_FONT_DEVANAGARI_FIXED,IDS_FONT_DEVANAGARI_PROP, SCRIPTCONTF_SCRIPT_USER}, // 10
  572. {sidBengali, IDS_SIDBENGALI, 0, 0x0985, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 11
  573. {sidGurmukhi, IDS_SIDGURMUKHI, 0, 0x0A05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 12
  574. {sidGujarati, IDS_SIDGUJARATI, 0, 0x0A85, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 13
  575. {sidOriya, IDS_SIDORIYA, 0, 0x0B05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 14
  576. {sidTamil, IDS_SIDTAMIL, 0, 0x0B85, IDS_FONT_TAMIL_FIXED, IDS_FONT_TAMIL_PROP, SCRIPTCONTF_SCRIPT_USER}, // 15
  577. {sidTelugu, IDS_SIDTELUGU, 0, 0x0C05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 16
  578. {sidKannada, IDS_SIDKANNADA, 0, 0x0C85, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 17
  579. {sidMalayalam, IDS_SIDMALAYALAM, 0, 0x0D05, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 18
  580. {sidThai, IDS_SIDTHAI, 874, 0x0E01, IDS_FONT_THAI_FIXED2, IDS_FONT_THAI_PROP2, SCRIPTCONTF_SCRIPT_USER}, // 19
  581. {sidLao, IDS_SIDLAO, 0, 0x0E81, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 20
  582. {sidTibetan, IDS_SIDTIBETAN, 0, 0x0F40, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 21
  583. {sidGeorgian, IDS_SIDGEORGIAN, 0, 0x10D0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 22
  584. {sidHangul, IDS_SIDHANGUL, 949, 0, IDS_FONT_KOREAN_FIXED, IDS_FONT_KOREAN_PROP, SCRIPTCONTF_SCRIPT_USER}, // 23
  585. {sidKana, IDS_SIDKANA, 932, 0, IDS_FONT_JAPANESE_FIXED, IDS_FONT_JAPANESE_PROP, SCRIPTCONTF_SCRIPT_USER}, // 24
  586. {sidBopomofo, IDS_SIDBOPOMOFO, 950, 0, IDS_FONT_TAIWAN_FIXED, IDS_FONT_TAIWAN_PROP, SCRIPTCONTF_SCRIPT_USER}, // 25
  587. {sidHan, IDS_SIDHAN, 936, 0, IDS_FONT_CHINESE_FIXED, IDS_FONT_CHINESE_PROP, SCRIPTCONTF_SCRIPT_USER}, // 26
  588. {sidEthiopic, IDS_SIDETHIOPIC, 0, 0x1300, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 27
  589. {sidCanSyllabic,IDS_SIDCANSYLLABIC, 0, 0x1401, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 28
  590. {sidCherokee, IDS_SIDCHEROKEE, 0, 0x13A0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 29
  591. {sidYi, IDS_SIDYI, 0, 0xA000, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 30
  592. {sidBraille, IDS_SIDBRAILLE, 0, 0x2800, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 31
  593. {sidRunic, IDS_SIDRUNIC, 0, 0x16A0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 32
  594. {sidOgham, IDS_SIDOGHAM, 0, 0x1680, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 33
  595. {sidSinhala, IDS_SIDSINHALA, 0, 0x0D85, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 34
  596. {sidSyriac, IDS_SIDSYRIAC, 0, 0x0710, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 35
  597. {sidBurmese, IDS_SIDBURMESE, 0, 0x1700, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 36
  598. {sidKhmer, IDS_SIDKHMER, 0, 0x1780, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 37
  599. {sidThaana, IDS_SIDTHAANA, 0, 0x0780, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 38
  600. {sidMongolian, IDS_SIDMONGOLIAN, 0, 0, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 39
  601. {sidUserDefined,IDS_SIDUSERDEFINED, 0, 0x0020, 0, 0, SCRIPTCONTF_SCRIPT_USER}, // 40
  602. };
  603. UINT g_cScript = ARRAYSIZE(ScriptTable);
  604. /////////////////////////////////////////////////////////////////////////////
  605. // CMLFLink Free Global Objects
  606. void CMLangFontLink_FreeGlobalObjects()
  607. {
  608. if (g_pMLFLink)
  609. g_pMLFLink->Release();
  610. if (CMLFLink::m_pCodePagesCache)
  611. delete CMLFLink::m_pCodePagesCache;
  612. if (CMLFLink::m_pFontMappingCache)
  613. delete CMLFLink::m_pFontMappingCache;
  614. if (CMLFLink2::m_pFontMappingCache2)
  615. delete CMLFLink2::m_pFontMappingCache2;
  616. }
  617. /////////////////////////////////////////////////////////////////////////////
  618. // CMLFLink
  619. CMLFLink::CMLFLink()
  620. {
  621. DllAddRef();
  622. EnterCriticalSection(&g_cs);
  623. if (!m_pCodePagesCache)
  624. m_pCodePagesCache = new CCodePagesCache;
  625. if (!m_pFontMappingCache)
  626. m_pFontMappingCache = new CFontMappingCache;
  627. LeaveCriticalSection(&g_cs);
  628. m_pFlinkTable = NULL;
  629. }
  630. STDMETHODIMP CMLFLink::GetCharCodePages(WCHAR chSrc, DWORD* pdwCodePages)
  631. {
  632. return ::GetCharCodePagesEx(chSrc, pdwCodePages, CPBITS_WINDOWS);
  633. }
  634. /////////////////////////////////////////////////////////////////////////////
  635. // CMLFLink : IMLangCodePages
  636. HRESULT GetCharCodePagesEx(WCHAR chSrc, DWORD* pdwCodePages, DWORD dwFlags)
  637. {
  638. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  639. HRESULT hr = S_OK;
  640. int nLen;
  641. int iCmd = 0;
  642. int nPickOffset;
  643. int nBitOffset = 0;
  644. int nBitCount = 32;
  645. DWORD dwDiff = 0xffffffff;
  646. DWORD dwOr = 0;
  647. DWORD dwCodePages;
  648. DWORD adwBitsMap[32];
  649. const CCodePagesHeader* pHeader;
  650. const WORD* pwTable;
  651. int nBlock;
  652. int nEndLen;
  653. const BYTE* pbBlock;
  654. BYTE *pBuffer = NULL;
  655. if (!CMLFLink::m_pCodePagesCache)
  656. CMLFLink::m_pCodePagesCache = new CMLFLink::CCodePagesCache;
  657. if (CMLFLink::m_pCodePagesCache)
  658. hr = CMLFLink::m_pCodePagesCache->Load();
  659. else
  660. {
  661. hr = E_FAIL;
  662. }
  663. if (SUCCEEDED(hr))
  664. {
  665. pBuffer = CMLFLink::m_pCodePagesCache->GetCodePageBits(dwFlags & CPBITS_WINDOWS? FALSE:TRUE);
  666. pHeader = (CCodePagesHeader*) pBuffer;
  667. pwTable = (WORD*)(pBuffer + READWINTELDWORD(pHeader->m_dwTableOffset));
  668. nBlock = chSrc / READWINTELDWORD(pHeader->m_dwBlockSize);
  669. nEndLen = chSrc % READWINTELDWORD(pHeader->m_dwBlockSize);
  670. pbBlock = pBuffer + READWINTELWORD(pwTable[nBlock]);
  671. }
  672. for (int nDoneLen = 0; SUCCEEDED(hr) && nDoneLen < (int)READWINTELDWORD(pHeader->m_dwBlockSize); nDoneLen += nLen)
  673. {
  674. BYTE bCmd = pbBlock[--iCmd];
  675. if (bCmd < pHeader->m_abCmdCode[1])
  676. {
  677. // Flat
  678. nLen = bCmd + 1;
  679. nPickOffset = nBitOffset + nBitCount * (nEndLen - nDoneLen);
  680. nBitOffset += nBitCount * nLen;
  681. }
  682. else if (bCmd < pHeader->m_abCmdCode[2])
  683. {
  684. // Pack
  685. nLen = bCmd - pHeader->m_abCmdCode[1] + 2;
  686. nPickOffset = nBitOffset;
  687. nBitOffset += nBitCount;
  688. }
  689. else if (bCmd < pHeader->m_abCmdCode[4])
  690. {
  691. // Diff & Or
  692. nLen = 0;
  693. DWORD dw = pbBlock[--iCmd];
  694. dw <<= 8;
  695. dw |= pbBlock[--iCmd];
  696. dw <<= 8;
  697. dw |= pbBlock[--iCmd];
  698. dw <<= 8;
  699. dw |= pbBlock[--iCmd];
  700. if (bCmd < pHeader->m_abCmdCode[3])
  701. {
  702. // Diff
  703. dwDiff = dw;
  704. DWORD dwShift = 1;
  705. nBitCount = 0;
  706. for (int nBit = 0; nBit < 32; nBit++)
  707. {
  708. if (dwDiff & (1 << nBit))
  709. {
  710. adwBitsMap[nBit] = dwShift;
  711. dwShift <<= 1;
  712. nBitCount++;
  713. }
  714. else
  715. {
  716. adwBitsMap[nBit] = 0;
  717. }
  718. }
  719. }
  720. else
  721. {
  722. // Or
  723. dwOr = dw;
  724. }
  725. }
  726. else
  727. {
  728. // Big Pack
  729. nLen = (bCmd - pHeader->m_abCmdCode[4]) * 0x100 + pbBlock[--iCmd] + pHeader->m_abCmdCode[2] - pHeader->m_abCmdCode[1] + 1 + 1;
  730. nPickOffset = nBitOffset;
  731. nBitOffset += nBitCount;
  732. }
  733. if (nEndLen < nDoneLen + nLen)
  734. break;
  735. }
  736. if (SUCCEEDED(hr) &&
  737. nDoneLen < (int)READWINTELDWORD(pHeader->m_dwBlockSize))
  738. {
  739. const BYTE* const pbBuf = &pbBlock[nPickOffset / 8];
  740. DWORD dwCompBits = pbBuf[0] | (DWORD(pbBuf[1]) << 8) | (DWORD(pbBuf[2]) << 16) | (DWORD(pbBuf[3]) << 24);
  741. dwCompBits >>= nPickOffset % 8;
  742. if (nBitOffset % 8)
  743. dwCompBits |= pbBuf[4] << (32 - nBitOffset % 8);
  744. if (nBitCount < 32)
  745. {
  746. dwCompBits &= (1 << nBitCount) - 1;
  747. dwCodePages = 0;
  748. for (int nBit = 0; nBit < 32; nBit++)
  749. {
  750. if (dwCompBits & adwBitsMap[nBit])
  751. dwCodePages |= (1 << nBit);
  752. }
  753. }
  754. else
  755. {
  756. dwCodePages = dwCompBits;
  757. }
  758. dwCodePages |= dwOr;
  759. }
  760. else
  761. {
  762. hr = E_FAIL; // Probably Code Pages data is broken.
  763. }
  764. if (pdwCodePages)
  765. {
  766. if (SUCCEEDED(hr))
  767. {
  768. if (dwFlags & CPBITS_WINDOWS)
  769. {
  770. // 04/07/00 WEIWU
  771. // Need to match latest NLS file (Currently W2K RTM) if we're in strict mode for outbound encoding detection
  772. // For backward compatibilities reasons, we don't want to change our raw Windows CP data.
  773. // We patch up major differences between Win95/NT4 NLS files and current NLS files here
  774. // For non-Windows CP data, we'll modify them directly since it doesn't affect text rendering
  775. if (dwFlags & CPBITS_STRICT)
  776. {
  777. // Add Euro support for 936,950, 949 if we're in strict mode
  778. if (chSrc == 0x20AC)
  779. {
  780. dwCodePages |= FS_WANSUNG|FS_CHINESESIMP|FS_CHINESETRAD;
  781. }
  782. else if (chSrc == 0x00AE)
  783. {
  784. dwCodePages |= FS_WANSUNG;
  785. }
  786. // Clear K1_HANJA bits if we're in strict mode
  787. dwCodePages &= ~FS_MLANG_K1HANJA;
  788. }
  789. else
  790. {
  791. // We introduce this new internal charset bit, FS_MLANG_K1HANJA, to support Korean K1 Hanja
  792. // K1 Hanja is defined in KSC 5657-1991, it contains non-cp949 DBCS characters
  793. // Currenly, Korean fonts shipped with NT5 and Win98 support K1 Hanja glyphs
  794. // and we don't want to switch font to other DBCS fonts in this case.
  795. if (dwCodePages & FS_MLANG_K1HANJA)
  796. {
  797. // Assume Korean font supports K1_HANJA on Win98 and NT5
  798. if (g_bIsNT5 || (g_bIsWin98 && CP_KOR_5601 == g_uACP))
  799. dwCodePages |= FS_WANSUNG;
  800. dwCodePages &= ~FS_MLANG_K1HANJA;
  801. }
  802. }
  803. }
  804. *pdwCodePages = dwCodePages;
  805. }
  806. else
  807. {
  808. *pdwCodePages = 0;
  809. }
  810. }
  811. return hr;
  812. }
  813. HRESULT GetStrCodePagesEx(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages, DWORD dwFlags)
  814. {
  815. ASSERT_READ_BLOCK(pszSrc, cchSrc);
  816. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  817. ASSERT_WRITE_PTR_OR_NULL(pcchCodePages);
  818. HRESULT hr = S_OK;
  819. long cchCodePages = 0;
  820. DWORD dwStrCodePages = (DWORD)~0;
  821. BOOL fInit = FALSE;
  822. BOOL fNoPri = FALSE;
  823. if (!pszSrc || cchSrc <= 0) // We can't make dwStrCodePages when cchSrc is zero
  824. hr = E_INVALIDARG;
  825. while (SUCCEEDED(hr) && cchSrc > 0)
  826. {
  827. DWORD dwCharCodePages;
  828. if (SUCCEEDED(hr = GetCharCodePagesEx(*pszSrc, &dwCharCodePages, dwFlags)))
  829. {
  830. if (!fInit)
  831. {
  832. fInit = TRUE;
  833. fNoPri = !(dwPriorityCodePages & dwCharCodePages);
  834. }
  835. else if (fNoPri != !(dwPriorityCodePages & dwCharCodePages))
  836. {
  837. break;
  838. }
  839. if (!fNoPri)
  840. dwPriorityCodePages &= dwCharCodePages;
  841. if (dwCharCodePages & dwStrCodePages)
  842. dwStrCodePages &= dwCharCodePages;
  843. // Don't break if dwCharCodePages is zero and we're not in strict mode
  844. else if (dwCharCodePages || dwFlags & CPBITS_STRICT)
  845. break;
  846. pszSrc++;
  847. cchSrc--;
  848. cchCodePages++;
  849. }
  850. }
  851. // Codepage bits defines don't take full 32 bits.
  852. // If no bits are flipped, we don't have any candidate code pages, we should clear the bits
  853. if (dwStrCodePages == (DWORD)~0)
  854. dwStrCodePages = 0;
  855. if (SUCCEEDED(hr))
  856. {
  857. if (pcchCodePages)
  858. *pcchCodePages = cchCodePages;
  859. if (pdwCodePages)
  860. *pdwCodePages = dwStrCodePages;
  861. }
  862. else
  863. {
  864. if (pcchCodePages)
  865. *pcchCodePages = 0;
  866. if (pdwCodePages)
  867. *pdwCodePages = 0;
  868. }
  869. return hr;
  870. }
  871. STDMETHODIMP CMLFLink::GetStrCodePages(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages)
  872. {
  873. return ::GetStrCodePagesEx(pszSrc, cchSrc, dwPriorityCodePages, pdwCodePages, pcchCodePages, CPBITS_WINDOWS);
  874. }
  875. HRESULT CodePageToCodePagesEx(UINT uCodePage, DWORD* pdwCodePages, DWORD* pdwCodePagesExt)
  876. {
  877. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  878. int iCharSet;
  879. if (pdwCodePages)
  880. *pdwCodePages = 0;
  881. if (pdwCodePagesExt)
  882. *pdwCodePagesExt = 0;
  883. for (iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  884. {
  885. if (uCodePage == g_CharSetTransTable[iCharSet].uCodePage)
  886. {
  887. if (pdwCodePages)
  888. *pdwCodePages = g_CharSetTransTable[iCharSet].dwCodePages;
  889. return S_OK;
  890. }
  891. }
  892. for (iCharSet = 0; g_CharSetTransTableExt[iCharSet].uCodePage; iCharSet++)
  893. {
  894. if (uCodePage == g_CharSetTransTableExt[iCharSet].uCodePage)
  895. {
  896. if (pdwCodePages)
  897. *pdwCodePagesExt = g_CharSetTransTableExt[iCharSet].dwCodePages;
  898. return S_OK;
  899. }
  900. }
  901. return E_FAIL; // Unknown code page
  902. }
  903. STDMETHODIMP CMLFLink::CodePageToCodePages(UINT uCodePage, DWORD* pdwCodePages)
  904. {
  905. ASSERT_THIS;
  906. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  907. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  908. {
  909. if (uCodePage == g_CharSetTransTable[iCharSet].uCodePage)
  910. {
  911. if (pdwCodePages)
  912. *pdwCodePages = g_CharSetTransTable[iCharSet].dwCodePages;
  913. return S_OK;
  914. }
  915. }
  916. if (pdwCodePages)
  917. *pdwCodePages = 0;
  918. return E_FAIL; // Unknown code page
  919. }
  920. STDMETHODIMP CMLFLink::CodePagesToCodePage(DWORD dwCodePages, UINT uDefaultCodePage, UINT* puCodePage)
  921. {
  922. return ::CodePagesToCodePageEx(dwCodePages, uDefaultCodePage, puCodePage, 0);
  923. }
  924. HRESULT CodePagesToCodePageEx(DWORD dwCodePages, UINT uDefaultCodePage, UINT* puCodePage, BOOL bCodePagesExt)
  925. {
  926. ASSERT_WRITE_PTR_OR_NULL(puCodePage);
  927. HRESULT hr = E_FAIL; // Unknown code pages
  928. DWORD dwDefaultCodePages;
  929. if (uDefaultCodePage &&
  930. SUCCEEDED(hr = CodePageToCodePagesEx(uDefaultCodePage, &dwDefaultCodePages, NULL)) &&
  931. (dwDefaultCodePages & dwCodePages))
  932. {
  933. hr = S_OK;
  934. }
  935. else
  936. {
  937. if (bCodePagesExt)
  938. {
  939. for (int iCharSet = 0; g_CharSetTransTableExt[iCharSet].dwCodePages; iCharSet++)
  940. {
  941. if (dwCodePages & g_CharSetTransTableExt[iCharSet].dwCodePages)
  942. {
  943. uDefaultCodePage = g_CharSetTransTableExt[iCharSet].uCodePage;
  944. hr = S_OK;
  945. break;
  946. }
  947. }
  948. }
  949. else
  950. {
  951. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].dwCodePages; iCharSet++)
  952. {
  953. if (dwCodePages & g_CharSetTransTable[iCharSet].dwCodePages)
  954. {
  955. uDefaultCodePage = g_CharSetTransTable[iCharSet].uCodePage;
  956. hr = S_OK;
  957. break;
  958. }
  959. }
  960. }
  961. }
  962. if (puCodePage)
  963. {
  964. if (SUCCEEDED(hr))
  965. *puCodePage = uDefaultCodePage;
  966. else
  967. *puCodePage = 0;
  968. }
  969. return hr;
  970. }
  971. #define REGSTR_PATH_FONTLINK TSZMICROSOFTPATH TEXT("\\Windows NT\\CurrentVersion\\FontLink\\SystemLink")
  972. void CMLFLink::FreeFlinkTable(void)
  973. {
  974. if (m_pFlinkTable)
  975. {
  976. for (UINT i=0; i<m_uiFLinkFontNum; i++)
  977. if (m_pFlinkTable[i].pmszFaceName)
  978. LocalFree(m_pFlinkTable[i].pmszFaceName);
  979. LocalFree(m_pFlinkTable);
  980. m_pFlinkTable = NULL;
  981. m_uiFLinkFontNum = 0;
  982. }
  983. }
  984. #define MAX_FONTLINK_BUFFER_SIZE 1024
  985. HRESULT CMLFLink::CreateNT5FontLinkTable(void)
  986. {
  987. HKEY hKey = NULL;
  988. HKEY hKeyFont = NULL;
  989. ULONG ulFonts = 0;
  990. ULONG ulFLinkFonts = 0;
  991. DWORD dwIndex = 0;
  992. WCHAR szFaceName[MAX_PATH];
  993. LPWSTR pNewFaceName = NULL;
  994. DWORD dwOffset = 0;
  995. DWORD dwOffset2 = 0;
  996. DWORD dwValue;
  997. DWORD dwData;
  998. WCHAR szFontFile[LF_FACESIZE];
  999. DWORD dwType;
  1000. WCHAR szFlinkFont[MAX_FONTLINK_BUFFER_SIZE];
  1001. // Internal temperate data
  1002. struct tagFontTable
  1003. {
  1004. WCHAR szFontFile[LF_FACESIZE];
  1005. WCHAR szFaceName[LF_FACESIZE];
  1006. }* tmpFontTable = NULL;
  1007. HRESULT hr;
  1008. // Open system font and fontlink key
  1009. if ((ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_FONTLINK, 0, KEY_READ, &hKey)) ||
  1010. (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEYNT, 0, KEY_READ, &hKeyFont)))
  1011. {
  1012. hr = E_FAIL;
  1013. goto TABLE_DONE;
  1014. }
  1015. // Get number of items
  1016. if ((ERROR_SUCCESS != RegQueryInfoKey(hKey, NULL, NULL, 0, NULL,
  1017. NULL, NULL, &ulFLinkFonts, NULL, NULL, NULL, NULL) || 0 == ulFLinkFonts) ||
  1018. (ERROR_SUCCESS != RegQueryInfoKey(hKeyFont, NULL, NULL, 0, NULL,
  1019. NULL, NULL, &ulFonts, NULL, NULL, NULL, NULL) || 0 == ulFonts))
  1020. {
  1021. hr = E_FAIL;
  1022. goto TABLE_DONE;
  1023. }
  1024. tmpFontTable = (struct tagFontTable *)LocalAlloc(LPTR, sizeof(struct tagFontTable)*ulFonts);
  1025. if (NULL == tmpFontTable)
  1026. {
  1027. hr = E_OUTOFMEMORY;
  1028. goto TABLE_DONE;
  1029. }
  1030. dwValue = dwData = LF_FACESIZE;
  1031. dwType = REG_SZ;
  1032. dwIndex = 0;
  1033. ulFonts = 0;
  1034. while (ERROR_NO_MORE_ITEMS != RegEnumValueW(
  1035. hKeyFont,
  1036. dwIndex++,
  1037. szFaceName,
  1038. &dwValue,
  1039. NULL,
  1040. &dwType,
  1041. (LPBYTE)szFontFile,
  1042. &dwData ))
  1043. {
  1044. // TTF fonts only, TTC fonts already have face name under fontlink
  1045. if (pNewFaceName = wcsstr(szFaceName, L" & "))
  1046. break;
  1047. pNewFaceName = wcsstr(szFaceName, L" (TrueType)");
  1048. if(pNewFaceName)
  1049. {
  1050. *pNewFaceName = 0;
  1051. MLStrCpyNW(tmpFontTable[ulFonts].szFaceName, szFaceName, LF_FACESIZE);
  1052. MLStrCpyNW(tmpFontTable[ulFonts++].szFontFile, szFontFile, LF_FACESIZE);
  1053. }
  1054. dwValue = dwData = LF_FACESIZE;
  1055. dwType = REG_SZ;
  1056. }
  1057. m_pFlinkTable = (PFLINKFONT) LocalAlloc(LPTR, sizeof(FLINKFONT)*ulFLinkFonts);
  1058. if (NULL == m_pFlinkTable)
  1059. {
  1060. hr = E_OUTOFMEMORY;
  1061. goto TABLE_DONE;
  1062. }
  1063. dwValue = LF_FACESIZE;
  1064. dwData = MAX_FONTLINK_BUFFER_SIZE;
  1065. dwType = REG_MULTI_SZ;
  1066. dwIndex = 0;
  1067. while (ERROR_NO_MORE_ITEMS != RegEnumValueW(
  1068. hKey,
  1069. dwIndex,
  1070. m_pFlinkTable[dwIndex].szFaceName,
  1071. &dwValue,
  1072. NULL,
  1073. &dwType,
  1074. (LPBYTE)szFlinkFont,
  1075. &dwData ))
  1076. {
  1077. m_pFlinkTable[dwIndex].pmszFaceName = (LPWSTR) LocalAlloc(LPTR, MAX_FONTLINK_BUFFER_SIZE);
  1078. if (!m_pFlinkTable[dwIndex].pmszFaceName)
  1079. {
  1080. hr = E_OUTOFMEMORY;
  1081. goto TABLE_DONE;
  1082. }
  1083. while (TRUE)
  1084. {
  1085. pNewFaceName = wcsstr(&szFlinkFont[dwOffset], L",");
  1086. if (pNewFaceName) // TTC font, get face name from registry
  1087. {
  1088. MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), ++pNewFaceName, LF_FACESIZE);
  1089. dwOffset2 += lstrlenW(pNewFaceName)+1;
  1090. }
  1091. else // TTF font, search font table for face name
  1092. {
  1093. if (szFlinkFont[dwOffset])
  1094. for (UINT i=0; i<ulFonts; i++)
  1095. {
  1096. if (!MLStrCmpNIW(&szFlinkFont[dwOffset], tmpFontTable[i].szFontFile, LF_FACESIZE))
  1097. {
  1098. MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), tmpFontTable[i].szFaceName, LF_FACESIZE);
  1099. dwOffset2 += lstrlenW(tmpFontTable[i].szFaceName)+1;
  1100. break;
  1101. }
  1102. }
  1103. else // End of multiple string, break out
  1104. break;
  1105. }
  1106. dwOffset += lstrlenW(&szFlinkFont[dwOffset])+1;
  1107. // Prevent infinitive loop, shouldn't happen
  1108. if (dwOffset >= MAX_FONTLINK_BUFFER_SIZE)
  1109. {
  1110. break;
  1111. }
  1112. }
  1113. dwValue = LF_FACESIZE;
  1114. dwData = MAX_FONTLINK_BUFFER_SIZE;
  1115. dwType = REG_MULTI_SZ;
  1116. dwOffset = dwOffset2 = 0;
  1117. dwIndex++;
  1118. }
  1119. m_uiFLinkFontNum = ulFLinkFonts;
  1120. hr = S_OK;
  1121. TABLE_DONE:
  1122. if (hKey)
  1123. RegCloseKey(hKey);
  1124. if (hKeyFont)
  1125. RegCloseKey(hKeyFont);
  1126. if (tmpFontTable)
  1127. LocalFree(tmpFontTable);
  1128. if ((hr != S_OK) && m_pFlinkTable)
  1129. FreeFlinkTable();
  1130. return hr;
  1131. }
  1132. HRESULT CMLFLink::GetNT5FLinkFontCodePages(HDC hDC, LOGFONTW* plfEnum, DWORD * lpdwCodePages)
  1133. {
  1134. HRESULT hr = S_OK;
  1135. UINT i;
  1136. if (!EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0))
  1137. return E_FAIL;
  1138. if (NULL == m_pFlinkTable)
  1139. CreateNT5FontLinkTable();
  1140. if (m_pFlinkTable)
  1141. {
  1142. for (i=0; i<m_uiFLinkFontNum;i++)
  1143. {
  1144. if (!MLStrCmpNIW(plfEnum->lfFaceName, m_pFlinkTable[i].szFaceName, LF_FACESIZE))
  1145. {
  1146. DWORD dwOffset=0;
  1147. // Internal buffer, we're sure it'll end
  1148. while(TRUE)
  1149. {
  1150. MLStrCpyNW(plfEnum->lfFaceName, &m_pFlinkTable[i].pmszFaceName[dwOffset], LF_FACESIZE);
  1151. EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0);
  1152. dwOffset += lstrlenW(&m_pFlinkTable[i].pmszFaceName[dwOffset])+1;
  1153. // End of multiple string ?
  1154. if (m_pFlinkTable[i].pmszFaceName[dwOffset] == 0)
  1155. break;
  1156. }
  1157. break;
  1158. }
  1159. }
  1160. }
  1161. return hr;
  1162. }
  1163. /////////////////////////////////////////////////////////////////////////////
  1164. // CMLFLink : IMLangFontLink
  1165. // 1/29/99 - Change HR return
  1166. // Now, we always return S_OK unless system error, caller will
  1167. // check code pages bits in dwCodePages for font code page coverage
  1168. STDMETHODIMP CMLFLink::GetFontCodePages(HDC hDC, HFONT hFont, DWORD* pdwCodePages)
  1169. {
  1170. ASSERT_THIS;
  1171. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  1172. HRESULT hr = S_OK;
  1173. LOGFONT lfFont;
  1174. DWORD dwCodePages = 0;
  1175. if (!::GetObject(hFont, sizeof(lfFont), &lfFont))
  1176. hr = E_FAIL; // Invalid hFont
  1177. if (SUCCEEDED(hr))
  1178. {
  1179. LOGFONT lfEnum;
  1180. // Enumerates all character sets of given font's facename
  1181. // Then, combines them in dwCodePages
  1182. ::memset(&lfEnum, 0, sizeof(lfEnum));
  1183. lfEnum.lfCharSet = DEFAULT_CHARSET;
  1184. _tcsncpy(lfEnum.lfFaceName, lfFont.lfFaceName, ARRAYSIZE(lfEnum.lfFaceName));
  1185. if (g_bIsNT5)
  1186. {
  1187. LOGFONTW lfEnumW = {0};
  1188. lfEnumW.lfCharSet = DEFAULT_CHARSET;
  1189. if (MultiByteToWideChar(g_uACP, 0, lfFont.lfFaceName, LF_FACESIZE, lfEnumW.lfFaceName, LF_FACESIZE))
  1190. hr = GetNT5FLinkFontCodePages(hDC, &lfEnumW, &dwCodePages);
  1191. else
  1192. if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0))
  1193. hr = E_FAIL; // Invalid hDC
  1194. }
  1195. else
  1196. {
  1197. if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0))
  1198. hr = E_FAIL; // Invalid hDC
  1199. }
  1200. }
  1201. //############################
  1202. //###### MingLiU HACK ######
  1203. //## Fix the bogus font !!! ##
  1204. //############################
  1205. if (SUCCEEDED(hr) && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, _T("MingLiU"), -1) == 2)
  1206. {
  1207. dwCodePages &= ~FS_LATIN1; // Actually it doesn't have the characters of ANSI_CHARSET.
  1208. }
  1209. //############################
  1210. // We should use following logic to replace above hack code
  1211. // But, there is another DBCS<->Western font size mapping issue, we should disable this code until that issue is resolved,
  1212. #if 0
  1213. // If font claims FE and 1252 and 1250, believe it can do 1252.
  1214. // If font claims FE and 1252 and not 1250, don't believe it can do 1252.
  1215. // This lets full Unicode fonts pass but blocks bad FE fonts.
  1216. if (SUCCEEDED(hr) && (dwCodePages & (FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD)) && (dwCodePages & FS_LATIN1) && !(dwCodePages & FS_LATIN2))
  1217. {
  1218. dwCodePages &= ~FS_LATIN1;
  1219. }
  1220. #endif
  1221. #ifdef UNICODE
  1222. #define PRC_DEFAULT_GUI_FONT L"\x5b8b\x4f53"
  1223. #else
  1224. #define PRC_DEFAULT_GUI_FONT "\xcb\xce\xcc\xe5"
  1225. #endif
  1226. // PRC Win95 DEFAULT_GUI_FONT HACK !!!
  1227. if (SUCCEEDED(hr) && lfFont.lfCharSet == ANSI_CHARSET && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, PRC_DEFAULT_GUI_FONT, -1) == 2)
  1228. {
  1229. dwCodePages &= ~FS_CHINESESIMP; // Actually it doesn't have the characters of GB2321_CHARSET.
  1230. }
  1231. if (pdwCodePages)
  1232. {
  1233. if (SUCCEEDED(hr))
  1234. *pdwCodePages = dwCodePages;
  1235. else
  1236. *pdwCodePages = 0;
  1237. }
  1238. return hr;
  1239. }
  1240. int CALLBACK CMLFLink::GetFontCodePagesEnumFontProc(const LOGFONT* plf, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  1241. {
  1242. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++)
  1243. {
  1244. if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet)
  1245. {
  1246. if ((FontType == TRUETYPE_FONTTYPE) ||
  1247. (g_CharSetTransTable[iCharSet].uCodePage == g_uACP))
  1248. {
  1249. *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages;
  1250. break;
  1251. }
  1252. }
  1253. }
  1254. return TRUE;
  1255. }
  1256. int CALLBACK CMLFLink::GetFontCodePagesEnumFontProcW(const LOGFONTW* plf, const TEXTMETRICW*, DWORD FontType, LPARAM lParam)
  1257. {
  1258. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++)
  1259. {
  1260. if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet)
  1261. {
  1262. if ((FontType == TRUETYPE_FONTTYPE) ||
  1263. (g_CharSetTransTable[iCharSet].uCodePage == g_uACP))
  1264. {
  1265. *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages;
  1266. break;
  1267. }
  1268. }
  1269. }
  1270. return TRUE;
  1271. }
  1272. STDMETHODIMP CMLFLink::MapFont(HDC hDC, DWORD dwCodePages, HFONT hSrcFont, HFONT* phDestFont)
  1273. {
  1274. ASSERT_THIS;
  1275. ASSERT_WRITE_PTR_OR_NULL(phDestFont);
  1276. HRESULT hr = S_OK;
  1277. CFontMappingInfo fm; // To accelerate internal subroutine calls
  1278. fm.hDC = hDC;
  1279. // Font mapping cache works only for Display
  1280. BOOL fDisplay = (::GetDeviceCaps(hDC, TECHNOLOGY) == DT_RASDISPLAY);
  1281. dwCodePages &= ~FS_SYMBOL; // We don't map symbol font.
  1282. if (!::GetObject(hSrcFont, sizeof(fm.lfSrcFont), &fm.lfSrcFont))
  1283. hr = E_FAIL; // Invalid hSrcFont
  1284. // Do two things at same time
  1285. // (1) Find given font in the font mapping cache
  1286. // (2) Build m_auCodePage[] and m_adwCodePages[]
  1287. if (SUCCEEDED(hr))
  1288. {
  1289. if (fDisplay)
  1290. {
  1291. BYTE nCharSet = fm.lfSrcFont.lfCharSet;
  1292. fm.lfSrcFont.lfCharSet = DEFAULT_CHARSET;
  1293. EnumFontFamiliesEx(hDC, &fm.lfSrcFont, (FONTENUMPROC)VerifyFontSizeEnumFontProc, (LPARAM)&fm.lfSrcFont, 0);
  1294. fm.lfSrcFont.lfCharSet = nCharSet;
  1295. }
  1296. hr = S_FALSE; // hr == S_FALSE means that we didn't find the font in the cache
  1297. for (int n = 0; n < 32 && dwCodePages; n++)
  1298. {
  1299. hr = CodePagesToCodePage(dwCodePages, 0, &fm.auCodePage[n]); // Pick one of CodePages
  1300. if (SUCCEEDED(hr))
  1301. hr = CodePageToCodePages(fm.auCodePage[n], &fm.adwCodePages[n]);
  1302. if (SUCCEEDED(hr))
  1303. {
  1304. if (fDisplay && m_pFontMappingCache)
  1305. hr = m_pFontMappingCache->FindEntry(fm.auCodePage[n], fm.lfSrcFont, &fm.hDestFont);
  1306. else
  1307. hr = S_FALSE;
  1308. }
  1309. if (hr != S_FALSE)
  1310. break;
  1311. dwCodePages &= ~fm.adwCodePages[n];
  1312. }
  1313. fm.auCodePage[n] = NULL; // End mark
  1314. fm.adwCodePages[n] = 0;
  1315. }
  1316. if (hr == S_FALSE) // Not exist in cache
  1317. {
  1318. hr = MapFontCodePages(fm, GetFaceNameRegistry);
  1319. if (hr == MLSTR_E_FACEMAPPINGFAILURE)
  1320. hr = MapFontCodePages(fm, GetFaceNameGDI);
  1321. // Handle font link failure case for NT5
  1322. if (hr == MLSTR_E_FACEMAPPINGFAILURE && g_bIsNT5)
  1323. hr = MapFontCodePages(fm, GetFaceNameMIME);
  1324. if (SUCCEEDED(hr) && fDisplay && m_pFontMappingCache)
  1325. hr = m_pFontMappingCache->AddEntry(fm.auCodePage[fm.iCP], fm.lfSrcFont, fm.hDestFont);
  1326. }
  1327. if (phDestFont)
  1328. {
  1329. if (SUCCEEDED(hr))
  1330. {
  1331. *phDestFont = fm.hDestFont;
  1332. fm.hDestFont = NULL; // Avoid being deleted it in destructor
  1333. }
  1334. else
  1335. {
  1336. *phDestFont = NULL;
  1337. }
  1338. }
  1339. return hr;
  1340. }
  1341. STDMETHODIMP CMLFLink::ReleaseFont(HFONT hFont)
  1342. {
  1343. ASSERT_THIS;
  1344. HRESULT hr = S_OK;
  1345. if (!m_pFontMappingCache || FAILED(hr = m_pFontMappingCache->UnlockEntry(hFont)))
  1346. {
  1347. // For non display DC
  1348. if (::DeleteObject(hFont))
  1349. hr = S_OK;
  1350. else
  1351. hr = E_FAIL; // Invalid hFont
  1352. }
  1353. return hr;
  1354. }
  1355. STDMETHODIMP CMLFLink::ResetFontMapping(void)
  1356. {
  1357. ASSERT_THIS;
  1358. HRESULT hr = S_OK;
  1359. if (m_pFontMappingCache)
  1360. hr = m_pFontMappingCache->FlushEntries();
  1361. return hr;
  1362. }
  1363. STDMETHODIMP CMLFLink2::ResetFontMapping(void)
  1364. {
  1365. ASSERT_THIS;
  1366. HRESULT hr = S_OK;
  1367. if (m_pIMLFLnk)
  1368. hr = m_pIMLFLnk->ResetFontMapping();
  1369. if (m_pFontMappingCache2)
  1370. hr = (S_OK == m_pFontMappingCache2->EnsureFontTable(FALSE)? hr : E_FAIL);
  1371. return hr;
  1372. }
  1373. HRESULT CMLFLink::MapFontCodePages(CFontMappingInfo& fm, PFNGETFACENAME pfnGetFaceName)
  1374. {
  1375. HRESULT hr = MLSTR_E_FACEMAPPINGFAILURE;
  1376. for (fm.iCP = 0; fm.auCodePage[fm.iCP]; fm.iCP++)
  1377. {
  1378. fm.lfDestFont.lfCharSet = DEFAULT_CHARSET;
  1379. hr = (this->*pfnGetFaceName)(fm);
  1380. if (SUCCEEDED(hr))
  1381. {
  1382. LOGFONT lf = {0};
  1383. // If face name is from registry or MIMEDB, we set charset to codepage charset.
  1384. if (fm.lfDestFont.lfCharSet == DEFAULT_CHARSET)
  1385. {
  1386. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  1387. {
  1388. if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage)
  1389. {
  1390. fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet;
  1391. break;
  1392. }
  1393. }
  1394. }
  1395. lf.lfCharSet = DEFAULT_CHARSET;
  1396. MLStrCpyN(lf.lfFaceName, fm.szFaceName, LF_FACESIZE);
  1397. // Retrieve LOGFONT from gotten facename
  1398. fm.lfDestFont.lfFaceName[0] = _T('\0');
  1399. if (!::EnumFontFamiliesEx(fm.hDC, &lf, MapFontEnumFontProc, (LPARAM)&fm.lfDestFont, 0))
  1400. hr = E_FAIL; // Invalid hDC
  1401. else if (fm.lfDestFont.lfFaceName[0] == _T('\0'))
  1402. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1403. }
  1404. if (SUCCEEDED(hr))
  1405. {
  1406. fm.lfDestFont.lfHeight = fm.lfSrcFont.lfHeight;
  1407. fm.lfDestFont.lfWidth = fm.lfSrcFont.lfWidth;
  1408. fm.lfDestFont.lfEscapement = fm.lfSrcFont.lfEscapement;
  1409. fm.lfDestFont.lfOrientation = fm.lfSrcFont.lfOrientation;
  1410. fm.lfDestFont.lfWeight = fm.lfSrcFont.lfWeight;
  1411. fm.lfDestFont.lfItalic = fm.lfSrcFont.lfItalic;
  1412. fm.lfDestFont.lfUnderline = fm.lfSrcFont.lfUnderline;
  1413. fm.lfDestFont.lfStrikeOut = fm.lfSrcFont.lfStrikeOut;
  1414. HRESULT hrTemp = VerifyFaceMap(fm);
  1415. if (hrTemp == MLSTR_E_FACEMAPPINGFAILURE && fm.lfDestFont.lfWidth)
  1416. {
  1417. fm.lfDestFont.lfWidth = 0; // To recover non-scalable font
  1418. hr = VerifyFaceMap(fm);
  1419. }
  1420. else
  1421. {
  1422. hr = hrTemp;
  1423. }
  1424. }
  1425. if (hr != MLSTR_E_FACEMAPPINGFAILURE)
  1426. break;
  1427. }
  1428. return hr;
  1429. }
  1430. int CALLBACK CMLFLink::MapFontEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD, LPARAM lParam)
  1431. {
  1432. LOGFONT* plfDestFont = (LOGFONT*)lParam;
  1433. if (!plfDestFont->lfFaceName[0] )
  1434. {
  1435. if (plfDestFont->lfCharSet != DEFAULT_CHARSET)
  1436. {
  1437. if (plfDestFont->lfCharSet == plfFont->lfCharSet)
  1438. *plfDestFont = *plfFont;
  1439. }
  1440. else
  1441. *plfDestFont = *plfFont;
  1442. }
  1443. return TRUE;
  1444. }
  1445. HRESULT CMLFLink::GetFaceNameRegistry(CFontMappingInfo& fm)
  1446. {
  1447. static const TCHAR szRootKey[] = _T("Software\\Microsoft\\Internet Explorer");
  1448. static const TCHAR szIntlKey[] = _T("International\\%d");
  1449. static const TCHAR szPropFontName[] = _T("IEPropFontName");
  1450. static const TCHAR szFixedFontName[] = _T("IEFixedFontName");
  1451. HRESULT hr = S_OK;
  1452. HKEY hKeyRoot;
  1453. if (::RegOpenKeyEx(HKEY_CURRENT_USER, szRootKey, 0, KEY_READ, &hKeyRoot) == ERROR_SUCCESS)
  1454. {
  1455. TCHAR szCodePageKey[ARRAYSIZE(szIntlKey) + 10];
  1456. HKEY hKeySub;
  1457. ::wsprintf(szCodePageKey, szIntlKey, fm.auCodePage[fm.iCP]);
  1458. if (::RegOpenKeyEx(hKeyRoot, szCodePageKey, 0, KEY_READ, &hKeySub) == ERROR_SUCCESS)
  1459. {
  1460. const TCHAR* pszFontNameValue;
  1461. DWORD dwType;
  1462. DWORD dwSize = sizeof(fm.szFaceName);
  1463. if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH)
  1464. pszFontNameValue = szFixedFontName;
  1465. else
  1466. pszFontNameValue = szPropFontName;
  1467. if (::RegQueryValueEx(hKeySub, pszFontNameValue, 0, &dwType, (LPBYTE)fm.szFaceName, &dwSize) != ERROR_SUCCESS)
  1468. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1469. if (::RegCloseKey(hKeySub) != ERROR_SUCCESS && SUCCEEDED(hr))
  1470. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1471. }
  1472. else
  1473. {
  1474. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1475. }
  1476. if (::RegCloseKey(hKeyRoot) != ERROR_SUCCESS && SUCCEEDED(hr))
  1477. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1478. }
  1479. else
  1480. {
  1481. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1482. }
  1483. return hr;
  1484. }
  1485. HRESULT CMLFLink::GetFaceNameGDI(CFontMappingInfo& fm)
  1486. {
  1487. HRESULT hr = S_OK;
  1488. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  1489. {
  1490. if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage)
  1491. break;
  1492. }
  1493. if (g_CharSetTransTable[iCharSet].uCodePage)
  1494. {
  1495. ::memset(&fm.lfDestFont, 0, sizeof(fm.lfDestFont));
  1496. // Specify font weight as NORMAL to avoid NT GDI font mapping bugs
  1497. fm.lfDestFont.lfWeight = FW_NORMAL;
  1498. fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet;
  1499. hr = GetFaceNameRealizeFont(fm);
  1500. }
  1501. else
  1502. {
  1503. hr = E_FAIL; // Unknown code page
  1504. }
  1505. if (SUCCEEDED(hr))
  1506. {
  1507. // Height, CharSet, Pitch and Family
  1508. fm.lfDestFont.lfHeight = fm.lfSrcFont.lfHeight;
  1509. fm.lfDestFont.lfPitchAndFamily = fm.lfSrcFont.lfPitchAndFamily;
  1510. hr = GetFaceNameRealizeFont(fm);
  1511. if (FAILED(hr))
  1512. {
  1513. // CharSet, Pitch and Family
  1514. fm.lfDestFont.lfHeight = 0;
  1515. hr = GetFaceNameRealizeFont(fm);
  1516. }
  1517. if (FAILED(hr))
  1518. {
  1519. // CharSet and Pitch
  1520. fm.lfDestFont.lfPitchAndFamily &= 0x03; // Pitch Mask
  1521. hr = GetFaceNameRealizeFont(fm);
  1522. }
  1523. if (FAILED(hr))
  1524. {
  1525. // CharSet only
  1526. fm.lfDestFont.lfPitchAndFamily = 0;
  1527. hr = GetFaceNameRealizeFont(fm);
  1528. }
  1529. }
  1530. return hr;
  1531. }
  1532. HRESULT CMLFLink::GetFaceNameMIME(CFontMappingInfo& fm)
  1533. {
  1534. HRESULT hr = E_FAIL;
  1535. MIMECPINFO cpInfo;
  1536. if (fm.auCodePage[fm.iCP] == 936)
  1537. {
  1538. MLStrCpyN(fm.szFaceName, TEXT("SimSun"), LF_FACESIZE);
  1539. return S_OK;
  1540. }
  1541. if (!g_pMimeDatabase)
  1542. BuildGlobalObjects();
  1543. if (NULL != g_pMimeDatabase)
  1544. {
  1545. if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(fm.auCodePage[fm.iCP], 0x409, &cpInfo)))
  1546. {
  1547. TCHAR szFontFaceName[LF_FACESIZE];
  1548. szFontFaceName[0] = 0;
  1549. if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH && cpInfo.wszFixedWidthFont[0])
  1550. {
  1551. #ifdef UNICODE
  1552. MLStrCpyNW(szFontFaceName, cpInfo.wszFixedWidthFont, LF_FACESIZE);
  1553. #else
  1554. WideCharToMultiByte(CP_ACP, 0, cpInfo.wszFixedWidthFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL);
  1555. #endif
  1556. }
  1557. else
  1558. if (cpInfo.wszProportionalFont[0])
  1559. {
  1560. #ifdef UNICODE
  1561. MLStrCpyNW(szFontFaceName, cpInfo.wszProportionalFont, LF_FACESIZE);
  1562. #else
  1563. WideCharToMultiByte(CP_ACP, 0, cpInfo.wszProportionalFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL);
  1564. #endif
  1565. }
  1566. if (szFontFaceName[0])
  1567. {
  1568. MLStrCpyN(fm.szFaceName, szFontFaceName, LF_FACESIZE);
  1569. hr = S_OK;
  1570. }
  1571. }
  1572. else
  1573. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1574. }
  1575. return hr;
  1576. }
  1577. HRESULT CMLFLink::GetFaceNameRealizeFont(CFontMappingInfo& fm)
  1578. {
  1579. HRESULT hr = S_OK;
  1580. HFONT hFont = NULL;
  1581. HFONT hOldFont;
  1582. DWORD dwFontCodePages;
  1583. // First let's get a facename based on the given lfDestFont
  1584. // Then verify if the font of the found facename has the code pages we want.
  1585. hFont = ::CreateFontIndirect(&fm.lfDestFont);
  1586. if (!hFont)
  1587. hr = E_FAIL; // Out of memory or GDI resource
  1588. if (SUCCEEDED(hr))
  1589. {
  1590. hOldFont = (HFONT)::SelectObject(fm.hDC, hFont);
  1591. if (!hOldFont)
  1592. hr = E_FAIL; // Out of memory or GDI resource
  1593. }
  1594. if (SUCCEEDED(hr))
  1595. {
  1596. if (!::GetTextFace(fm.hDC, ARRAYSIZE(fm.szFaceName), fm.szFaceName))
  1597. hr = E_FAIL; // Out of memory or GDI resource
  1598. if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr))
  1599. hr = E_FAIL; // Out of memory or GDI resource
  1600. }
  1601. if (hFont)
  1602. ::DeleteObject(hFont);
  1603. if (SUCCEEDED(hr))
  1604. {
  1605. LOGFONT lfTemp;
  1606. lfTemp = fm.lfDestFont;
  1607. _tcsncpy(lfTemp.lfFaceName, fm.szFaceName, ARRAYSIZE(lfTemp.lfFaceName));
  1608. hFont = ::CreateFontIndirect(&lfTemp);
  1609. if (!hFont)
  1610. hr = E_FAIL; // Out of memory or GDI resource
  1611. if (SUCCEEDED(hr = GetFontCodePages(fm.hDC, hFont, &dwFontCodePages)) && !(dwFontCodePages & fm.adwCodePages[fm.iCP]))
  1612. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1613. if (hFont)
  1614. ::DeleteObject(hFont);
  1615. }
  1616. return hr;
  1617. }
  1618. HRESULT CMLFLink::VerifyFaceMap(CFontMappingInfo& fm)
  1619. {
  1620. HRESULT hr = S_OK;
  1621. HFONT hOldFont;
  1622. if (fm.hDestFont)
  1623. ::DeleteObject(fm.hDestFont);
  1624. fm.hDestFont = ::CreateFontIndirect(&fm.lfDestFont);
  1625. if (!fm.hDestFont)
  1626. hr = E_FAIL; // Out of memory or GDI resource
  1627. if (SUCCEEDED(hr))
  1628. {
  1629. hOldFont = (HFONT)::SelectObject(fm.hDC, fm.hDestFont);
  1630. if (!hOldFont)
  1631. hr = E_FAIL; // Out of memory or GDI resource
  1632. }
  1633. if (SUCCEEDED(hr))
  1634. {
  1635. TCHAR szFaceName[LF_FACESIZE];
  1636. if (!::GetTextFace(fm.hDC, ARRAYSIZE(szFaceName), szFaceName))
  1637. hr = E_FAIL; // Out of memory or GDI resource
  1638. if (SUCCEEDED(hr))
  1639. {
  1640. int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, fm.lfDestFont.lfFaceName, -1, szFaceName, -1);
  1641. if (!nRet)
  1642. hr = E_FAIL; // Unexpected error
  1643. else if (nRet != 2) // Not Equal
  1644. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1645. }
  1646. if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr))
  1647. hr = E_FAIL; // Out of memory or GDI resource
  1648. }
  1649. return hr;
  1650. }
  1651. /////////////////////////////////////////////////////////////////////////////
  1652. // CMLFLink::CFontMappingCache
  1653. CMLFLink::CFontMappingCache::CFontMappingCache(void) :
  1654. m_pEntries(NULL),
  1655. m_pFree(NULL),
  1656. m_cEntries(0)
  1657. {
  1658. ::InitializeCriticalSection(&m_cs);
  1659. }
  1660. CMLFLink::CFontMappingCache::~CFontMappingCache(void)
  1661. {
  1662. FlushEntries();
  1663. DeleteCriticalSection(&m_cs);
  1664. }
  1665. HRESULT CMLFLink::CFontMappingCache::FindEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT* phDestFont)
  1666. {
  1667. HRESULT hr = S_FALSE;
  1668. ::EnterCriticalSection(&m_cs);
  1669. if (m_pEntries)
  1670. {
  1671. CFontMappingCacheEntry* pEntry = m_pEntries;
  1672. while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1673. {
  1674. if (uCodePage == pEntry->m_uSrcCodePage &&
  1675. lfSrcFont.lfPitchAndFamily == pEntry->m_bSrcPitchAndFamily &&
  1676. lfSrcFont.lfHeight == pEntry->m_lSrcHeight &&
  1677. lfSrcFont.lfWidth == pEntry->m_lSrcWidth &&
  1678. lfSrcFont.lfEscapement == pEntry->m_lSrcEscapement &&
  1679. lfSrcFont.lfOrientation == pEntry->m_lSrcOrientation &&
  1680. lfSrcFont.lfWeight == pEntry->m_lSrcWeight &&
  1681. lfSrcFont.lfItalic == pEntry->m_bSrcItalic &&
  1682. lfSrcFont.lfUnderline == pEntry->m_bSrcUnderline &&
  1683. lfSrcFont.lfStrikeOut == pEntry->m_bSrcStrikeOut)
  1684. {
  1685. int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfSrcFont.lfFaceName, -1, pEntry->m_szSrcFaceName, -1);
  1686. if (!nRet)
  1687. {
  1688. hr = E_FAIL; // Unexpected error
  1689. break;
  1690. }
  1691. else if (nRet == 2) // Equal
  1692. {
  1693. if (phDestFont)
  1694. *phDestFont = pEntry->m_hDestFont;
  1695. pEntry->m_nLockCount++;
  1696. hr = S_OK;
  1697. break;
  1698. }
  1699. }
  1700. }
  1701. }
  1702. ::LeaveCriticalSection(&m_cs);
  1703. if (phDestFont && hr != S_OK)
  1704. *phDestFont = NULL;
  1705. return hr;
  1706. }
  1707. HRESULT CMLFLink::CFontMappingCache::UnlockEntry(HFONT hDestFont)
  1708. {
  1709. HRESULT hr = E_FAIL; // hDestFont is not found in the cache
  1710. ::EnterCriticalSection(&m_cs);
  1711. if (m_pEntries)
  1712. {
  1713. CFontMappingCacheEntry* pEntry = m_pEntries;
  1714. while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1715. {
  1716. if (hDestFont == pEntry->m_hDestFont)
  1717. {
  1718. if (pEntry->m_nLockCount - 1 >= 0)
  1719. {
  1720. pEntry->m_nLockCount--;
  1721. hr = S_OK;
  1722. }
  1723. break;
  1724. }
  1725. }
  1726. }
  1727. ::LeaveCriticalSection(&m_cs);
  1728. return hr;
  1729. }
  1730. HRESULT CMLFLink::CFontMappingCache::AddEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT hDestFont)
  1731. {
  1732. HRESULT hr = S_OK;
  1733. ::EnterCriticalSection(&m_cs);
  1734. if (!m_pEntries) // Need to allocate all the entries
  1735. {
  1736. CFontMappingCacheEntry* pEntries;
  1737. pEntries = new CFontMappingCacheEntry[NUMFONTMAPENTRIES + 1]; // +1 for sentinel
  1738. if (pEntries)
  1739. {
  1740. // Init sentinel
  1741. pEntries[0].m_pPrev = &pEntries[0];
  1742. pEntries[0].m_pNext = &pEntries[0];
  1743. // Init free entries
  1744. for (int n = 0; n < NUMFONTMAPENTRIES; n++)
  1745. {
  1746. const nEnt = n + 1; // + 1 for sentinel
  1747. if (n < NUMFONTMAPENTRIES - 1)
  1748. pEntries[nEnt].m_pNext = &pEntries[nEnt + 1];
  1749. else
  1750. pEntries[nEnt].m_pNext = NULL;
  1751. }
  1752. m_pEntries = &pEntries[0];
  1753. m_pFree = &pEntries[1];
  1754. }
  1755. else
  1756. {
  1757. hr = E_OUTOFMEMORY;
  1758. }
  1759. }
  1760. if (SUCCEEDED(hr) && !m_pFree) // Need to delete oldest entry
  1761. {
  1762. CFontMappingCacheEntry* pOldestEntry = m_pEntries->m_pPrev;
  1763. while (pOldestEntry->m_nLockCount > 0 && pOldestEntry != m_pEntries) // Entry is locked
  1764. pOldestEntry = pOldestEntry->m_pPrev;
  1765. if (pOldestEntry != m_pEntries)
  1766. {
  1767. if (pOldestEntry->m_hDestFont)
  1768. ::DeleteObject(pOldestEntry->m_hDestFont);
  1769. // Delete it from m_pEntries list
  1770. pOldestEntry->m_pPrev->m_pNext = pOldestEntry->m_pNext;
  1771. pOldestEntry->m_pNext->m_pPrev = pOldestEntry->m_pPrev;
  1772. // Insert it into m_pFree list
  1773. pOldestEntry->m_pNext = m_pFree;
  1774. m_pFree = pOldestEntry;
  1775. }
  1776. else // No entry available
  1777. {
  1778. hr = E_FAIL; // Out of cache entries
  1779. }
  1780. }
  1781. if (SUCCEEDED(hr)) // Create new entry and fill it
  1782. {
  1783. CFontMappingCacheEntry* pNewEntry;
  1784. // Delete it from m_pFree list
  1785. pNewEntry = m_pFree; // shouldn't be NULL
  1786. m_pFree = pNewEntry->m_pNext;
  1787. // Insert it into m_pEntries list
  1788. pNewEntry->m_pNext = m_pEntries->m_pNext;
  1789. pNewEntry->m_pPrev = m_pEntries;
  1790. m_pEntries->m_pNext->m_pPrev = pNewEntry;
  1791. m_pEntries->m_pNext = pNewEntry;
  1792. // Fill it
  1793. pNewEntry->m_nLockCount = 1;
  1794. pNewEntry->m_uSrcCodePage = uCodePage;
  1795. pNewEntry->m_lSrcHeight = lfSrcFont.lfHeight;
  1796. pNewEntry->m_lSrcWidth = lfSrcFont.lfWidth;
  1797. pNewEntry->m_lSrcEscapement = lfSrcFont.lfEscapement;
  1798. pNewEntry->m_lSrcOrientation = lfSrcFont.lfOrientation;
  1799. pNewEntry->m_lSrcWeight = lfSrcFont.lfWeight;
  1800. pNewEntry->m_bSrcItalic = lfSrcFont.lfItalic;
  1801. pNewEntry->m_bSrcUnderline = lfSrcFont.lfUnderline;
  1802. pNewEntry->m_bSrcStrikeOut = lfSrcFont.lfStrikeOut;
  1803. pNewEntry->m_bSrcPitchAndFamily = lfSrcFont.lfPitchAndFamily;
  1804. _tcsncpy(pNewEntry->m_szSrcFaceName, lfSrcFont.lfFaceName, ARRAYSIZE(pNewEntry->m_szSrcFaceName));
  1805. pNewEntry->m_hDestFont = hDestFont;
  1806. }
  1807. ::LeaveCriticalSection(&m_cs);
  1808. return hr;
  1809. }
  1810. HRESULT CMLFLink::CFontMappingCache::FlushEntries(void)
  1811. {
  1812. ::EnterCriticalSection(&m_cs);
  1813. if (m_pEntries)
  1814. {
  1815. CFontMappingCacheEntry* pEntry = m_pEntries;
  1816. while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1817. {
  1818. if (pEntry->m_hDestFont)
  1819. ::DeleteObject(pEntry->m_hDestFont);
  1820. }
  1821. delete[] m_pEntries;
  1822. m_pEntries = NULL;
  1823. m_cEntries = 0;
  1824. }
  1825. ::LeaveCriticalSection(&m_cs);
  1826. return S_OK;
  1827. }
  1828. /////////////////////////////////////////////////////////////////////////////
  1829. // CMLFLink::CCodePagesCache
  1830. CMLFLink::CCodePagesCache::CCodePagesCache(void) :
  1831. m_pbBuf(NULL),m_pbBufExt(NULL)
  1832. {
  1833. ::InitializeCriticalSection(&m_cs);
  1834. }
  1835. CMLFLink::CCodePagesCache::~CCodePagesCache(void)
  1836. {
  1837. DeleteCriticalSection(&m_cs);
  1838. }
  1839. HRESULT CMLFLink::CCodePagesCache::RealLoad(void)
  1840. {
  1841. HRESULT hr = S_OK;
  1842. ::EnterCriticalSection(&m_cs);
  1843. if (!m_pbBuf && !m_pbBufExt)
  1844. {
  1845. HRSRC hrCodePages;
  1846. HGLOBAL hgCodePages;
  1847. HRSRC hrCodePagesExt;
  1848. HGLOBAL hgCodePagesExt;
  1849. if (SUCCEEDED(hr))
  1850. {
  1851. hrCodePages = ::FindResource(g_hInst, MAKEINTRESOURCE(IDR_CODEPAGES), _T("CODEPAGES"));
  1852. hrCodePagesExt = ::FindResource(g_hInst, MAKEINTRESOURCE(IDR_CODEPAGESEXT), _T("CODEPAGESEXT"));
  1853. if (!hrCodePages || !hrCodePagesExt)
  1854. hr = E_FAIL; // Build error?
  1855. }
  1856. if (SUCCEEDED(hr))
  1857. {
  1858. hgCodePages = ::LoadResource(g_hInst, hrCodePages);
  1859. hgCodePagesExt = ::LoadResource(g_hInst, hrCodePagesExt);
  1860. if (!hgCodePages && !hgCodePagesExt)
  1861. hr = E_FAIL; // Unexpected error
  1862. }
  1863. if (SUCCEEDED(hr))
  1864. {
  1865. m_pbBuf = (BYTE*)::LockResource(hgCodePages);
  1866. m_pbBufExt = (BYTE*)::LockResource(hgCodePagesExt);
  1867. if (!m_pbBuf || !m_pbBufExt)
  1868. hr = E_FAIL; // Unexpected error
  1869. }
  1870. }
  1871. ::LeaveCriticalSection(&m_cs);
  1872. return hr;
  1873. }
  1874. extern "C" HRESULT GetGlobalFontLinkObject(IMLangFontLink **ppMLFontLink)
  1875. {
  1876. HRESULT hr = E_INVALIDARG;
  1877. if (NULL != ppMLFontLink)
  1878. {
  1879. if (NULL == g_pMLFLink)
  1880. {
  1881. EnterCriticalSection(&g_cs);
  1882. if (NULL == g_pMLFLink)
  1883. CComCreator< CComPolyObject< CMLFLink > >::CreateInstance(NULL, IID_IMLangFontLink, (void **)&g_pMLFLink);
  1884. LeaveCriticalSection(&g_cs);
  1885. }
  1886. *ppMLFontLink = g_pMLFLink;
  1887. if (g_pMLFLink)
  1888. {
  1889. g_pMLFLink->AddRef();
  1890. hr = S_OK;
  1891. }
  1892. else
  1893. hr = E_FAIL;
  1894. }
  1895. return hr;
  1896. }
  1897. HRESULT CMLFLink2::CFontMappingCache2::MapFontFromCMAP(HDC hDC, WCHAR wchar, HFONT hSrcFont, HFONT *phDestFont)
  1898. {
  1899. BOOL bFont = FALSE;
  1900. HRESULT hr = E_FAIL;
  1901. int i,j,k;
  1902. LOGFONT LogFont;
  1903. if (!phDestFont)
  1904. return E_INVALIDARG;
  1905. if (!GetObject(hSrcFont, sizeof(LOGFONT), &LogFont))
  1906. return hr;
  1907. if (!g_pfont_table || !g_pfont_table[0].szFaceName[0])
  1908. {
  1909. if (FAILED(LoadFontDataFile()))
  1910. {
  1911. return hr;
  1912. }
  1913. }
  1914. i=0;
  1915. j=ARRAYSIZE(g_urange_table);
  1916. k = j/2;
  1917. while (i<=j)
  1918. {
  1919. if (wchar >= g_urange_table[k].wcFrom && wchar <= g_urange_table[k].wcTo)
  1920. break;
  1921. else
  1922. if (wchar < g_urange_table[k].wcFrom)
  1923. {
  1924. j = k -1;
  1925. }
  1926. else
  1927. {
  1928. i = k + 1;
  1929. }
  1930. k = (i+j)/2;
  1931. }
  1932. if (i<=j && g_urange_table[k].nFonts)
  1933. {
  1934. TCHAR szFaceName[LF_FACESIZE];
  1935. GetTextFace(hDC, LF_FACESIZE, szFaceName);
  1936. // Check if it supports the character
  1937. for (i=0; i<g_urange_table[k].nFonts; i++)
  1938. {
  1939. if (!MLStrCmpI(szFaceName,g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName))
  1940. break;
  1941. }
  1942. // Current font doesn't support this character
  1943. if (i == g_urange_table[k].nFonts)
  1944. {
  1945. for (i=0; i<g_urange_table[k].nFonts; i++)
  1946. {
  1947. if (LogFont.lfCharSet == g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfCharSet)
  1948. break;
  1949. }
  1950. // No font available for current CharSet, then return the first one in the list
  1951. if (i >= g_urange_table[k].nFonts)
  1952. {
  1953. i = fetchCharSet((BYTE *) &(LogFont.lfCharSet), k);
  1954. }
  1955. MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE);
  1956. }
  1957. if (i < g_urange_table[k].nFonts)
  1958. {
  1959. MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE);
  1960. }
  1961. bFont = TRUE;
  1962. }
  1963. if (bFont && (*phDestFont = CreateFontIndirect(&LogFont)))
  1964. {
  1965. hr = S_OK;
  1966. }
  1967. else
  1968. {
  1969. *phDestFont = NULL;
  1970. }
  1971. return hr;
  1972. }
  1973. HRESULT CMLFLink2::CFontMappingCache2::UnicodeRanges(
  1974. LPTSTR szFont,
  1975. UINT *puiRanges,
  1976. UNICODERANGE* pURanges
  1977. )
  1978. {
  1979. HRESULT hr = E_FAIL;
  1980. UINT nURange = 0;
  1981. DWORD cmap = 0;
  1982. DWORD name = 0;
  1983. HANDLE hTTF;
  1984. TCHAR szFontPath[MAX_PATH];
  1985. static TCHAR s_szFontDir[MAX_PATH] = {0};
  1986. HANDLE hTTFMap;
  1987. DWORD dwFileSize;
  1988. LPVOID lpvFile = NULL;
  1989. LPBYTE lp, lp1, lp2, lpMax = NULL;
  1990. DWORD Num;
  1991. WORD i, j, Len;
  1992. if (!szFont[0])
  1993. return hr;
  1994. if (!s_szFontDir[0])
  1995. {
  1996. MLGetWindowsDirectory(s_szFontDir, MAX_PATH);
  1997. MLPathCombine(s_szFontDir, s_szFontDir, FONT_FOLDER);
  1998. }
  1999. MLPathCombine(szFontPath, s_szFontDir, szFont);
  2000. hTTF = CreateFile( szFontPath, // pointer to name of the file
  2001. GENERIC_READ, // access (read-write) mode
  2002. FILE_SHARE_READ, // share mode
  2003. NULL, // pointer to security attributes
  2004. OPEN_EXISTING, // how to create
  2005. FILE_ATTRIBUTE_NORMAL, // file attributes
  2006. NULL); // handle to file with attributes to copy;
  2007. if (INVALID_HANDLE_VALUE == hTTF)
  2008. return hr;
  2009. dwFileSize = GetFileSize(hTTF, NULL);
  2010. hTTFMap = CreateFileMapping(
  2011. hTTF,
  2012. NULL,
  2013. PAGE_READONLY,
  2014. 0,
  2015. dwFileSize,
  2016. NULL
  2017. );
  2018. if(hTTFMap == NULL)
  2019. {
  2020. goto CloseHandle0;
  2021. }
  2022. lpvFile = MapViewOfFile(
  2023. hTTFMap,
  2024. FILE_MAP_READ,
  2025. 0,
  2026. 0,
  2027. 0
  2028. );
  2029. if(lpvFile == NULL)
  2030. {
  2031. goto CloseHandle;
  2032. }
  2033. lp = (LPBYTE)lpvFile;
  2034. // The maximum boundary we can go
  2035. lpMax = (LPBYTE)lpvFile + dwFileSize;
  2036. // Font table name uses ASCII
  2037. if(strncmp(((TTC_HEAD*)lp)->TTCTag, "ttcf", 4) == 0) // TTC format
  2038. {
  2039. lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1); // points to first TTF
  2040. }
  2041. Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables); // Number of Tables
  2042. lp += sizeof(TTF_HEAD);
  2043. if (lp+Num*sizeof(TABLE_DIR) >= lpMax) // Not a valid TrueType file if table size >= TTF file size
  2044. goto CloseHandle;
  2045. for(i = 0; i < Num ; i++) // go thru all tables to find cmap and name
  2046. {
  2047. if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0)
  2048. {
  2049. cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2050. if (name) break;
  2051. }
  2052. else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0)
  2053. {
  2054. name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2055. if (cmap) break;
  2056. }
  2057. lp += sizeof(TABLE_DIR);
  2058. }
  2059. if((!cmap) || (!name)) // Can't find cmap or name
  2060. {
  2061. goto CloseHandle;
  2062. }
  2063. // Read thru all name records
  2064. // to see if font subfamily name is "Regular"
  2065. lp = (LPBYTE)lpvFile + name; // point to name table
  2066. Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec); // # of name record
  2067. if (lp + sizeof(NAME_TABLE)*Num >= lpMax)
  2068. goto CloseHandle;
  2069. lp1 = lp + sizeof(NAME_TABLE); // point to name record
  2070. for(i = 0; i < Num; i++)
  2071. {
  2072. if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID))
  2073. {
  2074. lp2 = lp + // point to string store
  2075. TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) +
  2076. TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset);
  2077. // Invalid TTF file
  2078. if (lp2 >= lpMax)
  2079. break;
  2080. Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length);
  2081. if(((MICROSOFT_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) &&
  2082. (UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))) ||
  2083. ((APPLE_UNICODE_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) &&
  2084. (APPLE_UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))))
  2085. {
  2086. Len >>= 1;
  2087. const char *pStr = szRegular;
  2088. if (Len == sizeof(szNormal) -1)
  2089. pStr = szNormal;
  2090. else
  2091. if (Len != sizeof(szRegular)-1)
  2092. {
  2093. lp1 += sizeof(NAME_RECORD);
  2094. continue;
  2095. }
  2096. while(--Len > 0)
  2097. {
  2098. if(*(lp2+(Len<<1)+1) != pStr[Len])
  2099. break;
  2100. }
  2101. if (!Len)
  2102. break;
  2103. else
  2104. {
  2105. lp1 += sizeof(NAME_RECORD);
  2106. continue;
  2107. }
  2108. }
  2109. else
  2110. {
  2111. if(strncmp((char*)lp2, szRegular, sizeof(szRegular)-1) != 0 &&
  2112. strncmp((char*)lp2, szNormal, sizeof(szNormal)-1) != 0)
  2113. {
  2114. lp1 += sizeof(NAME_RECORD);
  2115. continue;
  2116. }
  2117. else
  2118. break;
  2119. }
  2120. }
  2121. lp1 += sizeof(NAME_RECORD);
  2122. }
  2123. // If no regular font, exit
  2124. if (i == Num)
  2125. goto CloseHandle;
  2126. // all non-regular fonts have already been eliminated
  2127. lp1 = (LPBYTE)lpvFile + cmap; // point to cmap table
  2128. if (lp1 + sizeof(CMAP_TABLE)*Num >= lpMax)
  2129. goto CloseHandle;
  2130. Num = TWO_BYTE_NUM(((CMAP_HEAD*)lp1)->NumTables);
  2131. lp1 += sizeof(CMAP_HEAD);
  2132. while(Num >0)
  2133. {
  2134. if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM &&
  2135. (TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING ||
  2136. TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_SYMBOL_INDEXING))
  2137. {
  2138. lp = (LPBYTE)lpvFile
  2139. + cmap
  2140. + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset);
  2141. if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR)
  2142. {
  2143. break;
  2144. }
  2145. }
  2146. Num--;
  2147. lp1 += sizeof(CMAP_TABLE);
  2148. }
  2149. if(Num == 0) // can't find Platform:3/Encoding:1 (Unicode)
  2150. goto CloseHandle;
  2151. Num = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2);
  2152. lp2 = lp + sizeof(CMAP_FORMAT); // lp2 -> first WCHAR of wcTo
  2153. lp1 = lp2 + Num + 2; // lp1 -> first WCHAR of wcFrom
  2154. if (lp1 + Num >= lpMax)
  2155. goto CloseHandle;
  2156. Num /= 2;
  2157. if (pURanges == NULL)
  2158. {
  2159. *puiRanges = Num;
  2160. }
  2161. else
  2162. {
  2163. if (Num > *puiRanges)
  2164. Num = *puiRanges;
  2165. else
  2166. *puiRanges = Num;
  2167. for(i=0, j=0; i < Num; i++, j++, j++)
  2168. {
  2169. pURanges[i].wcFrom = TWO_BYTE_NUM((lp1+j));
  2170. pURanges[i].wcTo = TWO_BYTE_NUM((lp2+j));
  2171. }
  2172. }
  2173. hr = S_OK;
  2174. CloseHandle:
  2175. UnmapViewOfFile(lpvFile);
  2176. CloseHandle0:
  2177. CloseHandle(hTTFMap);
  2178. CloseHandle(hTTF);
  2179. return hr;
  2180. }
  2181. int CMLFLink2::CFontMappingCache2::fetchCharSet(BYTE *pCharset, int iURange)
  2182. {
  2183. int i,j;
  2184. //Check if current charset valid for the font
  2185. for (i=0; i<g_urange_table[iURange].nFonts; i++)
  2186. {
  2187. for (j=0;(j<32) && g_CharSetTransTable[j].uCodePage;j++)
  2188. {
  2189. if (g_pfont_table[*(g_urange_table[iURange].pFontIndex+i)].dwCodePages[0] & g_CharSetTransTable[j].dwCodePages)
  2190. if (*pCharset == g_CharSetTransTable[j].nCharSet)
  2191. return i;
  2192. }
  2193. }
  2194. //If invalid, fetch first valid one.
  2195. for (i=0;(i<32) && g_CharSetTransTable[i].uCodePage;i++)
  2196. {
  2197. if (g_pfont_table[*(g_urange_table[iURange].pFontIndex)].dwCodePages[0] & g_CharSetTransTable[i].dwCodePages)
  2198. {
  2199. *pCharset = (BYTE)g_CharSetTransTable[i].nCharSet;
  2200. break;
  2201. }
  2202. }
  2203. return 0;
  2204. }
  2205. BOOL CMLFLink2::CFontMappingCache2::GetNonCpFontUnicodeRanges(TCHAR *szFontName, int iFontIndex)
  2206. {
  2207. LONG nURange = 0;
  2208. DWORD cmap = 0;
  2209. DWORD name = 0;
  2210. DWORD os2 = 0;
  2211. HANDLE hTTFMap;
  2212. DWORD dwFileSize;
  2213. LPVOID lpvFile;
  2214. LPBYTE lp, lp1, lp2;
  2215. DWORD Num;
  2216. int i, j, k, m;
  2217. WORD Len;
  2218. HANDLE hTTF;
  2219. BOOL bRet = FALSE;
  2220. hTTF = CreateFile( szFontName, // pointer to name of the file
  2221. GENERIC_READ, // access (read-write) mode
  2222. FILE_SHARE_READ, // share mode
  2223. NULL, // pointer to security attributes
  2224. OPEN_EXISTING, // how to create
  2225. FILE_ATTRIBUTE_NORMAL, // file attributes
  2226. NULL); // handle to file with attributes to copy;
  2227. if (hTTF == INVALID_HANDLE_VALUE)
  2228. return FALSE;
  2229. dwFileSize = GetFileSize(hTTF, NULL);
  2230. hTTFMap = CreateFileMapping(
  2231. hTTF,
  2232. NULL,
  2233. PAGE_READONLY,
  2234. 0,
  2235. dwFileSize,
  2236. NULL
  2237. );
  2238. if(hTTFMap == NULL)
  2239. {
  2240. goto CloseHandle01;
  2241. }
  2242. lpvFile = MapViewOfFile(
  2243. hTTFMap,
  2244. FILE_MAP_READ,
  2245. 0,
  2246. 0,
  2247. 0
  2248. );
  2249. if(lpvFile == NULL)
  2250. {
  2251. goto CloseHandle00;
  2252. }
  2253. lp = (LPBYTE)lpvFile;
  2254. if(strncmp(((TTC_HEAD*)lp)->TTCTag, "ttcf", 4) == 0) // TTC format
  2255. {
  2256. lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1); // points to first TTF
  2257. }
  2258. Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables); // Number of Tables
  2259. {
  2260. // if SearchRange != (Maximum power of 2 <= Num)*16,
  2261. // then this is not a TTF file
  2262. DWORD wTmp = 1;
  2263. while(wTmp <= Num)
  2264. {
  2265. wTmp <<= 1;
  2266. }
  2267. wTmp <<= 3; // (wTmp/2)*16
  2268. if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->SearchRange))
  2269. {
  2270. goto CloseHandle00;
  2271. }
  2272. // if RangeShift != (Num*16) - SearchRange,
  2273. // then this is not a TTF file
  2274. wTmp = (Num<<4) - wTmp;
  2275. if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->RangeShift))
  2276. {
  2277. goto CloseHandle00;
  2278. }
  2279. }
  2280. lp += sizeof(TTF_HEAD);
  2281. for(i = 0; i < (int)Num; i++) // go thru all tables to find cmap and name
  2282. {
  2283. if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0)
  2284. {
  2285. cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2286. if (name && os2) break;
  2287. }
  2288. else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0)
  2289. {
  2290. name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2291. if (cmap && os2) break;
  2292. }
  2293. else if(strncmp( ((TABLE_DIR*)lp)->Tag, "OS/2", 4) == 0)
  2294. {
  2295. os2 = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2296. if (cmap && name) break;
  2297. }
  2298. lp += sizeof(TABLE_DIR);
  2299. }
  2300. if((!cmap) || (!name) || (!os2)) // Can't find cmap or name
  2301. {
  2302. goto CloseHandle00;
  2303. }
  2304. // Read thru all name records
  2305. // to see if font subfamily name is "Regular"
  2306. lp = (LPBYTE)lpvFile + name; // point to name table
  2307. Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec); // # of name record
  2308. lp1 = lp + sizeof(NAME_TABLE); // point to name record
  2309. for(i = 0; i < (int)Num; i++)
  2310. {
  2311. if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID))
  2312. {
  2313. lp2 = lp + // point to string store
  2314. TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) +
  2315. TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset);
  2316. Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length);
  2317. if(UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))
  2318. {
  2319. Len >>= 1;
  2320. while(--Len > 0)
  2321. {
  2322. if(*(lp2+(Len<<1)+1) != szRegular[Len])
  2323. goto CloseHandle00;
  2324. }
  2325. break;
  2326. }
  2327. else
  2328. {
  2329. if(strncmp((char*)lp2, szRegular, Len) != 0)
  2330. goto CloseHandle00;
  2331. else
  2332. break;
  2333. }
  2334. }
  2335. lp1 += sizeof(NAME_RECORD);
  2336. }
  2337. // all non-regular fonts have already been eliminated
  2338. lp1 = (LPBYTE)lpvFile + cmap; // point to cmap table
  2339. Num = TWO_BYTE_NUM(((CMAP_HEAD*)lp)->NumTables);
  2340. lp1 += sizeof(CMAP_HEAD);
  2341. while(Num >0)
  2342. {
  2343. if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM &&
  2344. TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING)
  2345. {
  2346. lp = (LPBYTE)lpvFile
  2347. + cmap
  2348. + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset);
  2349. if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR)
  2350. {
  2351. break;
  2352. }
  2353. }
  2354. Num--;
  2355. lp1 += sizeof(CMAP_TABLE);
  2356. }
  2357. if(Num == 0) // can't find Platform:3/Encoding:1 (Unicode)
  2358. goto CloseHandle00;
  2359. Num = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2) ;
  2360. m = ARRAYSIZE(g_urange_table);
  2361. lp2 = lp + sizeof(CMAP_FORMAT); // lp2 -> first WCHAR of wcTo
  2362. lp1 = lp2 + Num + 2; // lp1 -> first WCHAR of wcFrom
  2363. // Fast parse !!!
  2364. while (--m)
  2365. {
  2366. // URANGE binary search
  2367. i=0;
  2368. j= (int) Num - 2;
  2369. k=j/2;
  2370. while (i<=j)
  2371. {
  2372. if (k % 2)
  2373. k++;
  2374. if (g_urange_table[m].wcFrom >= TWO_BYTE_NUM((lp1+k)) && g_urange_table[m].wcTo <= TWO_BYTE_NUM((lp2+k)))
  2375. {
  2376. EnterCriticalSection(&g_cs);
  2377. if (!g_urange_table[m].pFontIndex)
  2378. g_urange_table[m].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)* MAX_FONT_INDEX);
  2379. if (!g_urange_table[m].pFontIndex)
  2380. {
  2381. goto CloseHandle00;
  2382. }
  2383. if (g_urange_table[m].nFonts >= MAX_FONT_INDEX)
  2384. {
  2385. break;
  2386. }
  2387. g_urange_table[m].pFontIndex[g_urange_table[m].nFonts] = iFontIndex;
  2388. g_urange_table[m].nFonts++;
  2389. // Fill in font code page signature
  2390. g_pfont_table[iFontIndex].dwCodePages[0] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE));
  2391. g_pfont_table[iFontIndex].dwCodePages[1] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE+1));
  2392. LeaveCriticalSection(&g_cs);
  2393. break;
  2394. }
  2395. else
  2396. {
  2397. if (g_urange_table[m].wcFrom < TWO_BYTE_NUM((lp1+k)))
  2398. {
  2399. j = k-2;
  2400. }
  2401. else
  2402. {
  2403. i = k+2;
  2404. }
  2405. k = (i+j)/2;
  2406. }
  2407. }
  2408. }
  2409. bRet = TRUE;
  2410. CloseHandle00:
  2411. UnmapViewOfFile(lpvFile);
  2412. CloseHandle01:
  2413. CloseHandle(hTTF);
  2414. CloseHandle(hTTFMap);
  2415. return bRet;
  2416. }
  2417. HRESULT GetRegFontKey(HKEY *phKey, DWORD *pdwValues)
  2418. {
  2419. HRESULT hr = E_FAIL;
  2420. if (ERROR_SUCCESS == (g_bIsNT?
  2421. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEYNT, 0, KEY_READ, phKey):
  2422. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEY95, 0, KEY_READ, phKey)))
  2423. {
  2424. if (ERROR_SUCCESS == RegQueryInfoKey(*phKey, NULL, NULL, 0, NULL,
  2425. NULL, NULL, pdwValues, NULL, NULL, NULL, NULL))
  2426. {
  2427. hr = S_OK;
  2428. }
  2429. }
  2430. return hr;
  2431. }
  2432. BOOL CMLFLink2::CFontMappingCache2::GetFontURangeBits(TCHAR *szFontFile, DWORD * pdwURange)
  2433. {
  2434. // We can make use of font Unicode range signature if needed.
  2435. return TRUE;
  2436. }
  2437. BOOL CMLFLink2::CFontMappingCache2::SetFontScripts(void)
  2438. {
  2439. LOGFONT lf;
  2440. int i,j;
  2441. HWND hWnd = GetTopWindow(GetDesktopWindow());
  2442. HDC hDC = GetDC(hWnd);
  2443. if (!g_pfont_table)
  2444. return FALSE;
  2445. // Process code page based scripts (g_CharSetTransTable.sid)
  2446. for (i = 0; g_CharSetTransTable[i].nCharSet != DEFAULT_CHARSET; i++)
  2447. {
  2448. j = 0;
  2449. ZeroMemory(&lf, sizeof(lf));
  2450. lf.lfCharSet = (BYTE)g_CharSetTransTable[i].nCharSet;
  2451. while (g_CharSetTransTable[i].sid[j] != sidDefault)
  2452. {
  2453. EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)SetFontScriptsEnumFontProc, (LPARAM)g_CharSetTransTable[i].sid[j], 0);
  2454. j++;
  2455. }
  2456. }
  2457. if (hDC)
  2458. ReleaseDC(hWnd, hDC);
  2459. // Process Unicode subrange based scripts (not implemented)
  2460. // Skip this part since we need to access font CMAP anyway
  2461. // Process char based scripts (g_wCharToScript)
  2462. for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  2463. {
  2464. UINT uiRanges = 0;
  2465. UNICODERANGE* pURanges = NULL;
  2466. SCRIPT_IDS scripts;
  2467. if (SUCCEEDED(m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges)))
  2468. {
  2469. if (uiRanges)
  2470. {
  2471. int l, m, n;
  2472. pURanges = (UNICODERANGE *)LocalAlloc(LPTR, sizeof(UNICODERANGE) * uiRanges);
  2473. if (!pURanges)
  2474. return FALSE;
  2475. m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges);
  2476. for (j=0; j< ARRAYSIZE(g_wCharToScript); j++)
  2477. {
  2478. l = 0;
  2479. m = uiRanges;
  2480. n = m/2;
  2481. while (l <= m)
  2482. {
  2483. if ((g_wCharToScript[j].wch >= pURanges[n].wcFrom) && (g_wCharToScript[j].wch <= pURanges[n].wcTo))
  2484. {
  2485. scripts = 1;
  2486. scripts <<= g_wCharToScript[j].sid;
  2487. g_pfont_table[i].scripts |= scripts;
  2488. break;
  2489. }
  2490. else
  2491. {
  2492. if (g_wCharToScript[j].wch < pURanges[n].wcFrom)
  2493. m = n-1;
  2494. else
  2495. l = n+1;
  2496. n = (m+l)/2;
  2497. }
  2498. }
  2499. }
  2500. LocalFree(pURanges);
  2501. pURanges = NULL;
  2502. }
  2503. }
  2504. // sidUserDefined should contain all valid regular TrueType fonts
  2505. if (!MLStrStr(g_pfont_table[i].szFaceName, TEXT("Bold")) && !MLStrStr(g_pfont_table[i].szFaceName, TEXT("Italic")))
  2506. {
  2507. scripts = 1;
  2508. scripts <<= sidUserDefined;
  2509. g_pfont_table[i].scripts |= scripts;
  2510. }
  2511. }
  2512. //GetFontScriptFromCMAP(szFont, &(g_pfont_table[i].scripts));
  2513. return TRUE;
  2514. }
  2515. BOOL CMLFLink2::CFontMappingCache2::IsFontUpdated(void)
  2516. {
  2517. HKEY hkey;
  2518. DWORD dwFonts = 0;
  2519. BOOL bRet = FALSE;
  2520. if (g_pfont_table)
  2521. {
  2522. if (S_OK == GetRegFontKey(&hkey, &dwFonts))
  2523. {
  2524. if (g_pfont_table[0].dwCodePages[1] != dwFonts)
  2525. bRet = TRUE;
  2526. RegCloseKey(hkey);
  2527. }
  2528. }
  2529. else
  2530. {
  2531. // font table not created yet, need to update
  2532. bRet = TRUE;
  2533. }
  2534. return bRet;
  2535. }
  2536. // Make sure we have font data table available and it is updated
  2537. HRESULT CMLFLink2::CFontMappingCache2::EnsureFontTable(BOOL bUpdateURangeTable)
  2538. {
  2539. BOOL bRet;
  2540. if (IsFontUpdated())
  2541. {
  2542. // Need to guard the whole font creation procedure by critical sections
  2543. EnterCriticalSection(&g_cs);
  2544. if (IsFontUpdated())
  2545. {
  2546. if (g_pfont_table)
  2547. {
  2548. if (g_pfont_table[0].szFaceName[0])
  2549. {
  2550. bUpdateURangeTable = TRUE;
  2551. }
  2552. if (g_pfont_table)
  2553. {
  2554. LocalFree(g_pfont_table);
  2555. g_pfont_table = NULL;
  2556. }
  2557. }
  2558. bRet = SetFontTable();
  2559. if (!bRet)
  2560. return E_OUTOFMEMORY;
  2561. }
  2562. LeaveCriticalSection(&g_cs);
  2563. }
  2564. if (bUpdateURangeTable)
  2565. {
  2566. EnterCriticalSection(&g_cs);
  2567. for (int i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2568. {
  2569. if (g_urange_table[i].nFonts)
  2570. {
  2571. LocalFree(g_urange_table[i].pFontIndex);
  2572. g_urange_table[i].pFontIndex = NULL;
  2573. g_urange_table[i].nFonts = 0;
  2574. }
  2575. }
  2576. LeaveCriticalSection(&g_cs);
  2577. if (S_OK != SetFontUnicodeRanges())
  2578. return E_OUTOFMEMORY;
  2579. SaveFontDataFile();
  2580. }
  2581. // All tables created successfully
  2582. return S_OK;
  2583. }
  2584. #ifdef UNIX
  2585. typedef struct tagTable_info{
  2586. int count;
  2587. int table_size;
  2588. } Table_info;
  2589. int UnixGetAllFontsProc(ENUMLOGFONTEX* plfFont, NEWTEXTMETRICEX* lpntm, int iFontType, LPARAM lParam)
  2590. {
  2591. LOGFONT *lplf;
  2592. int *pcount = &((Table_info*)lParam)->count;
  2593. int *ptable_size = &((Table_info*)lParam)->table_size;
  2594. lplf = &(plfFont->elfLogFont);
  2595. // We don't use non TrueType fonts
  2596. if (iFontType == DEVICE_FONTTYPE || iFontType == RASTER_FONTTYPE)
  2597. return 1; // keep going but don't use this font
  2598. // We don't use the SYMBOL, Mac Charset fonts
  2599. if(lplf->lfCharSet == SYMBOL_CHARSET || lplf->lfCharSet == MAC_CHARSET)
  2600. return 1;
  2601. // We don't handle vertical fonts
  2602. if (TEXT('@') == lplf->lfFaceName[0])
  2603. return 1;
  2604. // Now update the font-table
  2605. // Does UNIX use TTF? // if (FontType == TRUETYPE_FONTTYPE)
  2606. {
  2607. CopyMemory(&g_pfont_table[*pcount].lf, lplf, sizeof(LOGFONT));
  2608. MLStrCpyN(g_pfont_table[*pcount].szFaceName, lplf->lfFaceName, LF_FACESIZE);
  2609. (*pcount)++;
  2610. }
  2611. if (*pcount >= *ptable_size)
  2612. {
  2613. FONTINFO * pfont_table = NULL;
  2614. *ptable_size += FONT_TABLE_INIT_SIZE;
  2615. pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table,
  2616. sizeof(FONTINFO) * *ptable_size,
  2617. LMEM_MOVEABLE | LMEM_ZEROINIT);
  2618. if (NULL == pfont_table)
  2619. {
  2620. return 0; // Stop enum.
  2621. }
  2622. else
  2623. {
  2624. g_pfont_table = pfont_table;
  2625. }
  2626. }
  2627. return 1; // Keep enum.
  2628. }
  2629. #endif
  2630. BOOL CMLFLink2::CFontMappingCache2::SetFontTable(void)
  2631. {
  2632. BOOL bRet = TRUE;
  2633. TCHAR szFaceName[MAX_PATH];
  2634. DWORD dwValue;
  2635. TCHAR szFontFile[MAX_FONT_FILE_NAME];
  2636. DWORD dwData;
  2637. DWORD dwType = REG_SZ;
  2638. DWORD dwFonts;
  2639. int i, table_size = FONT_TABLE_INIT_SIZE;
  2640. LPTSTR pNewFaceName = NULL;
  2641. HKEY hkey = NULL;
  2642. static int count;
  2643. HDC hDC = NULL;
  2644. HWND hWnd = NULL;
  2645. count = 1;
  2646. if (!g_pfont_table)
  2647. {
  2648. g_pfont_table = (FONTINFO *)LocalAlloc(LPTR, sizeof(FONTINFO) * FONT_TABLE_INIT_SIZE);
  2649. if (!g_pfont_table)
  2650. {
  2651. bRet = FALSE;
  2652. goto SETFONT_DONE;
  2653. }
  2654. }
  2655. else
  2656. {
  2657. goto SETFONT_DONE;
  2658. }
  2659. #ifndef UNIX
  2660. if (S_OK != GetRegFontKey(&hkey, &dwFonts))
  2661. {
  2662. bRet = FALSE;
  2663. goto SETFONT_DONE;
  2664. }
  2665. hWnd = GetTopWindow(GetDesktopWindow());
  2666. hDC = GetDC(hWnd);
  2667. for (i=0; ;i++)
  2668. {
  2669. dwValue = sizeof(szFaceName);
  2670. dwData = sizeof(szFontFile);
  2671. if (ERROR_NO_MORE_ITEMS == RegEnumValue(
  2672. hkey,
  2673. i,
  2674. szFaceName,
  2675. &dwValue,
  2676. NULL,
  2677. &dwType,
  2678. (LPBYTE)szFontFile,
  2679. &dwData ))
  2680. {
  2681. break;
  2682. }
  2683. DWORD dwOffset = 0;
  2684. FIND_NEXT_FACENAME:
  2685. pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT(" & "));
  2686. if (pNewFaceName)
  2687. {
  2688. *pNewFaceName = 0;
  2689. // Skip " & ", look for next font face name
  2690. pNewFaceName+=3;
  2691. }
  2692. else
  2693. {
  2694. pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT("(TrueType)"));
  2695. if(pNewFaceName)
  2696. {
  2697. // Ignor the space between face name and "(TrueTye)" signature
  2698. if ((pNewFaceName > szFaceName) && (*(pNewFaceName-1) == 0x20))
  2699. pNewFaceName--;
  2700. *pNewFaceName = 0;
  2701. }
  2702. }
  2703. if (pNewFaceName && !EnumFontFamilies(hDC, &szFaceName[dwOffset], MapFontExEnumFontProc, (LPARAM)&count)) //TrueType font
  2704. {
  2705. int nSize;
  2706. LPTSTR pFontFile;
  2707. if (count >= table_size)
  2708. {
  2709. FONTINFO * _pfont_table = NULL;
  2710. table_size += FONT_TABLE_INIT_SIZE;
  2711. _pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, sizeof(FONTINFO) * table_size,
  2712. LMEM_MOVEABLE | LMEM_ZEROINIT);
  2713. if (NULL == _pfont_table)
  2714. {
  2715. bRet = FALSE;
  2716. goto SETFONT_DONE;
  2717. }
  2718. else
  2719. {
  2720. g_pfont_table = _pfont_table;
  2721. }
  2722. }
  2723. nSize = lstrlen(szFontFile);
  2724. if (!MLStrCmpNI(&szFontFile[nSize-3], "fot", 3))
  2725. MLStrCpyN(&szFontFile[nSize-3], "ttf", 3);
  2726. //
  2727. // Trim off path
  2728. //
  2729. // #335900, some third party apps write font file names to registry directly
  2730. // and the names they used could have redundant font path
  2731. //
  2732. pFontFile = szFontFile;
  2733. while (nSize)
  2734. {
  2735. // Font file name contains only ASCII characters,
  2736. // So, we can safely trim the path by backward searching '\'
  2737. if (szFontFile[nSize] == TEXT('\\'))
  2738. {
  2739. pFontFile = &szFontFile[nSize];
  2740. pFontFile++;
  2741. break;
  2742. }
  2743. nSize--;
  2744. }
  2745. GetFontURangeBits(szFontFile, &(g_pfont_table[count-1].dwUniSubRanges[0]));
  2746. MLStrCpyN(g_pfont_table[count-1].szFaceName, &szFaceName[dwOffset], LF_FACESIZE);
  2747. MLStrCpyN(g_pfont_table[count-1].szFileName, pFontFile, LF_FACESIZE);
  2748. }
  2749. if (pNewFaceName && (*pNewFaceName))
  2750. {
  2751. dwOffset = (DWORD)(pNewFaceName - &szFaceName[0]);
  2752. goto FIND_NEXT_FACENAME;
  2753. }
  2754. }
  2755. #else
  2756. // For UNIX, we don't have registry font information,
  2757. // Let's create font table through EnumFontFamiliesEx.
  2758. Table_info table_info;
  2759. table_info.count = 1;
  2760. table_info.table_size = table_size;
  2761. int iRet;
  2762. LOGFONT lf;
  2763. lf.lfCharSet = DEFAULT_CHARSET; // give me all fonts
  2764. lf.lfFaceName[0] = _T('\0');
  2765. lf.lfPitchAndFamily = 0;
  2766. hWnd = GetTopWindow(GetDesktopWindow());
  2767. hDC = GetDC(hWnd);
  2768. iRet = EnumFontFamiliesEx(hDC, // Enum all fonts
  2769. &lf,
  2770. (FONTENUMPROC)UnixGetAllFontsProc,
  2771. (LPARAM)&table_info,
  2772. 0);
  2773. count = table_info.count;
  2774. if (iRet == 0) // abort
  2775. {
  2776. bRet = FALSE;
  2777. goto SETFONT_DONE;
  2778. }
  2779. #endif // UNIX
  2780. // Release un-used memory
  2781. g_pfont_table = (FONTINFO *)LocalReAlloc(g_pfont_table, (count)*sizeof(FONTINFO), LMEM_MOVEABLE);
  2782. // Save TrueType font number
  2783. g_pfont_table[0].dwCodePages[0] = count-1;
  2784. #ifndef UNIX
  2785. // Unix doesn't have this number.
  2786. // Save total font number for font change verification
  2787. g_pfont_table[0].dwCodePages[1] = dwFonts;
  2788. RegCloseKey(hkey);
  2789. #endif
  2790. if (count > 1)
  2791. SetFontScripts();
  2792. SETFONT_DONE:
  2793. if (hDC)
  2794. ReleaseDC(hWnd, hDC);
  2795. if (count <= 1)
  2796. {
  2797. if (g_pfont_table)
  2798. {
  2799. LocalFree(g_pfont_table);
  2800. g_pfont_table = NULL;
  2801. }
  2802. bRet = FALSE;
  2803. }
  2804. return bRet;
  2805. }
  2806. HRESULT CMLFLink2::CFontMappingCache2::SaveFontDataFile(void)
  2807. {
  2808. FONTDATAHEADER fileHeader;
  2809. HRESULT hr = E_FAIL;
  2810. int *pTmpBuf = NULL;
  2811. HANDLE hFile = NULL;
  2812. int i, j, Count = 0;
  2813. DWORD dwSize;
  2814. FONTDATATABLE fontInfoTable, fontIndexTable;
  2815. hFile = CreateFile( szFontDataFilePath,
  2816. GENERIC_WRITE,
  2817. 0,
  2818. NULL,
  2819. CREATE_ALWAYS,
  2820. FILE_ATTRIBUTE_HIDDEN,
  2821. NULL);
  2822. if (hFile == INVALID_HANDLE_VALUE)
  2823. {
  2824. goto SAVE_FONT_DATA_DONE;
  2825. }
  2826. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2827. {
  2828. Count += (g_urange_table[i].nFonts+1);
  2829. }
  2830. // Create file header
  2831. lstrcpyA(fileHeader.FileSig, FONT_DATA_SIGNATURE);
  2832. fileHeader.dwVersion = 0x00010000;
  2833. // Use file size as CheckSum
  2834. fileHeader.dwCheckSum = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1)+Count*sizeof(int)+
  2835. + sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM;
  2836. fileHeader.nTable = FONTDATATABLENUM;
  2837. pTmpBuf = (int *)LocalAlloc(LPTR, Count*sizeof(int));
  2838. if (!pTmpBuf)
  2839. goto SAVE_FONT_DATA_DONE;
  2840. // Get font index data
  2841. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2842. {
  2843. *pTmpBuf++ = g_urange_table[i].nFonts;
  2844. if (g_urange_table[i].nFonts)
  2845. {
  2846. for (j = 0; j< g_urange_table[i].nFonts; j++)
  2847. {
  2848. *pTmpBuf++ = *(g_urange_table[i].pFontIndex+j);
  2849. }
  2850. }
  2851. }
  2852. pTmpBuf -= Count;
  2853. // Create Dir tables
  2854. lstrcpyA(fontInfoTable.szName, "fnt");
  2855. fontInfoTable.dwOffset = sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM;
  2856. fontInfoTable.dwSize = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1);
  2857. lstrcpyA(fontIndexTable.szName, "idx");
  2858. fontIndexTable.dwOffset = fontInfoTable.dwSize+fontInfoTable.dwOffset;
  2859. fontIndexTable.dwSize = Count*sizeof(int);
  2860. if (WriteFile(hFile, &fileHeader, sizeof(FONTDATAHEADER), &dwSize, NULL) &&
  2861. WriteFile(hFile, &fontInfoTable, sizeof(FONTDATATABLE), &dwSize, NULL) &&
  2862. WriteFile(hFile, &fontIndexTable, sizeof(FONTDATATABLE), &dwSize, NULL) &&
  2863. WriteFile(hFile, g_pfont_table, fontInfoTable.dwSize, &dwSize, NULL) &&
  2864. WriteFile(hFile, pTmpBuf, fontIndexTable.dwSize, &dwSize, NULL))
  2865. {
  2866. hr = S_OK;
  2867. }
  2868. SAVE_FONT_DATA_DONE:
  2869. if (hFile)
  2870. CloseHandle(hFile);
  2871. if (pTmpBuf)
  2872. LocalFree(pTmpBuf);
  2873. return hr;
  2874. }
  2875. HRESULT CMLFLink2::CFontMappingCache2::LoadFontDataFile(void)
  2876. {
  2877. HANDLE hFontData = NULL;
  2878. HANDLE hFileMap = NULL;
  2879. LPVOID lpvFile = NULL;
  2880. int * lp;
  2881. HRESULT hr = E_FAIL;
  2882. DWORD dwFileSize;
  2883. int i, j;
  2884. HKEY hKey = NULL;
  2885. DWORD nFonts;
  2886. FONTDATAHEADER *pHeader;
  2887. FONTDATATABLE *pfTable;
  2888. hFontData = CreateFile(szFontDataFilePath,
  2889. GENERIC_READ,
  2890. FILE_SHARE_READ,
  2891. NULL,
  2892. OPEN_EXISTING,
  2893. FILE_ATTRIBUTE_NORMAL,
  2894. NULL);
  2895. if (hFontData == INVALID_HANDLE_VALUE)
  2896. return EnsureFontTable(TRUE);
  2897. dwFileSize = GetFileSize(hFontData, NULL);
  2898. hFileMap = CreateFileMapping(
  2899. hFontData,
  2900. NULL,
  2901. PAGE_READONLY,
  2902. 0,
  2903. dwFileSize,
  2904. NULL
  2905. );
  2906. if(hFileMap == NULL)
  2907. {
  2908. goto Load_File_Done;
  2909. }
  2910. lpvFile = MapViewOfFile(
  2911. hFileMap,
  2912. FILE_MAP_READ,
  2913. 0,
  2914. 0,
  2915. 0
  2916. );
  2917. if (lpvFile == NULL)
  2918. {
  2919. goto Load_File_Done;
  2920. }
  2921. pHeader = (FONTDATAHEADER *)lpvFile;
  2922. // Check mlang font cache file by signature and checksum
  2923. if (lstrcmpA(pHeader->FileSig, FONT_DATA_SIGNATURE) || pHeader->dwCheckSum != dwFileSize)
  2924. {
  2925. goto Load_File_Done;
  2926. }
  2927. if (S_OK != GetRegFontKey(&hKey, &nFonts))
  2928. {
  2929. goto Load_File_Done;
  2930. }
  2931. pfTable = (FONTDATATABLE *) ((LPBYTE)lpvFile + sizeof(FONTDATAHEADER));
  2932. // Check if there is any font change (no guarantee, but works in most cases)
  2933. if (nFonts != ((FONTINFO*)((LPBYTE)lpvFile + pfTable[0].dwOffset))->dwCodePages[1])
  2934. {
  2935. // If there is a change in system font number, we reload everything
  2936. UnmapViewOfFile(lpvFile);
  2937. CloseHandle(hFileMap);
  2938. CloseHandle(hFontData);
  2939. RegCloseKey(hKey);
  2940. return EnsureFontTable(TRUE);
  2941. }
  2942. EnterCriticalSection(&g_cs);
  2943. // Reset cache information
  2944. if (g_pfont_table)
  2945. {
  2946. LocalFree(g_pfont_table);
  2947. g_pfont_table = NULL;
  2948. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2949. {
  2950. if (g_urange_table[i].nFonts)
  2951. {
  2952. LocalFree(g_urange_table[i].pFontIndex);
  2953. g_urange_table[i].pFontIndex = NULL;
  2954. g_urange_table[i].nFonts = 0;
  2955. }
  2956. }
  2957. }
  2958. if(!(g_pfont_table = (FONTINFO *) (LocalAlloc(LPTR, pfTable[0].dwSize))))
  2959. {
  2960. hr = E_OUTOFMEMORY;
  2961. goto Load_File_Done;
  2962. }
  2963. CopyMemory(g_pfont_table, (LPBYTE)lpvFile + pfTable[0].dwOffset, pfTable[0].dwSize);
  2964. lp = (int *)((LPBYTE)lpvFile + pfTable[1].dwOffset);
  2965. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2966. {
  2967. if (g_urange_table[i].nFonts = *lp++)
  2968. {
  2969. //g_urange_table[i].nFonts = *lp++;
  2970. g_urange_table[i].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)*g_urange_table[i].nFonts);
  2971. for (j = 0; j< g_urange_table[i].nFonts; j++)
  2972. {
  2973. g_urange_table[i].pFontIndex[j] = *lp++;
  2974. }
  2975. }
  2976. }
  2977. LeaveCriticalSection(&g_cs);
  2978. hr = S_OK;
  2979. Load_File_Done:
  2980. if (lpvFile)
  2981. UnmapViewOfFile(lpvFile);
  2982. if (hFileMap)
  2983. CloseHandle(hFileMap);
  2984. if (hFontData)
  2985. CloseHandle(hFontData);
  2986. if (hKey)
  2987. RegCloseKey(hKey);
  2988. return hr;
  2989. }
  2990. HRESULT CMLFLink2::CFontMappingCache2::SetFontUnicodeRanges(void)
  2991. {
  2992. TCHAR szFontPath[MAX_PATH];
  2993. TCHAR szFont[MAX_PATH];
  2994. HRESULT hr = S_OK;
  2995. int i;
  2996. EnterCriticalSection(&g_cs);
  2997. g_pfont_table[0].szFaceName[0] = 1;
  2998. LeaveCriticalSection(&g_cs);
  2999. MLGetWindowsDirectory(szFontPath, MAX_PATH);
  3000. MLPathCombine(szFontPath, szFontPath, FONT_FOLDER);
  3001. for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  3002. {
  3003. MLPathCombine(szFont, szFontPath, g_pfont_table[i].szFileName);
  3004. GetNonCpFontUnicodeRanges(szFont, i);
  3005. }
  3006. // Release un-used memory
  3007. for (i=0; i< ARRAYSIZE(g_urange_table); i++)
  3008. {
  3009. if (g_urange_table[i].nFonts)
  3010. g_urange_table[i].pFontIndex = (int *)LocalReAlloc(g_urange_table[i].pFontIndex, g_urange_table[i].nFonts*sizeof(int), LMEM_MOVEABLE);
  3011. }
  3012. return hr;
  3013. }
  3014. STDMETHODIMP CMLFLink2::GetStrCodePages(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages)
  3015. {
  3016. ASSERT_THIS;
  3017. ASSERT_READ_BLOCK(pszSrc, cchSrc);
  3018. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  3019. ASSERT_WRITE_PTR_OR_NULL(pcchCodePages);
  3020. HRESULT hr = S_OK;
  3021. long cchCodePages = 0;
  3022. DWORD dwStrCodePages = (DWORD)~0;
  3023. BOOL fInit = FALSE;
  3024. BOOL fNoPri = FALSE;
  3025. if (!pszSrc || cchSrc <= 0) // We can't make dwStrCodePages when cchSrc is zero
  3026. hr = E_INVALIDARG;
  3027. if (!m_pIMLFLnk)
  3028. return E_OUTOFMEMORY;
  3029. while (SUCCEEDED(hr) && cchSrc > 0)
  3030. {
  3031. DWORD dwCharCodePages;
  3032. if (SUCCEEDED(hr = m_pIMLFLnk->GetCharCodePages(*pszSrc, &dwCharCodePages)))
  3033. {
  3034. if (!fInit)
  3035. {
  3036. fInit = TRUE;
  3037. fNoPri = !(dwPriorityCodePages & dwCharCodePages);
  3038. }
  3039. else if (fNoPri != !(dwPriorityCodePages & dwCharCodePages))
  3040. {
  3041. break;
  3042. }
  3043. if (!fNoPri)
  3044. dwPriorityCodePages &= dwCharCodePages;
  3045. if (dwCharCodePages && (dwCharCodePages & dwStrCodePages))
  3046. dwStrCodePages &= dwCharCodePages;
  3047. else
  3048. break;
  3049. pszSrc++;
  3050. cchSrc--;
  3051. cchCodePages++;
  3052. }
  3053. }
  3054. if (SUCCEEDED(hr))
  3055. {
  3056. if (!cchCodePages)
  3057. {
  3058. dwStrCodePages = 0;
  3059. cchCodePages++;
  3060. }
  3061. if (pcchCodePages)
  3062. *pcchCodePages = cchCodePages;
  3063. if (pdwCodePages)
  3064. *pdwCodePages = dwStrCodePages;
  3065. }
  3066. else
  3067. {
  3068. if (pcchCodePages)
  3069. *pcchCodePages = 0;
  3070. if (pdwCodePages)
  3071. *pdwCodePages = 0;
  3072. }
  3073. return hr;
  3074. }
  3075. STDMETHODIMP CMLFLink2::MapFont(HDC hDC, DWORD dwCodePages, WCHAR wchar, HFONT* phDestFont)
  3076. {
  3077. HFONT hSrcFont = NULL;
  3078. if (NULL == (hSrcFont = (HFONT) GetCurrentObject(hDC, OBJ_FONT)))
  3079. return E_FAIL;
  3080. if (dwCodePages)
  3081. {
  3082. if (m_pIMLFLnk)
  3083. return m_pIMLFLnk->MapFont(hDC, dwCodePages, hSrcFont, phDestFont);
  3084. return E_OUTOFMEMORY;
  3085. }
  3086. else
  3087. {
  3088. if (!m_pFontMappingCache2)
  3089. m_pFontMappingCache2 = new CFontMappingCache2;
  3090. if (m_pFontMappingCache2)
  3091. return m_pFontMappingCache2->MapFontFromCMAP(hDC, wchar, hSrcFont, phDestFont);
  3092. else
  3093. return E_OUTOFMEMORY;
  3094. }
  3095. }
  3096. STDMETHODIMP CMLFLink2::GetFontUnicodeRanges(HDC hDC, UINT *puiRanges, UNICODERANGE* pURanges)
  3097. {
  3098. int i;
  3099. LOGFONT lf;
  3100. HRESULT hr = E_FAIL;
  3101. HFONT hFont = NULL;
  3102. if (!puiRanges)
  3103. return E_INVALIDARG;
  3104. if (!m_pFontMappingCache2)
  3105. m_pFontMappingCache2 = new CFontMappingCache2;
  3106. if (!m_pFontMappingCache2)
  3107. return E_OUTOFMEMORY;
  3108. if (!(hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT)))
  3109. return hr;
  3110. if (FAILED(m_pFontMappingCache2->EnsureFontTable(FALSE)))
  3111. return hr;
  3112. if (!GetObject(hFont, sizeof(LOGFONT), &lf))
  3113. return hr;
  3114. for (i=1; i<= (int) g_pfont_table[0].dwCodePages[0]; i++)
  3115. {
  3116. if (!lstrcmp(lf.lfFaceName, g_pfont_table[i].szFaceName))
  3117. break;
  3118. }
  3119. if (i > (int) g_pfont_table[0].dwCodePages[0])
  3120. return hr;
  3121. return m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, puiRanges, pURanges);
  3122. }
  3123. STDMETHODIMP CMLFLink2::GetScriptFontInfo(SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts, SCRIPTFONTINFO* pScriptFont)
  3124. {
  3125. HRESULT hr = E_FAIL;
  3126. UINT uiNum;
  3127. BYTE bPitch = dwFlags & SCRIPTCONTF_FIXED_FONT? FIXED_PITCH:VARIABLE_PITCH;
  3128. if (!m_pFontMappingCache2)
  3129. m_pFontMappingCache2 = new CFontMappingCache2;
  3130. if (m_pFontMappingCache2)
  3131. m_pFontMappingCache2->EnsureFontTable(FALSE);
  3132. if (!g_pfont_table)
  3133. return hr;
  3134. if (!pScriptFont)
  3135. {
  3136. uiNum = g_pfont_table[0].dwCodePages[0];
  3137. }
  3138. else
  3139. {
  3140. uiNum = *puiFonts;
  3141. }
  3142. *puiFonts = 0;
  3143. // Binary search font table to match script id.
  3144. for (UINT i=1; i<= g_pfont_table[0].dwCodePages[0]; i++)
  3145. {
  3146. // Check font pitch
  3147. if (!(g_pfont_table[i].lf.lfPitchAndFamily & bPitch))
  3148. continue;
  3149. // Get sid bit mask
  3150. SCRIPT_IDS sids = 1;
  3151. sids <<= sid;
  3152. if (sids & g_pfont_table[i].scripts)
  3153. {
  3154. // Bail out is required number reached
  3155. if (*puiFonts >= uiNum)
  3156. {
  3157. break;
  3158. }
  3159. if (pScriptFont)
  3160. {
  3161. MultiByteToWideChar(CP_ACP, 0, g_pfont_table[i].szFaceName, -1, (pScriptFont + *puiFonts)->wszFont, MAX_MIMEFACE_NAME);
  3162. (pScriptFont + *puiFonts)->scripts = g_pfont_table[i].scripts;
  3163. }
  3164. (*puiFonts)++;
  3165. }
  3166. }
  3167. return S_OK;
  3168. }
  3169. // Map Windows code page to script id
  3170. // if multiple script id exist, we'll return the default one
  3171. STDMETHODIMP CMLFLink2::CodePageToScriptID(UINT uiCodePage, SCRIPT_ID *pSid)
  3172. {
  3173. MIMECPINFO cpInfo;
  3174. HRESULT hr = E_FAIL;
  3175. if (!pSid)
  3176. return E_INVALIDARG;
  3177. if (NULL != g_pMimeDatabase)
  3178. {
  3179. if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo)))
  3180. {
  3181. if (cpInfo.uiFamilyCodePage == CP_USER_DEFINED)
  3182. {
  3183. *pSid = sidUserDefined;
  3184. hr = S_OK;
  3185. }
  3186. else
  3187. for (int i = 0; g_CharSetTransTable[i].uCodePage; i++)
  3188. {
  3189. if (cpInfo.uiFamilyCodePage == g_CharSetTransTable[i].uCodePage)
  3190. {
  3191. *pSid = g_CharSetTransTable[i].sid[0];
  3192. hr = S_OK;
  3193. break;
  3194. }
  3195. }
  3196. }
  3197. }
  3198. return hr;
  3199. }
  3200. CMLFLink2::CFontMappingCache2::CFontMappingCache2(void)
  3201. {
  3202. GetSystemDirectory(szFontDataFilePath, MAX_PATH);
  3203. MLPathCombine(szFontDataFilePath, szFontDataFilePath, FONT_DATA_FILE_NAME);
  3204. }
  3205. CMLFLink2::CFontMappingCache2::~CFontMappingCache2(void)
  3206. {
  3207. EnterCriticalSection(&g_cs);
  3208. if (g_pfont_table)
  3209. {
  3210. LocalFree(g_pfont_table);
  3211. g_pfont_table = NULL;
  3212. }
  3213. for (int i=0; i< ARRAYSIZE(g_urange_table); i++)
  3214. {
  3215. if (g_urange_table[i].nFonts)
  3216. {
  3217. LocalFree(g_urange_table[i].pFontIndex);
  3218. g_urange_table[i].nFonts = 0;
  3219. }
  3220. }
  3221. LeaveCriticalSection(&g_cs);
  3222. }
  3223. int CALLBACK CMLFLink2::CFontMappingCache2::MapFontExEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  3224. {
  3225. if (FontType == TRUETYPE_FONTTYPE && plfFont->lfFaceName[0] != TEXT('@') )
  3226. {
  3227. CopyMemory(&g_pfont_table[*(int *)lParam].lf, plfFont, sizeof(LOGFONT));
  3228. (*(int *)lParam)++;
  3229. return 0;
  3230. }
  3231. return 1;
  3232. }
  3233. int CALLBACK CMLFLink2::CFontMappingCache2::SetFontScriptsEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  3234. {
  3235. if (FontType == TRUETYPE_FONTTYPE)
  3236. {
  3237. if (g_pfont_table)
  3238. {
  3239. for (int i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  3240. if (!MLStrCmpNI(plfFont->lfFaceName, g_pfont_table[i].szFaceName, LF_FACESIZE))
  3241. {
  3242. SCRIPT_IDS scripts = 1;
  3243. scripts <<= lParam;
  3244. g_pfont_table[i].scripts |= scripts;
  3245. break;
  3246. }
  3247. if (i > (int)g_pfont_table[0].dwCodePages[0] && plfFont->lfFaceName[0] != TEXT('@')) // GDI font not in current font table?
  3248. {
  3249. FONTINFO * pfont_table = NULL;
  3250. pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table,
  3251. sizeof(FONTINFO) * (g_pfont_table[0].dwCodePages[0]+2),
  3252. LMEM_MOVEABLE | LMEM_ZEROINIT);
  3253. if (NULL != pfont_table)
  3254. {
  3255. g_pfont_table = pfont_table;
  3256. g_pfont_table[0].dwCodePages[0]++;
  3257. MLStrCpyN(g_pfont_table[i].szFaceName, (char *)plfFont->lfFaceName, LF_FACESIZE);
  3258. CopyMemory(&g_pfont_table[i].lf, plfFont, sizeof(LOGFONT));
  3259. SCRIPT_IDS scripts = 1;
  3260. scripts <<= lParam;
  3261. g_pfont_table[i].scripts |= scripts;
  3262. }
  3263. }
  3264. }
  3265. }
  3266. return 1;
  3267. }
  3268. int CALLBACK CMLFLink::VerifyFontSizeEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC* ptm, DWORD FontType, LPARAM lParam)
  3269. {
  3270. LOGFONT* plfSrcFont = (LOGFONT*)lParam;
  3271. if (FontType != TRUETYPE_FONTTYPE)
  3272. {
  3273. LONG lHeight = ptm->tmInternalLeading - ptm->tmHeight;
  3274. // Match source font's lfHeight to physical bitmap font's lfHeight
  3275. if (lHeight < 0 && plfSrcFont->lfHeight < 0 && lHeight < plfSrcFont->lfHeight)
  3276. {
  3277. plfSrcFont->lfHeight = lHeight ;
  3278. }
  3279. }
  3280. return 0;
  3281. }