Source code of Windows XP (NT5)
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.

1819 lines
46 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module FONT.CPP -- font cache |
  5. *
  6. * Includes font cache, char width cache;
  7. * create logical font if not in cache, look up
  8. * character widths on an as needed basis (this
  9. * has been abstracted away into a separate class
  10. * so that different char width caching algos can
  11. * be tried.) <nl>
  12. *
  13. * Owner: <nl>
  14. * RichEdit 1.0 code: David R. Fulmer
  15. * Christian Fortini (initial conversion to C++)
  16. * Jon Matousek <nl>
  17. *
  18. * History: <nl>
  19. * 7/26/95 jonmat cleanup and reorganization, factored out
  20. * char width caching code into a separate class.
  21. * 7/1/99 KeithCu Removed multiple levels in CWidthCache, cached
  22. * 30K FE characters in 2 bytes, sped up cache by
  23. * lowering acceptable collision rate, halved memory
  24. * usage by storing widths in 2 bytes instead of 4
  25. * Shrunk much out of CCcs (i.e. LOGFONT)
  26. *
  27. * Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
  28. */
  29. #include "_common.h"
  30. #include "_font.h"
  31. #include "_rtfconv.h" // Needed for GetCodePage
  32. #include "_uspi.h"
  33. #define CLIP_DFA_OVERRIDE 0x40 // Used to disable Korea & Taiwan font association
  34. #define FF_BIDI 7
  35. extern ICustomTextOut *g_pcto;
  36. ASSERTDATA
  37. // Corresponds to yHeightCharPtsMost in richedit.h
  38. #define yHeightCharMost 32760
  39. // NOTE: this is global across all instances in the same process.
  40. static CFontCache *g_fc;
  41. static FONTINFO *g_pFontInfo = NULL;
  42. static LONG g_cFontInfo = 0;
  43. static LONG g_cFontInfoMax = 0;
  44. //Fonts automatically added to our font table
  45. const WCHAR *szArial = L"Arial"; // IFONT_ARIAL
  46. const WCHAR *szTimesNewRoman = L"Times New Roman"; // IFONT_TIMESNEWROMAN
  47. const WCHAR *szSymbol = L"Symbol"; // IFONT_SYMBOL
  48. const WCHAR *szSystem = L"System"; // IFONT_SYSTEM
  49. const int cfontsDflt = 4;
  50. //Other fonts that we do use, but aren't automatically added to our font table
  51. const WCHAR *szMicrosSansSerif = L"Microsoft Sans Serif";
  52. const WCHAR *szMSSansSerif = L"MS Sans Serif";
  53. const WCHAR *szMangal = L"Mangal";
  54. const WCHAR *szLatha = L"Latha";
  55. const WCHAR *szRaavi = L"Raavi";
  56. const WCHAR *szShruti = L"Shruti";
  57. const WCHAR *szTunga = L"Tunga";
  58. const WCHAR *szGautami = L"Gautami";
  59. const WCHAR *szCordiaNew = L"Cordia New";
  60. const WCHAR *szTahoma = L"Tahoma";
  61. const WCHAR *szArialUnicode = L"Arial Unicode MS";
  62. const WCHAR *szWingdings = L"Wingdings";
  63. const WCHAR *szSylfaen = L"Sylfaen";
  64. const WCHAR *szSyriac = L"Estrangelo Edessa";
  65. const WCHAR *szThaana = L"MV Boli";
  66. #define szFontOfChoice szArial
  67. /*
  68. * GetFontNameIndex(pFontName)
  69. *
  70. * @func
  71. * return index into global pszFontName table for fontname pFontName.
  72. * If fontname isn't in table, add it and return index.
  73. *
  74. * @rdesc
  75. * fontname index corresponding to pFontName
  76. *
  77. * @devnote
  78. * This uses a linear search, so the most common font names should be
  79. * up front. Internally, we use the fontname indices, so the search
  80. * isn't done that often. Note also that the fontname table only grows,
  81. * but this is probably OK for most clients. Else we need ref counting...
  82. */
  83. SHORT GetFontNameIndex(
  84. const WCHAR *pFontName)
  85. {
  86. CLock Lock; // Wonder how much this slows things down...
  87. for(LONG i = 0; i < g_cFontInfo; i++)
  88. {
  89. // A hash could speed this up if perf turns out poor
  90. if(!wcscmp(pFontName, g_pFontInfo[i].szFontName))
  91. return i;
  92. }
  93. if(g_cFontInfo + 1 >= g_cFontInfoMax)
  94. {
  95. // Note that PvReAlloc() reverts to PvAlloc() if g_pFontInfo is NULL
  96. FONTINFO *pFI = (FONTINFO *)PvReAlloc((LPVOID)g_pFontInfo,
  97. sizeof(FONTINFO) * (8 + g_cFontInfo));
  98. if(!pFI)
  99. return IFONT_ARIAL; // Out of memory...
  100. // Initialize the structure
  101. ZeroMemory (&pFI[g_cFontInfo], 8 * sizeof(FONTINFO));
  102. // attempts to fill them in
  103. if(!g_cFontInfoMax) // First allocation
  104. {
  105. Assert(IFONT_ARIAL == 0 && IFONT_TMSNEWRMN == 1 &&
  106. IFONT_SYMBOL == 2 && IFONT_SYSTEM == 3);
  107. pFI[IFONT_ARIAL].szFontName = szArial;
  108. pFI[IFONT_TMSNEWRMN].szFontName = szTimesNewRoman;
  109. pFI[IFONT_SYMBOL].szFontName = szSymbol;
  110. pFI[IFONT_SYSTEM].szFontName = szSystem;
  111. g_cFontInfo = cfontsDflt;
  112. }
  113. g_pFontInfo = pFI;
  114. g_cFontInfoMax += 8;
  115. }
  116. LONG cb = (wcslen(pFontName) + 1)*sizeof(WCHAR);
  117. WCHAR * pch = (WCHAR *)PvAlloc(cb, GMEM_MOVEABLE);
  118. if(!pch)
  119. return IFONT_ARIAL; // Out of memory...
  120. g_pFontInfo[g_cFontInfo].szFontName = pch;
  121. CopyMemory((void *)pch, pFontName, cb);
  122. return g_cFontInfo++;
  123. }
  124. /*
  125. * GetFontName(iFont)
  126. *
  127. * @func
  128. * return fontname given by g_pFontInfo[iFont].szFontName.
  129. *
  130. * @rdesc
  131. * fontname corresponding to fontname index iFont
  132. */
  133. const WCHAR *GetFontName(
  134. LONG iFont)
  135. {
  136. return (iFont >= 0 && iFont < g_cFontInfo) ? g_pFontInfo[iFont].szFontName : NULL;
  137. }
  138. void SetFontSignature(
  139. LONG iFont,
  140. QWORD qwFontSig)
  141. {
  142. if(iFont >= 0 && iFont < g_cFontInfo)
  143. g_pFontInfo[iFont].qwFontSig |= qwFontSig;
  144. }
  145. /*
  146. * SetFontLegitimateSize(iFont, fUIFont, bSize, fFEcpg)
  147. *
  148. * @func
  149. * Set the legitimate size (readable smallest size to use) of a given font
  150. *
  151. * @rdesc
  152. * TRUE if successful
  153. */
  154. BOOL SetFontLegitimateSize(
  155. LONG iFont,
  156. BOOL fUIFont,
  157. BYTE bSize,
  158. BOOL fFEcpg)
  159. {
  160. if (iFont < g_cFontInfo)
  161. {
  162. // East Asia wanted to do it per codepage.
  163. //
  164. // FUTURE: Bear in mind that this approach is bug-prone. Once there's
  165. // any new FE font created with different metric from the existing one.
  166. // Font scaling will not perform well or even broken for such font [wchao].
  167. g_pFontInfo[iFont].ff.fScaleByCpg = fFEcpg;
  168. if (fUIFont)
  169. {
  170. if (!g_pFontInfo[iFont].bSizeUI)
  171. g_pFontInfo[iFont].bSizeUI = bSize;
  172. else
  173. // more than one legit size were updated per font,
  174. // We fallback to the codepage-driven approach.
  175. g_pFontInfo[iFont].ff.fScaleByCpg = g_pFontInfo[iFont].bSizeUI != bSize;
  176. }
  177. else
  178. {
  179. if (!g_pFontInfo[iFont].bSizeNonUI)
  180. g_pFontInfo[iFont].bSizeNonUI = bSize;
  181. else
  182. g_pFontInfo[iFont].ff.fScaleByCpg = g_pFontInfo[iFont].bSizeNonUI != bSize;
  183. }
  184. return TRUE;
  185. }
  186. return FALSE;
  187. }
  188. /*
  189. * GetFontLegitimateSize(iFont, fUIFont, iCharRep)
  190. *
  191. * @func
  192. * Get the legitimate size (readable smallest size to use) of a given font
  193. *
  194. * @rdesc
  195. * Legitimate size of font
  196. */
  197. BYTE GetFontLegitimateSize(
  198. LONG iFont, //@parm Font to get size for
  199. BOOL fUIFont, //@parm TRUE if for UI font
  200. int iCharRep) //@parm Char repertoire to use
  201. {
  202. BYTE bDefPaf;
  203. SHORT iDefFont;
  204. BYTE yHeight = 0;
  205. if (iFont < g_cFontInfo && !g_pFontInfo[iFont].ff.fScaleByCpg)
  206. yHeight = fUIFont ? g_pFontInfo[iFont].bSizeUI : g_pFontInfo[iFont].bSizeNonUI;
  207. if (!yHeight && fc().GetInfoFlags(iFont).fNonBiDiAscii)
  208. {
  209. // Non-BiDi ASCII font uses table font (of the same charset) legitimate height
  210. QWORD qwFontSig = GetFontSignatureFromFace(iFont) & ~(FASCII | FFE);
  211. LONG iCharRepT = GetFirstAvailCharRep(qwFontSig);
  212. if(W32->GetPreferredFontInfo(iCharRepT, fUIFont ? true : false, iDefFont, yHeight, bDefPaf))
  213. {
  214. SetFontLegitimateSize(iFont, fUIFont, yHeight ? yHeight : fUIFont ? 8 : 10,
  215. IsFECharRep(iCharRepT));
  216. }
  217. }
  218. if (!yHeight)
  219. {
  220. if (fc().GetInfoFlags(iFont).fThaiDTP)
  221. {
  222. iCharRep = THAI_INDEX;
  223. fUIFont = FALSE;
  224. }
  225. W32->GetPreferredFontInfo(iCharRep, fUIFont ? true : false, iDefFont, yHeight, bDefPaf);
  226. }
  227. return yHeight ? yHeight : fUIFont ? 8 : 10;
  228. }
  229. /*
  230. * GetTextCharsetInfoPri(hdc, pFontSig, dwFlags)
  231. *
  232. * @func
  233. * Wrapper to GDI's GetTextCharsetInfo. This to handle BiDi old-style fonts
  234. *
  235. * @rdesc
  236. * CharSet for info
  237. */
  238. UINT GetTextCharsetInfoPri(
  239. HDC hdc,
  240. FONTSIGNATURE* pFontSig,
  241. DWORD dwFlags)
  242. {
  243. #ifndef NOCOMPLEXSCRIPTS
  244. OUTLINETEXTMETRICA otm;
  245. INT uCharSet = -1;
  246. if (pFontSig && GetOutlineTextMetricsA(hdc, sizeof(OUTLINETEXTMETRICA), &otm))
  247. {
  248. ZeroMemory (pFontSig, sizeof(FONTSIGNATURE));
  249. switch (otm.otmfsSelection & 0xFF00)
  250. {
  251. case 0xB200: // Arabic Simplified
  252. case 0xB300: // Arabic Traditional
  253. case 0xB400: // Arabic Old UDF
  254. uCharSet = ARABIC_CHARSET; break;
  255. case 0xB100: // Hebrew Old style
  256. uCharSet = HEBREW_CHARSET;
  257. }
  258. }
  259. if (uCharSet == -1)
  260. uCharSet = W32->GetTextCharsetInfo(hdc, pFontSig, dwFlags);
  261. if (uCharSet == DEFAULT_CHARSET)
  262. uCharSet = ANSI_CHARSET; // never return ambiguous
  263. return (UINT)uCharSet;
  264. #else
  265. return DEFAULT_CHARSET;
  266. #endif
  267. }
  268. /*
  269. * GetFontSignatureFromDC(hdc, &fNonBiDiAscii)
  270. *
  271. * @func
  272. * Compute RichEdit font signature for font selected into hdc. Uses
  273. * info from OS font signature
  274. *
  275. * @rdesc
  276. * RichEdit font signature for font selected into hdc
  277. */
  278. QWORD GetFontSignatureFromDC(
  279. HDC hdc,
  280. BOOL & fNonBiDiAscii)
  281. {
  282. union
  283. { // Endian-dependent way of
  284. QWORD qwFontSig; // avoiding 64-bit shifts
  285. DWORD dwFontSig[2];
  286. };
  287. #ifndef NOCOMPLEXSCRIPTS
  288. // Try to get FONTSIGNATURE data
  289. CHARSETINFO csi;
  290. UINT uCharSet = GetTextCharsetInfoPri(hdc, &(csi.fs), 0);
  291. DWORD dwUsb0 = 0;
  292. DWORD dwUsb2 = 0;
  293. if(!W32->OnWin9x())
  294. {
  295. dwUsb0 = csi.fs.fsUsb[0];
  296. dwUsb2 = csi.fs.fsUsb[2];
  297. }
  298. if ((csi.fs.fsCsb[0] | dwUsb0 | dwUsb2) ||
  299. TranslateCharsetInfo((DWORD *)(DWORD_PTR)uCharSet, &csi, TCI_SRCCHARSET))
  300. {
  301. DWORD fsCsb0 = csi.fs.fsCsb[0];
  302. CUniscribe * pusp;
  303. SCRIPT_CACHE sc = NULL;
  304. WORD wGlyph;
  305. qwFontSig = ((fsCsb0 & 0x1FF) << 8) // Shift left since we use
  306. | ((fsCsb0 & 0x1F0000) << 3); // low byte for fBiDi, etc.
  307. // Also look at Unicode subrange if available
  308. // FUTURE: we may want to drive Unicode ranges with a
  309. // table approach, i.e., use for loop shifting dwUsb0 right
  310. // to convert each bit into an index into a table of BYTEs
  311. // that return the appropriate script index for rgCpgCharSet:
  312. //
  313. // for(LONG i = 0; dwUsb0; dwUsb0 >>= 1, i++)
  314. // {
  315. // static const BYTE rgiCharRep[32] = {...};
  316. // if(dwUsb0 & 1)
  317. // dwFontSig |= FontSigFromCharRep(rgiCharRep[i]);
  318. // }
  319. if(dwUsb0)
  320. {
  321. if (dwUsb0 & 0x00000400)
  322. qwFontSig |= FARMENIAN;
  323. Assert(FDEVANAGARI == 0x0000000800000000);
  324. dwFontSig[1] |= (dwUsb0 & 0x00FF8000) >> 12; // 9 Indic scripts
  325. if (dwUsb0 & 0x02000000)
  326. qwFontSig |= FLAO;
  327. if (dwUsb0 & 0x04000000)
  328. qwFontSig |= FGEORGIAN;
  329. if (dwUsb0 & 0x10000000)
  330. qwFontSig |= FJAMO;
  331. }
  332. // The new Unicode 3.0 scripts are defined by dwUsb2 as follows
  333. // (see \\sparrow\sysnls\nlsapi\font-sig.txt):
  334. // 128 32 Script
  335. //----------------------
  336. // 70 6 Tibetan
  337. // 71 7 Syriac
  338. // 72 8 Thaana
  339. // 73 9 Sinhala
  340. // 74 10 Myanmar
  341. // 75 11 Ethiopic
  342. // 76 12 Cherokee
  343. // 77 13 Canadian Aboriginal Syllabics
  344. // 78 14 Ogham
  345. // 79 15 Runic
  346. // 80 16 Khmer
  347. // 81 17 Mongolian
  348. // 82 18 Braille
  349. // 83 19 Yi
  350. if(dwUsb2 & 0xFFFC0) // Bits 6 - 19
  351. {
  352. if(dwUsb2 & 0x40) // Bit 6 of dwUsb[2]
  353. dwFontSig[1] |= FTIBETAN > 32; // is Tibetan
  354. dwFontSig[1] |= (dwUsb2 & 0x180) >> 6; // Syriac (7), Thaana (8)
  355. if(dwUsb2 & 0x200) // Bit 9 of dwUsb[2]
  356. dwFontSig[1] |= FSINHALA > 32; // is Sinhala
  357. if(dwUsb2 & 0x400) // Bit 10 of dwUsb[2]
  358. dwFontSig[1] |= FMYANMAR > 32; // is Myanmar
  359. dwFontSig[1] |= (dwUsb2 & 0xFF800) << 6;// Bits 11-19 of dwUsb[2]
  360. }
  361. if((qwFontSig & FCOMPLEX_SCRIPT) && !(qwFontSig & FHILATIN1)
  362. && (pusp = GetUniscribe()))
  363. {
  364. // Signature says no Latin-1 support
  365. // Search for the 'a' and '0' glyph in the font to
  366. // determine if the font supports ASCII or European
  367. // Digit. This is necessary to overcome the font having
  368. // an incomplete font signature.
  369. if(ScriptGetCMap(hdc, &sc, L"a", 1, 0, &wGlyph) == S_OK)
  370. qwFontSig |= FASCIIUPR;
  371. if(ScriptGetCMap(hdc, &sc, L"0", 1, 0, &wGlyph) == S_OK)
  372. qwFontSig |= FBELOWX40;
  373. if(!IsBiDiCharSet(uCharSet) &&
  374. (qwFontSig & FASCII) == FASCII)
  375. fNonBiDiAscii = TRUE; // Non-BiDi ASCII font
  376. ScriptFreeCache(&sc);
  377. }
  378. if (qwFontSig & FHILATIN1)
  379. qwFontSig |= FASCII; // FLATIN1 has 3 bits
  380. // HACK for symbol font. We assign FSYMBOL for Symbol font signature.
  381. // REVIEW: should we just use csi.fs.fsCsb[0] bit 31 for symbol bit?
  382. if (uCharSet == SYMBOL_CHARSET && !qwFontSig || fsCsb0 & 0x80000000)
  383. qwFontSig = FSYMBOL;
  384. }
  385. else // No font signature info
  386. qwFontSig = FontSigFromCharRep(CharRepFromCharSet(uCharSet));
  387. #else
  388. qwFontSig = FLATIN1; // Default Latin1
  389. #endif // NOCOMPLEXSCRIPTS
  390. return qwFontSig;
  391. }
  392. /*
  393. * GetFontSignatureFromFace(iFont, pqwFontSig)
  394. *
  395. * @func
  396. * Giving font signature matching the index of given facename.
  397. * This signature may not match the one in Cccs since this is the
  398. * signature of the font of given facename. The Cccs one is
  399. * per GDI realization.
  400. *
  401. * @rdesc
  402. * - font signature if pqwFontSig is NULL.
  403. * - If pqwFontSig != NULL. It's a boolean.
  404. * ZERO means returned signature is not sensible by following reasons
  405. * 1. Bad facename (junk like "!@#$" or name that doesnt exist in the system)
  406. * 2. Given face doesnt support even one valid ANSI codepage (symbol fonts,
  407. * e.g., Marlett)
  408. */
  409. QWORD GetFontSignatureFromFace(
  410. int iFont,
  411. QWORD * pqwFontSig)
  412. {
  413. Assert((unsigned)iFont < (unsigned)g_cFontInfo);
  414. FONTINFO_FLAGS ff;
  415. QWORD qwFontSig = g_pFontInfo[iFont].qwFontSig;
  416. ff.wFlags = g_pFontInfo[iFont].ff.wFlags;
  417. if(!ff.fCached)
  418. {
  419. int i = 0;
  420. HDC hdc = GetDC(NULL);
  421. LOGFONT lf;
  422. WCHAR* pwchTag = lf.lfFaceName;
  423. ZeroMemory(&lf, sizeof(LOGFONT));
  424. wcscpy(lf.lfFaceName, GetFontName(iFont));
  425. // Exclude Win95's tag name e.g. "Arial(Greek)"
  426. while (pwchTag[i] && pwchTag[i] != '(')
  427. i++;
  428. if(pwchTag[i] && i > 0)
  429. {
  430. while (i > 0 && pwchTag[i-1] == 0x20)
  431. i--;
  432. pwchTag[i] = 0;
  433. }
  434. lf.lfCharSet = DEFAULT_CHARSET;
  435. // Obtain a charset supported by given facename
  436. // to force GDI gives facename priority over charset.
  437. W32->GetFacePriCharSet(hdc, &lf);
  438. HFONT hfont = CreateFontIndirect(&lf);
  439. if(hfont)
  440. {
  441. HFONT hfontOld = SelectFont(hdc, hfont);
  442. WCHAR szNewFaceName[LF_FACESIZE];
  443. GetTextFace(hdc, LF_FACESIZE, szNewFaceName);
  444. if(!wcsicmp(szNewFaceName, lf.lfFaceName) || // Got it
  445. ((GetCharFlags(szNewFaceName, 2) & FFE) && // or Get back FE font name for English name
  446. (GetCharFlags(lf.lfFaceName, 2) & FASCII)))// because NT5 supports dual font names.
  447. {
  448. BOOL fNonBiDiAscii = FALSE;
  449. qwFontSig = GetFontSignatureFromDC(hdc, fNonBiDiAscii);
  450. if(fNonBiDiAscii)
  451. ff.fNonBiDiAscii = TRUE;
  452. }
  453. else
  454. ff.fBadFaceName = TRUE;
  455. TEXTMETRIC tm;
  456. GetTextMetrics(hdc, &tm);
  457. ff.fTrueType = tm.tmPitchAndFamily & TMPF_TRUETYPE ? 1 : 0;
  458. ff.fBitmap = tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR | TMPF_DEVICE) ? 0 : 1;
  459. if(!ff.fBadFaceName && qwFontSig & FTHAI)
  460. {
  461. // Some heuristic test on Thai fonts.
  462. // Most Thai fonts will fall to this category currently except for
  463. // Tahoma and Microsoft Sans Serif.
  464. ff.fThaiDTP = tm.tmDescent && tm.tmAscent/tm.tmDescent < 3;
  465. }
  466. SelectObject(hdc, hfontOld);
  467. SideAssert(DeleteObject(hfont));
  468. }
  469. ReleaseDC(NULL, hdc);
  470. // Cache code pages supported by this font
  471. ff.fCached = TRUE;
  472. g_pFontInfo[iFont].qwFontSig |= qwFontSig;
  473. g_pFontInfo[iFont].ff.wFlags = ff.wFlags;
  474. }
  475. if (!pqwFontSig)
  476. return qwFontSig;
  477. *pqwFontSig = qwFontSig;
  478. // 22-29 are reserved for alternate ANSI/OEM, as of now we use 21, 22 for Devanagari and Tamil
  479. return qwFontSig && !ff.fBadFaceName;
  480. }
  481. /*
  482. * FreeFontNames()
  483. *
  484. * @func
  485. * Free fontnames given by g_pFontInfo[i].szFontName allocated by
  486. * GetFontNameIndex() as well as g_pFontInfo itself.
  487. */
  488. void FreeFontNames()
  489. {
  490. for(LONG i = cfontsDflt; i < g_cFontInfo; i++)
  491. FreePv((LPVOID)g_pFontInfo[i].szFontName);
  492. FreePv(g_pFontInfo);
  493. g_pFontInfo = NULL;
  494. }
  495. SHORT g_iFontJapanese;
  496. SHORT g_iFontHangul;
  497. SHORT g_iFontBig5;
  498. SHORT g_iFontGB2312;
  499. /*
  500. * InitFontCache()
  501. *
  502. * @func
  503. * Initializes font cache.
  504. *
  505. * @devnote
  506. * This is exists so reinit.cpp doesn't have to know all about the
  507. * font cache.
  508. */
  509. void InitFontCache()
  510. {
  511. g_fc = new CFontCache;
  512. g_fc->Init();
  513. }
  514. /*
  515. * FreeFontCache()
  516. *
  517. * @mfunc
  518. * Frees font cache.
  519. *
  520. * @devnote
  521. * This is exists so reinit.cpp doesn't have to know all about the
  522. * font cache.
  523. */
  524. void FreeFontCache()
  525. {
  526. for (int i = 0; i < g_cFontInfo; i++)
  527. delete g_pFontInfo[i]._pffm;
  528. delete g_fc;
  529. g_fc = NULL;
  530. FreeFontNames();
  531. }
  532. /*
  533. * CFontCache & fc()
  534. *
  535. * @func
  536. * initialize the global g_fc.
  537. * @comm
  538. * current #defined to store 16 logical fonts and
  539. * respective character widths.
  540. */
  541. CFontCache & fc()
  542. {
  543. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "fc");
  544. return *g_fc;
  545. }
  546. FONTINFO_FLAGS CFontCache::GetInfoFlags(int ifont)
  547. {
  548. if (!g_pFontInfo[ifont].ff.fCached)
  549. GetFontSignatureFromFace(ifont);
  550. return g_pFontInfo[ifont].ff;
  551. }
  552. CFontFamilyMgr::~CFontFamilyMgr()
  553. {
  554. for (int i = 0; i < _rgf.Count(); i++)
  555. {
  556. CFontFamilyMember *pf = _rgf.Elem(i);
  557. pf->Free();
  558. }
  559. }
  560. CFontFamilyMember* CFontFamilyMgr::GetFontFamilyMember(LONG weight, BOOL fItalic)
  561. {
  562. for (int i = 0; i < _rgf.Count(); i++)
  563. {
  564. CFontFamilyMember *pf = _rgf.Elem(i);
  565. if (pf->_weight == weight && pf->_fItalic == fItalic)
  566. return pf;
  567. }
  568. CFontFamilyMember f(weight, fItalic);
  569. CFontFamilyMember *pf = _rgf.Add(1, 0);
  570. *pf = f;
  571. return pf;
  572. }
  573. CKernCache * CFontCache::GetKernCache(LONG iFont, LONG weight, BOOL fItalic)
  574. {
  575. if (!g_fc->GetInfoFlags(iFont).fTrueType)
  576. return 0;
  577. CFontFamilyMgr *pffm = GetFontFamilyMgr(iFont);
  578. CFontFamilyMember *pf = pffm->GetFontFamilyMember(weight, fItalic);
  579. return pf->GetKernCache();
  580. }
  581. CFontFamilyMgr* CFontCache::GetFontFamilyMgr(LONG iFont)
  582. {
  583. if (!g_pFontInfo[iFont]._pffm)
  584. g_pFontInfo[iFont]._pffm = new CFontFamilyMgr();
  585. return g_pFontInfo[iFont]._pffm;
  586. }
  587. // =================================== CFontCache ====================================
  588. /*
  589. * CFontCache::Init()
  590. *
  591. * @mfunc
  592. * Initializes font cache.
  593. *
  594. * @devnote
  595. * This is not a constructor because something bad seems to happen
  596. * if we try to construct a global object.
  597. */
  598. void CFontCache::Init()
  599. {
  600. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CFontCache::CFontCache");
  601. _dwAgeNext = 0;
  602. }
  603. /*
  604. * CFontCache::MakeHashKey(pCF)
  605. *
  606. * @mfunc
  607. * Build a hash key for quick searches for a CCcs matching
  608. * the pCF.
  609. * Format:
  610. * iFont : 14
  611. * Bold/Italic : 2
  612. * Height : 16
  613. *
  614. */
  615. CCSHASHKEY CFontCache::MakeHashKey(
  616. const CCharFormat *pCF)
  617. {
  618. CCSHASHKEY ccshashkey;
  619. ccshashkey = pCF->_iFont | ((pCF->_dwEffects & 3) << 14);
  620. ccshashkey |= pCF->_yHeight << 16;
  621. return ccshashkey;
  622. }
  623. /*
  624. * CFontCache::GetCcs(pCF, dvpInch, dwFlags, hdc)
  625. *
  626. * @mfunc
  627. * Search the font cache for a matching logical font and return it.
  628. * If a match is not found in the cache, create one.
  629. *
  630. * @rdesc
  631. * A logical font matching the given CHARFORMAT info.
  632. *
  633. * @devnote
  634. * The calling chain must be protected by a CLock, since this present
  635. * routine access the global (shared) FontCache facility.
  636. */
  637. CCcs* CFontCache::GetCcs(
  638. CCharFormat *pCF, //@parm Logical font (routine is allowed to change it)
  639. const LONG dvpInch, //@parm Y pixels per inch
  640. DWORD dwFlags, //@parm flags
  641. HDC hdc) //@parm HDC font is to be created for
  642. {
  643. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CFontCache::GetCcs");
  644. // display font
  645. const CCcs * const pccsMost = &_rgccs[FONTCACHESIZE - 1];
  646. CCcs * pccs;
  647. CCSHASHKEY ccshashkey;
  648. int iccsHash;
  649. if (dwFlags & FGCCSUSETRUETYPE)
  650. {
  651. //On Win '9x Thai/Vietnamese, you cannot force truetype fonts! Therefore,
  652. //we will force Tahoma if the font doesn't support the right charset.
  653. if (W32->OnWin9x())
  654. {
  655. UINT acp = GetACP();
  656. if (acp == 1258 || acp == 874)
  657. {
  658. QWORD qwFontSig = GetFontSignatureFromFace(pCF->_iFont);
  659. if (pCF->_iCharRep == THAI_INDEX && (qwFontSig & FTHAI) == 0 ||
  660. pCF->_iCharRep == VIET_INDEX && (qwFontSig & FVIETNAMESE) == 0 ||
  661. !g_fc->GetInfoFlags(pCF->_iFont).fTrueType)
  662. {
  663. pCF->_iFont = GetFontNameIndex(szTahoma);
  664. }
  665. }
  666. }
  667. else if (!g_fc->GetInfoFlags(pCF->_iFont).fTrueType)
  668. dwFlags |= FGCCSUSETRUETYPE;
  669. }
  670. if (hdc == NULL)
  671. hdc = W32->GetScreenDC();
  672. // Change _yHeight in the case of sub/superscript
  673. if(pCF->_dwEffects & (CFE_SUPERSCRIPT | CFE_SUBSCRIPT))
  674. pCF->_yHeight = 2 * pCF->_yHeight / 3;
  675. //Convert CCharFormat into logical units (round)
  676. pCF->_yHeight = (pCF->_yHeight * dvpInch + LY_PER_INCH / 2) / LY_PER_INCH;
  677. if (pCF->_yHeight == 0)
  678. pCF->_yHeight = 1;
  679. if ((dwFlags & FGCCSUSEATFONT) && !IsFECharRep(pCF->_iCharRep))
  680. {
  681. QWORD qwFontSig = GetFontSignatureFromFace(pCF->_iFont);
  682. if (!(qwFontSig & FFE)) // No At font for non-FE charset and
  683. dwFlags &= ~FGCCSUSEATFONT; // font signature doesen't support FE
  684. }
  685. ccshashkey = MakeHashKey(pCF);
  686. // Check our hash before going sequential.
  687. iccsHash = ccshashkey % CCSHASHSEARCHSIZE;
  688. if(ccshashkey == quickHashSearch[iccsHash].ccshashkey)
  689. {
  690. pccs = quickHashSearch[iccsHash].pccs;
  691. if(pccs && pccs->_fValid)
  692. {
  693. if(pccs->Compare(pCF, hdc, dwFlags))
  694. goto matched;
  695. }
  696. }
  697. else //Setup this hash hint for next time
  698. quickHashSearch[iccsHash].ccshashkey = ccshashkey;
  699. // Sequentially search ccs for same character format
  700. for(pccs = &_rgccs[0]; pccs <= pccsMost; pccs++)
  701. {
  702. if(pccs->_ccshashkey == ccshashkey && pccs->_fValid)
  703. {
  704. if(!pccs->Compare(pCF, hdc, dwFlags))
  705. continue;
  706. quickHashSearch[iccsHash].pccs = pccs;
  707. matched:
  708. //$ FUTURE: make this work even with wrap around of dwAgeNext
  709. // Mark as most recently used if it isn't already in use.
  710. if(pccs->_dwAge != _dwAgeNext - 1)
  711. pccs->_dwAge = _dwAgeNext++;
  712. pccs->_cRefs++; // bump up ref. count
  713. return pccs;
  714. }
  715. }
  716. // We did not find a match: init a new font cache.
  717. pccs = GrabInitNewCcs(pCF, hdc, dwFlags);
  718. quickHashSearch[iccsHash].pccs = pccs;
  719. pccs->_ccshashkey = ccshashkey;
  720. return pccs;
  721. }
  722. /*
  723. * CFontCache::GrabInitNewCcs(pCF, hdc, dwFlags)
  724. *
  725. * @mfunc
  726. * Create a logical font and store it in our cache.
  727. *
  728. * @rdesc
  729. * New CCcs created
  730. */
  731. CCcs* CFontCache::GrabInitNewCcs(
  732. const CCharFormat * const pCF, //@parm Description of desired logical font
  733. HDC hdc,
  734. DWORD dwFlags)
  735. {
  736. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CFontCache::GrabInitNewCcs");
  737. DWORD dwAgeOldest = 0xffffffff;
  738. CCcs * pccs;
  739. const CCcs * const pccsMost = &_rgccs[FONTCACHESIZE - 1];
  740. CCcs * pccsOldest = NULL;
  741. // Look for unused entry and oldest in use entry
  742. for(pccs = &_rgccs[0]; pccs <= pccsMost && pccs->_fValid; pccs++)
  743. if(pccs->_cRefs == 0 && pccs->_dwAge < dwAgeOldest)
  744. {
  745. dwAgeOldest = pccs->_dwAge;
  746. pccsOldest = pccs;
  747. }
  748. if(pccs > pccsMost) // Didn't find an unused entry, use oldest entry
  749. {
  750. pccs = pccsOldest;
  751. if(!pccs)
  752. {
  753. AssertSz(FALSE, "CFontCache::GrabInitNewCcs oldest entry is NULL");
  754. return NULL;
  755. }
  756. }
  757. // Initialize new CCcs
  758. pccs->_hdc = hdc;
  759. pccs->_fFECharSet = IsFECharRep(pCF->_iCharRep);
  760. pccs->_fUseAtFont = (dwFlags & FGCCSUSEATFONT) != 0;
  761. pccs->_tflow = dwFlags & 0x3;
  762. if(!pccs->Init(pCF))
  763. return NULL;
  764. pccs->_cRefs++;
  765. return pccs;
  766. }
  767. // ============================= CCcs class ===================================================
  768. /*
  769. * BOOL CCcs::Init(pCF)
  770. *
  771. * @mfunc
  772. * Init one font cache object. The global font cache stores
  773. * individual CCcs objects.
  774. */
  775. BOOL CCcs::Init (
  776. const CCharFormat * const pCF) //@parm description of desired logical font
  777. {
  778. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::Init");
  779. if(_fValid)
  780. Free(); // recycle already in-use fonts.
  781. if(MakeFont(pCF))
  782. {
  783. _iFont = pCF->_iFont;
  784. _dwAge = g_fc->_dwAgeNext++;
  785. _fValid = TRUE; // successfully created a new font cache.
  786. }
  787. return _fValid;
  788. }
  789. /*
  790. * void CCcs::Free()
  791. *
  792. * @mfunc
  793. * Free any dynamic memory allocated by an individual font's cache.
  794. */
  795. void CCcs::Free()
  796. {
  797. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::Free");
  798. Assert(_fValid);
  799. _widths.Free();
  800. if(_hfont)
  801. {
  802. DestroyFont();
  803. if (_fCustomTextOut)
  804. g_pcto->NotifyDestroyFont(_hfont);
  805. }
  806. #ifndef NOCOMPLEXSCRIPTS
  807. if (_sc && g_pusp)
  808. ScriptFreeCache(&_sc);
  809. #endif
  810. _fValid = FALSE;
  811. _cRefs = 0;
  812. }
  813. /*
  814. * CCcs::BestCharRep(iCharRep, iCharRepDefault, fFontMatching)
  815. *
  816. * @mfunc
  817. * This function returns the best charset that the currently selected font
  818. * is capable of rendering. If the currently selected font cannot support
  819. * the requested charset, then the function returns bCharSetDefault, which
  820. * is generally taken from the charformat.
  821. *
  822. * @rdesc
  823. * The closest charset to bCharSet that can be rendered by the current
  824. * font.
  825. *
  826. * @devnote
  827. * Currently this function is only used with plain text, however I don't
  828. * believe there is any special reason it couldn't be used to improve
  829. * rendering of rich text as well.
  830. */
  831. BYTE CCcs::BestCharRep(
  832. BYTE iCharRep,
  833. BYTE iCharRepDefault,
  834. int fFontMatching)
  835. {
  836. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::BestCharSet");
  837. // Does desired charset match currently selected charset or is it
  838. // supported by the currently selected font?
  839. if((iCharRep != CharRepFromCharSet(_bCharSet) || !iCharRep) &&
  840. (fFontMatching == MATCH_CURRENT_CHARSET || !(_qwFontSig & FontSigFromCharRep(iCharRep))))
  841. {
  842. // If desired charset is not selected and we can't switch to it,
  843. // switch to fallback charset (probably from backing store).
  844. return iCharRepDefault;
  845. }
  846. // We already match desired charset, or it is supported by the font.
  847. // Either way, we can just return the requested charset.
  848. return iCharRep;
  849. }
  850. /*
  851. * CCcs::FillWidth (ch, &dup)
  852. *
  853. * @mfunc
  854. * Fill in width for given character. Sometimes we don't
  855. * call the OS for the certain characters because fonts have bugs.
  856. *
  857. * @rdesc
  858. * TRUE if OK, FALSE if failed
  859. */
  860. BOOL CCcs::FillWidth(
  861. WCHAR ch, //@parm WCHAR character we need a width for.
  862. LONG &dup) //@parm the width of the character
  863. {
  864. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::FillWidth");
  865. AssertSz(_hfont, "CCcs::Fill - CCcs has no font");
  866. dup = 0;
  867. WCHAR chWidth = ch;
  868. HFONT hfontOld = SelectFont(_hdc, _hfont);
  869. BOOL fLookaside = _widths.FLookasideCharacter(ch);
  870. if (fLookaside)
  871. chWidth = 0x4E00;
  872. else switch(ch)
  873. {
  874. case NBHYPHEN:
  875. case SOFTHYPHEN:
  876. chWidth = '-';
  877. break;
  878. case NBSPACE:
  879. chWidth = ' ';
  880. break;
  881. case EMSPACE:
  882. chWidth = EMDASH;
  883. break;
  884. case ENSPACE:
  885. chWidth = ENDASH;
  886. break;
  887. }
  888. W32->REGetCharWidth(_hdc, chWidth, (INT*) &dup, _wCodePage, _fCustomTextOut);
  889. dup -= _xOverhangAdjust;
  890. if (dup <= 0)
  891. dup = max(_xAveCharWidth, 1);
  892. if (fLookaside)
  893. _widths._dupCJK = dup;
  894. else
  895. {
  896. CacheEntry *pWidthData = _widths.GetEntry(ch);
  897. pWidthData->ch = ch;
  898. pWidthData->width = dup;
  899. }
  900. SelectFont(_hdc, hfontOld);
  901. return TRUE;
  902. }
  903. /*
  904. * BOOL CCcs::MakeFont(pCF)
  905. *
  906. * @mfunc
  907. * Wrapper, setup for CreateFontIndirect() to create the font to be
  908. * selected into the HDC.
  909. *
  910. * @devnote The pCF here is in logical units
  911. *
  912. * @rdesc
  913. * TRUE if OK, FALSE if allocation failure
  914. */
  915. BOOL CCcs::MakeFont(
  916. const CCharFormat * const pCF) //@parm description of desired logical font
  917. {
  918. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::MakeFont");
  919. LONG iFont = pCF->_iFont;
  920. LOGFONT lf;
  921. ZeroMemory(&lf, sizeof(lf));
  922. _bCMDefault = pCF->_dwEffects & CFE_RUNISDBCS ? CVT_LOWBYTE : CVT_NONE;
  923. _yHeightRequest = pCF->_yHeight;
  924. _bCharSetRequest = CharSetFromCharRep(pCF->_iCharRep);
  925. _fCustomTextOut = (pCF->_dwEffects & CFE_CUSTOMTEXTOUT) ? TRUE : FALSE;
  926. lf.lfHeight = -_yHeightRequest;
  927. if(pCF->_wWeight)
  928. _weight = pCF->_wWeight;
  929. else
  930. _weight = (pCF->_dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
  931. lf.lfWeight = _weight;
  932. lf.lfItalic = _fItalic = (pCF->_dwEffects & CFE_ITALIC) != 0;
  933. lf.lfCharSet = _bCMDefault == CVT_LOWBYTE ? ANSI_CHARSET : CharSetFromCharRep(pCF->_iCharRep);
  934. if (lf.lfCharSet == PC437_CHARSET)
  935. lf.lfCharSet = DEFAULT_CHARSET;
  936. lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  937. if (_tflow)
  938. lf.lfOrientation = lf.lfEscapement = (4 - _tflow) * 900;
  939. #ifndef UNDER_CE
  940. if (_fForceTrueType || _tflow && g_fc->GetInfoFlags(GetFontNameIndex(lf.lfFaceName)).fBitmap)
  941. {
  942. lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  943. if (!W32->OnWin9x() && g_fc->GetInfoFlags(iFont).fTrueType)
  944. lf.lfOutPrecision = OUT_SCREEN_OUTLINE_PRECIS;
  945. }
  946. #endif
  947. lf.lfClipPrecision = CLIP_DFA_OVERRIDE;
  948. lf.lfPitchAndFamily = _bPitchAndFamily = pCF->_bPitchAndFamily;
  949. lf.lfQuality = _bQuality = pCF->_bQuality;
  950. #ifdef UNDER_CE
  951. // DEBUGGGGGG for EBOOK!! Presumably this should be a registry setting
  952. // that overrules DEFAULT_QUALITY (0) the way ANTIALIASED_QUALITY, etc., do
  953. #ifndef CLEARTYPE_QUALITY
  954. #define CLEARTYPE_QUALITY 5
  955. #endif
  956. lf.lfQuality = CLEARTYPE_QUALITY;
  957. #endif
  958. // If family is virtual BiDi family (FF_BIDI), replace by FF_ROMAN
  959. if((lf.lfPitchAndFamily & 0xF0) == (FF_BIDI << 4))
  960. lf.lfPitchAndFamily = (FF_ROMAN << 4) | (lf.lfPitchAndFamily & 0xF);
  961. // If the run is DBCS, that means the font's codepage is not available in
  962. // this system. Use the English ANSI codepage instead so we will display
  963. // ANSI characters correctly. NOTE: _wCodePage is only used for Win95.
  964. _wCodePage = CodePageFromCharRep(CharRepFromCharSet(lf.lfCharSet));
  965. wcscpy(lf.lfFaceName, GetFontName(iFont));
  966. if (_fUseAtFont && lf.lfFaceName[0] != L'@')
  967. {
  968. wcscpy(&(lf.lfFaceName[1]), GetFontName(iFont));
  969. lf.lfFaceName[0] = L'@';
  970. }
  971. // In BiDi system, always create ANSI bitmap font with system charset
  972. BYTE bCharSetSys = W32->GetSysCharSet();
  973. if (IsBiDiCharSet(bCharSetSys) && lf.lfCharSet == ANSI_CHARSET &&
  974. fc().GetInfoFlags(iFont).fBitmap &&
  975. !fc().GetInfoFlags(iFont).fBadFaceName)
  976. lf.lfCharSet = bCharSetSys;
  977. // Reader! A bundle of spagghetti code lies ahead of you!
  978. // But go on boldly, for these spagghetti are seasoned with
  979. // lots of comments, and ... good luck to you...
  980. HFONT hfontOriginalCharset = NULL;
  981. BYTE bCharSetOriginal = lf.lfCharSet;
  982. WCHAR szNewFaceName[LF_FACESIZE];
  983. if(pCF->_dwEffects & (CFE_BOLD | CFE_ITALIC))
  984. iFont = -1; // Don't use cached font info unless
  985. // normal font
  986. GetFontWithMetrics(&lf, szNewFaceName);
  987. if(0 != wcsicmp(szNewFaceName, lf.lfFaceName))
  988. {
  989. BOOL fCorrectFont = FALSE;
  990. iFont = -1; // pCF->_iFont wasn't used
  991. if(lf.lfCharSet == SYMBOL_CHARSET)
  992. {
  993. // #1. if the face changed, and the specified charset was SYMBOL,
  994. // but the face name exists and suports ANSI, we give preference
  995. // to the face name
  996. lf.lfCharSet = ANSI_CHARSET;
  997. hfontOriginalCharset = _hfont;
  998. GetFontWithMetrics(&lf, szNewFaceName);
  999. if(0 == wcsicmp(szNewFaceName, lf.lfFaceName))
  1000. // That's right, ANSI is the asnwer
  1001. fCorrectFont = TRUE;
  1002. else
  1003. // No, fall back by default; the charset we got was right
  1004. lf.lfCharSet = bCharSetOriginal;
  1005. }
  1006. else if(lf.lfCharSet == DEFAULT_CHARSET && _bCharSet == DEFAULT_CHARSET)
  1007. {
  1008. // #2. If we got the "default" font back, we don't know what it means
  1009. // (could be anything) so we veryfy that this guy's not SYMBOL
  1010. // (symbol is never default, but the OS could be lying to us!!!)
  1011. // we would like to veryfy more like whether it actually gave us
  1012. // Japanese instead of ANSI and labeled it "default"...
  1013. // but SYMBOL is the least we can do
  1014. lf.lfCharSet = SYMBOL_CHARSET;
  1015. wcscpy(lf.lfFaceName, szNewFaceName);
  1016. hfontOriginalCharset = _hfont;
  1017. GetFontWithMetrics(&lf, szNewFaceName);
  1018. if(0 == wcsicmp(szNewFaceName, lf.lfFaceName))
  1019. // That's right, it IS symbol!
  1020. // 'correct' the font to the 'true' one,
  1021. // and we'll get fMappedToSymbol
  1022. fCorrectFont = TRUE;
  1023. // Always restore the charset name, we didn't want to
  1024. // question the original choice of charset here
  1025. lf.lfCharSet = bCharSetOriginal;
  1026. }
  1027. else if(lf.lfCharSet == ARABIC_CHARSET || lf.lfCharSet == HEBREW_CHARSET)
  1028. {
  1029. DestroyFont();
  1030. wcscpy(lf.lfFaceName, szNewFaceName);
  1031. GetFontWithMetrics(&lf, szNewFaceName);
  1032. fCorrectFont = TRUE;
  1033. }
  1034. else if(_bConvertMode != CVT_LOWBYTE && IsFECharSet(lf.lfCharSet)
  1035. && !OnWinNTFE() && !W32->OnWin9xFE())
  1036. {
  1037. const WCHAR *pch = NULL;
  1038. if(_bCharSet != lf.lfCharSet && W32->OnWin9x())
  1039. {
  1040. // On Win95 when rendering to PS driver, we'll get something
  1041. // other than what we asked. So try a known font we got from GDI
  1042. switch (lf.lfCharSet)
  1043. {
  1044. case CHINESEBIG5_CHARSET:
  1045. pch = GetFontName(g_iFontBig5);
  1046. break;
  1047. case SHIFTJIS_CHARSET:
  1048. pch = GetFontName(g_iFontJapanese);
  1049. break;
  1050. case HANGEUL_CHARSET:
  1051. pch = GetFontName(g_iFontHangul);
  1052. break;
  1053. case GB2312_CHARSET:
  1054. pch = GetFontName(g_iFontGB2312);
  1055. break;
  1056. }
  1057. }
  1058. else // FE Font (from Lang pack)
  1059. pch = szNewFaceName; // on a nonFEsystem
  1060. if(pch)
  1061. wcscpy(lf.lfFaceName, pch);
  1062. hfontOriginalCharset = _hfont;
  1063. GetFontWithMetrics(&lf, szNewFaceName);
  1064. if(0 == wcsicmp(szNewFaceName, lf.lfFaceName))
  1065. {
  1066. // That's right, it IS the FE font we want!
  1067. // 'correct' the font to the 'true' one.
  1068. fCorrectFont = TRUE;
  1069. if(W32->OnWin9x())
  1070. {
  1071. // Save up the GDI font names for later printing use
  1072. switch(lf.lfCharSet)
  1073. {
  1074. case CHINESEBIG5_CHARSET:
  1075. g_iFontBig5 = GetFontNameIndex(lf.lfFaceName);
  1076. break;
  1077. case SHIFTJIS_CHARSET:
  1078. g_iFontJapanese = GetFontNameIndex(lf.lfFaceName);
  1079. break;
  1080. case HANGEUL_CHARSET:
  1081. g_iFontHangul = GetFontNameIndex(lf.lfFaceName);
  1082. break;
  1083. case GB2312_CHARSET:
  1084. g_iFontGB2312 = GetFontNameIndex(lf.lfFaceName);
  1085. break;
  1086. }
  1087. }
  1088. }
  1089. }
  1090. if(hfontOriginalCharset)
  1091. {
  1092. // Either keep old font or new one
  1093. if(fCorrectFont)
  1094. {
  1095. SideAssert(DeleteObject(hfontOriginalCharset));
  1096. }
  1097. else
  1098. {
  1099. // Fall back to original font
  1100. DestroyFont();
  1101. _hfont = hfontOriginalCharset;
  1102. GetMetrics();
  1103. }
  1104. hfontOriginalCharset = NULL;
  1105. }
  1106. }
  1107. RetryCreateFont:
  1108. {
  1109. // Could be that we just plain simply get mapped to symbol.
  1110. // Avoid it
  1111. BOOL fMappedToSymbol = (_bCharSet == SYMBOL_CHARSET &&
  1112. lf.lfCharSet != SYMBOL_CHARSET);
  1113. BOOL fChangedCharset = (_bCharSet != lf.lfCharSet &&
  1114. lf.lfCharSet != DEFAULT_CHARSET);
  1115. if(fChangedCharset || fMappedToSymbol)
  1116. {
  1117. // Here, the system did not preserve the font language or mapped
  1118. // our non-symbol font onto a symbol font, which will look awful
  1119. // when displayed. Giving us a symbol font when we asked for a
  1120. // non-symbol font (default can never be symbol) is very bizarre
  1121. // and means that either the font name is not known or the system
  1122. // has gone complete nuts. The charset language takes priority
  1123. // over the font name. Hence, I would argue that nothing can be
  1124. // done to save the situation at this point, and we have to
  1125. // delete the font name and retry.
  1126. if (fChangedCharset && lf.lfCharSet == THAI_CHARSET && _bCharSet == ANSI_CHARSET)
  1127. {
  1128. // We have charset substitution entries in Thai platforms that
  1129. // will substitute all the core fonts with THAI_CHARSET to
  1130. // ANSI_CHARSET. This is because we dont have Thai in such fonts.
  1131. // Here we'll internally substitute the core font to Thai default
  1132. // font so it matches its underlying THAI_CHARSET request (wchao).
  1133. SHORT iDefFont;
  1134. BYTE yDefHeight;
  1135. BYTE bDefPaf;
  1136. W32->GetPreferredFontInfo(THAI_INDEX, TRUE, iDefFont, (BYTE&)yDefHeight, bDefPaf);
  1137. const WCHAR* szThaiDefault = GetFontName(iDefFont);
  1138. if (szThaiDefault)
  1139. {
  1140. DestroyFont();
  1141. wcscpy(lf.lfFaceName, szThaiDefault);
  1142. GetFontWithMetrics(&lf, szNewFaceName);
  1143. goto GetOutOfHere;
  1144. }
  1145. }
  1146. if(!wcsicmp(lf.lfFaceName, szFontOfChoice))
  1147. {
  1148. // We've been here already; no font with an appropriate
  1149. // charset is on the system. Try getting the ANSI one for
  1150. // the original font name. Next time around, we'll null
  1151. // out the name as well!!
  1152. if (lf.lfCharSet == ANSI_CHARSET)
  1153. {
  1154. TRACEINFOSZ("Asking for ANSI ARIAL and not getting it?!");
  1155. // Those Win95 guys have definitely outbugged me
  1156. goto GetOutOfHere;
  1157. }
  1158. DestroyFont();
  1159. wcscpy(lf.lfFaceName, GetFontName(pCF->_iFont));
  1160. lf.lfCharSet = ANSI_CHARSET;
  1161. }
  1162. else
  1163. {
  1164. DestroyFont();
  1165. wcscpy(lf.lfFaceName, szFontOfChoice);
  1166. }
  1167. GetFontWithMetrics(&lf, szNewFaceName);
  1168. goto RetryCreateFont;
  1169. }
  1170. }
  1171. GetOutOfHere:
  1172. if (hfontOriginalCharset)
  1173. SideAssert(DeleteObject(hfontOriginalCharset));
  1174. // If we're really really stuck, get system font and hope for the best
  1175. if(!_hfont)
  1176. {
  1177. iFont = IFONT_SYSTEM;
  1178. _hfont = W32->GetSystemFont();
  1179. }
  1180. // Cache essential FONTSIGNATURE and GetFontLanguageInfo() information
  1181. Assert(_hfont);
  1182. if(iFont >= 0) // Use cached value
  1183. _qwFontSig = GetFontSignatureFromFace(iFont, NULL);
  1184. if(_hfont && (iFont < 0 || _fCustomTextOut))
  1185. {
  1186. BOOL fNonBiDiAscii;
  1187. HFONT hfontOld = SelectFont(_hdc, _hfont);
  1188. if (_fCustomTextOut)
  1189. g_pcto->NotifyCreateFont(_hdc);
  1190. if(iFont < 0)
  1191. _qwFontSig = GetFontSignatureFromDC(_hdc, fNonBiDiAscii);
  1192. SelectFont(_hdc, hfontOld);
  1193. }
  1194. return TRUE;
  1195. }
  1196. /*
  1197. * HFONT CCcs::GetFontWithMetrics (plf, szNewFaceName)
  1198. *
  1199. * @mfunc
  1200. * Get metrics used by the measurer and renderer and the new face name.
  1201. *
  1202. * @rdesc
  1203. * HFONT if successful
  1204. */
  1205. HFONT CCcs::GetFontWithMetrics (
  1206. LOGFONT *plf,
  1207. WCHAR * szNewFaceName)
  1208. {
  1209. _hfont = CreateFontIndirect(plf);
  1210. if(_hfont)
  1211. GetMetrics(szNewFaceName);
  1212. return (_hfont);
  1213. }
  1214. /*
  1215. * CCcs::GetOffset(pCF, dvpInch, pyOffset, pyAdjust);
  1216. *
  1217. * @mfunc
  1218. * Return the offset information for
  1219. *
  1220. * @comm
  1221. * Return the offset value (used in line height calculations)
  1222. * and the amount to raise or lower the text because of superscript
  1223. * or subscript considerations.
  1224. */
  1225. void CCcs::GetOffset(
  1226. const CCharFormat * const pCF,
  1227. LONG dvpInch,
  1228. LONG * pyOffset,
  1229. LONG * pyAdjust)
  1230. {
  1231. *pyOffset = 0;
  1232. *pyAdjust = 0;
  1233. if (pCF->_yOffset)
  1234. *pyOffset = MulDiv(pCF->_yOffset, dvpInch, LY_PER_INCH);
  1235. if (pCF->_dwEffects & CFE_SUPERSCRIPT)
  1236. *pyAdjust = _yHeight * 2 / 5;
  1237. else if (pCF->_dwEffects & CFE_SUBSCRIPT)
  1238. *pyAdjust = -_yDescent * 3 / 5;
  1239. }
  1240. /*
  1241. * void CCcs::GetFontOverhang(pdupOverhang, pdupUnderhang)
  1242. *
  1243. * @mfunc
  1244. * Synthesize font overhang/underhang information.
  1245. * Only applies to italic fonts.
  1246. */
  1247. void CCcs::GetFontOverhang(
  1248. LONG *pdupOverhang,
  1249. LONG *pdupUnderhang)
  1250. {
  1251. if(_fItalic)
  1252. {
  1253. *pdupOverhang = (_yHeight - _yDescent + 1) / 4;
  1254. *pdupUnderhang = (_yDescent + 1) / 4;
  1255. }
  1256. else
  1257. {
  1258. *pdupOverhang = 0;
  1259. *pdupUnderhang = 0;
  1260. }
  1261. }
  1262. /*
  1263. * BOOL CCcs::GetMetrics(szNewFaceName)
  1264. *
  1265. * @mfunc
  1266. * Get metrics used by the measurer and renderer.
  1267. *
  1268. * @rdesc
  1269. * TRUE if successful
  1270. *
  1271. * @comm
  1272. * These are in logical coordinates which are dependent
  1273. * on the mapping mode and font selected into the hdc.
  1274. */
  1275. BOOL CCcs::GetMetrics(
  1276. WCHAR *szNewFaceName)
  1277. {
  1278. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::GetMetrics");
  1279. AssertSz(_hfont, "No font has been created.");
  1280. if (szNewFaceName)
  1281. *szNewFaceName = 0;
  1282. HFONT hfontOld = SelectFont(_hdc, _hfont);
  1283. if(!hfontOld)
  1284. {
  1285. DestroyFont();
  1286. return FALSE;
  1287. }
  1288. if (szNewFaceName)
  1289. GetTextFace(_hdc, LF_FACESIZE, szNewFaceName);
  1290. TEXTMETRIC tm;
  1291. if(!GetTextMetrics(_hdc, &tm))
  1292. {
  1293. SelectFont(_hdc, hfontOld);
  1294. DestroyFont();
  1295. return FALSE;
  1296. }
  1297. // The metrics, in logical units, dependent on the map mode and font.
  1298. _yHeight = (SHORT) tm.tmHeight;
  1299. _yDescent = (SHORT) tm.tmDescent;
  1300. _xAveCharWidth = (SHORT) tm.tmAveCharWidth;
  1301. _xOverhangAdjust= (SHORT) tm.tmOverhang;
  1302. // If fixed pitch, the tm bit is clear
  1303. _fFixPitchFont = !(TMPF_FIXED_PITCH & tm.tmPitchAndFamily);
  1304. _bCharSet = tm.tmCharSet;
  1305. _fFECharSet = IsFECharSet(_bCharSet);
  1306. // Use convert-mode proposed by CF, for which we are creating the font and
  1307. // then tweak as necessary below.
  1308. _bConvertMode = _bCMDefault;
  1309. // If SYMBOL_CHARSET is used, use the A APIs with the low bytes of the
  1310. // characters in the run
  1311. if(_bCharSet == SYMBOL_CHARSET)
  1312. _bConvertMode = CVT_LOWBYTE;
  1313. else if (_bConvertMode == CVT_NONE)
  1314. _bConvertMode = W32->DetermineConvertMode(_hdc, tm.tmCharSet);
  1315. W32->CalcUnderlineInfo(_hdc, this, &tm);
  1316. SelectFont(_hdc, hfontOld);
  1317. return TRUE;
  1318. }
  1319. /*
  1320. * CCcs::DestroyFont()
  1321. *
  1322. * @mfunc
  1323. * Destroy font handle for this CCcs
  1324. */
  1325. void CCcs::DestroyFont()
  1326. {
  1327. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::DestroyFont");
  1328. // Clear out any old font
  1329. if(_hfont)
  1330. {
  1331. SideAssert(DeleteObject(_hfont));
  1332. _hfont = 0;
  1333. }
  1334. }
  1335. /*
  1336. * CCcs::Compare (pCF, hdc, dwFlags)
  1337. *
  1338. * @mfunc
  1339. * Compares this font cache with the font properties of a
  1340. * given CHARFORMAT
  1341. * @devnote The pCF size here is in logical units
  1342. *
  1343. * @rdesc
  1344. * FALSE iff did not match exactly.
  1345. */
  1346. BOOL CCcs::Compare (
  1347. const CCharFormat * const pCF, //@parm Description of desired font
  1348. HDC hdc,
  1349. DWORD dwFlags)
  1350. {
  1351. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CCcs::Compare");
  1352. BYTE bCharSet = CharSetFromCharRep(pCF->_iCharRep);
  1353. BOOL result =
  1354. _iFont == pCF->_iFont &&
  1355. _weight == pCF->_wWeight &&
  1356. _fItalic == ((pCF->_dwEffects & CFE_ITALIC) != 0) &&
  1357. _hdc == hdc &&
  1358. _yHeightRequest == pCF->_yHeight &&
  1359. (_bCharSetRequest == bCharSet || _bCharSet == bCharSet
  1360. // || _qwFontSig & FontSigFromCharRep(pCF->_iCharRep)// FUTURE:
  1361. ) && // ok except for codepage conversions (metafiles and Win9x)
  1362. _fCustomTextOut == ((pCF->_dwEffects & CFE_CUSTOMTEXTOUT) != 0) &&
  1363. _fForceTrueType == ((dwFlags & FGCCSUSETRUETYPE) != 0) &&
  1364. _fUseAtFont == ((dwFlags & FGCCSUSEATFONT) != 0) &&
  1365. _tflow == (dwFlags & 0x3) &&
  1366. _bPitchAndFamily == pCF->_bPitchAndFamily &&
  1367. (!(pCF->_dwEffects & CFE_RUNISDBCS) || _bConvertMode == CVT_LOWBYTE);
  1368. return result;
  1369. }
  1370. // ========================= WidthCache by jonmat =========================
  1371. /*
  1372. * CWidthCache::CheckWidth(ch, &dup)
  1373. *
  1374. * @mfunc
  1375. * Check to see if we have a width for a WCHAR character.
  1376. *
  1377. * @comm
  1378. * Used prior to calling FillWidth(). Since FillWidth
  1379. * may require selecting the map mode and font in the HDC,
  1380. * checking here first saves time.
  1381. *
  1382. * @comm
  1383. * Statistics are maintained to determine when to
  1384. * expand the cache. The determination is made after a constant
  1385. * number of calls in order to make calculations faster.
  1386. *
  1387. * @rdesc
  1388. * returns TRUE if we have the width of the given WCHAR.
  1389. */
  1390. BOOL CWidthCache::CheckWidth (
  1391. const WCHAR ch, //@parm char, can be Unicode, to check width for
  1392. LONG & dup) //@parm Width of character
  1393. {
  1394. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CWidthCache::CheckWidth");
  1395. BOOL fExist;
  1396. // 30,000 FE characters all have the same width
  1397. if (FLookasideCharacter(ch))
  1398. {
  1399. dup = _dupCJK;
  1400. return dup != 0;
  1401. }
  1402. const CacheEntry * pWidthData = GetEntry ( ch );
  1403. fExist = (ch == pWidthData->ch // Have we fetched the width?
  1404. && pWidthData->width); // only because we may have ch == 0.
  1405. dup = fExist ? pWidthData->width : 0;
  1406. if(!_fMaxPerformance) // if we have not grown to the max...
  1407. {
  1408. _accesses++;
  1409. if(!fExist) // Only interesting on collision.
  1410. {
  1411. if(0 == pWidthData->width) // Test width not ch, 0 is valid ch.
  1412. {
  1413. _cacheUsed++; // Used another entry.
  1414. AssertSz( _cacheUsed <= _cacheSize+1, "huh?");
  1415. }
  1416. else
  1417. _collisions++; // We had a collision.
  1418. if(_accesses >= PERFCHECKEPOCH)
  1419. CheckPerformance(); // After some history, tune cache.
  1420. }
  1421. }
  1422. #ifdef DEBUG // Continue to monitor performance
  1423. else
  1424. {
  1425. _accesses++;
  1426. if(!fExist) // Only interesting on collision.
  1427. {
  1428. if(0 == pWidthData->width) // Test width not ch, 0 is valid ch.
  1429. {
  1430. _cacheUsed++; // Used another entry.
  1431. AssertSz( _cacheUsed <= _cacheSize+1, "huh?");
  1432. }
  1433. else
  1434. _collisions++; // We had a collision.
  1435. }
  1436. if(_accesses > PERFCHECKEPOCH)
  1437. {
  1438. _accesses = 0;
  1439. _collisions = 0;
  1440. }
  1441. }
  1442. #endif
  1443. return fExist;
  1444. }
  1445. /*
  1446. * CWidthCache::CheckPerformance()
  1447. *
  1448. * @mfunc
  1449. * check performance and increase cache size if deemed necessary.
  1450. *
  1451. */
  1452. void CWidthCache::CheckPerformance()
  1453. {
  1454. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CWidthCache::CheckPerformance");
  1455. if(_fMaxPerformance) // Exit if already grown to our max.
  1456. return;
  1457. // Grow the cache when cacheSize > 0 && 75% utilized or approx 8%
  1458. // collision rate
  1459. if (_cacheSize > DEFAULTCACHESIZE && (_cacheSize >> 1) + (_cacheSize >> 2) < _cacheUsed ||
  1460. _collisions > 0 && _accesses / _collisions <= 12)
  1461. {
  1462. GrowCache( &_pWidthCache, &_cacheSize, &_cacheUsed );
  1463. }
  1464. _collisions = 0; // This prevents wraps but makes
  1465. _accesses = 0; // calc a local rate, not global.
  1466. if(_cacheSize >= maxCacheSize) // Note if we've max'ed out
  1467. _fMaxPerformance = TRUE;
  1468. AssertSz( _cacheSize <= maxCacheSize, "max must be 2^n-1");
  1469. AssertSz( _cacheUsed <= _cacheSize+1, "huh?");
  1470. }
  1471. /*
  1472. * CWidthCache::GrowCache(ppWidthCache, pCacheSize, pCacheUsed)
  1473. *
  1474. * @mfunc
  1475. * Exponentially expand the size of the cache.
  1476. *
  1477. * @comm
  1478. * The cache size must be of the form 2^n as we use a
  1479. * logical & to get the hash MOD by storing 2^n-1 as
  1480. * the size and using this as the modulo.
  1481. *
  1482. * @rdesc
  1483. * Returns TRUE if we were able to allocate the new cache.
  1484. * All in params are also out params.
  1485. *
  1486. */
  1487. BOOL CWidthCache::GrowCache(
  1488. CacheEntry **ppWidthCache, //@parm cache
  1489. INT * pCacheSize, //@parm cache's respective size.
  1490. INT * pCacheUsed) //@parm cache's respective utilization.
  1491. {
  1492. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CWidthCache::GrowCache");
  1493. CacheEntry *pNewWidthCache, *pOldWidthCache, *pWidthData;
  1494. INT j, newCacheSize, newCacheUsed;
  1495. WCHAR ch;
  1496. j = *pCacheSize; // Allocate cache of 2^n.
  1497. newCacheSize = max ( INITIALCACHESIZE, (j << 1) + 1);
  1498. pNewWidthCache = (CacheEntry *)
  1499. PvAlloc( sizeof(CacheEntry) * (newCacheSize + 1 ), GMEM_ZEROINIT);
  1500. if(pNewWidthCache)
  1501. {
  1502. newCacheUsed = 0;
  1503. *pCacheSize = newCacheSize; // Update out params.
  1504. pOldWidthCache = *ppWidthCache;
  1505. *ppWidthCache = pNewWidthCache;
  1506. for (; j >= 0; j--) // Move old cache info to new.
  1507. {
  1508. ch = pOldWidthCache[j].ch;
  1509. if ( ch )
  1510. {
  1511. pWidthData = &pNewWidthCache [ch & newCacheSize];
  1512. if ( 0 == pWidthData->ch )
  1513. newCacheUsed++; // Used another entry.
  1514. pWidthData->ch = ch;
  1515. pWidthData->width = pOldWidthCache[j].width;
  1516. }
  1517. }
  1518. *pCacheUsed = newCacheUsed; // Update out param.
  1519. // Free old cache.
  1520. if (pOldWidthCache < &_defaultWidthCache[0] ||
  1521. pOldWidthCache >= &_defaultWidthCache[DEFAULTCACHESIZE+1])
  1522. {
  1523. FreePv(pOldWidthCache);
  1524. }
  1525. }
  1526. return NULL != pNewWidthCache;
  1527. }
  1528. /*
  1529. * CWidthCache::Free()
  1530. *
  1531. * @mfunc
  1532. * Free any dynamic memory allocated by the width cache and prepare
  1533. * it to be recycled.
  1534. */
  1535. void CWidthCache::Free()
  1536. {
  1537. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CWidthCache::Free");
  1538. _fMaxPerformance = FALSE;
  1539. _dupCJK = 0;
  1540. _cacheSize = DEFAULTCACHESIZE;
  1541. _cacheUsed = 0;
  1542. _collisions = 0;
  1543. _accesses = 0;
  1544. if(_pWidthCache != &_defaultWidthCache[0])
  1545. {
  1546. FreePv(_pWidthCache);
  1547. _pWidthCache = &_defaultWidthCache[0];
  1548. }
  1549. ZeroMemory(_pWidthCache, sizeof(CacheEntry)*(DEFAULTCACHESIZE + 1));
  1550. }
  1551. /*
  1552. * CWidthCache::CWidthCache()
  1553. *
  1554. * @mfunc
  1555. * Point the caches to the defaults.
  1556. */
  1557. CWidthCache::CWidthCache()
  1558. {
  1559. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CWidthCache::CWidthCache");
  1560. _pWidthCache = &_defaultWidthCache[0];
  1561. }
  1562. /*
  1563. * CWidthCache::~CWidthCache()
  1564. *
  1565. * @mfunc
  1566. * Free any allocated caches.
  1567. */
  1568. CWidthCache::~CWidthCache()
  1569. {
  1570. TRACEBEGIN(TRCSUBSYSFONT, TRCSCOPEINTERN, "CWidthCache::~CWidthCache");
  1571. if (_pWidthCache != &_defaultWidthCache[0])
  1572. FreePv(_pWidthCache);
  1573. }