Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3924 lines
116 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[LF_FACESIZE];
  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, ARRAYSIZE(tmpFontTable[ulFonts].szFaceName));
  1052. MLStrCpyNW(tmpFontTable[ulFonts].szFontFile, szFontFile, ARRAYSIZE(tmpFontTable[ulFonts].szFontFile));
  1053. ulFonts++;
  1054. }
  1055. dwValue = dwData = LF_FACESIZE;
  1056. dwType = REG_SZ;
  1057. }
  1058. m_pFlinkTable = (PFLINKFONT) LocalAlloc(LPTR, sizeof(FLINKFONT)*ulFLinkFonts);
  1059. if (NULL == m_pFlinkTable)
  1060. {
  1061. hr = E_OUTOFMEMORY;
  1062. goto TABLE_DONE;
  1063. }
  1064. dwValue = LF_FACESIZE;
  1065. dwData = MAX_FONTLINK_BUFFER_SIZE;
  1066. dwType = REG_MULTI_SZ;
  1067. dwIndex = 0;
  1068. while (ERROR_NO_MORE_ITEMS != RegEnumValueW(
  1069. hKey,
  1070. dwIndex,
  1071. m_pFlinkTable[dwIndex].szFaceName,
  1072. &dwValue,
  1073. NULL,
  1074. &dwType,
  1075. (LPBYTE)szFlinkFont,
  1076. &dwData ))
  1077. {
  1078. m_pFlinkTable[dwIndex].pmszFaceName = (LPWSTR) LocalAlloc(LPTR, MAX_FONTLINK_BUFFER_SIZE);
  1079. if (!m_pFlinkTable[dwIndex].pmszFaceName)
  1080. {
  1081. hr = E_OUTOFMEMORY;
  1082. goto TABLE_DONE;
  1083. }
  1084. while (TRUE)
  1085. {
  1086. pNewFaceName = wcsstr(&szFlinkFont[dwOffset], L",");
  1087. if (pNewFaceName) // TTC font, get face name from registry
  1088. {
  1089. MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), ++pNewFaceName, LF_FACESIZE);
  1090. dwOffset2 += lstrlenW(pNewFaceName)+1;
  1091. }
  1092. else // TTF font, search font table for face name
  1093. {
  1094. if (szFlinkFont[dwOffset])
  1095. for (UINT i=0; i<ulFonts; i++)
  1096. {
  1097. if (!MLStrCmpNIW(&szFlinkFont[dwOffset], tmpFontTable[i].szFontFile, LF_FACESIZE))
  1098. {
  1099. MLStrCpyNW(&(m_pFlinkTable[dwIndex].pmszFaceName[dwOffset2]), tmpFontTable[i].szFaceName, LF_FACESIZE);
  1100. dwOffset2 += lstrlenW(tmpFontTable[i].szFaceName)+1;
  1101. break;
  1102. }
  1103. }
  1104. else // End of multiple string, break out
  1105. break;
  1106. }
  1107. dwOffset += lstrlenW(&szFlinkFont[dwOffset])+1;
  1108. // Prevent infinitive loop, shouldn't happen
  1109. if (dwOffset >= MAX_FONTLINK_BUFFER_SIZE)
  1110. {
  1111. break;
  1112. }
  1113. }
  1114. dwValue = LF_FACESIZE;
  1115. dwData = MAX_FONTLINK_BUFFER_SIZE;
  1116. dwType = REG_MULTI_SZ;
  1117. dwOffset = dwOffset2 = 0;
  1118. dwIndex++;
  1119. }
  1120. m_uiFLinkFontNum = ulFLinkFonts;
  1121. hr = S_OK;
  1122. TABLE_DONE:
  1123. if (hKey)
  1124. RegCloseKey(hKey);
  1125. if (hKeyFont)
  1126. RegCloseKey(hKeyFont);
  1127. if (tmpFontTable)
  1128. LocalFree(tmpFontTable);
  1129. if ((hr != S_OK) && m_pFlinkTable)
  1130. FreeFlinkTable();
  1131. return hr;
  1132. }
  1133. HRESULT CMLFLink::GetNT5FLinkFontCodePages(HDC hDC, LOGFONTW* plfEnum, DWORD * lpdwCodePages)
  1134. {
  1135. HRESULT hr = S_OK;
  1136. UINT i;
  1137. if (!EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0))
  1138. return E_FAIL;
  1139. if (NULL == m_pFlinkTable)
  1140. CreateNT5FontLinkTable();
  1141. if (m_pFlinkTable)
  1142. {
  1143. for (i=0; i<m_uiFLinkFontNum;i++)
  1144. {
  1145. if (!MLStrCmpNIW(plfEnum->lfFaceName, m_pFlinkTable[i].szFaceName, LF_FACESIZE))
  1146. {
  1147. DWORD dwOffset=0;
  1148. // Internal buffer, we're sure it'll end
  1149. while(TRUE)
  1150. {
  1151. MLStrCpyNW(plfEnum->lfFaceName, &m_pFlinkTable[i].pmszFaceName[dwOffset], LF_FACESIZE);
  1152. EnumFontFamiliesExW(hDC, plfEnum, GetFontCodePagesEnumFontProcW, (LPARAM)lpdwCodePages, 0);
  1153. dwOffset += lstrlenW(&m_pFlinkTable[i].pmszFaceName[dwOffset])+1;
  1154. // End of multiple string ?
  1155. if (m_pFlinkTable[i].pmszFaceName[dwOffset] == 0)
  1156. break;
  1157. }
  1158. break;
  1159. }
  1160. }
  1161. }
  1162. return hr;
  1163. }
  1164. /////////////////////////////////////////////////////////////////////////////
  1165. // CMLFLink : IMLangFontLink
  1166. // 1/29/99 - Change HR return
  1167. // Now, we always return S_OK unless system error, caller will
  1168. // check code pages bits in dwCodePages for font code page coverage
  1169. STDMETHODIMP CMLFLink::GetFontCodePages(HDC hDC, HFONT hFont, DWORD* pdwCodePages)
  1170. {
  1171. ASSERT_THIS;
  1172. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  1173. HRESULT hr = S_OK;
  1174. LOGFONT lfFont;
  1175. DWORD dwCodePages = 0;
  1176. if (!::GetObject(hFont, sizeof(lfFont), &lfFont))
  1177. hr = E_FAIL; // Invalid hFont
  1178. if (SUCCEEDED(hr))
  1179. {
  1180. LOGFONT lfEnum;
  1181. // Enumerates all character sets of given font's facename
  1182. // Then, combines them in dwCodePages
  1183. ::memset(&lfEnum, 0, sizeof(lfEnum));
  1184. lfEnum.lfCharSet = DEFAULT_CHARSET;
  1185. //
  1186. //Security, strsafe
  1187. //
  1188. _tcsncpy(lfEnum.lfFaceName, lfFont.lfFaceName, ARRAYSIZE(lfEnum.lfFaceName));
  1189. if (g_bIsNT5)
  1190. {
  1191. LOGFONTW lfEnumW = {0};
  1192. lfEnumW.lfCharSet = DEFAULT_CHARSET;
  1193. if (MultiByteToWideChar(g_uACP, 0, lfFont.lfFaceName, LF_FACESIZE, lfEnumW.lfFaceName, LF_FACESIZE))
  1194. hr = GetNT5FLinkFontCodePages(hDC, &lfEnumW, &dwCodePages);
  1195. else
  1196. if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0))
  1197. hr = E_FAIL; // Invalid hDC
  1198. }
  1199. else
  1200. {
  1201. if (!::EnumFontFamiliesEx(hDC, &lfEnum, GetFontCodePagesEnumFontProc, (LPARAM)&dwCodePages, 0))
  1202. hr = E_FAIL; // Invalid hDC
  1203. }
  1204. }
  1205. //############################
  1206. //###### MingLiU HACK ######
  1207. //## Fix the bogus font !!! ##
  1208. //############################
  1209. if (SUCCEEDED(hr) && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, _T("MingLiU"), -1) == 2)
  1210. {
  1211. dwCodePages &= ~FS_LATIN1; // Actually it doesn't have the characters of ANSI_CHARSET.
  1212. }
  1213. //############################
  1214. // We should use following logic to replace above hack code
  1215. // But, there is another DBCS<->Western font size mapping issue, we should disable this code until that issue is resolved,
  1216. #if 0
  1217. // If font claims FE and 1252 and 1250, believe it can do 1252.
  1218. // If font claims FE and 1252 and not 1250, don't believe it can do 1252.
  1219. // This lets full Unicode fonts pass but blocks bad FE fonts.
  1220. if (SUCCEEDED(hr) && (dwCodePages & (FS_JISJAPAN|FS_CHINESESIMP|FS_WANSUNG|FS_CHINESETRAD)) && (dwCodePages & FS_LATIN1) && !(dwCodePages & FS_LATIN2))
  1221. {
  1222. dwCodePages &= ~FS_LATIN1;
  1223. }
  1224. #endif
  1225. #ifdef UNICODE
  1226. #define PRC_DEFAULT_GUI_FONT L"\x5b8b\x4f53"
  1227. #else
  1228. #define PRC_DEFAULT_GUI_FONT "\xcb\xce\xcc\xe5"
  1229. #endif
  1230. // PRC Win95 DEFAULT_GUI_FONT HACK !!!
  1231. if (SUCCEEDED(hr) && lfFont.lfCharSet == ANSI_CHARSET && ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfFont.lfFaceName, -1, PRC_DEFAULT_GUI_FONT, -1) == 2)
  1232. {
  1233. dwCodePages &= ~FS_CHINESESIMP; // Actually it doesn't have the characters of GB2321_CHARSET.
  1234. }
  1235. if (pdwCodePages)
  1236. {
  1237. if (SUCCEEDED(hr))
  1238. *pdwCodePages = dwCodePages;
  1239. else
  1240. *pdwCodePages = 0;
  1241. }
  1242. return hr;
  1243. }
  1244. int CALLBACK CMLFLink::GetFontCodePagesEnumFontProc(const LOGFONT* plf, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  1245. {
  1246. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++)
  1247. {
  1248. if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet)
  1249. {
  1250. if ((FontType == TRUETYPE_FONTTYPE) ||
  1251. (g_CharSetTransTable[iCharSet].uCodePage == g_uACP))
  1252. {
  1253. *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages;
  1254. break;
  1255. }
  1256. }
  1257. }
  1258. return TRUE;
  1259. }
  1260. int CALLBACK CMLFLink::GetFontCodePagesEnumFontProcW(const LOGFONTW* plf, const TEXTMETRICW*, DWORD FontType, LPARAM lParam)
  1261. {
  1262. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].nCharSet != DEFAULT_CHARSET; iCharSet++)
  1263. {
  1264. if (plf->lfCharSet == g_CharSetTransTable[iCharSet].nCharSet)
  1265. {
  1266. if ((FontType == TRUETYPE_FONTTYPE) ||
  1267. (g_CharSetTransTable[iCharSet].uCodePage == g_uACP))
  1268. {
  1269. *((DWORD*)lParam) |= g_CharSetTransTable[iCharSet].dwCodePages;
  1270. break;
  1271. }
  1272. }
  1273. }
  1274. return TRUE;
  1275. }
  1276. STDMETHODIMP CMLFLink::MapFont(HDC hDC, DWORD dwCodePages, HFONT hSrcFont, HFONT* phDestFont)
  1277. {
  1278. ASSERT_THIS;
  1279. ASSERT_WRITE_PTR_OR_NULL(phDestFont);
  1280. HRESULT hr = S_OK;
  1281. CFontMappingInfo fm; // To accelerate internal subroutine calls
  1282. fm.hDC = hDC;
  1283. // Font mapping cache works only for Display
  1284. BOOL fDisplay = (::GetDeviceCaps(hDC, TECHNOLOGY) == DT_RASDISPLAY);
  1285. dwCodePages &= ~FS_SYMBOL; // We don't map symbol font.
  1286. if (!::GetObject(hSrcFont, sizeof(fm.lfSrcFont), &fm.lfSrcFont))
  1287. hr = E_FAIL; // Invalid hSrcFont
  1288. // Do two things at same time
  1289. // (1) Find given font in the font mapping cache
  1290. // (2) Build m_auCodePage[] and m_adwCodePages[]
  1291. if (SUCCEEDED(hr))
  1292. {
  1293. if (fDisplay)
  1294. {
  1295. BYTE nCharSet = fm.lfSrcFont.lfCharSet;
  1296. fm.lfSrcFont.lfCharSet = DEFAULT_CHARSET;
  1297. EnumFontFamiliesEx(hDC, &fm.lfSrcFont, (FONTENUMPROC)VerifyFontSizeEnumFontProc, (LPARAM)&fm.lfSrcFont, 0);
  1298. fm.lfSrcFont.lfCharSet = nCharSet;
  1299. }
  1300. hr = S_FALSE; // hr == S_FALSE means that we didn't find the font in the cache
  1301. for (int n = 0; n < 32 && dwCodePages; n++)
  1302. {
  1303. hr = CodePagesToCodePage(dwCodePages, 0, &fm.auCodePage[n]); // Pick one of CodePages
  1304. if (SUCCEEDED(hr))
  1305. hr = CodePageToCodePages(fm.auCodePage[n], &fm.adwCodePages[n]);
  1306. if (SUCCEEDED(hr))
  1307. {
  1308. if (fDisplay && m_pFontMappingCache)
  1309. hr = m_pFontMappingCache->FindEntry(fm.auCodePage[n], fm.lfSrcFont, &fm.hDestFont);
  1310. else
  1311. hr = S_FALSE;
  1312. }
  1313. if (hr != S_FALSE)
  1314. break;
  1315. dwCodePages &= ~fm.adwCodePages[n];
  1316. }
  1317. fm.auCodePage[n] = NULL; // End mark
  1318. fm.adwCodePages[n] = 0;
  1319. }
  1320. if (hr == S_FALSE) // Not exist in cache
  1321. {
  1322. hr = MapFontCodePages(fm, GetFaceNameRegistry);
  1323. if (hr == MLSTR_E_FACEMAPPINGFAILURE)
  1324. hr = MapFontCodePages(fm, GetFaceNameGDI);
  1325. // Handle font link failure case for NT5
  1326. if (hr == MLSTR_E_FACEMAPPINGFAILURE && g_bIsNT5)
  1327. hr = MapFontCodePages(fm, GetFaceNameMIME);
  1328. if (SUCCEEDED(hr) && fDisplay && m_pFontMappingCache)
  1329. hr = m_pFontMappingCache->AddEntry(fm.auCodePage[fm.iCP], fm.lfSrcFont, fm.hDestFont);
  1330. }
  1331. if (phDestFont)
  1332. {
  1333. if (SUCCEEDED(hr))
  1334. {
  1335. *phDestFont = fm.hDestFont;
  1336. fm.hDestFont = NULL; // Avoid being deleted it in destructor
  1337. }
  1338. else
  1339. {
  1340. *phDestFont = NULL;
  1341. }
  1342. }
  1343. return hr;
  1344. }
  1345. STDMETHODIMP CMLFLink::ReleaseFont(HFONT hFont)
  1346. {
  1347. ASSERT_THIS;
  1348. HRESULT hr = S_OK;
  1349. if (!m_pFontMappingCache || FAILED(hr = m_pFontMappingCache->UnlockEntry(hFont)))
  1350. {
  1351. // For non display DC
  1352. if (::DeleteObject(hFont))
  1353. hr = S_OK;
  1354. else
  1355. hr = E_FAIL; // Invalid hFont
  1356. }
  1357. return hr;
  1358. }
  1359. STDMETHODIMP CMLFLink::ResetFontMapping(void)
  1360. {
  1361. ASSERT_THIS;
  1362. HRESULT hr = S_OK;
  1363. if (m_pFontMappingCache)
  1364. hr = m_pFontMappingCache->FlushEntries();
  1365. return hr;
  1366. }
  1367. STDMETHODIMP CMLFLink2::ResetFontMapping(void)
  1368. {
  1369. ASSERT_THIS;
  1370. HRESULT hr = S_OK;
  1371. if (m_pIMLFLnk)
  1372. hr = m_pIMLFLnk->ResetFontMapping();
  1373. if (m_pFontMappingCache2)
  1374. hr = (S_OK == m_pFontMappingCache2->EnsureFontTable(FALSE)? hr : E_FAIL);
  1375. return hr;
  1376. }
  1377. HRESULT CMLFLink::MapFontCodePages(CFontMappingInfo& fm, PFNGETFACENAME pfnGetFaceName)
  1378. {
  1379. HRESULT hr = MLSTR_E_FACEMAPPINGFAILURE;
  1380. for (fm.iCP = 0; fm.auCodePage[fm.iCP]; fm.iCP++)
  1381. {
  1382. fm.lfDestFont.lfCharSet = DEFAULT_CHARSET;
  1383. hr = (this->*pfnGetFaceName)(fm);
  1384. if (SUCCEEDED(hr))
  1385. {
  1386. LOGFONT lf = {0};
  1387. // If face name is from registry or MIMEDB, we set charset to codepage charset.
  1388. if (fm.lfDestFont.lfCharSet == DEFAULT_CHARSET)
  1389. {
  1390. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  1391. {
  1392. if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage)
  1393. {
  1394. fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet;
  1395. break;
  1396. }
  1397. }
  1398. }
  1399. lf.lfCharSet = DEFAULT_CHARSET;
  1400. MLStrCpyN(lf.lfFaceName, fm.szFaceName, LF_FACESIZE);
  1401. // Retrieve LOGFONT from gotten facename
  1402. fm.lfDestFont.lfFaceName[0] = _T('\0');
  1403. if (!::EnumFontFamiliesEx(fm.hDC, &lf, MapFontEnumFontProc, (LPARAM)&fm.lfDestFont, 0))
  1404. hr = E_FAIL; // Invalid hDC
  1405. else if (fm.lfDestFont.lfFaceName[0] == _T('\0'))
  1406. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1407. }
  1408. if (SUCCEEDED(hr))
  1409. {
  1410. fm.lfDestFont.lfHeight = fm.lfSrcFont.lfHeight;
  1411. fm.lfDestFont.lfWidth = fm.lfSrcFont.lfWidth;
  1412. fm.lfDestFont.lfEscapement = fm.lfSrcFont.lfEscapement;
  1413. fm.lfDestFont.lfOrientation = fm.lfSrcFont.lfOrientation;
  1414. fm.lfDestFont.lfWeight = fm.lfSrcFont.lfWeight;
  1415. fm.lfDestFont.lfItalic = fm.lfSrcFont.lfItalic;
  1416. fm.lfDestFont.lfUnderline = fm.lfSrcFont.lfUnderline;
  1417. fm.lfDestFont.lfStrikeOut = fm.lfSrcFont.lfStrikeOut;
  1418. HRESULT hrTemp = VerifyFaceMap(fm);
  1419. if (hrTemp == MLSTR_E_FACEMAPPINGFAILURE && fm.lfDestFont.lfWidth)
  1420. {
  1421. fm.lfDestFont.lfWidth = 0; // To recover non-scalable font
  1422. hr = VerifyFaceMap(fm);
  1423. }
  1424. else
  1425. {
  1426. hr = hrTemp;
  1427. }
  1428. }
  1429. if (hr != MLSTR_E_FACEMAPPINGFAILURE)
  1430. break;
  1431. }
  1432. return hr;
  1433. }
  1434. int CALLBACK CMLFLink::MapFontEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD, LPARAM lParam)
  1435. {
  1436. LOGFONT* plfDestFont = (LOGFONT*)lParam;
  1437. if (!plfDestFont->lfFaceName[0] )
  1438. {
  1439. if (plfDestFont->lfCharSet != DEFAULT_CHARSET)
  1440. {
  1441. if (plfDestFont->lfCharSet == plfFont->lfCharSet)
  1442. *plfDestFont = *plfFont;
  1443. }
  1444. else
  1445. *plfDestFont = *plfFont;
  1446. }
  1447. return TRUE;
  1448. }
  1449. HRESULT CMLFLink::GetFaceNameRegistry(CFontMappingInfo& fm)
  1450. {
  1451. static const TCHAR szRootKey[] = _T("Software\\Microsoft\\Internet Explorer");
  1452. static const TCHAR szIntlKey[] = _T("International\\%d");
  1453. static const TCHAR szPropFontName[] = _T("IEPropFontName");
  1454. static const TCHAR szFixedFontName[] = _T("IEFixedFontName");
  1455. HRESULT hr = S_OK;
  1456. HKEY hKeyRoot;
  1457. if (::RegOpenKeyEx(HKEY_CURRENT_USER, szRootKey, 0, KEY_READ, &hKeyRoot) == ERROR_SUCCESS)
  1458. {
  1459. TCHAR szCodePageKey[ARRAYSIZE(szIntlKey) + 10];
  1460. HKEY hKeySub;
  1461. ::wsprintf(szCodePageKey, szIntlKey, fm.auCodePage[fm.iCP]);
  1462. if (::RegOpenKeyEx(hKeyRoot, szCodePageKey, 0, KEY_READ, &hKeySub) == ERROR_SUCCESS)
  1463. {
  1464. const TCHAR* pszFontNameValue;
  1465. DWORD dwType;
  1466. DWORD dwSize = sizeof(fm.szFaceName);
  1467. if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH)
  1468. pszFontNameValue = szFixedFontName;
  1469. else
  1470. pszFontNameValue = szPropFontName;
  1471. if (::RegQueryValueEx(hKeySub, pszFontNameValue, 0, &dwType, (LPBYTE)fm.szFaceName, &dwSize) != ERROR_SUCCESS)
  1472. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1473. if (::RegCloseKey(hKeySub) != ERROR_SUCCESS && SUCCEEDED(hr))
  1474. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1475. }
  1476. else
  1477. {
  1478. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1479. }
  1480. if (::RegCloseKey(hKeyRoot) != ERROR_SUCCESS && SUCCEEDED(hr))
  1481. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1482. }
  1483. else
  1484. {
  1485. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1486. }
  1487. return hr;
  1488. }
  1489. HRESULT CMLFLink::GetFaceNameGDI(CFontMappingInfo& fm)
  1490. {
  1491. HRESULT hr = S_OK;
  1492. for (int iCharSet = 0; g_CharSetTransTable[iCharSet].uCodePage; iCharSet++)
  1493. {
  1494. if (fm.auCodePage[fm.iCP] == g_CharSetTransTable[iCharSet].uCodePage)
  1495. break;
  1496. }
  1497. if (g_CharSetTransTable[iCharSet].uCodePage)
  1498. {
  1499. ::memset(&fm.lfDestFont, 0, sizeof(fm.lfDestFont));
  1500. // Specify font weight as NORMAL to avoid NT GDI font mapping bugs
  1501. fm.lfDestFont.lfWeight = FW_NORMAL;
  1502. fm.lfDestFont.lfCharSet = (BYTE)g_CharSetTransTable[iCharSet].nCharSet;
  1503. hr = GetFaceNameRealizeFont(fm);
  1504. }
  1505. else
  1506. {
  1507. hr = E_FAIL; // Unknown code page
  1508. }
  1509. if (SUCCEEDED(hr))
  1510. {
  1511. // Height, CharSet, Pitch and Family
  1512. fm.lfDestFont.lfHeight = fm.lfSrcFont.lfHeight;
  1513. fm.lfDestFont.lfPitchAndFamily = fm.lfSrcFont.lfPitchAndFamily;
  1514. hr = GetFaceNameRealizeFont(fm);
  1515. if (FAILED(hr))
  1516. {
  1517. // CharSet, Pitch and Family
  1518. fm.lfDestFont.lfHeight = 0;
  1519. hr = GetFaceNameRealizeFont(fm);
  1520. }
  1521. if (FAILED(hr))
  1522. {
  1523. // CharSet and Pitch
  1524. fm.lfDestFont.lfPitchAndFamily &= 0x03; // Pitch Mask
  1525. hr = GetFaceNameRealizeFont(fm);
  1526. }
  1527. if (FAILED(hr))
  1528. {
  1529. // CharSet only
  1530. fm.lfDestFont.lfPitchAndFamily = 0;
  1531. hr = GetFaceNameRealizeFont(fm);
  1532. }
  1533. }
  1534. return hr;
  1535. }
  1536. HRESULT CMLFLink::GetFaceNameMIME(CFontMappingInfo& fm)
  1537. {
  1538. HRESULT hr = E_FAIL;
  1539. MIMECPINFO cpInfo;
  1540. if (fm.auCodePage[fm.iCP] == 936)
  1541. {
  1542. MLStrCpyN(fm.szFaceName, TEXT("SimSun"), LF_FACESIZE);
  1543. return S_OK;
  1544. }
  1545. if (!g_pMimeDatabase)
  1546. BuildGlobalObjects();
  1547. if (NULL != g_pMimeDatabase)
  1548. {
  1549. if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(fm.auCodePage[fm.iCP], 0x409, &cpInfo)))
  1550. {
  1551. TCHAR szFontFaceName[LF_FACESIZE];
  1552. szFontFaceName[0] = 0;
  1553. if ((fm.lfSrcFont.lfPitchAndFamily & 0x03) == FIXED_PITCH && cpInfo.wszFixedWidthFont[0])
  1554. {
  1555. #ifdef UNICODE
  1556. MLStrCpyNW(szFontFaceName, cpInfo.wszFixedWidthFont, LF_FACESIZE);
  1557. #else
  1558. WideCharToMultiByte(CP_ACP, 0, cpInfo.wszFixedWidthFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL);
  1559. #endif
  1560. }
  1561. else
  1562. if (cpInfo.wszProportionalFont[0])
  1563. {
  1564. #ifdef UNICODE
  1565. MLStrCpyNW(szFontFaceName, cpInfo.wszProportionalFont, LF_FACESIZE);
  1566. #else
  1567. WideCharToMultiByte(CP_ACP, 0, cpInfo.wszProportionalFont, -1, szFontFaceName, LF_FACESIZE, NULL, NULL);
  1568. #endif
  1569. }
  1570. if (szFontFaceName[0])
  1571. {
  1572. MLStrCpyN(fm.szFaceName, szFontFaceName, LF_FACESIZE);
  1573. hr = S_OK;
  1574. }
  1575. }
  1576. else
  1577. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1578. }
  1579. return hr;
  1580. }
  1581. HRESULT CMLFLink::GetFaceNameRealizeFont(CFontMappingInfo& fm)
  1582. {
  1583. HRESULT hr = S_OK;
  1584. HFONT hFont = NULL;
  1585. HFONT hOldFont;
  1586. DWORD dwFontCodePages;
  1587. // First let's get a facename based on the given lfDestFont
  1588. // Then verify if the font of the found facename has the code pages we want.
  1589. hFont = ::CreateFontIndirect(&fm.lfDestFont);
  1590. if (!hFont)
  1591. hr = E_FAIL; // Out of memory or GDI resource
  1592. if (SUCCEEDED(hr))
  1593. {
  1594. hOldFont = (HFONT)::SelectObject(fm.hDC, hFont);
  1595. if (!hOldFont)
  1596. hr = E_FAIL; // Out of memory or GDI resource
  1597. }
  1598. if (SUCCEEDED(hr))
  1599. {
  1600. if (!::GetTextFace(fm.hDC, ARRAYSIZE(fm.szFaceName), fm.szFaceName))
  1601. hr = E_FAIL; // Out of memory or GDI resource
  1602. if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr))
  1603. hr = E_FAIL; // Out of memory or GDI resource
  1604. }
  1605. if (hFont)
  1606. ::DeleteObject(hFont);
  1607. if (SUCCEEDED(hr))
  1608. {
  1609. LOGFONT lfTemp;
  1610. lfTemp = fm.lfDestFont;
  1611. //
  1612. // Security
  1613. //
  1614. _tcsncpy(lfTemp.lfFaceName, fm.szFaceName, ARRAYSIZE(lfTemp.lfFaceName));
  1615. hFont = ::CreateFontIndirect(&lfTemp);
  1616. if (!hFont)
  1617. hr = E_FAIL; // Out of memory or GDI resource
  1618. if (SUCCEEDED(hr = GetFontCodePages(fm.hDC, hFont, &dwFontCodePages)) && !(dwFontCodePages & fm.adwCodePages[fm.iCP]))
  1619. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1620. if (hFont)
  1621. ::DeleteObject(hFont);
  1622. }
  1623. return hr;
  1624. }
  1625. HRESULT CMLFLink::VerifyFaceMap(CFontMappingInfo& fm)
  1626. {
  1627. HRESULT hr = S_OK;
  1628. HFONT hOldFont;
  1629. if (fm.hDestFont)
  1630. ::DeleteObject(fm.hDestFont);
  1631. fm.hDestFont = ::CreateFontIndirect(&fm.lfDestFont);
  1632. if (!fm.hDestFont)
  1633. hr = E_FAIL; // Out of memory or GDI resource
  1634. if (SUCCEEDED(hr))
  1635. {
  1636. hOldFont = (HFONT)::SelectObject(fm.hDC, fm.hDestFont);
  1637. if (!hOldFont)
  1638. hr = E_FAIL; // Out of memory or GDI resource
  1639. }
  1640. if (SUCCEEDED(hr))
  1641. {
  1642. TCHAR szFaceName[LF_FACESIZE];
  1643. if (!::GetTextFace(fm.hDC, ARRAYSIZE(szFaceName), szFaceName))
  1644. hr = E_FAIL; // Out of memory or GDI resource
  1645. if (SUCCEEDED(hr))
  1646. {
  1647. int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, fm.lfDestFont.lfFaceName, -1, szFaceName, -1);
  1648. if (!nRet)
  1649. hr = E_FAIL; // Unexpected error
  1650. else if (nRet != 2) // Not Equal
  1651. hr = MLSTR_E_FACEMAPPINGFAILURE;
  1652. }
  1653. if (!::SelectObject(fm.hDC, hOldFont) && SUCCEEDED(hr))
  1654. hr = E_FAIL; // Out of memory or GDI resource
  1655. }
  1656. return hr;
  1657. }
  1658. /////////////////////////////////////////////////////////////////////////////
  1659. // CMLFLink::CFontMappingCache
  1660. CMLFLink::CFontMappingCache::CFontMappingCache(void) :
  1661. m_pEntries(NULL),
  1662. m_pFree(NULL),
  1663. m_cEntries(0)
  1664. {
  1665. ::InitializeCriticalSection(&m_cs);
  1666. }
  1667. CMLFLink::CFontMappingCache::~CFontMappingCache(void)
  1668. {
  1669. FlushEntries();
  1670. DeleteCriticalSection(&m_cs);
  1671. }
  1672. HRESULT CMLFLink::CFontMappingCache::FindEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT* phDestFont)
  1673. {
  1674. HRESULT hr = S_FALSE;
  1675. ::EnterCriticalSection(&m_cs);
  1676. if (m_pEntries)
  1677. {
  1678. CFontMappingCacheEntry* pEntry = m_pEntries;
  1679. while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1680. {
  1681. if (uCodePage == pEntry->m_uSrcCodePage &&
  1682. lfSrcFont.lfPitchAndFamily == pEntry->m_bSrcPitchAndFamily &&
  1683. lfSrcFont.lfHeight == pEntry->m_lSrcHeight &&
  1684. lfSrcFont.lfWidth == pEntry->m_lSrcWidth &&
  1685. lfSrcFont.lfEscapement == pEntry->m_lSrcEscapement &&
  1686. lfSrcFont.lfOrientation == pEntry->m_lSrcOrientation &&
  1687. lfSrcFont.lfWeight == pEntry->m_lSrcWeight &&
  1688. lfSrcFont.lfItalic == pEntry->m_bSrcItalic &&
  1689. lfSrcFont.lfUnderline == pEntry->m_bSrcUnderline &&
  1690. lfSrcFont.lfStrikeOut == pEntry->m_bSrcStrikeOut)
  1691. {
  1692. int nRet = ::CompareString(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lfSrcFont.lfFaceName, -1, pEntry->m_szSrcFaceName, -1);
  1693. if (!nRet)
  1694. {
  1695. hr = E_FAIL; // Unexpected error
  1696. break;
  1697. }
  1698. else if (nRet == 2) // Equal
  1699. {
  1700. if (phDestFont)
  1701. *phDestFont = pEntry->m_hDestFont;
  1702. pEntry->m_nLockCount++;
  1703. hr = S_OK;
  1704. break;
  1705. }
  1706. }
  1707. }
  1708. }
  1709. ::LeaveCriticalSection(&m_cs);
  1710. if (phDestFont && hr != S_OK)
  1711. *phDestFont = NULL;
  1712. return hr;
  1713. }
  1714. HRESULT CMLFLink::CFontMappingCache::UnlockEntry(HFONT hDestFont)
  1715. {
  1716. HRESULT hr = E_FAIL; // hDestFont is not found in the cache
  1717. ::EnterCriticalSection(&m_cs);
  1718. if (m_pEntries)
  1719. {
  1720. CFontMappingCacheEntry* pEntry = m_pEntries;
  1721. while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1722. {
  1723. if (hDestFont == pEntry->m_hDestFont)
  1724. {
  1725. if (pEntry->m_nLockCount - 1 >= 0)
  1726. {
  1727. pEntry->m_nLockCount--;
  1728. hr = S_OK;
  1729. }
  1730. break;
  1731. }
  1732. }
  1733. }
  1734. ::LeaveCriticalSection(&m_cs);
  1735. return hr;
  1736. }
  1737. HRESULT CMLFLink::CFontMappingCache::AddEntry(UINT uCodePage, const LOGFONT& lfSrcFont, HFONT hDestFont)
  1738. {
  1739. HRESULT hr = S_OK;
  1740. ::EnterCriticalSection(&m_cs);
  1741. if (!m_pEntries) // Need to allocate all the entries
  1742. {
  1743. CFontMappingCacheEntry* pEntries;
  1744. pEntries = new CFontMappingCacheEntry[NUMFONTMAPENTRIES + 1]; // +1 for sentinel
  1745. if (pEntries)
  1746. {
  1747. // Init sentinel
  1748. pEntries[0].m_pPrev = &pEntries[0];
  1749. pEntries[0].m_pNext = &pEntries[0];
  1750. // Init free entries
  1751. for (int n = 0; n < NUMFONTMAPENTRIES; n++)
  1752. {
  1753. const nEnt = n + 1; // + 1 for sentinel
  1754. if (n < NUMFONTMAPENTRIES - 1)
  1755. pEntries[nEnt].m_pNext = &pEntries[nEnt + 1];
  1756. else
  1757. pEntries[nEnt].m_pNext = NULL;
  1758. }
  1759. m_pEntries = &pEntries[0];
  1760. m_pFree = &pEntries[1];
  1761. }
  1762. else
  1763. {
  1764. hr = E_OUTOFMEMORY;
  1765. }
  1766. }
  1767. if (SUCCEEDED(hr) && !m_pFree) // Need to delete oldest entry
  1768. {
  1769. CFontMappingCacheEntry* pOldestEntry = m_pEntries->m_pPrev;
  1770. while (pOldestEntry->m_nLockCount > 0 && pOldestEntry != m_pEntries) // Entry is locked
  1771. pOldestEntry = pOldestEntry->m_pPrev;
  1772. if (pOldestEntry != m_pEntries)
  1773. {
  1774. if (pOldestEntry->m_hDestFont)
  1775. ::DeleteObject(pOldestEntry->m_hDestFont);
  1776. // Delete it from m_pEntries list
  1777. pOldestEntry->m_pPrev->m_pNext = pOldestEntry->m_pNext;
  1778. pOldestEntry->m_pNext->m_pPrev = pOldestEntry->m_pPrev;
  1779. // Insert it into m_pFree list
  1780. pOldestEntry->m_pNext = m_pFree;
  1781. m_pFree = pOldestEntry;
  1782. }
  1783. else // No entry available
  1784. {
  1785. hr = E_FAIL; // Out of cache entries
  1786. }
  1787. }
  1788. if (SUCCEEDED(hr)) // Create new entry and fill it
  1789. {
  1790. CFontMappingCacheEntry* pNewEntry;
  1791. // Delete it from m_pFree list
  1792. pNewEntry = m_pFree; // shouldn't be NULL
  1793. m_pFree = pNewEntry->m_pNext;
  1794. // Insert it into m_pEntries list
  1795. pNewEntry->m_pNext = m_pEntries->m_pNext;
  1796. pNewEntry->m_pPrev = m_pEntries;
  1797. m_pEntries->m_pNext->m_pPrev = pNewEntry;
  1798. m_pEntries->m_pNext = pNewEntry;
  1799. // Fill it
  1800. pNewEntry->m_nLockCount = 1;
  1801. pNewEntry->m_uSrcCodePage = uCodePage;
  1802. pNewEntry->m_lSrcHeight = lfSrcFont.lfHeight;
  1803. pNewEntry->m_lSrcWidth = lfSrcFont.lfWidth;
  1804. pNewEntry->m_lSrcEscapement = lfSrcFont.lfEscapement;
  1805. pNewEntry->m_lSrcOrientation = lfSrcFont.lfOrientation;
  1806. pNewEntry->m_lSrcWeight = lfSrcFont.lfWeight;
  1807. pNewEntry->m_bSrcItalic = lfSrcFont.lfItalic;
  1808. pNewEntry->m_bSrcUnderline = lfSrcFont.lfUnderline;
  1809. pNewEntry->m_bSrcStrikeOut = lfSrcFont.lfStrikeOut;
  1810. pNewEntry->m_bSrcPitchAndFamily = lfSrcFont.lfPitchAndFamily;
  1811. //security
  1812. _tcsncpy(pNewEntry->m_szSrcFaceName, lfSrcFont.lfFaceName, ARRAYSIZE(pNewEntry->m_szSrcFaceName));
  1813. pNewEntry->m_hDestFont = hDestFont;
  1814. }
  1815. ::LeaveCriticalSection(&m_cs);
  1816. return hr;
  1817. }
  1818. HRESULT CMLFLink::CFontMappingCache::FlushEntries(void)
  1819. {
  1820. ::EnterCriticalSection(&m_cs);
  1821. if (m_pEntries)
  1822. {
  1823. CFontMappingCacheEntry* pEntry = m_pEntries;
  1824. while ((pEntry = pEntry->m_pPrev) != m_pEntries)
  1825. {
  1826. if (pEntry->m_hDestFont)
  1827. ::DeleteObject(pEntry->m_hDestFont);
  1828. }
  1829. delete[] m_pEntries;
  1830. m_pEntries = NULL;
  1831. m_cEntries = 0;
  1832. }
  1833. ::LeaveCriticalSection(&m_cs);
  1834. return S_OK;
  1835. }
  1836. /////////////////////////////////////////////////////////////////////////////
  1837. // CMLFLink::CCodePagesCache
  1838. CMLFLink::CCodePagesCache::CCodePagesCache(void) :
  1839. m_pbBuf(NULL),m_pbBufExt(NULL)
  1840. {
  1841. ::InitializeCriticalSection(&m_cs);
  1842. }
  1843. CMLFLink::CCodePagesCache::~CCodePagesCache(void)
  1844. {
  1845. DeleteCriticalSection(&m_cs);
  1846. }
  1847. HRESULT CMLFLink::CCodePagesCache::RealLoad(void)
  1848. {
  1849. HRESULT hr = S_OK;
  1850. ::EnterCriticalSection(&m_cs);
  1851. if (!m_pbBuf && !m_pbBufExt)
  1852. {
  1853. HRSRC hrCodePages;
  1854. HGLOBAL hgCodePages;
  1855. HRSRC hrCodePagesExt;
  1856. HGLOBAL hgCodePagesExt;
  1857. if (SUCCEEDED(hr))
  1858. {
  1859. hrCodePages = ::FindResource(g_hInst, MAKEINTRESOURCE(IDR_CODEPAGES), _T("CODEPAGES"));
  1860. hrCodePagesExt = ::FindResource(g_hInst, MAKEINTRESOURCE(IDR_CODEPAGESEXT), _T("CODEPAGESEXT"));
  1861. if (!hrCodePages || !hrCodePagesExt)
  1862. hr = E_FAIL; // Build error?
  1863. }
  1864. if (SUCCEEDED(hr))
  1865. {
  1866. hgCodePages = ::LoadResource(g_hInst, hrCodePages);
  1867. hgCodePagesExt = ::LoadResource(g_hInst, hrCodePagesExt);
  1868. if (!hgCodePages && !hgCodePagesExt)
  1869. hr = E_FAIL; // Unexpected error
  1870. }
  1871. if (SUCCEEDED(hr))
  1872. {
  1873. m_pbBuf = (BYTE*)::LockResource(hgCodePages);
  1874. m_pbBufExt = (BYTE*)::LockResource(hgCodePagesExt);
  1875. if (!m_pbBuf || !m_pbBufExt)
  1876. hr = E_FAIL; // Unexpected error
  1877. }
  1878. }
  1879. ::LeaveCriticalSection(&m_cs);
  1880. return hr;
  1881. }
  1882. extern "C" HRESULT GetGlobalFontLinkObject(IMLangFontLink **ppMLFontLink)
  1883. {
  1884. HRESULT hr = E_INVALIDARG;
  1885. if (NULL != ppMLFontLink)
  1886. {
  1887. if (NULL == g_pMLFLink)
  1888. {
  1889. EnterCriticalSection(&g_cs);
  1890. if (NULL == g_pMLFLink)
  1891. CComCreator< CComPolyObject< CMLFLink > >::CreateInstance(NULL, IID_IMLangFontLink, (void **)&g_pMLFLink);
  1892. LeaveCriticalSection(&g_cs);
  1893. }
  1894. *ppMLFontLink = g_pMLFLink;
  1895. if (g_pMLFLink)
  1896. {
  1897. g_pMLFLink->AddRef();
  1898. hr = S_OK;
  1899. }
  1900. else
  1901. hr = E_FAIL;
  1902. }
  1903. return hr;
  1904. }
  1905. HRESULT CMLFLink2::CFontMappingCache2::MapFontFromCMAP(HDC hDC, WCHAR wchar, HFONT hSrcFont, HFONT *phDestFont)
  1906. {
  1907. BOOL bFont = FALSE;
  1908. HRESULT hr = E_FAIL;
  1909. int i,j,k;
  1910. LOGFONT LogFont;
  1911. if (!phDestFont)
  1912. return E_INVALIDARG;
  1913. if (!GetObject(hSrcFont, sizeof(LOGFONT), &LogFont))
  1914. return hr;
  1915. if (!g_pfont_table || !g_pfont_table[0].szFaceName[0])
  1916. {
  1917. if (FAILED(LoadFontDataFile()))
  1918. {
  1919. return hr;
  1920. }
  1921. }
  1922. i=0;
  1923. j=ARRAYSIZE(g_urange_table);
  1924. k = j/2;
  1925. while (i<=j)
  1926. {
  1927. if (wchar >= g_urange_table[k].wcFrom && wchar <= g_urange_table[k].wcTo)
  1928. break;
  1929. else
  1930. if (wchar < g_urange_table[k].wcFrom)
  1931. {
  1932. j = k -1;
  1933. }
  1934. else
  1935. {
  1936. i = k + 1;
  1937. }
  1938. k = (i+j)/2;
  1939. }
  1940. if (i<=j && g_urange_table[k].nFonts)
  1941. {
  1942. TCHAR szFaceName[LF_FACESIZE];
  1943. GetTextFace(hDC, LF_FACESIZE, szFaceName);
  1944. // Check if it supports the character
  1945. for (i=0; i<g_urange_table[k].nFonts; i++)
  1946. {
  1947. if (!MLStrCmpI(szFaceName,g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName))
  1948. break;
  1949. }
  1950. // Current font doesn't support this character
  1951. if (i == g_urange_table[k].nFonts)
  1952. {
  1953. for (i=0; i<g_urange_table[k].nFonts; i++)
  1954. {
  1955. if (LogFont.lfCharSet == g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfCharSet)
  1956. break;
  1957. }
  1958. // No font available for current CharSet, then return the first one in the list
  1959. if (i >= g_urange_table[k].nFonts)
  1960. {
  1961. i = fetchCharSet((BYTE *) &(LogFont.lfCharSet), k);
  1962. }
  1963. MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE);
  1964. }
  1965. if (i < g_urange_table[k].nFonts)
  1966. {
  1967. MLStrCpyN(LogFont.lfFaceName, g_pfont_table[*(g_urange_table[k].pFontIndex+i)].lf.lfFaceName, LF_FACESIZE);
  1968. }
  1969. bFont = TRUE;
  1970. }
  1971. if (bFont && (*phDestFont = CreateFontIndirect(&LogFont)))
  1972. {
  1973. hr = S_OK;
  1974. }
  1975. else
  1976. {
  1977. *phDestFont = NULL;
  1978. }
  1979. return hr;
  1980. }
  1981. HRESULT CMLFLink2::CFontMappingCache2::UnicodeRanges(
  1982. LPTSTR szFont,
  1983. UINT *puiRanges,
  1984. UNICODERANGE* pURanges
  1985. )
  1986. {
  1987. HRESULT hr = E_FAIL;
  1988. UINT nURange = 0;
  1989. DWORD cmap = 0;
  1990. DWORD name = 0;
  1991. HANDLE hTTF;
  1992. TCHAR szFontPath[MAX_PATH];
  1993. static TCHAR s_szFontDir[MAX_PATH] = {0};
  1994. HANDLE hTTFMap;
  1995. DWORD dwFileSize;
  1996. LPVOID lpvFile = NULL;
  1997. LPBYTE lp, lp1, lp2, lpMax = NULL;
  1998. DWORD Num;
  1999. WORD i, j, Len;
  2000. if (!szFont[0])
  2001. return hr;
  2002. if (!s_szFontDir[0])
  2003. {
  2004. MLGetWindowsDirectory(s_szFontDir, MAX_PATH);
  2005. MLPathCombine(s_szFontDir, ARRAYSIZE(s_szFontDir), s_szFontDir, FONT_FOLDER);
  2006. }
  2007. MLPathCombine(szFontPath, ARRAYSIZE(szFontPath), s_szFontDir, szFont);
  2008. hTTF = CreateFile( szFontPath, // pointer to name of the file
  2009. GENERIC_READ, // access (read-write) mode
  2010. FILE_SHARE_READ, // share mode
  2011. NULL, // pointer to security attributes
  2012. OPEN_EXISTING, // how to create
  2013. FILE_ATTRIBUTE_NORMAL, // file attributes
  2014. NULL); // handle to file with attributes to copy;
  2015. if (INVALID_HANDLE_VALUE == hTTF)
  2016. return hr;
  2017. dwFileSize = GetFileSize(hTTF, NULL);
  2018. hTTFMap = CreateFileMapping(
  2019. hTTF,
  2020. NULL,
  2021. PAGE_READONLY,
  2022. 0,
  2023. dwFileSize,
  2024. NULL
  2025. );
  2026. if(hTTFMap == NULL)
  2027. {
  2028. goto CloseHandle;
  2029. }
  2030. lpvFile = MapViewOfFile(
  2031. hTTFMap,
  2032. FILE_MAP_READ,
  2033. 0,
  2034. 0,
  2035. 0
  2036. );
  2037. if(lpvFile == NULL)
  2038. {
  2039. goto CloseHandle;
  2040. }
  2041. lp = (LPBYTE)lpvFile;
  2042. // The maximum boundary we can go
  2043. lpMax = (LPBYTE)lpvFile + dwFileSize;
  2044. // Font table name uses ASCII
  2045. if(strncmp(((TTC_HEAD*)lp)->TTCTag, "ttcf", 4) == 0) // TTC format
  2046. {
  2047. lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1); // points to first TTF
  2048. }
  2049. Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables); // Number of Tables
  2050. lp += sizeof(TTF_HEAD);
  2051. if (lp+Num*sizeof(TABLE_DIR) >= lpMax) // Not a valid TrueType file if table size >= TTF file size
  2052. goto CloseHandle;
  2053. for(i = 0; i < Num ; i++) // go thru all tables to find cmap and name
  2054. {
  2055. if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0)
  2056. {
  2057. cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2058. if (name) break;
  2059. }
  2060. else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0)
  2061. {
  2062. name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2063. if (cmap) break;
  2064. }
  2065. lp += sizeof(TABLE_DIR);
  2066. }
  2067. if((!cmap) || (!name)) // Can't find cmap or name
  2068. {
  2069. goto CloseHandle;
  2070. }
  2071. // Read thru all name records
  2072. // to see if font subfamily name is "Regular"
  2073. lp = (LPBYTE)lpvFile + name; // point to name table
  2074. Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec); // # of name record
  2075. if (lp + sizeof(NAME_TABLE)*Num >= lpMax)
  2076. goto CloseHandle;
  2077. lp1 = lp + sizeof(NAME_TABLE); // point to name record
  2078. for(i = 0; i < Num; i++)
  2079. {
  2080. if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID))
  2081. {
  2082. lp2 = lp + // point to string store
  2083. TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) +
  2084. TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset);
  2085. // Invalid TTF file
  2086. if (lp2 >= lpMax)
  2087. break;
  2088. Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length);
  2089. if(((MICROSOFT_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) &&
  2090. (UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))) ||
  2091. ((APPLE_UNICODE_PLATFORM == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Platform)) &&
  2092. (APPLE_UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))))
  2093. {
  2094. Len >>= 1;
  2095. const char *pStr = szRegular;
  2096. if (Len == sizeof(szNormal) -1)
  2097. pStr = szNormal;
  2098. else
  2099. if (Len != sizeof(szRegular)-1)
  2100. {
  2101. lp1 += sizeof(NAME_RECORD);
  2102. continue;
  2103. }
  2104. while(--Len > 0)
  2105. {
  2106. if(*(lp2+(Len<<1)+1) != pStr[Len])
  2107. break;
  2108. }
  2109. if (!Len)
  2110. break;
  2111. else
  2112. {
  2113. lp1 += sizeof(NAME_RECORD);
  2114. continue;
  2115. }
  2116. }
  2117. else
  2118. {
  2119. if(strncmp((char*)lp2, szRegular, sizeof(szRegular)-1) != 0 &&
  2120. strncmp((char*)lp2, szNormal, sizeof(szNormal)-1) != 0)
  2121. {
  2122. lp1 += sizeof(NAME_RECORD);
  2123. continue;
  2124. }
  2125. else
  2126. break;
  2127. }
  2128. }
  2129. lp1 += sizeof(NAME_RECORD);
  2130. }
  2131. // If no regular font, exit
  2132. if (i == Num)
  2133. goto CloseHandle;
  2134. // all non-regular fonts have already been eliminated
  2135. lp1 = (LPBYTE)lpvFile + cmap; // point to cmap table
  2136. if (lp1 + sizeof(CMAP_TABLE)*Num >= lpMax)
  2137. goto CloseHandle;
  2138. Num = TWO_BYTE_NUM(((CMAP_HEAD*)lp1)->NumTables);
  2139. lp1 += sizeof(CMAP_HEAD);
  2140. while(Num >0)
  2141. {
  2142. if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM &&
  2143. (TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING ||
  2144. TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_SYMBOL_INDEXING))
  2145. {
  2146. lp = (LPBYTE)lpvFile
  2147. + cmap
  2148. + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset);
  2149. if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR)
  2150. {
  2151. break;
  2152. }
  2153. }
  2154. Num--;
  2155. lp1 += sizeof(CMAP_TABLE);
  2156. }
  2157. if(Num == 0) // can't find Platform:3/Encoding:1 (Unicode)
  2158. goto CloseHandle;
  2159. Num = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2);
  2160. lp2 = lp + sizeof(CMAP_FORMAT); // lp2 -> first WCHAR of wcTo
  2161. lp1 = lp2 + Num + 2; // lp1 -> first WCHAR of wcFrom
  2162. if (lp1 + Num >= lpMax)
  2163. goto CloseHandle;
  2164. Num /= 2;
  2165. if (pURanges == NULL)
  2166. {
  2167. *puiRanges = Num;
  2168. }
  2169. else
  2170. {
  2171. if (Num > *puiRanges)
  2172. Num = *puiRanges;
  2173. else
  2174. *puiRanges = Num;
  2175. for(i=0, j=0; i < Num; i++, j++, j++)
  2176. {
  2177. pURanges[i].wcFrom = TWO_BYTE_NUM((lp1+j));
  2178. pURanges[i].wcTo = TWO_BYTE_NUM((lp2+j));
  2179. }
  2180. }
  2181. hr = S_OK;
  2182. CloseHandle:
  2183. if (lpvFile)
  2184. {
  2185. UnmapViewOfFile(lpvFile);
  2186. }
  2187. if (hTTFMap)
  2188. {
  2189. CloseHandle(hTTFMap);
  2190. }
  2191. // Handle is checked after creation.
  2192. CloseHandle(hTTF);
  2193. return hr;
  2194. }
  2195. int CMLFLink2::CFontMappingCache2::fetchCharSet(BYTE *pCharset, int iURange)
  2196. {
  2197. int i,j;
  2198. //Check if current charset valid for the font
  2199. for (i=0; i<g_urange_table[iURange].nFonts; i++)
  2200. {
  2201. for (j=0;(j<32) && g_CharSetTransTable[j].uCodePage;j++)
  2202. {
  2203. if (g_pfont_table[*(g_urange_table[iURange].pFontIndex+i)].dwCodePages[0] & g_CharSetTransTable[j].dwCodePages)
  2204. if (*pCharset == g_CharSetTransTable[j].nCharSet)
  2205. return i;
  2206. }
  2207. }
  2208. //If invalid, fetch first valid one.
  2209. for (i=0;(i<32) && g_CharSetTransTable[i].uCodePage;i++)
  2210. {
  2211. if (g_pfont_table[*(g_urange_table[iURange].pFontIndex)].dwCodePages[0] & g_CharSetTransTable[i].dwCodePages)
  2212. {
  2213. *pCharset = (BYTE)g_CharSetTransTable[i].nCharSet;
  2214. break;
  2215. }
  2216. }
  2217. return 0;
  2218. }
  2219. BOOL CMLFLink2::CFontMappingCache2::GetNonCpFontUnicodeRanges(TCHAR *szFontName, int iFontIndex)
  2220. {
  2221. LONG nURange = 0;
  2222. DWORD cmap = 0;
  2223. DWORD name = 0;
  2224. DWORD os2 = 0;
  2225. HANDLE hTTFMap;
  2226. DWORD dwFileSize;
  2227. LPVOID lpvFile = NULL;
  2228. LPBYTE lp, lp1, lp2;
  2229. DWORD Num;
  2230. int i, j, k, m;
  2231. WORD Len;
  2232. HANDLE hTTF;
  2233. BOOL bRet = FALSE;
  2234. hTTF = CreateFile( szFontName, // pointer to name of the file
  2235. GENERIC_READ, // access (read-write) mode
  2236. FILE_SHARE_READ, // share mode
  2237. NULL, // pointer to security attributes
  2238. OPEN_EXISTING, // how to create
  2239. FILE_ATTRIBUTE_NORMAL, // file attributes
  2240. NULL); // handle to file with attributes to copy;
  2241. if (hTTF == INVALID_HANDLE_VALUE)
  2242. return FALSE;
  2243. dwFileSize = GetFileSize(hTTF, NULL);
  2244. hTTFMap = CreateFileMapping(
  2245. hTTF,
  2246. NULL,
  2247. PAGE_READONLY,
  2248. 0,
  2249. dwFileSize,
  2250. NULL
  2251. );
  2252. if(hTTFMap == NULL)
  2253. {
  2254. goto GET_NCP_EXIT;
  2255. }
  2256. lpvFile = MapViewOfFile(
  2257. hTTFMap,
  2258. FILE_MAP_READ,
  2259. 0,
  2260. 0,
  2261. 0
  2262. );
  2263. if(lpvFile == NULL)
  2264. {
  2265. goto GET_NCP_EXIT;
  2266. }
  2267. lp = (LPBYTE)lpvFile;
  2268. if(strncmp(((TTC_HEAD*)lp)->TTCTag, "ttcf", 4) == 0) // TTC format
  2269. {
  2270. lp += FOUR_BYTE_NUM(((TTC_HEAD*)lp)->OffsetTTF1); // points to first TTF
  2271. }
  2272. Num = TWO_BYTE_NUM(((TTF_HEAD*)lp)->NumTables); // Number of Tables
  2273. {
  2274. // if SearchRange != (Maximum power of 2 <= Num)*16,
  2275. // then this is not a TTF file
  2276. DWORD wTmp = 1;
  2277. while(wTmp <= Num)
  2278. {
  2279. wTmp <<= 1;
  2280. }
  2281. wTmp <<= 3; // (wTmp/2)*16
  2282. if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->SearchRange))
  2283. {
  2284. goto GET_NCP_EXIT;
  2285. }
  2286. // if RangeShift != (Num*16) - SearchRange,
  2287. // then this is not a TTF file
  2288. wTmp = (Num<<4) - wTmp;
  2289. if(wTmp != (DWORD)TWO_BYTE_NUM(((TTF_HEAD*)lp)->RangeShift))
  2290. {
  2291. goto GET_NCP_EXIT;
  2292. }
  2293. }
  2294. lp += sizeof(TTF_HEAD);
  2295. for(i = 0; i < (int)Num; i++) // go thru all tables to find cmap and name
  2296. {
  2297. if(strncmp( ((TABLE_DIR*)lp)->Tag, "cmap", 4) == 0)
  2298. {
  2299. cmap = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2300. if (name && os2) break;
  2301. }
  2302. else if(strncmp( ((TABLE_DIR*)lp)->Tag, "name", 4) == 0)
  2303. {
  2304. name = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2305. if (cmap && os2) break;
  2306. }
  2307. else if(strncmp( ((TABLE_DIR*)lp)->Tag, "OS/2", 4) == 0)
  2308. {
  2309. os2 = FOUR_BYTE_NUM(((TABLE_DIR*)lp)->Offset);
  2310. if (cmap && name) break;
  2311. }
  2312. lp += sizeof(TABLE_DIR);
  2313. }
  2314. if((!cmap) || (!name) || (!os2)) // Can't find cmap or name
  2315. {
  2316. goto GET_NCP_EXIT;
  2317. }
  2318. // Read thru all name records
  2319. // to see if font subfamily name is "Regular"
  2320. lp = (LPBYTE)lpvFile + name; // point to name table
  2321. Num = TWO_BYTE_NUM(((NAME_TABLE*)lp)->NumRec); // # of name record
  2322. lp1 = lp + sizeof(NAME_TABLE); // point to name record
  2323. for(i = 0; i < (int)Num; i++)
  2324. {
  2325. if(FONT_SUBFAMILY_NAME == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->NameID))
  2326. {
  2327. lp2 = lp + // point to string store
  2328. TWO_BYTE_NUM(((NAME_TABLE* )lp )->Offset) +
  2329. TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Offset);
  2330. Len = TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Length);
  2331. if(UNICODE_INDEXING == TWO_BYTE_NUM(((NAME_RECORD*)lp1)->Encoding))
  2332. {
  2333. Len >>= 1;
  2334. while(--Len > 0)
  2335. {
  2336. if(*(lp2+(Len<<1)+1) != szRegular[Len])
  2337. goto GET_NCP_EXIT;
  2338. }
  2339. break;
  2340. }
  2341. else
  2342. {
  2343. if(strncmp((char*)lp2, szRegular, Len) != 0)
  2344. goto GET_NCP_EXIT;
  2345. else
  2346. break;
  2347. }
  2348. }
  2349. lp1 += sizeof(NAME_RECORD);
  2350. }
  2351. // all non-regular fonts have already been eliminated
  2352. lp1 = (LPBYTE)lpvFile + cmap; // point to cmap table
  2353. Num = TWO_BYTE_NUM(((CMAP_HEAD*)lp)->NumTables);
  2354. lp1 += sizeof(CMAP_HEAD);
  2355. while(Num >0)
  2356. {
  2357. if(TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Platform) == MICROSOFT_PLATFORM &&
  2358. TWO_BYTE_NUM(((CMAP_TABLE*)lp1)->Encoding) == UNICODE_INDEXING)
  2359. {
  2360. lp = (LPBYTE)lpvFile
  2361. + cmap
  2362. + FOUR_BYTE_NUM(((CMAP_TABLE*)lp1)->Offset);
  2363. if(TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->Format) == CMAP_FORMAT_FOUR)
  2364. {
  2365. break;
  2366. }
  2367. }
  2368. Num--;
  2369. lp1 += sizeof(CMAP_TABLE);
  2370. }
  2371. if(Num == 0) // can't find Platform:3/Encoding:1 (Unicode)
  2372. goto GET_NCP_EXIT;
  2373. Num = TWO_BYTE_NUM(((CMAP_FORMAT*)lp)->SegCountX2) ;
  2374. m = ARRAYSIZE(g_urange_table);
  2375. lp2 = lp + sizeof(CMAP_FORMAT); // lp2 -> first WCHAR of wcTo
  2376. lp1 = lp2 + Num + 2; // lp1 -> first WCHAR of wcFrom
  2377. // Fast parse !!!
  2378. while (--m)
  2379. {
  2380. // URANGE binary search
  2381. i=0;
  2382. j= (int) Num - 2;
  2383. k=j/2;
  2384. while (i<=j)
  2385. {
  2386. if (k % 2)
  2387. k++;
  2388. if (g_urange_table[m].wcFrom >= TWO_BYTE_NUM((lp1+k)) && g_urange_table[m].wcTo <= TWO_BYTE_NUM((lp2+k)))
  2389. {
  2390. EnterCriticalSection(&g_cs);
  2391. if (!g_urange_table[m].pFontIndex)
  2392. g_urange_table[m].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)* MAX_FONT_INDEX);
  2393. if (!g_urange_table[m].pFontIndex)
  2394. {
  2395. LeaveCriticalSection(&g_cs);
  2396. goto GET_NCP_EXIT;
  2397. }
  2398. if (g_urange_table[m].nFonts >= MAX_FONT_INDEX)
  2399. {
  2400. LeaveCriticalSection(&g_cs);
  2401. break;
  2402. }
  2403. g_urange_table[m].pFontIndex[g_urange_table[m].nFonts] = iFontIndex;
  2404. g_urange_table[m].nFonts++;
  2405. // Fill in font code page signature
  2406. g_pfont_table[iFontIndex].dwCodePages[0] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE));
  2407. g_pfont_table[iFontIndex].dwCodePages[1] = FOUR_BYTE_NUM(((BYTE *)lpvFile+os2+OFFSET_OS2CPRANGE+1));
  2408. LeaveCriticalSection(&g_cs);
  2409. break;
  2410. }
  2411. else
  2412. {
  2413. if (g_urange_table[m].wcFrom < TWO_BYTE_NUM((lp1+k)))
  2414. {
  2415. j = k-2;
  2416. }
  2417. else
  2418. {
  2419. i = k+2;
  2420. }
  2421. k = (i+j)/2;
  2422. }
  2423. }
  2424. }
  2425. bRet = TRUE;
  2426. GET_NCP_EXIT:
  2427. if (lpvFile)
  2428. {
  2429. UnmapViewOfFile(lpvFile);
  2430. }
  2431. if (hTTFMap)
  2432. {
  2433. CloseHandle(hTTFMap);
  2434. }
  2435. CloseHandle(hTTF);
  2436. return bRet;
  2437. }
  2438. HRESULT GetRegFontKey(HKEY *phKey, DWORD *pdwValues)
  2439. {
  2440. HRESULT hr = E_FAIL;
  2441. if (ERROR_SUCCESS == (g_bIsNT?
  2442. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEYNT, 0, KEY_READ, phKey):
  2443. RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGFONTKEY95, 0, KEY_READ, phKey)))
  2444. {
  2445. if (ERROR_SUCCESS == RegQueryInfoKey(*phKey, NULL, NULL, 0, NULL,
  2446. NULL, NULL, pdwValues, NULL, NULL, NULL, NULL))
  2447. {
  2448. hr = S_OK;
  2449. }
  2450. else
  2451. {
  2452. RegCloseKey(*phKey);
  2453. }
  2454. }
  2455. return hr;
  2456. }
  2457. BOOL CMLFLink2::CFontMappingCache2::GetFontURangeBits(TCHAR *szFontFile, DWORD * pdwURange)
  2458. {
  2459. // We can make use of font Unicode range signature if needed.
  2460. return TRUE;
  2461. }
  2462. BOOL CMLFLink2::CFontMappingCache2::SetFontScripts(void)
  2463. {
  2464. LOGFONT lf;
  2465. int i,j;
  2466. HWND hWnd = GetTopWindow(GetDesktopWindow());
  2467. HDC hDC = GetDC(hWnd);
  2468. if (!g_pfont_table)
  2469. return FALSE;
  2470. // Process code page based scripts (g_CharSetTransTable.sid)
  2471. for (i = 0; g_CharSetTransTable[i].nCharSet != DEFAULT_CHARSET; i++)
  2472. {
  2473. j = 0;
  2474. ZeroMemory(&lf, sizeof(lf));
  2475. lf.lfCharSet = (BYTE)g_CharSetTransTable[i].nCharSet;
  2476. while (g_CharSetTransTable[i].sid[j] != sidDefault)
  2477. {
  2478. EnumFontFamiliesEx(hDC, &lf, (FONTENUMPROC)SetFontScriptsEnumFontProc, (LPARAM)g_CharSetTransTable[i].sid[j], 0);
  2479. j++;
  2480. }
  2481. }
  2482. if (hDC)
  2483. ReleaseDC(hWnd, hDC);
  2484. // Process Unicode subrange based scripts (not implemented)
  2485. // Skip this part since we need to access font CMAP anyway
  2486. // Process char based scripts (g_wCharToScript)
  2487. for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  2488. {
  2489. UINT uiRanges = 0;
  2490. UNICODERANGE* pURanges = NULL;
  2491. SCRIPT_IDS scripts;
  2492. if (SUCCEEDED(m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges)))
  2493. {
  2494. if (uiRanges)
  2495. {
  2496. int l, m, n;
  2497. pURanges = (UNICODERANGE *)LocalAlloc(LPTR, sizeof(UNICODERANGE) * uiRanges);
  2498. if (!pURanges)
  2499. return FALSE;
  2500. m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, &uiRanges, pURanges);
  2501. for (j=0; j< ARRAYSIZE(g_wCharToScript); j++)
  2502. {
  2503. l = 0;
  2504. m = uiRanges;
  2505. n = m/2;
  2506. while (l <= m)
  2507. {
  2508. if ((g_wCharToScript[j].wch >= pURanges[n].wcFrom) && (g_wCharToScript[j].wch <= pURanges[n].wcTo))
  2509. {
  2510. scripts = 1;
  2511. scripts <<= g_wCharToScript[j].sid;
  2512. g_pfont_table[i].scripts |= scripts;
  2513. break;
  2514. }
  2515. else
  2516. {
  2517. if (g_wCharToScript[j].wch < pURanges[n].wcFrom)
  2518. m = n-1;
  2519. else
  2520. l = n+1;
  2521. n = (m+l)/2;
  2522. }
  2523. }
  2524. }
  2525. LocalFree(pURanges);
  2526. pURanges = NULL;
  2527. }
  2528. }
  2529. // sidUserDefined should contain all valid regular TrueType fonts
  2530. if (!MLStrStr(g_pfont_table[i].szFaceName, TEXT("Bold")) && !MLStrStr(g_pfont_table[i].szFaceName, TEXT("Italic")))
  2531. {
  2532. scripts = 1;
  2533. scripts <<= sidUserDefined;
  2534. g_pfont_table[i].scripts |= scripts;
  2535. }
  2536. }
  2537. //GetFontScriptFromCMAP(szFont, &(g_pfont_table[i].scripts));
  2538. return TRUE;
  2539. }
  2540. BOOL CMLFLink2::CFontMappingCache2::IsFontUpdated(void)
  2541. {
  2542. HKEY hkey;
  2543. DWORD dwFonts = 0;
  2544. BOOL bRet = FALSE;
  2545. if (g_pfont_table)
  2546. {
  2547. if (S_OK == GetRegFontKey(&hkey, &dwFonts))
  2548. {
  2549. if (g_pfont_table[0].dwCodePages[1] != dwFonts)
  2550. bRet = TRUE;
  2551. RegCloseKey(hkey);
  2552. }
  2553. }
  2554. else
  2555. {
  2556. // font table not created yet, need to update
  2557. bRet = TRUE;
  2558. }
  2559. return bRet;
  2560. }
  2561. // Make sure we have font data table available and it is updated
  2562. HRESULT CMLFLink2::CFontMappingCache2::EnsureFontTable(BOOL bUpdateURangeTable)
  2563. {
  2564. BOOL bRet;
  2565. if (IsFontUpdated())
  2566. {
  2567. // Need to guard the whole font creation procedure by critical sections
  2568. EnterCriticalSection(&g_cs);
  2569. if (IsFontUpdated())
  2570. {
  2571. if (g_pfont_table)
  2572. {
  2573. if (g_pfont_table[0].szFaceName[0])
  2574. {
  2575. bUpdateURangeTable = TRUE;
  2576. }
  2577. LocalFree(g_pfont_table);
  2578. g_pfont_table = NULL;
  2579. }
  2580. bRet = SetFontTable();
  2581. if (!bRet)
  2582. {
  2583. LeaveCriticalSection(&g_cs);
  2584. return E_OUTOFMEMORY;
  2585. }
  2586. }
  2587. LeaveCriticalSection(&g_cs);
  2588. }
  2589. if (bUpdateURangeTable)
  2590. {
  2591. EnterCriticalSection(&g_cs);
  2592. for (int i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2593. {
  2594. if (g_urange_table[i].nFonts)
  2595. {
  2596. LocalFree(g_urange_table[i].pFontIndex);
  2597. g_urange_table[i].pFontIndex = NULL;
  2598. g_urange_table[i].nFonts = 0;
  2599. }
  2600. }
  2601. LeaveCriticalSection(&g_cs);
  2602. if (S_OK != SetFontUnicodeRanges())
  2603. return E_OUTOFMEMORY;
  2604. SaveFontDataFile();
  2605. }
  2606. // All tables created successfully
  2607. return S_OK;
  2608. }
  2609. #ifdef UNIX
  2610. typedef struct tagTable_info{
  2611. int count;
  2612. int table_size;
  2613. } Table_info;
  2614. int UnixGetAllFontsProc(ENUMLOGFONTEX* plfFont, NEWTEXTMETRICEX* lpntm, int iFontType, LPARAM lParam)
  2615. {
  2616. LOGFONT *lplf;
  2617. int *pcount = &((Table_info*)lParam)->count;
  2618. int *ptable_size = &((Table_info*)lParam)->table_size;
  2619. lplf = &(plfFont->elfLogFont);
  2620. // We don't use non TrueType fonts
  2621. if (iFontType == DEVICE_FONTTYPE || iFontType == RASTER_FONTTYPE)
  2622. return 1; // keep going but don't use this font
  2623. // We don't use the SYMBOL, Mac Charset fonts
  2624. if(lplf->lfCharSet == SYMBOL_CHARSET || lplf->lfCharSet == MAC_CHARSET)
  2625. return 1;
  2626. // We don't handle vertical fonts
  2627. if (TEXT('@') == lplf->lfFaceName[0])
  2628. return 1;
  2629. // Now update the font-table
  2630. // Does UNIX use TTF? // if (FontType == TRUETYPE_FONTTYPE)
  2631. {
  2632. CopyMemory(&g_pfont_table[*pcount].lf, lplf, sizeof(LOGFONT));
  2633. MLStrCpyN(g_pfont_table[*pcount].szFaceName, lplf->lfFaceName, LF_FACESIZE);
  2634. (*pcount)++;
  2635. }
  2636. if (*pcount >= *ptable_size)
  2637. {
  2638. FONTINFO * pfont_table = NULL;
  2639. *ptable_size += FONT_TABLE_INIT_SIZE;
  2640. pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table,
  2641. sizeof(FONTINFO) * *ptable_size,
  2642. LMEM_MOVEABLE | LMEM_ZEROINIT);
  2643. if (NULL == pfont_table)
  2644. {
  2645. return 0; // Stop enum.
  2646. }
  2647. else
  2648. {
  2649. g_pfont_table = pfont_table;
  2650. }
  2651. }
  2652. return 1; // Keep enum.
  2653. }
  2654. #endif
  2655. BOOL CMLFLink2::CFontMappingCache2::SetFontTable(void)
  2656. {
  2657. BOOL bRet = TRUE;
  2658. TCHAR szFaceName[MAX_PATH];
  2659. DWORD dwValue;
  2660. TCHAR szFontFile[MAX_FONT_FILE_NAME];
  2661. DWORD dwData;
  2662. DWORD dwType = REG_SZ;
  2663. DWORD dwFonts;
  2664. int i, table_size = FONT_TABLE_INIT_SIZE;
  2665. LPTSTR pNewFaceName = NULL;
  2666. HKEY hkey = NULL;
  2667. static int count;
  2668. HDC hDC = NULL;
  2669. HWND hWnd = NULL;
  2670. FONTINFO * pFontTable;
  2671. count = 1;
  2672. if (!g_pfont_table)
  2673. {
  2674. g_pfont_table = (FONTINFO *)LocalAlloc(LPTR, sizeof(FONTINFO) * FONT_TABLE_INIT_SIZE);
  2675. if (!g_pfont_table)
  2676. {
  2677. bRet = FALSE;
  2678. goto SETFONT_DONE;
  2679. }
  2680. }
  2681. else
  2682. {
  2683. // weiwu: Need to clean up this code
  2684. goto SETFONT_DONE;
  2685. }
  2686. #ifndef UNIX
  2687. if (S_OK != GetRegFontKey(&hkey, &dwFonts))
  2688. {
  2689. bRet = FALSE;
  2690. goto SETFONT_DONE;
  2691. }
  2692. hWnd = GetTopWindow(GetDesktopWindow());
  2693. hDC = GetDC(hWnd);
  2694. for (i=0; ;i++)
  2695. {
  2696. dwValue = sizeof(szFaceName);
  2697. dwData = sizeof(szFontFile);
  2698. if (ERROR_NO_MORE_ITEMS == RegEnumValue(
  2699. hkey,
  2700. i,
  2701. szFaceName,
  2702. &dwValue,
  2703. NULL,
  2704. &dwType,
  2705. (LPBYTE)szFontFile,
  2706. &dwData ))
  2707. {
  2708. break;
  2709. }
  2710. DWORD dwOffset = 0;
  2711. FIND_NEXT_FACENAME:
  2712. pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT(" & "));
  2713. if (pNewFaceName)
  2714. {
  2715. *pNewFaceName = 0;
  2716. // Skip " & ", look for next font face name
  2717. pNewFaceName+=3;
  2718. }
  2719. else
  2720. {
  2721. pNewFaceName = MLStrStr(&szFaceName[dwOffset], TEXT("(TrueType)"));
  2722. if(pNewFaceName)
  2723. {
  2724. // Ignor the space between face name and "(TrueTye)" signature
  2725. if ((pNewFaceName > szFaceName) && (*(pNewFaceName-1) == 0x20))
  2726. pNewFaceName--;
  2727. *pNewFaceName = 0;
  2728. }
  2729. }
  2730. if (pNewFaceName && !EnumFontFamilies(hDC, &szFaceName[dwOffset], MapFontExEnumFontProc, (LPARAM)&count)) //TrueType font
  2731. {
  2732. int nSize;
  2733. LPTSTR pFontFile;
  2734. if (count >= table_size)
  2735. {
  2736. FONTINFO * _pfont_table = NULL;
  2737. table_size += FONT_TABLE_INIT_SIZE;
  2738. _pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table, sizeof(FONTINFO) * table_size,
  2739. LMEM_MOVEABLE | LMEM_ZEROINIT);
  2740. if (NULL == _pfont_table)
  2741. {
  2742. bRet = FALSE;
  2743. RegCloseKey(hkey);
  2744. goto SETFONT_DONE;
  2745. }
  2746. else
  2747. {
  2748. g_pfont_table = _pfont_table;
  2749. }
  2750. }
  2751. nSize = lstrlen(szFontFile);
  2752. if (!MLStrCmpNI(&szFontFile[nSize-3], "fot", 3))
  2753. _tcsncpy(&szFontFile[nSize-3], "ttf", 3);
  2754. //
  2755. // Trim off path
  2756. //
  2757. // #335900, some third party apps write font file names to registry directly
  2758. // and the names they used could have redundant font path
  2759. //
  2760. pFontFile = szFontFile;
  2761. while (nSize)
  2762. {
  2763. // Font file name contains only ASCII characters,
  2764. // So, we can safely trim the path by backward searching '\'
  2765. if (szFontFile[nSize] == TEXT('\\'))
  2766. {
  2767. pFontFile = &szFontFile[nSize];
  2768. pFontFile++;
  2769. break;
  2770. }
  2771. nSize--;
  2772. }
  2773. GetFontURangeBits(szFontFile, &(g_pfont_table[count-1].dwUniSubRanges[0]));
  2774. MLStrCpyN(g_pfont_table[count-1].szFaceName, &szFaceName[dwOffset], LF_FACESIZE);
  2775. MLStrCpyN(g_pfont_table[count-1].szFileName, pFontFile, LF_FACESIZE);
  2776. }
  2777. if (pNewFaceName && (*pNewFaceName))
  2778. {
  2779. dwOffset = (DWORD)(pNewFaceName - &szFaceName[0]);
  2780. goto FIND_NEXT_FACENAME;
  2781. }
  2782. }
  2783. #else
  2784. // For UNIX, we don't have registry font information,
  2785. // Let's create font table through EnumFontFamiliesEx.
  2786. Table_info table_info;
  2787. table_info.count = 1;
  2788. table_info.table_size = table_size;
  2789. int iRet;
  2790. LOGFONT lf;
  2791. lf.lfCharSet = DEFAULT_CHARSET; // give me all fonts
  2792. lf.lfFaceName[0] = _T('\0');
  2793. lf.lfPitchAndFamily = 0;
  2794. hWnd = GetTopWindow(GetDesktopWindow());
  2795. hDC = GetDC(hWnd);
  2796. iRet = EnumFontFamiliesEx(hDC, // Enum all fonts
  2797. &lf,
  2798. (FONTENUMPROC)UnixGetAllFontsProc,
  2799. (LPARAM)&table_info,
  2800. 0);
  2801. count = table_info.count;
  2802. if (iRet == 0) // abort
  2803. {
  2804. bRet = FALSE;
  2805. goto SETFONT_DONE;
  2806. }
  2807. #endif // UNIX
  2808. // Release un-used memory
  2809. pFontTable = (FONTINFO *)LocalReAlloc(g_pfont_table, (count)*sizeof(FONTINFO), LMEM_MOVEABLE);
  2810. if (pFontTable)
  2811. {
  2812. g_pfont_table = pFontTable;
  2813. }
  2814. // Save TrueType font number
  2815. g_pfont_table[0].dwCodePages[0] = count-1;
  2816. #ifndef UNIX
  2817. // Unix doesn't have this number.
  2818. // Save total font number for font change verification
  2819. g_pfont_table[0].dwCodePages[1] = dwFonts;
  2820. RegCloseKey(hkey);
  2821. #endif
  2822. if (count > 1)
  2823. SetFontScripts();
  2824. SETFONT_DONE:
  2825. if (hDC)
  2826. ReleaseDC(hWnd, hDC);
  2827. if (count <= 1)
  2828. {
  2829. if (g_pfont_table)
  2830. {
  2831. LocalFree(g_pfont_table);
  2832. g_pfont_table = NULL;
  2833. }
  2834. bRet = FALSE;
  2835. }
  2836. return bRet;
  2837. }
  2838. HRESULT CMLFLink2::CFontMappingCache2::SaveFontDataFile(void)
  2839. {
  2840. FONTDATAHEADER fileHeader;
  2841. HRESULT hr = E_FAIL;
  2842. int *pTmpBuf = NULL;
  2843. HANDLE hFile = NULL;
  2844. int i, j, Count = 0;
  2845. DWORD dwSize;
  2846. FONTDATATABLE fontInfoTable, fontIndexTable;
  2847. hFile = CreateFile( szFontDataFilePath,
  2848. GENERIC_WRITE,
  2849. 0,
  2850. NULL,
  2851. CREATE_ALWAYS,
  2852. FILE_ATTRIBUTE_HIDDEN,
  2853. NULL);
  2854. if (hFile == INVALID_HANDLE_VALUE)
  2855. {
  2856. goto SAVE_FONT_DATA_DONE;
  2857. }
  2858. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2859. {
  2860. Count += (g_urange_table[i].nFonts+1);
  2861. }
  2862. // Create file header
  2863. lstrcpynA(fileHeader.FileSig, FONT_DATA_SIGNATURE, sizeof(fileHeader.FileSig));
  2864. fileHeader.dwVersion = 0x00010000;
  2865. // Use file size as CheckSum
  2866. fileHeader.dwCheckSum = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1)+Count*sizeof(int)+
  2867. + sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM;
  2868. fileHeader.nTable = FONTDATATABLENUM;
  2869. pTmpBuf = (int *)LocalAlloc(LPTR, Count*sizeof(int));
  2870. if (!pTmpBuf)
  2871. goto SAVE_FONT_DATA_DONE;
  2872. // Get font index data
  2873. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2874. {
  2875. *pTmpBuf++ = g_urange_table[i].nFonts;
  2876. if (g_urange_table[i].nFonts)
  2877. {
  2878. for (j = 0; j< g_urange_table[i].nFonts; j++)
  2879. {
  2880. *pTmpBuf++ = *(g_urange_table[i].pFontIndex+j);
  2881. }
  2882. }
  2883. }
  2884. pTmpBuf -= Count;
  2885. // Create Dir tables
  2886. lstrcpynA(fontInfoTable.szName, "fnt", sizeof(fontInfoTable.szName));
  2887. fontInfoTable.dwOffset = sizeof(FONTDATAHEADER) + sizeof(FONTDATATABLE)*FONTDATATABLENUM;
  2888. fontInfoTable.dwSize = sizeof(FONTINFO)*(g_pfont_table[0].dwCodePages[0]+1);
  2889. lstrcpynA(fontIndexTable.szName, "idx", sizeof(fontIndexTable.szName));
  2890. fontIndexTable.dwOffset = fontInfoTable.dwSize+fontInfoTable.dwOffset;
  2891. fontIndexTable.dwSize = Count*sizeof(int);
  2892. if (WriteFile(hFile, &fileHeader, sizeof(FONTDATAHEADER), &dwSize, NULL) &&
  2893. WriteFile(hFile, &fontInfoTable, sizeof(FONTDATATABLE), &dwSize, NULL) &&
  2894. WriteFile(hFile, &fontIndexTable, sizeof(FONTDATATABLE), &dwSize, NULL) &&
  2895. WriteFile(hFile, g_pfont_table, fontInfoTable.dwSize, &dwSize, NULL) &&
  2896. WriteFile(hFile, pTmpBuf, fontIndexTable.dwSize, &dwSize, NULL))
  2897. {
  2898. hr = S_OK;
  2899. }
  2900. SAVE_FONT_DATA_DONE:
  2901. if (hFile)
  2902. CloseHandle(hFile);
  2903. if (pTmpBuf)
  2904. LocalFree(pTmpBuf);
  2905. return hr;
  2906. }
  2907. HRESULT CMLFLink2::CFontMappingCache2::LoadFontDataFile(void)
  2908. {
  2909. HANDLE hFontData = NULL;
  2910. HANDLE hFileMap = NULL;
  2911. LPVOID lpvFile = NULL;
  2912. int * lp;
  2913. HRESULT hr = E_FAIL;
  2914. DWORD dwFileSize;
  2915. int i, j;
  2916. HKEY hKey = NULL;
  2917. DWORD nFonts;
  2918. FONTDATAHEADER *pHeader;
  2919. FONTDATATABLE *pfTable;
  2920. hFontData = CreateFile(szFontDataFilePath,
  2921. GENERIC_READ,
  2922. FILE_SHARE_READ,
  2923. NULL,
  2924. OPEN_EXISTING,
  2925. FILE_ATTRIBUTE_NORMAL,
  2926. NULL);
  2927. if (hFontData == INVALID_HANDLE_VALUE)
  2928. return EnsureFontTable(TRUE);
  2929. dwFileSize = GetFileSize(hFontData, NULL);
  2930. hFileMap = CreateFileMapping(
  2931. hFontData,
  2932. NULL,
  2933. PAGE_READONLY,
  2934. 0,
  2935. dwFileSize,
  2936. NULL
  2937. );
  2938. if(hFileMap == NULL)
  2939. {
  2940. goto Load_File_Done;
  2941. }
  2942. lpvFile = MapViewOfFile(
  2943. hFileMap,
  2944. FILE_MAP_READ,
  2945. 0,
  2946. 0,
  2947. 0
  2948. );
  2949. if (lpvFile == NULL)
  2950. {
  2951. goto Load_File_Done;
  2952. }
  2953. pHeader = (FONTDATAHEADER *)lpvFile;
  2954. // Check mlang font cache file by signature and checksum
  2955. if (lstrcmpA(pHeader->FileSig, FONT_DATA_SIGNATURE) || pHeader->dwCheckSum != dwFileSize)
  2956. {
  2957. goto Load_File_Done;
  2958. }
  2959. if (S_OK != GetRegFontKey(&hKey, &nFonts))
  2960. {
  2961. goto Load_File_Done;
  2962. }
  2963. pfTable = (FONTDATATABLE *) ((LPBYTE)lpvFile + sizeof(FONTDATAHEADER));
  2964. // Check if there is any font change (no guarantee, but works in most cases)
  2965. if (nFonts != ((FONTINFO*)((LPBYTE)lpvFile + pfTable[0].dwOffset))->dwCodePages[1])
  2966. {
  2967. // If there is a change in system font number, we reload everything
  2968. UnmapViewOfFile(lpvFile);
  2969. CloseHandle(hFileMap);
  2970. CloseHandle(hFontData);
  2971. RegCloseKey(hKey);
  2972. return EnsureFontTable(TRUE);
  2973. }
  2974. EnterCriticalSection(&g_cs);
  2975. // Reset cache information
  2976. if (g_pfont_table)
  2977. {
  2978. LocalFree(g_pfont_table);
  2979. g_pfont_table = NULL;
  2980. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2981. {
  2982. if (g_urange_table[i].nFonts)
  2983. {
  2984. LocalFree(g_urange_table[i].pFontIndex);
  2985. g_urange_table[i].pFontIndex = NULL;
  2986. g_urange_table[i].nFonts = 0;
  2987. }
  2988. }
  2989. }
  2990. if(!(g_pfont_table = (FONTINFO *) (LocalAlloc(LPTR, pfTable[0].dwSize))))
  2991. {
  2992. LeaveCriticalSection(&g_cs);
  2993. hr = E_OUTOFMEMORY;
  2994. goto Load_File_Done;
  2995. }
  2996. CopyMemory(g_pfont_table, (LPBYTE)lpvFile + pfTable[0].dwOffset, pfTable[0].dwSize);
  2997. lp = (int *)((LPBYTE)lpvFile + pfTable[1].dwOffset);
  2998. for (i = 0; i < ARRAYSIZE(g_urange_table); i++)
  2999. {
  3000. if (g_urange_table[i].nFonts = *lp++)
  3001. {
  3002. //g_urange_table[i].nFonts = *lp++;
  3003. g_urange_table[i].pFontIndex = (int *)LocalAlloc(LPTR, sizeof(int)*g_urange_table[i].nFonts);
  3004. for (j = 0; j< g_urange_table[i].nFonts; j++)
  3005. {
  3006. g_urange_table[i].pFontIndex[j] = *lp++;
  3007. }
  3008. }
  3009. }
  3010. LeaveCriticalSection(&g_cs);
  3011. hr = S_OK;
  3012. Load_File_Done:
  3013. if (lpvFile)
  3014. UnmapViewOfFile(lpvFile);
  3015. if (hFileMap)
  3016. CloseHandle(hFileMap);
  3017. if (hFontData)
  3018. CloseHandle(hFontData);
  3019. if (hKey)
  3020. RegCloseKey(hKey);
  3021. return hr;
  3022. }
  3023. HRESULT CMLFLink2::CFontMappingCache2::SetFontUnicodeRanges(void)
  3024. {
  3025. TCHAR szFontPath[MAX_PATH];
  3026. TCHAR szFont[MAX_PATH];
  3027. HRESULT hr = S_OK;
  3028. int i;
  3029. int *pInt;
  3030. EnterCriticalSection(&g_cs);
  3031. g_pfont_table[0].szFaceName[0] = 1;
  3032. LeaveCriticalSection(&g_cs);
  3033. MLGetWindowsDirectory(szFontPath, MAX_PATH);
  3034. MLPathCombine(szFontPath, ARRAYSIZE(szFontPath), szFontPath, FONT_FOLDER);
  3035. for (i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  3036. {
  3037. MLPathCombine(szFont, ARRAYSIZE(szFont), szFontPath, g_pfont_table[i].szFileName);
  3038. GetNonCpFontUnicodeRanges(szFont, i);
  3039. }
  3040. // Release un-used memory
  3041. for (i=0; i< ARRAYSIZE(g_urange_table); i++)
  3042. {
  3043. if (g_urange_table[i].nFonts)
  3044. {
  3045. pInt = (int *)LocalReAlloc(g_urange_table[i].pFontIndex, g_urange_table[i].nFonts*sizeof(int), LMEM_MOVEABLE);
  3046. if (pInt)
  3047. {
  3048. g_urange_table[i].pFontIndex = pInt;
  3049. }
  3050. }
  3051. }
  3052. return hr;
  3053. }
  3054. STDMETHODIMP CMLFLink2::GetStrCodePages(const WCHAR* pszSrc, long cchSrc, DWORD dwPriorityCodePages, DWORD* pdwCodePages, long* pcchCodePages)
  3055. {
  3056. ASSERT_THIS;
  3057. ASSERT_READ_BLOCK(pszSrc, cchSrc);
  3058. ASSERT_WRITE_PTR_OR_NULL(pdwCodePages);
  3059. ASSERT_WRITE_PTR_OR_NULL(pcchCodePages);
  3060. HRESULT hr = S_OK;
  3061. long cchCodePages = 0;
  3062. DWORD dwStrCodePages = (DWORD)~0;
  3063. BOOL fInit = FALSE;
  3064. BOOL fNoPri = FALSE;
  3065. if (!pszSrc || cchSrc <= 0) // We can't make dwStrCodePages when cchSrc is zero
  3066. hr = E_INVALIDARG;
  3067. if (!m_pIMLFLnk)
  3068. return E_OUTOFMEMORY;
  3069. while (SUCCEEDED(hr) && cchSrc > 0)
  3070. {
  3071. DWORD dwCharCodePages;
  3072. if (SUCCEEDED(hr = m_pIMLFLnk->GetCharCodePages(*pszSrc, &dwCharCodePages)))
  3073. {
  3074. if (!fInit)
  3075. {
  3076. fInit = TRUE;
  3077. fNoPri = !(dwPriorityCodePages & dwCharCodePages);
  3078. }
  3079. else if (fNoPri != !(dwPriorityCodePages & dwCharCodePages))
  3080. {
  3081. break;
  3082. }
  3083. if (!fNoPri)
  3084. dwPriorityCodePages &= dwCharCodePages;
  3085. if (dwCharCodePages && (dwCharCodePages & dwStrCodePages))
  3086. dwStrCodePages &= dwCharCodePages;
  3087. else
  3088. break;
  3089. pszSrc++;
  3090. cchSrc--;
  3091. cchCodePages++;
  3092. }
  3093. }
  3094. if (SUCCEEDED(hr))
  3095. {
  3096. if (!cchCodePages)
  3097. {
  3098. dwStrCodePages = 0;
  3099. cchCodePages++;
  3100. }
  3101. if (pcchCodePages)
  3102. *pcchCodePages = cchCodePages;
  3103. if (pdwCodePages)
  3104. *pdwCodePages = dwStrCodePages;
  3105. }
  3106. else
  3107. {
  3108. if (pcchCodePages)
  3109. *pcchCodePages = 0;
  3110. if (pdwCodePages)
  3111. *pdwCodePages = 0;
  3112. }
  3113. return hr;
  3114. }
  3115. STDMETHODIMP CMLFLink2::MapFont(HDC hDC, DWORD dwCodePages, WCHAR wchar, HFONT* phDestFont)
  3116. {
  3117. HFONT hSrcFont = NULL;
  3118. if (NULL == (hSrcFont = (HFONT) GetCurrentObject(hDC, OBJ_FONT)))
  3119. return E_FAIL;
  3120. if (dwCodePages)
  3121. {
  3122. if (m_pIMLFLnk)
  3123. return m_pIMLFLnk->MapFont(hDC, dwCodePages, hSrcFont, phDestFont);
  3124. return E_OUTOFMEMORY;
  3125. }
  3126. else
  3127. {
  3128. if (!m_pFontMappingCache2)
  3129. m_pFontMappingCache2 = new CFontMappingCache2;
  3130. if (m_pFontMappingCache2)
  3131. return m_pFontMappingCache2->MapFontFromCMAP(hDC, wchar, hSrcFont, phDestFont);
  3132. else
  3133. return E_OUTOFMEMORY;
  3134. }
  3135. }
  3136. STDMETHODIMP CMLFLink2::GetFontUnicodeRanges(HDC hDC, UINT *puiRanges, UNICODERANGE* pURanges)
  3137. {
  3138. int i;
  3139. LOGFONT lf;
  3140. HRESULT hr = E_FAIL;
  3141. HFONT hFont = NULL;
  3142. if (!puiRanges)
  3143. return E_INVALIDARG;
  3144. if (!m_pFontMappingCache2)
  3145. m_pFontMappingCache2 = new CFontMappingCache2;
  3146. if (!m_pFontMappingCache2)
  3147. return E_OUTOFMEMORY;
  3148. if (!(hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT)))
  3149. return hr;
  3150. if (FAILED(m_pFontMappingCache2->EnsureFontTable(FALSE)))
  3151. return hr;
  3152. if (!GetObject(hFont, sizeof(LOGFONT), &lf))
  3153. return hr;
  3154. for (i=1; i<= (int) g_pfont_table[0].dwCodePages[0]; i++)
  3155. {
  3156. if (!lstrcmp(lf.lfFaceName, g_pfont_table[i].szFaceName))
  3157. break;
  3158. }
  3159. if (i > (int) g_pfont_table[0].dwCodePages[0])
  3160. return hr;
  3161. return m_pFontMappingCache2->UnicodeRanges(g_pfont_table[i].szFileName, puiRanges, pURanges);
  3162. }
  3163. STDMETHODIMP CMLFLink2::GetScriptFontInfo(SCRIPT_ID sid, DWORD dwFlags, UINT *puiFonts, SCRIPTFONTINFO* pScriptFont)
  3164. {
  3165. HRESULT hr = E_FAIL;
  3166. UINT uiNum;
  3167. BYTE bPitch = dwFlags & SCRIPTCONTF_FIXED_FONT? FIXED_PITCH:VARIABLE_PITCH;
  3168. if (!m_pFontMappingCache2)
  3169. m_pFontMappingCache2 = new CFontMappingCache2;
  3170. if (m_pFontMappingCache2)
  3171. m_pFontMappingCache2->EnsureFontTable(FALSE);
  3172. if (!g_pfont_table)
  3173. return hr;
  3174. if (!pScriptFont)
  3175. {
  3176. uiNum = g_pfont_table[0].dwCodePages[0];
  3177. }
  3178. else
  3179. {
  3180. uiNum = *puiFonts;
  3181. }
  3182. *puiFonts = 0;
  3183. // Binary search font table to match script id.
  3184. for (UINT i=1; i<= g_pfont_table[0].dwCodePages[0]; i++)
  3185. {
  3186. // Check font pitch
  3187. if (!(g_pfont_table[i].lf.lfPitchAndFamily & bPitch))
  3188. continue;
  3189. // Get sid bit mask
  3190. SCRIPT_IDS sids = 1;
  3191. sids <<= sid;
  3192. if (sids & g_pfont_table[i].scripts)
  3193. {
  3194. // Bail out is required number reached
  3195. if (*puiFonts >= uiNum)
  3196. {
  3197. break;
  3198. }
  3199. if (pScriptFont)
  3200. {
  3201. MultiByteToWideChar(CP_ACP, 0, g_pfont_table[i].szFaceName, -1, (pScriptFont + *puiFonts)->wszFont, MAX_MIMEFACE_NAME);
  3202. (pScriptFont + *puiFonts)->scripts = g_pfont_table[i].scripts;
  3203. }
  3204. (*puiFonts)++;
  3205. }
  3206. }
  3207. return S_OK;
  3208. }
  3209. // Map Windows code page to script id
  3210. // if multiple script id exist, we'll return the default one
  3211. STDMETHODIMP CMLFLink2::CodePageToScriptID(UINT uiCodePage, SCRIPT_ID *pSid)
  3212. {
  3213. MIMECPINFO cpInfo;
  3214. HRESULT hr = E_FAIL;
  3215. if (!pSid)
  3216. return E_INVALIDARG;
  3217. if (NULL != g_pMimeDatabase)
  3218. {
  3219. if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(uiCodePage, 0x409, &cpInfo)))
  3220. {
  3221. if (cpInfo.uiFamilyCodePage == CP_USER_DEFINED)
  3222. {
  3223. *pSid = sidUserDefined;
  3224. hr = S_OK;
  3225. }
  3226. else
  3227. for (int i = 0; g_CharSetTransTable[i].uCodePage; i++)
  3228. {
  3229. if (cpInfo.uiFamilyCodePage == g_CharSetTransTable[i].uCodePage)
  3230. {
  3231. *pSid = g_CharSetTransTable[i].sid[0];
  3232. hr = S_OK;
  3233. break;
  3234. }
  3235. }
  3236. }
  3237. }
  3238. return hr;
  3239. }
  3240. CMLFLink2::CFontMappingCache2::CFontMappingCache2(void)
  3241. {
  3242. if (GetSystemDirectory(szFontDataFilePath, MAX_PATH))
  3243. {
  3244. MLPathCombine(szFontDataFilePath, ARRAYSIZE(szFontDataFilePath), szFontDataFilePath, FONT_DATA_FILE_NAME);
  3245. }
  3246. }
  3247. CMLFLink2::CFontMappingCache2::~CFontMappingCache2(void)
  3248. {
  3249. EnterCriticalSection(&g_cs);
  3250. if (g_pfont_table)
  3251. {
  3252. LocalFree(g_pfont_table);
  3253. g_pfont_table = NULL;
  3254. }
  3255. for (int i=0; i< ARRAYSIZE(g_urange_table); i++)
  3256. {
  3257. if (g_urange_table[i].nFonts)
  3258. {
  3259. LocalFree(g_urange_table[i].pFontIndex);
  3260. g_urange_table[i].nFonts = 0;
  3261. }
  3262. }
  3263. LeaveCriticalSection(&g_cs);
  3264. }
  3265. int CALLBACK CMLFLink2::CFontMappingCache2::MapFontExEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  3266. {
  3267. if (FontType == TRUETYPE_FONTTYPE && plfFont->lfFaceName[0] != TEXT('@') )
  3268. {
  3269. CopyMemory(&g_pfont_table[*(int *)lParam].lf, plfFont, sizeof(LOGFONT));
  3270. (*(int *)lParam)++;
  3271. return 0;
  3272. }
  3273. return 1;
  3274. }
  3275. int CALLBACK CMLFLink2::CFontMappingCache2::SetFontScriptsEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC*, DWORD FontType, LPARAM lParam)
  3276. {
  3277. if (FontType == TRUETYPE_FONTTYPE)
  3278. {
  3279. if (g_pfont_table)
  3280. {
  3281. for (int i=1; i<= (int)g_pfont_table[0].dwCodePages[0]; i++)
  3282. if (!MLStrCmpNI(plfFont->lfFaceName, g_pfont_table[i].szFaceName, LF_FACESIZE))
  3283. {
  3284. SCRIPT_IDS scripts = 1;
  3285. scripts <<= lParam;
  3286. g_pfont_table[i].scripts |= scripts;
  3287. break;
  3288. }
  3289. if (i > (int)g_pfont_table[0].dwCodePages[0] && plfFont->lfFaceName[0] != TEXT('@')) // GDI font not in current font table?
  3290. {
  3291. FONTINFO * pfont_table = NULL;
  3292. pfont_table = (FONTINFO *) LocalReAlloc(g_pfont_table,
  3293. sizeof(FONTINFO) * (g_pfont_table[0].dwCodePages[0]+2),
  3294. LMEM_MOVEABLE | LMEM_ZEROINIT);
  3295. if (NULL != pfont_table)
  3296. {
  3297. g_pfont_table = pfont_table;
  3298. g_pfont_table[0].dwCodePages[0]++;
  3299. MLStrCpyN(g_pfont_table[i].szFaceName, (char *)plfFont->lfFaceName, ARRAYSIZE(g_pfont_table[i].szFaceName));
  3300. CopyMemory(&g_pfont_table[i].lf, plfFont, sizeof(LOGFONT));
  3301. SCRIPT_IDS scripts = 1;
  3302. scripts <<= lParam;
  3303. g_pfont_table[i].scripts |= scripts;
  3304. }
  3305. }
  3306. }
  3307. }
  3308. return 1;
  3309. }
  3310. int CALLBACK CMLFLink::VerifyFontSizeEnumFontProc(const LOGFONT* plfFont, const TEXTMETRIC* ptm, DWORD FontType, LPARAM lParam)
  3311. {
  3312. LOGFONT* plfSrcFont = (LOGFONT*)lParam;
  3313. if (FontType != TRUETYPE_FONTTYPE)
  3314. {
  3315. LONG lHeight = ptm->tmInternalLeading - ptm->tmHeight;
  3316. // Match source font's lfHeight to physical bitmap font's lfHeight
  3317. if (lHeight < 0 && plfSrcFont->lfHeight < 0 && lHeight < plfSrcFont->lfHeight)
  3318. {
  3319. plfSrcFont->lfHeight = lHeight ;
  3320. }
  3321. }
  3322. return 0;
  3323. }