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.

2645 lines
79 KiB

  1. /*
  2. * Microsoft Confidential
  3. * Copyright (C) Microsoft Corporation 1991
  4. * All Rights Reserved.
  5. *
  6. *
  7. * PIFFNT.C
  8. * User interface dialogs for GROUP_FNT
  9. *
  10. * History:
  11. * Created 04-Jan-1993 1:10pm by Jeff Parsons
  12. * Changed 05-May-1993 5:10pm by Raymond Chen -- New Chicago-look preview
  13. * Changed 12-Aug-1993 4:14pm by Raymond Chen -- Remove font inc and dec
  14. *
  15. * All font dialog code taken from font*.c in vmdosapp, 01-Apr-93
  16. */
  17. #include "shellprv.h"
  18. #pragma hdrstop
  19. #define REGSTR_MSDOSEMU_DISPLAYPARAMS TEXT("DisplayParams")
  20. #define REGSTR_PATH_MSDOSEMU "Software\\Microsoft\\Windows\\CurrentVersion\\MS-DOS Emulation"
  21. const TCHAR szWndPreviewClass[] = TEXT("WOAWinPreview");
  22. const TCHAR szFontPreviewClass[] = TEXT("WOAFontPreview");
  23. // The preview strings for bilingual dosbox.
  24. // We'll load this from our resource that will be properly
  25. // localized. We'll give up if it fails and use above sample
  26. // instead.
  27. UINT cxScreen, cyScreen, dyChar, dyItem;
  28. // Macro definitions that handle codepages
  29. //
  30. #define OEMCharsetFromCP(cp) \
  31. ((cp)==CP_JPN? SHIFTJIS_CHARSET : ((cp)==CP_WANSUNG? HANGEUL_CHARSET : OEM_CHARSET))
  32. /*
  33. * Font cache information. Note that this cache, being in PIFMGR,
  34. * is now global, which will make support for per-VM font files/faces
  35. * more problematic, if we even decide that's an interesting feature.
  36. *
  37. */
  38. DWORD bpfdiStart[2] = { 0 }; /* strage for the offset to cache */
  39. UINT cfdiCache[2]; /* # used entries in fdi cache */
  40. UINT cfdiCacheActual[2]; /* Total # entries in fdi cache */
  41. LPVOID lpCache = NULL;
  42. /*
  43. * Owner-draw list box information.
  44. *
  45. */
  46. HBITMAP hbmFont; /* Handle to "TrueType" logo */
  47. DWORD dwTimeCheck;
  48. COLORREF clrChecksum;
  49. HCURSOR hcursorWait;
  50. #define MAXDIMENSTRING 80
  51. /*
  52. * Initial font heights for TT fonts
  53. *
  54. * This is read from an INI file, so it must remain writeable.
  55. *
  56. * We don't try generating TT fonts below 12pt by default because
  57. * they just look crappy. Frosting setup will put a different
  58. * table into place because Lucida Console looks good down to 4pt.
  59. *
  60. * On NT, Lucida Console is installed be default, though.
  61. *
  62. * The Frosting table is
  63. * 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22
  64. */
  65. WORD rgwInitialTtHeights[] = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22 };
  66. /*
  67. * rgpnlPenalties -- Initialize penalty array to default values
  68. */
  69. INT rgpnlPenalties[] =
  70. { 5000, 1000, 0, 1000, 5000, 1000, 0, 1000, 1 };
  71. POINT ptNonAspectMin = { -1, -1 };
  72. // Context-sensitive help ids
  73. const static DWORD rgdwHelp[] = {
  74. IDC_FONTGRP, IDH_COMM_GROUPBOX,
  75. IDC_RASTERFONTS, IDH_DOS_AVAIL_FONTS,
  76. IDC_TTFONTS, IDH_DOS_AVAIL_FONTS,
  77. IDC_BOTHFONTS, IDH_DOS_AVAIL_FONTS,
  78. IDC_FONTSIZELBL, IDH_DOS_FONT_SIZE,
  79. IDC_FONTSIZE, IDH_DOS_FONT_SIZE,
  80. IDC_WNDPREVIEWLBL, IDH_DOS_FONT_WINDOW_PREVIEW,
  81. IDC_FONTPREVIEWLBL, IDH_DOS_FONT_FONT_PREVIEW,
  82. IDC_WNDPREVIEW, IDH_DOS_FONT_WINDOW_PREVIEW,
  83. IDC_FONTPREVIEW, IDH_DOS_FONT_FONT_PREVIEW,
  84. IDC_REALMODEDISABLE, IDH_DOS_REALMODEPROPS,
  85. 0, 0
  86. };
  87. BOOL_PTR CALLBACK DlgFntProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  88. {
  89. PFNTINFO pfi = (PFNTINFO)GetWindowLongPtr(hDlg, DWLP_USER);
  90. switch (uMsg)
  91. {
  92. case WM_INITDIALOG:
  93. // allocate dialog instance data
  94. if (NULL != (pfi = (PFNTINFO)LocalAlloc(LPTR, sizeof(FNTINFO))))
  95. {
  96. pfi->ppl = (PPROPLINK)((LPPROPSHEETPAGE)lParam)->lParam;
  97. SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pfi);
  98. InitFntDlg(hDlg, pfi);
  99. break;
  100. }
  101. else
  102. {
  103. EndDialog(hDlg, FALSE); // fail the dialog create
  104. }
  105. break;
  106. case WM_DESTROY:
  107. // free any allocations/resources inside the pfi first!
  108. if (pfi)
  109. {
  110. if (pfi->hFontPreview)
  111. {
  112. DeleteObject(pfi->hFontPreview);
  113. pfi->hFontPreview = NULL;
  114. }
  115. // ok, NOW we can free the pfi
  116. EVAL(LocalFree(pfi) == NULL);
  117. SetWindowLongPtr(hDlg, DWLP_USER, 0);
  118. }
  119. break;
  120. HELP_CASES(rgdwHelp) // Handle help messages
  121. case WM_COMMAND:
  122. if (LOWORD(lParam) == 0)
  123. break; // message not from a control
  124. switch (LOWORD(wParam))
  125. {
  126. case IDC_RASTERFONTS:
  127. case IDC_TTFONTS:
  128. case IDC_BOTHFONTS:
  129. /*
  130. * Rebuild the font list based on the user's selection of
  131. * which fonts to include/exclude.
  132. */
  133. pfi->fntProposed.flFnt &= ~FNT_BOTHFONTS;
  134. pfi->fntProposed.flFnt |= FNTFLAGSFROMID(wParam);
  135. CreateFontList(GetDlgItem(hDlg, IDC_FONTSIZE), TRUE, &pfi->fntProposed);
  136. PreviewUpdate(GetDlgItem(hDlg, IDC_FONTSIZE), pfi);
  137. if (HIWORD(wParam) == BN_CLICKED)
  138. SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  139. return FALSE;
  140. case IDC_FONTSIZE:
  141. if (HIWORD(wParam) == LBN_SELCHANGE)
  142. {
  143. PreviewUpdate(GetDlgItem(hDlg, IDC_FONTSIZE), pfi);
  144. SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
  145. return TRUE;
  146. }
  147. if (HIWORD(wParam) == LBN_DBLCLK)
  148. ApplyFntDlg(hDlg, pfi);
  149. return FALSE;
  150. }
  151. break;
  152. case WM_NOTIFY:
  153. switch (((NMHDR *)lParam)->code) {
  154. case PSN_SETACTIVE:
  155. AdjustRealModeControls(pfi->ppl, hDlg);
  156. break;
  157. case PSN_KILLACTIVE:
  158. // This gives the current page a chance to validate itself
  159. // SetWindowLong(hDlg, DWL_MSGRESULT, ValidFntDlg(hDlg, pfi));
  160. break;
  161. case PSN_APPLY:
  162. // This happens on OK....
  163. ApplyFntDlg(hDlg, pfi);
  164. break;
  165. case PSN_RESET:
  166. // This happens on Cancel....
  167. break;
  168. }
  169. break;
  170. /*
  171. * For WM_MEASUREITEM and WM_DRAWITEM, since there is only one
  172. * owner-draw list box in the entire dialog box, we don't have
  173. * to do a GetDlgItem to figure out who he is.
  174. */
  175. case WM_MEASUREITEM:
  176. // measure the owner draw listbox
  177. MeasureItemFontList((LPMEASUREITEMSTRUCT)lParam);
  178. break;
  179. case WM_DRAWITEM:
  180. DrawItemFontList(TRUE, (LPDRAWITEMSTRUCT)lParam);
  181. break;
  182. case WM_SYSCOLORCHANGE:
  183. UpdateTTBitmap();
  184. break;
  185. default:
  186. return FALSE; // return 0 when not processing
  187. }
  188. return TRUE;
  189. }
  190. /** InitFntDlg
  191. *
  192. * Create the list of appropriate fonts.
  193. *
  194. * This routine is broken out of FontDlgProc because it chew
  195. * up lots of stack for the message buffer, and we don't want to
  196. * eat that much stack on every entry to FontDlgProc.
  197. *
  198. * Note that we must defer CreateFontList until WM_INITDIALOG
  199. * time because it is not until then that we have a list box that
  200. * we can shove the data into.
  201. */
  202. void InitFntDlg(HWND hDlg, register PFNTINFO pfi)
  203. {
  204. HWND hwndList; /* The listbox of fonts */
  205. PPROPLINK ppl = pfi->ppl;
  206. WINDOWPLACEMENT wp;
  207. ASSERTTRUE(ppl->iSig == PROP_SIG);
  208. if (!PifMgr_GetProperties(ppl, MAKELP(0,GROUP_FNT),
  209. &pfi->fntProposed, sizeof(pfi->fntProposed), GETPROPS_NONE)
  210. ||
  211. !PifMgr_GetProperties(ppl, MAKELP(0,GROUP_WIN),
  212. &pfi->winOriginal, sizeof(pfi->winOriginal), GETPROPS_NONE)) {
  213. Warning(hDlg, IDS_QUERY_ERROR, MB_ICONEXCLAMATION | MB_OK);
  214. return;
  215. }
  216. /*
  217. * Set up instance variables for the window preview window.
  218. */
  219. /* Show preview maximized if window is maximized or restores to max'd.
  220. * Also if it is open restored and has no scrollbars.
  221. * (Determined by comparing the client window size against the cell
  222. * size and font size.)
  223. */
  224. pfi->fMax = FALSE;
  225. /*
  226. * Preload winOriginal with up-to-the-minute goodies, if we have
  227. * them.
  228. */
  229. #define HasScrollbars(z) \
  230. (pfi->winOriginal.c##z##Cells * pfi->fntProposed.c##z##FontActual > \
  231. pfi->winOriginal.c##z##Client)
  232. if (ppl->hwndTty) {
  233. wp.length = sizeof(WINDOWPLACEMENT);
  234. VERIFYTRUE(GetWindowPlacement(ppl->hwndTty, &wp));
  235. // Convert/Copy to 16-bit structure
  236. pfi->winOriginal.wLength = (WORD)wp.length;
  237. pfi->winOriginal.wShowFlags = (WORD)wp.flags;
  238. pfi->winOriginal.wShowCmd = (WORD)wp.showCmd;
  239. pfi->winOriginal.xMinimize = (WORD)wp.ptMinPosition.x;
  240. pfi->winOriginal.yMinimize = (WORD)wp.ptMinPosition.y;
  241. pfi->winOriginal.xMaximize = (WORD)wp.ptMaxPosition.x;
  242. pfi->winOriginal.yMaximize = (WORD)wp.ptMaxPosition.y;
  243. pfi->winOriginal.rcNormal.left = (WORD)wp.rcNormalPosition.left;
  244. pfi->winOriginal.rcNormal.top = (WORD)wp.rcNormalPosition.top;
  245. pfi->winOriginal.rcNormal.right = (WORD)wp.rcNormalPosition.right;
  246. pfi->winOriginal.rcNormal.bottom = (WORD)wp.rcNormalPosition.bottom;
  247. if (!IsIconic(ppl->hwndTty) &&
  248. !HasScrollbars(x) && !HasScrollbars(y)) {
  249. pfi->fMax = TRUE;
  250. }
  251. }
  252. if ((pfi->winOriginal.wShowCmd == SW_SHOWMAXIMIZED) ||
  253. (pfi->winOriginal.wShowFlags & WPF_RESTORETOMAXIMIZED)) {
  254. pfi->fMax = TRUE;
  255. }
  256. if (pfi->winOriginal.wShowCmd == SW_SHOWMAXIMIZED) {
  257. pfi->ptCorner.x = (LONG)pfi->winOriginal.xMaximize;
  258. pfi->ptCorner.y = (LONG)pfi->winOriginal.yMaximize;
  259. } else {
  260. if (pfi->winOriginal.rcNormal.left==0)
  261. {
  262. pfi->ptCorner.x = -1;
  263. }
  264. else
  265. {
  266. pfi->ptCorner.x = (LONG)pfi->winOriginal.rcNormal.left;
  267. }
  268. pfi->ptCorner.y = (LONG)pfi->winOriginal.rcNormal.top;
  269. }
  270. /*
  271. * First, check which fonts the user wants to see.
  272. *
  273. */
  274. CheckDlgButton(hDlg, IDFROMFNTFLAGS(pfi->fntProposed.flFnt), TRUE);
  275. hwndList = GetDlgItem(hDlg, IDC_FONTSIZE);
  276. // SendMessage(hwndList, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FIXED_FONT), FALSE);
  277. if (CreateFontList(hwndList, TRUE, &pfi->fntProposed) == LB_ERR) {
  278. MemoryWarning(hDlg);
  279. EndDialog(hDlg, PtrToLong(BPFDI_CANCEL)); /* Get out of the dialog */
  280. return;
  281. }
  282. /* Initialize the preview windows */
  283. PreviewInit(hDlg, pfi);
  284. PreviewUpdate(GetDlgItem(hDlg, IDC_FONTSIZE), pfi);
  285. }
  286. void ApplyFntDlg(HWND hDlg, register PFNTINFO pfi)
  287. {
  288. PPROPLINK ppl = pfi->ppl;
  289. ASSERTTRUE(ppl->iSig == PROP_SIG);
  290. if (!PifMgr_SetProperties(ppl, MAKELP(0,GROUP_FNT),
  291. &pfi->fntProposed, sizeof(pfi->fntProposed), SETPROPS_NONE))
  292. Warning(hDlg, IDS_UPDATE_ERROR, MB_ICONEXCLAMATION | MB_OK);
  293. else
  294. if (ppl->hwndNotify) {
  295. ppl->flProp |= PROP_NOTIFY;
  296. PostMessage(ppl->hwndNotify, ppl->uMsgNotify, sizeof(pfi->fntProposed), (LPARAM)MAKELP(0,GROUP_FNT));
  297. }
  298. }
  299. /*
  300. * Retrieves the name of the font to use for true-type DOS box
  301. * in a window given a registry tree root.
  302. *
  303. * Entry:
  304. *
  305. * hkRoot -> registry tree root to search
  306. * pszFaceSbcs -> LF_FACESIZE buffer for SBCS font
  307. * pszFaceDbcs -> LF_FACESIZE buffer for DBCS font (may be null)
  308. *
  309. * Exit:
  310. *
  311. * Buffers filled with new font names, or left unchanged if nothing
  312. * found in registry.
  313. *
  314. */
  315. #define REGSTR_MSDOSEMU_FONT "Font"
  316. #define REGSTR_MSDOSEMU_FONTDBCS "FontDBCS"
  317. void GetDosBoxTtFontsHkA(HKEY hkRoot, LPSTR pszFaceSbcs, LPSTR pszFaceDbcs)
  318. {
  319. static CHAR const szMsdosemu[] = REGSTR_PATH_MSDOSEMU;
  320. HKEY hk;
  321. DWORD cb;
  322. if (RegOpenKeyExA(hkRoot, szMsdosemu, 0, KEY_READ, &hk) == ERROR_SUCCESS)
  323. {
  324. static CHAR const szFont[] = REGSTR_MSDOSEMU_FONT;
  325. cb = LF_FACESIZE;
  326. RegQueryValueExA(hk, szFont, 0, 0, (LPBYTE)pszFaceSbcs, &cb);
  327. if (pszFaceDbcs)
  328. {
  329. static CHAR const szDbcsFont[] = REGSTR_MSDOSEMU_FONTDBCS;
  330. cb = LF_FACESIZE;
  331. RegQueryValueExA(hk, szDbcsFont, 0, 0, (LPBYTE)pszFaceDbcs, &cb);
  332. }
  333. RegCloseKey(hk);
  334. }
  335. }
  336. /*
  337. * Retrieves the name of the font to use for true-type DOS box
  338. * in a window.
  339. *
  340. * This routine consults the appropriate registry keys.
  341. *
  342. * The DOS box font comes first from HKLM, to establish a
  343. * machine-wide default, but can in turn be overridden by
  344. * HKCU for each user to override.
  345. *
  346. * Entry:
  347. *
  348. * pszFaceSbcs -> LF_FACESIZE buffer for SBCS font
  349. * pszFaceDbcs -> LF_FACESIZE buffer for DBCS font (may be null)
  350. *
  351. * Exit:
  352. *
  353. * Buffers filled with new font names, or left unchange if nothing
  354. * found in registry.
  355. *
  356. */
  357. void CoolGetDosBoxTtFontsA(LPSTR pszFaceSbcs, LPSTR pszFaceDbcs)
  358. {
  359. GetDosBoxTtFontsHkA(HKEY_LOCAL_MACHINE, pszFaceSbcs, pszFaceDbcs);
  360. GetDosBoxTtFontsHkA(HKEY_CURRENT_USER, pszFaceSbcs, pszFaceDbcs);
  361. }
  362. /** BroadcastFontChange
  363. *
  364. * HACK! for MS PowerPoint 4.0. These wallys, for some reason, will go
  365. * off and eat up reams of CPU time if they receive a WM_FONTCHANGE
  366. * message that was *posted*. But if the message is *sent*, they do
  367. * the right thing. The puzzling thing is that they never call
  368. * InSendMessage(), so how do they know? What's more, why do they care?
  369. * This was true in 3.1 also. What's their problem?
  370. *
  371. * The problem is that sending a broadcast risks deadlock city; see the
  372. * various hacks in winoldap for places where DDE broadcasting is bypassed.
  373. * In addition, since BroadcastFontChange is also called during the WEP,
  374. * multi-threaded apps will deadlock if we SendMessage back to a window
  375. * on a different thread in the app, because Kernel takes a process
  376. * critical section during DLL unload.
  377. *
  378. * So if PowerPig is running, we just don't tell anybody that we dorked
  379. * with the fonts.
  380. *
  381. * Returns:
  382. *
  383. * None.
  384. *
  385. */
  386. void BroadcastFontChange(void)
  387. {
  388. if (!GetModuleHandle(szPP4)) {
  389. PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0L);
  390. }
  391. }
  392. /** LoadGlobalFontData
  393. *
  394. * Get the name of the DOS box raster font and load it.
  395. *
  396. * Get the name of the TT font. (CheckDisplayParameters needs this.)
  397. *
  398. * Check the display parameters.
  399. *
  400. * Initialize the fdi cache. The cache remains in GlobalLock'd
  401. * memory throughout its lifetime. This is not a problem because
  402. * we are guaranteed to be in protected mode.
  403. *
  404. * We also load things necessary for the font combo/list boxes.
  405. *
  406. * And compute the height of the owner-draw list box item.
  407. *
  408. * Returns:
  409. *
  410. * TRUE on success. In which case the FDI cache and hbmFont
  411. * are ready to use.
  412. *
  413. * FALSE on failure. In which case there is insufficient memory
  414. * to complete the operation.
  415. */
  416. typedef void (WINAPI *LPFNGDBTF)(LPTSTR, LPTSTR); /* GetDosBoxTtFonts */
  417. BOOL LoadGlobalFontData(void)
  418. {
  419. HDC hDC;
  420. TEXTMETRIC tm;
  421. TCHAR szBuffer[MAXPATHNAME];
  422. cxScreen = GetSystemMetrics(SM_CXSCREEN);
  423. cyScreen = GetSystemMetrics(SM_CYSCREEN);
  424. /*
  425. * Get the system char size and save it away for later use.
  426. */
  427. hDC = GetDC(NULL);
  428. SelectObject(hDC, GetStockObject(SYSTEM_FONT));
  429. GetTextMetrics(hDC, &tm);
  430. ReleaseDC(NULL, hDC);
  431. dyChar = tm.tmHeight + tm.tmExternalLeading;
  432. dyItem = max(tm.tmHeight, DY_TTBITMAP);
  433. /*
  434. * Chicago's AddFontResource looks in the FONTS directory first, which
  435. * is great because it saves us the trouble of doing goofy disk access
  436. * optimizations.
  437. */
  438. GetPrivateProfileString(sz386EnhSection, szWOAFontKey,
  439. c_szNULL, szBuffer, ARRAYSIZE(szBuffer), szSystemINI);
  440. if (szBuffer[0] && AddFontResource(szBuffer)) {
  441. BroadcastFontChange();
  442. }
  443. /*
  444. * Add DBCS native font if it is present.
  445. */
  446. GetPrivateProfileString(sz386EnhSection, szWOADBCSFontKey,
  447. c_szNULL, szBuffer, ARRAYSIZE(szBuffer), szSystemINI);
  448. if (szBuffer[0] && AddFontResource(szBuffer)) {
  449. BroadcastFontChange();
  450. }
  451. /*
  452. * Load default TT font name(s) and TT cache section names from resource
  453. */
  454. LoadStringA(g_hinst, IDS_TTFACENAME_SBCS, szTTFaceName[0], ARRAYSIZE(szTTFaceName[0]));
  455. LoadString(g_hinst,IDS_TTCACHESEC_SBCS, szTTCacheSection[0], ARRAYSIZE(szTTCacheSection[0]));
  456. if (IsBilingualCP(g_uCodePage))
  457. {
  458. LoadStringA(g_hinst, IDS_TTFACENAME_DBCS, szTTFaceName[1], ARRAYSIZE(szTTFaceName[1]));
  459. LoadString(g_hinst, IDS_TTCACHESEC_DBCS, szTTCacheSection[1], ARRAYSIZE(szTTCacheSection[1]));
  460. }
  461. CoolGetDosBoxTtFontsA(szTTFaceName[0], szTTFaceName[1]);
  462. CheckDisplayParameters();
  463. // alloc needed # of cache
  464. //
  465. lpCache = (LPVOID)LocalAlloc(LPTR,
  466. FDI_TABLE_START * sizeof(FONTDIMENINFO) * (IsBilingualCP(g_uCodePage)? 2:1));
  467. if (!lpCache)
  468. return FALSE;
  469. hcursorWait = LoadCursor(NULL, IDC_WAIT);
  470. UpdateTTBitmap();
  471. if (!hbmFont)
  472. goto E0;
  473. // set initial value of # of cache entries which depends on whether we have
  474. // two codepage to handle
  475. //
  476. cfdiCacheActual[0] = FDI_TABLE_START;
  477. if (IsBilingualCP(g_uCodePage))
  478. {
  479. cfdiCacheActual[1] = FDI_TABLE_START;
  480. bpfdiStart[1] += FDI_TABLE_START;
  481. }
  482. FontSelInit();
  483. return TRUE;
  484. E0:
  485. EVAL(LocalFree(lpCache) == NULL);
  486. return FALSE;
  487. }
  488. void FreeGlobalFontData()
  489. {
  490. TCHAR szBuffer[MAXPATHNAME] = {0};
  491. if (hbmFont)
  492. DeleteObject(hbmFont);
  493. EVAL(LocalFree(lpCache) == NULL);
  494. GetPrivateProfileString(sz386EnhSection, szWOAFontKey,
  495. c_szNULL, szBuffer, ARRAYSIZE(szBuffer), szSystemINI);
  496. if (*szBuffer) {
  497. if (RemoveFontResource(szBuffer)) {
  498. BroadcastFontChange();
  499. }
  500. }
  501. GetPrivateProfileString(sz386EnhSection, szWOADBCSFontKey,
  502. c_szNULL, szBuffer, ARRAYSIZE(szBuffer), szSystemINI);
  503. if (*szBuffer) {
  504. if (RemoveFontResource(szBuffer)) {
  505. BroadcastFontChange();
  506. }
  507. }
  508. }
  509. BOOL LoadGlobalFontEditData()
  510. {
  511. WNDCLASS wc;
  512. // Set up the window preview class for piffnt.c
  513. wc.style = 0L;
  514. wc.lpfnWndProc = WndPreviewWndProc;
  515. wc.cbClsExtra = 0;
  516. wc.cbWndExtra = sizeof(PFNTINFO);
  517. wc.hInstance = g_hinst;
  518. wc.hIcon = NULL;
  519. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  520. wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
  521. wc.lpszMenuName = NULL;
  522. wc.lpszClassName = szWndPreviewClass;
  523. // Don't go through RegisterClassD because we manually unregister
  524. // this class ourselves.
  525. if (!RealRegisterClass(&wc))
  526. return FALSE;
  527. // Set up the font preview class for piffnt.c
  528. wc.style = 0L;
  529. wc.lpfnWndProc = FontPreviewWndProc;
  530. wc.cbClsExtra = 0;
  531. wc.cbWndExtra = sizeof(PFNTINFO);
  532. wc.hInstance = g_hinst;
  533. wc.hIcon = NULL;
  534. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  535. wc.hbrBackground = GetStockObject(BLACK_BRUSH);
  536. wc.lpszMenuName = NULL;
  537. wc.lpszClassName = szFontPreviewClass;
  538. // Don't go through RegisterClassD because we manually unregister
  539. // this class ourselves.
  540. if (!RealRegisterClass(&wc))
  541. return FALSE;
  542. return TRUE;
  543. }
  544. void FreeGlobalFontEditData()
  545. {
  546. UnregisterClass(szWndPreviewClass, g_hinst);
  547. UnregisterClass(szFontPreviewClass, g_hinst);
  548. }
  549. /*
  550. * Make sure that the display parameters have not changed, including
  551. * the name of the TT font(s).
  552. *
  553. * If they have, we BLAST OUR CACHE since it is no longer any good.
  554. *
  555. * Entry:
  556. * szTTFaceName contains the name of the TrueType font to use.
  557. *
  558. * Returns:
  559. * None.
  560. */
  561. void CheckDisplayParameters(void)
  562. {
  563. HDC hIC;
  564. HKEY hk;
  565. DISPLAYPARAMETERS dpTrue, dpStored;
  566. hIC = CreateIC(szDisplay, 0, 0, 0);
  567. if (!hIC) {
  568. /*
  569. * If things are really screwy, stay conservative and assume
  570. * that all is well.
  571. */
  572. return;
  573. }
  574. dpTrue.dpHorzSize = GetDeviceCaps(hIC, HORZSIZE);
  575. dpTrue.dpVertSize = GetDeviceCaps(hIC, VERTSIZE);
  576. dpTrue.dpHorzRes = GetDeviceCaps(hIC, HORZRES);
  577. dpTrue.dpVertRes = GetDeviceCaps(hIC, VERTRES);
  578. dpTrue.dpLogPixelsX = GetDeviceCaps(hIC, LOGPIXELSX);
  579. dpTrue.dpLogPixelsY = GetDeviceCaps(hIC, LOGPIXELSY);
  580. dpTrue.dpAspectX = GetDeviceCaps(hIC, ASPECTX);
  581. dpTrue.dpAspectY = GetDeviceCaps(hIC, ASPECTY);
  582. dpTrue.dpBitsPerPixel = GetDeviceCaps(hIC, BITSPIXEL);
  583. DeleteDC(hIC);
  584. /*
  585. * Since szTTFaceName is pre-initialized to "Courier New" padded
  586. * with nulls, we can rely on the garbage after the end of the
  587. * string always to be the same, so that a pure memory comparison
  588. * will work.
  589. */
  590. MultiByteToWideChar(CP_ACP, 0, szTTFaceName[0], -1, dpTrue.szTTFace[0], ARRAYSIZE(dpTrue.szTTFace[0]));
  591. if (IsBilingualCP(g_uCodePage))
  592. MultiByteToWideChar(CP_ACP, 0, szTTFaceName[1], -1, dpTrue.szTTFace[1], ARRAYSIZE(dpTrue.szTTFace[1]));
  593. /*
  594. * We must store the dimension information in the registry because
  595. * the install program for Omar Sharif Bridge will ERASE! your
  596. * SYSTEM.INI if it contains a line greater than 78 characters.
  597. * (I am not making this up. How could I?)
  598. */
  599. if (RegCreateKey(HKEY_LOCAL_MACHINE, TEXT(REGSTR_PATH_MSDOSEMU), &hk) == 0) {
  600. DWORD cb = sizeof(DISPLAYPARAMETERS);
  601. if (SHQueryValueEx(hk, REGSTR_MSDOSEMU_DISPLAYPARAMS, 0, 0, (LPVOID)&dpStored, &cb) != 0 || cb != sizeof(DISPLAYPARAMETERS) || IsBufferDifferent(&dpTrue, &dpStored, sizeof(DISPLAYPARAMETERS))) {
  602. /*
  603. * Not much we can do if the write fails, so don't check.
  604. */
  605. VERIFYTRUE(RegSetValueEx(hk, REGSTR_MSDOSEMU_DISPLAYPARAMS, 0, REG_BINARY, (LPVOID)&dpTrue, cb) == 0);
  606. /* Blast the font dimension cache */
  607. WritePrivateProfileString(szTTCacheSection[1], NULL, NULL, szSystemINI);
  608. if (IsBilingualCP(g_uCodePage))
  609. WritePrivateProfileString(szTTCacheSection[0], NULL, NULL, szSystemINI);
  610. }
  611. VERIFYTRUE(RegCloseKey(hk) == 0);
  612. } else {
  613. /*
  614. * Couldn't access registry. Oh well.
  615. */
  616. }
  617. }
  618. /*
  619. * When the dialog box is created, we create the Window
  620. * Preview child window, as well as the Font Preview window.
  621. *
  622. * The creation is deferred until the actual dialog box creation
  623. * because the size and shape of the Window Preview window depends
  624. * on the current video driver.
  625. */
  626. void PreviewInit(HWND hDlg, PFNTINFO pfi)
  627. {
  628. HWND hwnd;
  629. RECT rectLabel, rcPreview;
  630. /*
  631. * Compute the size of our preview window.
  632. *
  633. * The top is aligned with the top of IDC_WNDPREVIEWLBL,
  634. * minus a top margin of 3/2 dyChar.
  635. * The left edge is aligned with the left edge of IDC_WNDPREVIEWLBL.
  636. * The maximum width is the width of IDC_WNDPREVIEWLBL.
  637. * The bottom edge can go as far down as the bottom of the dialog,
  638. * minus a bottom margin of 3/2 dyChar.
  639. * And the shape of the preview window is determined by the screen
  640. * dimensions.
  641. *
  642. * We make the preview window as large as possible, given these
  643. * constraints.
  644. *
  645. */
  646. GetWindowRect(GetDlgItem(hDlg, IDC_WNDPREVIEWLBL), &rectLabel);
  647. ScreenToClient(hDlg, (LPPOINT)&rectLabel);
  648. ScreenToClient(hDlg, (LPPOINT)&rectLabel.right);
  649. /*
  650. * This GetWindowRect/ScreenToClient sets rcPreview.top.
  651. */
  652. GetWindowRect(GetDlgItem(hDlg, IDC_WNDPREVIEWLBL), &rcPreview);
  653. ScreenToClient(hDlg, (LPPOINT)&rcPreview);
  654. /*
  655. * Compute height based on width.
  656. */
  657. rcPreview.top += 3 * dyChar / 2;
  658. rcPreview.left = rectLabel.left;
  659. rcPreview.right = rectLabel.right - rectLabel.left;
  660. rcPreview.bottom = AspectScale(cyScreen, cxScreen, rcPreview.right);
  661. /*
  662. * Phew. Now we can create the preview window.
  663. */
  664. hwnd = CreateWindowEx(
  665. WS_EX_CLIENTEDGE,
  666. szWndPreviewClass, NULL,
  667. WS_CHILD | WS_VISIBLE,
  668. rcPreview.left, rcPreview.top,
  669. rcPreview.right, rcPreview.bottom,
  670. hDlg, (HMENU)IDC_WNDPREVIEW, g_hinst, NULL);
  671. if (hwnd)
  672. SetWindowLongPtr(hwnd, 0, (LONG_PTR)pfi);
  673. /*
  674. * Compute the size of the font preview. This is easier.
  675. */
  676. GetWindowRect(GetDlgItem(hDlg, IDC_FONTPREVIEWLBL), &rectLabel);
  677. ScreenToClient(hDlg, (LPPOINT)&rectLabel.left);
  678. ScreenToClient(hDlg, (LPPOINT)&rectLabel.right);
  679. hwnd = CreateWindowEx(
  680. WS_EX_CLIENTEDGE,
  681. szFontPreviewClass, NULL,
  682. WS_CHILD | WS_VISIBLE,
  683. rectLabel.left,
  684. rectLabel.top + 3 * dyChar / 2,
  685. rectLabel.right - rectLabel.left,
  686. rcPreview.bottom,
  687. hDlg, (HMENU)IDC_FONTPREVIEW, g_hinst, NULL);
  688. if (hwnd)
  689. SetWindowLongPtr(hwnd, 0, (LONG_PTR)pfi);
  690. }
  691. /* PreviewUpdate
  692. *
  693. * Does the preview of the selected font.
  694. */
  695. void PreviewUpdate(HWND hwndList, PFNTINFO pfi)
  696. {
  697. HWND hDlg;
  698. BPFDI bpfdi;
  699. /* Delete the old font if necessary */
  700. if (pfi->hFontPreview)
  701. {
  702. DeleteObject(pfi->hFontPreview);
  703. pfi->hFontPreview = NULL;
  704. }
  705. /* When we select a font, we do the font preview by setting it
  706. * into the appropriate list box
  707. */
  708. bpfdi = (BPFDI)GetFont(hwndList, TRUE, pfi);
  709. if (IsSpecialBpfdi(bpfdi))
  710. return;
  711. /* Update our internal font structure so that preview window
  712. * will actually change
  713. */
  714. pfi->bpfdi = bpfdi;
  715. SetFont(&pfi->fntProposed, bpfdi);
  716. /* Make the new font */
  717. pfi->hFontPreview = CreateFontFromBpfdi(bpfdi, pfi);
  718. /* Force the preview windows to repaint */
  719. hDlg = GetParent(hwndList);
  720. InvalidateRect(GetDlgItem(hDlg, IDC_WNDPREVIEW), NULL, TRUE);
  721. InvalidateRect(GetDlgItem(hDlg, IDC_FONTPREVIEW), NULL, TRUE);
  722. }
  723. /* WndPreviewWndProc
  724. *
  725. * Handles the window preview window.
  726. */
  727. LRESULT WndPreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  728. {
  729. switch (uMsg)
  730. {
  731. case WM_PAINT:
  732. WndPreviewPaint(GetParent(hwnd), hwnd);
  733. break;
  734. case WM_HELP: // Handles title bar help button message
  735. WinHelp(hwnd, NULL, HELP_CONTEXTPOPUP, IDH_DOS_FONT_WINDOW_PREVIEW);
  736. break;
  737. case WM_RBUTTONUP:
  738. case WM_NCRBUTTONUP: // Equivalent of WM_CONTEXTMENU
  739. OnWmContextMenu((WPARAM)hwnd, &rgdwHelp[0]);
  740. break;
  741. default:
  742. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  743. }
  744. return 0;
  745. }
  746. /* Swiped from Control Panel / Metrics.
  747. *
  748. * Draws the frame *and* modifies the rectangle to contain the
  749. * shrunk coordinates.
  750. */
  751. void _DrawFrame(HDC hdc, int clr, LPRECT lprc, int cx, int cy)
  752. {
  753. HBRUSH hbr;
  754. RECT rcT;
  755. CopyRect(&rcT, lprc);
  756. hbr = SelectObject(hdc, GetSysColorBrush(clr));
  757. /* Left */
  758. PatBlt(hdc, rcT.left, rcT.top, cx, rcT.bottom-rcT.top, PATCOPY);
  759. rcT.left += cx;
  760. /* Top */
  761. PatBlt(hdc, rcT.left, rcT.top, rcT.right-rcT.left, cy, PATCOPY);
  762. rcT.top += cy;
  763. /* Right */
  764. rcT.right -= cx;
  765. PatBlt(hdc, rcT.right, rcT.top, cx, rcT.bottom-rcT.top, PATCOPY);
  766. /* Bottom */
  767. rcT.bottom -= cy;
  768. PatBlt(hdc, rcT.left, rcT.bottom, rcT.right-rcT.left, cy, PATCOPY);
  769. SelectObject(hdc, hbr);
  770. CopyRect(lprc, &rcT);
  771. }
  772. /* WndPreviewPaint
  773. *
  774. * Paints the window preview window. This is called from its
  775. * paint message handler.
  776. *
  777. */
  778. void WndPreviewPaint(HWND hDlg, HWND hwnd)
  779. {
  780. PPROPLINK ppl;
  781. PFNTINFO pfi;
  782. RECT rcPreview;
  783. RECT rcWin;
  784. RECT rcClient;
  785. RECT rcT;
  786. POINT ptButton;
  787. #define cxButton ptButton.x
  788. #define cyButton ptButton.y
  789. POINT ptCorner;
  790. POINT ptFrame;
  791. #define cxFrame ptFrame.x
  792. #define cyFrame ptFrame.y
  793. BPFDI bpfdi;
  794. int cxBorder, cyBorder;
  795. int dyToolbar;
  796. PAINTSTRUCT ps;
  797. BOOL bCenter;
  798. BeginPaint(hwnd, &ps);
  799. pfi = (PFNTINFO)GetWindowLongPtr(hwnd, 0);
  800. ppl = pfi->ppl;
  801. ASSERTTRUE(ppl->iSig == PROP_SIG);
  802. bpfdi = pfi->bpfdi;
  803. /* If we don't have a font, get out */
  804. if (!pfi->hFontPreview)
  805. return;
  806. /* Get the width of the preview "screen" */
  807. GetClientRect(hwnd, &rcPreview);
  808. /* Figure out how large we would be as a result of the change.
  809. * This isn't perfect, but it'll probably be close enough.
  810. * (Imperfection if we chose AUTO as the font.)
  811. */
  812. /* Assume maximized */
  813. rcClient.left = rcClient.top = 0;
  814. if (pfi->winOriginal.cxCells) {
  815. rcClient.right = pfi->winOriginal.cxCells * bpfdi->fdiWidthActual;
  816. } else {
  817. rcClient.right = 80 * bpfdi->fdiWidthActual;
  818. }
  819. if (pfi->winOriginal.cyCells) {
  820. rcClient.bottom = pfi->winOriginal.cyCells * bpfdi->fdiHeightActual;
  821. } else {
  822. PROPVID vid;
  823. // set default value
  824. rcClient.bottom = 25 * bpfdi->fdiHeightActual;
  825. // now see if there is a value in the pif file for size of window...
  826. if (PifMgr_GetProperties(ppl, MAKELP(0,GROUP_VID),
  827. &vid, sizeof(vid), GETPROPS_NONE))
  828. {
  829. if (vid.cScreenLines > 0)
  830. rcClient.bottom = vid.cScreenLines * bpfdi->fdiHeightActual;
  831. }
  832. }
  833. if (!pfi->fMax && pfi->winOriginal.cxClient && pfi->winOriginal.cyClient) {
  834. /* Shrink down to window actual */
  835. if (rcClient.right > (int)pfi->winOriginal.cxClient)
  836. rcClient.right = (int)pfi->winOriginal.cxClient;
  837. if (rcClient.bottom > (int)pfi->winOriginal.cyClient)
  838. rcClient.bottom = (int)pfi->winOriginal.cyClient;
  839. }
  840. /* Get some more metrics */
  841. cxBorder = GetSystemMetrics(SM_CXBORDER);
  842. cyBorder = GetSystemMetrics(SM_CYBORDER);
  843. cxButton = GetSystemMetrics(SM_CXSIZE);
  844. cyButton = GetSystemMetrics(SM_CYSIZE);
  845. // cyButton *= 2; /* Double the height for "looks" */
  846. cxFrame = GetSystemMetrics(SM_CXFRAME);
  847. cyFrame = GetSystemMetrics(SM_CYFRAME);
  848. /* FLAG DAY! Convert everything from desktop coordinates to
  849. * aspect ratio-scaled preview coordinates
  850. *
  851. * Do **not** convert cxBorder and cyBorder!
  852. *
  853. * ptCorner must not be modified in-place since its value is used at
  854. * the next go-round.
  855. *
  856. * After translation, cxFrame and cyFrame are adjusted so that the
  857. * cxBorder counts against them. This allows for users who set
  858. * really wide frames, but doesn't penalize the users who have
  859. * narrow frames.
  860. */
  861. ptCorner = pfi->ptCorner;
  862. bCenter = (ptCorner.x == -1);
  863. AspectPoint(&rcPreview, &ptCorner);
  864. AspectPoint(&rcPreview, &ptFrame);
  865. AspectRect(&rcPreview, &rcClient);
  866. AspectPoint(&rcPreview, &ptButton);
  867. /*
  868. * The height of a toolbar is hard-coded at 30 pixels.
  869. */
  870. if (pfi->winOriginal.flWin & WIN_TOOLBAR) {
  871. dyToolbar = (int)AspectScale(rcPreview.bottom, cyScreen, 30);
  872. } else {
  873. dyToolbar = 0;
  874. }
  875. /* Make sure the buttons are nonzero in dimension */
  876. if (cxButton == 0) cxButton = 1;
  877. if (cyButton == 0) cyButton = 1;
  878. /*
  879. * Don't penalize people who have thin frames.
  880. */
  881. if (cxFrame < cxBorder) cxFrame = cxBorder;
  882. if (cyFrame < cyBorder) cyFrame = cyBorder;
  883. /*
  884. * Convert from client rectangle back to window rectangle.
  885. *
  886. * We must do this *AFTER* the flag day, because we need to use the
  887. * post-flag day cxBorder and cyBorder.
  888. */
  889. /* Put a (scaled-down) toolbar into place. We'll expand the client
  890. * region to accomodate it. (We'll subtract the toolbar off before
  891. * painting the client region.)
  892. */
  893. rcClient.bottom += dyToolbar;
  894. /* Shove the client region down to make room for the caption. */
  895. OffsetRect(&rcClient, 0, cyButton);
  896. rcWin = rcClient;
  897. rcWin.top = 0;
  898. InflateRect(&rcWin, cxFrame, cyFrame);
  899. /*
  900. * Now put it in the proper position on the (shrunk-down) desktop.
  901. * We cannot do this until rcWin's value is finalized.
  902. */
  903. if (bCenter)
  904. {
  905. ptCorner.x = ((rcPreview.right - rcPreview.left) -
  906. (rcWin.right - rcWin.left)
  907. ) / 2;
  908. if (ptCorner.x < 0)
  909. ptCorner.x = 0;
  910. ptCorner.y = ((rcPreview.bottom - rcPreview.top) -
  911. (rcWin.bottom - rcWin.top)
  912. ) / 5;
  913. if (ptCorner.y < 0)
  914. ptCorner.y = 0;
  915. }
  916. OffsetRect(&rcWin, ptCorner.x, ptCorner.y);
  917. OffsetRect(&rcClient, ptCorner.x, ptCorner.y);
  918. /* It's party time! */
  919. /* The outer border */
  920. DrawEdge(ps.hdc, &rcWin, BDR_RAISEDINNER, BF_RECT | BF_ADJUST);
  921. /* The sizing frame */
  922. _DrawFrame(ps.hdc, COLOR_ACTIVEBORDER,
  923. &rcWin, cxFrame - cxBorder, cyFrame - cyBorder);
  924. /* rcWin has now shrunk to its inner edge */
  925. /* Move its bottom edge upwards to meet the top of the client region.
  926. * This turns rcWin into the caption area.
  927. */
  928. rcWin.bottom = rcClient.top;
  929. FillRect(ps.hdc, &rcWin, (HBRUSH)(COLOR_ACTIVECAPTION+1));
  930. /* Next comes the toolbar */
  931. rcT= rcClient;
  932. rcT.bottom = rcT.top + dyToolbar;
  933. FillRect(ps.hdc, &rcT, (HBRUSH)(COLOR_BTNFACE+1));
  934. /* Next, draw the client region */
  935. rcClient.top += dyToolbar;
  936. DrawEdge(ps.hdc, &rcClient, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
  937. FillRect(ps.hdc, &rcClient, (HBRUSH)GetStockObject(BLACK_BRUSH));
  938. /*
  939. * Now draw the three caption buttons.
  940. */
  941. /*
  942. * The system menu.
  943. */
  944. rcT = rcWin;
  945. rcT.right = rcT.left + cxButton;
  946. //DrawFrameControl(ps.hdc, &rcT, DFC_SYSMENU, DFCS_SYSMENUMAIN);
  947. DrawFrameControl(ps.hdc, &rcT, DFC_CAPTION, DFCS_CAPTIONCLOSE);
  948. /*
  949. * The maximize menu.
  950. */
  951. rcWin.left = rcWin.right - cxButton;
  952. //DrawFrameControl(ps.hdc, &rcWin, DFC_SIZE, DFCS_SIZEMAX);
  953. DrawFrameControl(ps.hdc, &rcWin, DFC_CAPTION, DFCS_CAPTIONMAX);
  954. /*
  955. * The minimize menu.
  956. */
  957. rcWin.left -= cxButton;
  958. rcWin.right -= cxButton;
  959. //DrawFrameControl(ps.hdc, &rcWin, DFC_SIZE, DFCS_SIZEMIN);
  960. DrawFrameControl(ps.hdc, &rcWin, DFC_CAPTION, DFCS_CAPTIONMIN);
  961. EndPaint(hwnd, &ps);
  962. }
  963. #undef cxButton
  964. #undef cyButton
  965. #undef cxFrame
  966. #undef cyFrame
  967. LRESULT FontPreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  968. {
  969. RECT rect;
  970. PFNTINFO pfi;
  971. PAINTSTRUCT ps;
  972. switch (uMsg)
  973. {
  974. case WM_PAINT:
  975. BeginPaint(hwnd, &ps);
  976. pfi = (PFNTINFO)GetWindowLongPtr(hwnd, 0);
  977. /* Draw the font sample */
  978. SelectObject(ps.hdc, pfi->hFontPreview);
  979. SetTextColor(ps.hdc, RGB(192, 192, 192));
  980. SetBkColor(ps.hdc, RGB(0, 0, 0));
  981. GetClientRect(hwnd, &rect);
  982. InflateRect(&rect, -2, -2);
  983. {
  984. TCHAR szPreviewText[300];
  985. LoadString(g_hinst, IsBilingualCP(pfi->fntProposed.wCurrentCP) ? IDS_PREVIEWTEXT_BILNG : IDS_PREVIEWTEXT, szPreviewText, ARRAYSIZE(szPreviewText));
  986. // load a sample for their native codepage
  987. DrawText(ps.hdc, szPreviewText, -1, &rect, 0);
  988. }
  989. EndPaint(hwnd, &ps);
  990. break;
  991. case WM_HELP: // Handles title bar help button message
  992. WinHelp(hwnd, NULL, HELP_CONTEXTPOPUP, IDH_DOS_FONT_FONT_PREVIEW);
  993. break;
  994. case WM_RBUTTONUP:
  995. case WM_NCRBUTTONUP: // Equivalent of WM_CONTEXTMENU
  996. OnWmContextMenu((WPARAM)hwnd, &rgdwHelp[0]);
  997. break;
  998. default:
  999. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1000. }
  1001. return 0;
  1002. }
  1003. /*
  1004. * Loads the dialog control hwndList with all available font
  1005. * dimensions for raster fonts, and a selected collection of
  1006. * dimensions for TrueType fonts.
  1007. *
  1008. * The reference data for each control is an index into lpfniCache.
  1009. *
  1010. * The hourglass cursor is displayed during the font list build.
  1011. *
  1012. * Entry:
  1013. * hwndList == handle to listbox or combo box to fill
  1014. * fListBox == TRUE if hwndList is a listbox, FALSE if a combo box
  1015. * lpFnt -> PROPFNT structure
  1016. *
  1017. * If HIWORD(lpFnt) is NULL, then LOWORD(lpFnt) is used as an hProps
  1018. * to get obtain property info for that handle.
  1019. *
  1020. * Returns:
  1021. * >= 0 on success, indicating the current selection.
  1022. * In which case the FDI cache is valid and hwndList has been filled
  1023. * with font information, and the currently-selected font has been
  1024. * made the current selection.
  1025. *
  1026. * LB_ERR/CB_ERR on failure. The list box hwndList is left in an
  1027. * indeterminate state.
  1028. */
  1029. int WINAPI CreateFontList(HWND hwndList, BOOL fListBox, LPPROPFNT lpFnt)
  1030. {
  1031. DWORD dwIndex;
  1032. HCURSOR hcursor;
  1033. PROPFNT fntTemp;
  1034. int iReturn = LB_ERR;
  1035. TCHAR szBuf[MAXDIMENSTRING];
  1036. if (IS_INTRESOURCE(lpFnt))
  1037. {
  1038. if (!PifMgr_GetProperties(lpFnt, MAKELP(0,GROUP_FNT),
  1039. &fntTemp, sizeof(fntTemp), GETPROPS_NONE))
  1040. goto Exit2;
  1041. lpFnt = &fntTemp;
  1042. }
  1043. /*
  1044. * Put up an hourglass while the font list build is taking place,
  1045. * since it might take a long time if we have to re-rasterize
  1046. * TrueType fonts.
  1047. *
  1048. * NOTE! That we do not do a ShowCursor. Why?
  1049. *
  1050. * If the user is on a mouseless system, then he can't access his
  1051. * toolbar, and hence the only time this code can get called is
  1052. * during the creation of the font selection dialog box. In which
  1053. * case, DialogBox has already done a ShowCursor for us.
  1054. *
  1055. */
  1056. hcursor = SetCursor(hcursorWait);
  1057. /*
  1058. * Initialize the list box.
  1059. */
  1060. if (hwndList) {
  1061. SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
  1062. SendMessage(hwndList, fListBox ? LB_RESETCONTENT : CB_RESETCONTENT, 0, 0L);
  1063. }
  1064. /*
  1065. * Add the fonts.
  1066. */
  1067. if ((lpFnt->flFnt & FNT_RASTERFONTS) &&
  1068. !AddRasterFontsToFontListA(hwndList, fListBox,
  1069. lpFnt->achRasterFaceName, lpFnt->wCurrentCP))
  1070. goto Exit;
  1071. if ((lpFnt->flFnt & FNT_TTFONTS) &&
  1072. !AddTrueTypeFontsToFontListA(hwndList, fListBox,
  1073. lpFnt->achTTFaceName, lpFnt->wCurrentCP))
  1074. goto Exit;
  1075. /*
  1076. * And the magical "Auto" font size.
  1077. */
  1078. /*
  1079. * Beyond this point, success is assured, so at the very least,
  1080. * DON'T return LB_ERR; we may optionally set the return code to
  1081. * the current selection, below, too...
  1082. */
  1083. iReturn = 0;
  1084. if (hwndList) {
  1085. /*
  1086. * No error checking here because if anything fails, then the
  1087. * end result will be merely that the "Auto" option either
  1088. * (1) exists but is invisible, or (2) doesn't appear at all.
  1089. */
  1090. LoadString(g_hinst, IDS_AUTO, szBuf, ARRAYSIZE(szBuf));
  1091. dwIndex = lcbInsertString(hwndList, fListBox, szBuf, 0);
  1092. lcbSetItemDataPair(hwndList, fListBox, dwIndex, BPFDI_AUTO, 0);
  1093. /*
  1094. * Make yet another pass through the list to find the current
  1095. * font and select it. Thanks to an intentional flakiness
  1096. * in USER, we can't do this check at the point that the
  1097. * font is added, because the selection does not move with the
  1098. * item when a new item is inserted above the selection.
  1099. *
  1100. * Bleah.
  1101. */
  1102. if (!MatchCurrentFont(hwndList, fListBox, lpFnt)) {
  1103. /*
  1104. * If no font matched the current font, and we are a list box,
  1105. * then make the first font the current selection.
  1106. *
  1107. * We don't want to make any default selection if we are a
  1108. * combo box, because that would make the user think that the
  1109. * current font was something it wasn't.
  1110. */
  1111. if (fListBox) {
  1112. /*
  1113. * SORTING-SENSITIVE! This assumes that "Auto" is at the top
  1114. * of the list.
  1115. */
  1116. lcbSetCurSel(hwndList, TRUE, 0);
  1117. lpFnt->flFnt |= FNT_AUTOSIZE;
  1118. }
  1119. }
  1120. SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
  1121. iReturn = lcbGetCurSel(hwndList, fListBox);
  1122. }
  1123. Exit:
  1124. /*
  1125. * Reset the mouse cursor.
  1126. */
  1127. SetCursor(hcursor);
  1128. Exit2:
  1129. return iReturn;
  1130. }
  1131. /** UpdateTTBitmap
  1132. *
  1133. * Recompute the colors for the TrueType bitmap hbmFont.
  1134. *
  1135. * Since we may receive this several times for a single WM_SYSCOLORCHANGE,
  1136. * we update our colors under the following conditions:
  1137. *
  1138. * 1. More than one second has elapsed since the previous call, or
  1139. * 2. A crude checksum fails.
  1140. *
  1141. * Entry:
  1142. * None.
  1143. *
  1144. * Returns:
  1145. * hbmFont recomputed.
  1146. */
  1147. VOID WINAPI UpdateTTBitmap(void)
  1148. {
  1149. COLORREF clr;
  1150. /*
  1151. * Note that the checksum should not be a symmetric function,
  1152. * because a common color alteration is to exchange or permute
  1153. * the colors.
  1154. */
  1155. clr = + GetSysColor(COLOR_BTNTEXT)
  1156. - GetSysColor(COLOR_BTNSHADOW)
  1157. + (GetSysColor(COLOR_BTNFACE) ^ 1)
  1158. - (GetSysColor(COLOR_BTNHIGHLIGHT) ^ 2)
  1159. ^ GetSysColor(COLOR_WINDOW);
  1160. if (!hbmFont || clr != clrChecksum || GetTickCount() - dwTimeCheck < 1000) {
  1161. clrChecksum = clr;
  1162. dwTimeCheck = GetTickCount();
  1163. if (hbmFont) DeleteObject(hbmFont);
  1164. hbmFont = CreateMappedBitmap(g_hinst, IDB_TTBITMAP, 0, NULL, 0);
  1165. }
  1166. }
  1167. /** DrawItemFontList
  1168. *
  1169. * Answer the WM_DRAWITEM message sent from the font list box or
  1170. * font combo box.
  1171. *
  1172. * This code was originally lifted from FONT.C in sdk\commdlg.
  1173. *
  1174. * See fontutil.h for an explanation of the \1 hack.
  1175. *
  1176. * Entry:
  1177. * fListBox = TRUE if the item is a list box, FALSE if a combo box
  1178. * lpdis -> DRAWITEMSTRUCT describing object to be drawn
  1179. *
  1180. * Returns:
  1181. * None.
  1182. *
  1183. * The object is drawn.
  1184. */
  1185. #define cTabsList 3
  1186. typedef struct DIFLINFO {
  1187. LPTSTR di_lpsz;
  1188. PINT di_pTabs;
  1189. } DIFLINFO, *LPDIFLINFO;
  1190. #define lpdi ((LPDIFLINFO)lp)
  1191. BOOL CALLBACK diflGrayStringProc(HDC hdc, LPARAM lp, int cch)
  1192. {
  1193. return (BOOL)TabbedTextOut(hdc, 0, 0,
  1194. lpdi->di_lpsz, lstrlen(lpdi->di_lpsz),
  1195. cTabsList, lpdi->di_pTabs, 0);
  1196. }
  1197. #undef lpdi
  1198. VOID WINAPI DrawItemFontList(BOOL fListBox, const LPDRAWITEMSTRUCT lpdis)
  1199. {
  1200. HDC hDC, hdcMem;
  1201. DWORD rgbBack, rgbText;
  1202. int iColorBack;
  1203. COLORREF clrText;
  1204. COLORREF clrBack;
  1205. TCHAR szDimen[MAXDIMENSTRING];
  1206. HBITMAP hOld;
  1207. int dy;
  1208. DIFLINFO di;
  1209. static int rgTabsList[cTabsList] = {0, 0, 0};
  1210. static int rgTabsCombo[cTabsList] = {0, 0, 0};
  1211. #define lpsz di.di_lpsz
  1212. #define pTabs di.di_pTabs
  1213. if ((int)lpdis->itemID < 0)
  1214. return;
  1215. hDC = lpdis->hDC;
  1216. if (lpdis->itemAction & ODA_FOCUS) {
  1217. if (lpdis->itemState & ODS_SELECTED) {
  1218. DrawFocusRect(hDC, &lpdis->rcItem);
  1219. }
  1220. } else {
  1221. if (lpdis->itemState & ODS_SELECTED) {
  1222. clrBack = GetSysColor(iColorBack = COLOR_HIGHLIGHT);
  1223. clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  1224. } else {
  1225. clrBack = GetSysColor(iColorBack = COLOR_WINDOW);
  1226. clrText = GetSysColor(IsWindowEnabled(lpdis->hwndItem) ?
  1227. COLOR_WINDOWTEXT : COLOR_GRAYTEXT);
  1228. }
  1229. rgbText = SetTextColor(hDC, clrText);
  1230. rgbBack = SetBkColor(hDC, clrBack);
  1231. // draw selection background
  1232. FillRect(hDC, &lpdis->rcItem, (HBRUSH)UIntToPtr((iColorBack + 1)));
  1233. // get the string
  1234. SendMessage(lpdis->hwndItem, fListBox ? LB_GETTEXT : CB_GETLBTEXT, lpdis->itemID, (LPARAM)(LPTSTR)szDimen);
  1235. lpsz = szDimen;
  1236. if (szDimen[0] == TEXT('\1')) // hack for "Auto" string
  1237. lpsz++;
  1238. if (fListBox)
  1239. pTabs = rgTabsList;
  1240. else
  1241. pTabs = rgTabsCombo;
  1242. if (pTabs[0] == 0) { /* Never seen this font before */
  1243. /* Assumes GetTextExtent(hDC, ANSI_TIMES, 1) < 2 * dxChar */
  1244. SIZE sSize;
  1245. GetTextExtentPoint32(hDC, szZero, 1, &sSize); // size of '0'
  1246. /* A negative # for tab stop right aligns the tabs... */
  1247. pTabs[0] = -sSize.cx * 3;
  1248. pTabs[1] = -sSize.cx * 5;
  1249. pTabs[2] = -sSize.cx * 8;
  1250. }
  1251. // draw the text
  1252. //
  1253. // Note that the SDK dox for GrayString says that you can detect
  1254. // whether GrayString is needed by saying
  1255. //
  1256. // if (GetSysColor(COLOR_GRAYTEXT) == 0) {
  1257. // GrayString(...);
  1258. // } else {
  1259. // TextOut(...);
  1260. // }
  1261. //
  1262. // This is incorrect. The correct test is the one below, which
  1263. // also catches bad color combinations on color devices.
  1264. //
  1265. if (clrText == clrBack) {
  1266. SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  1267. GrayString(hDC, GetStockObject(GRAY_BRUSH), diflGrayStringProc ,
  1268. (LPARAM)(LPVOID)&di, 0,
  1269. lpdis->rcItem.left + DX_TTBITMAP,
  1270. lpdis->rcItem.top,
  1271. lpdis->rcItem.right - lpdis->rcItem.left - DX_TTBITMAP,
  1272. lpdis->rcItem.bottom - lpdis->rcItem.top);
  1273. } else {
  1274. TabbedTextOut(hDC, lpdis->rcItem.left + DX_TTBITMAP, lpdis->rcItem.top, lpsz, lstrlen(lpsz), cTabsList, pTabs, DX_TTBITMAP);
  1275. }
  1276. // and the bitmap if needed
  1277. if (!IsSpecialBpfdi((BPFDI)lpdis->itemData))
  1278. {
  1279. if (((BPFDI)(lpdis->itemData))->bTT) {
  1280. hdcMem = CreateCompatibleDC(hDC);
  1281. if (hdcMem) {
  1282. hOld = SelectObject(hdcMem, hbmFont);
  1283. dy = ((lpdis->rcItem.bottom - lpdis->rcItem.top) - DY_TTBITMAP) / 2;
  1284. BitBlt(hDC, lpdis->rcItem.left, lpdis->rcItem.top + dy,
  1285. DX_TTBITMAP, DY_TTBITMAP, hdcMem, 0,
  1286. lpdis->itemState & ODS_SELECTED ? 0 : DY_TTBITMAP, SRCCOPY);
  1287. if (hOld)
  1288. SelectObject(hdcMem, hOld);
  1289. DeleteDC(hdcMem);
  1290. }
  1291. }
  1292. }
  1293. SetTextColor(hDC, rgbText);
  1294. SetBkColor(hDC, rgbBack);
  1295. if (lpdis->itemState & ODS_FOCUS) {
  1296. DrawFocusRect(hDC, &lpdis->rcItem);
  1297. }
  1298. }
  1299. }
  1300. #undef lpsz
  1301. #undef pTabs
  1302. /** MeasureItemFontList
  1303. *
  1304. * Answer the WM_MEASUREITEM message sent from the font list box or
  1305. * font combo box. shared between the toolbar combo box code and
  1306. * the font preview property sheet
  1307. *
  1308. * Entry:
  1309. * lpmi -> LPMEASUREITEMSTRUCT describing object to be measured
  1310. *
  1311. * Returns:
  1312. * TRUE.
  1313. *
  1314. * lpmi->itemHeight filled with actual item height.
  1315. */
  1316. LONG WINAPI MeasureItemFontList(LPMEASUREITEMSTRUCT lpmi)
  1317. {
  1318. lpmi->itemHeight = dyItem;
  1319. return TRUE;
  1320. }
  1321. /** GetItemFontInfo
  1322. *
  1323. * Returns font information for the current selection in the given
  1324. * listbox/combobox.
  1325. *
  1326. * Entry:
  1327. * hwndList == handle to listbox or combo box to fill
  1328. * if NULL, then AUTO is assumed
  1329. * fListBox == TRUE if hwndList is a listbox, FALSE if a combo box
  1330. * hProps == property handle
  1331. * lpFnt -> PROPFNT structure (filled in upon return)
  1332. *
  1333. * Returns:
  1334. * LB_ERR/CB_ERR on error, index of current selection otherwise
  1335. */
  1336. int WINAPI GetItemFontInfo(HWND hwndList, BOOL fListBox, HANDLE hProps, LPPROPFNT lpFnt)
  1337. {
  1338. DWORD_PTR dw;
  1339. int index;
  1340. /*
  1341. * Get font defaults; the nice thing about this call is that
  1342. * it also takes care of calling ChooseBestFont if AUTOSIZE is set,
  1343. * which means we can tell GetFont() to not bother.
  1344. */
  1345. PifMgr_GetProperties(hProps, MAKELP(0,GROUP_FNT),
  1346. lpFnt, sizeof(PROPFNT), GETPROPS_NONE);
  1347. dw = GetFont(hwndList, fListBox, NULL);
  1348. if (IsSpecialBpfdi((BPFDI)dw))
  1349. {
  1350. return 0;
  1351. }
  1352. index = ((BPFDI)dw)->Index;
  1353. if (index == 0)
  1354. lpFnt->flFnt |= FNT_AUTOSIZE;
  1355. else if (index > 0)
  1356. lpFnt->flFnt &= ~FNT_AUTOSIZE;
  1357. /*
  1358. * Fill the caller's PROPFNT structure with all the font goodies (if any)
  1359. *
  1360. * Note that this does nothing if we ended up picking the AUTO font.
  1361. */
  1362. SetFont(lpFnt, (BPFDI)dw);
  1363. return index;
  1364. }
  1365. /** MatchCurrentFont
  1366. *
  1367. * Locates the current font in the indicated list box and
  1368. * makes him the current selection.
  1369. *
  1370. * If we are in auto-mode, then "Auto" is selected.
  1371. *
  1372. * Entry:
  1373. * hwndList == handle to listbox or combo box
  1374. * fListBox == TRUE if hwndList is a listbox, FALSE if a combo box
  1375. * lpFnt -> PROPFNT structure
  1376. *
  1377. * Returns:
  1378. * TRUE if the current font was found and selected.
  1379. */
  1380. BOOL WINAPI MatchCurrentFont(HWND hwndList, BOOL fListBox, LPPROPFNT lpFnt)
  1381. {
  1382. BPFDI bpfdi;
  1383. DWORD dwCount, dwIndex;
  1384. BOOL fCurFontIsTt = !!(lpFnt->flFnt & FNT_TT);
  1385. if (lpFnt->flFnt & FNT_AUTOSIZE) {
  1386. /*
  1387. * SORTING-SENSITIVE! This assumes that "Auto" is at the top
  1388. * of the list.
  1389. */
  1390. lcbSetCurSel(hwndList, fListBox, 0);
  1391. return TRUE;
  1392. }
  1393. dwCount = lcbGetCount(hwndList, fListBox);
  1394. for (dwIndex = 0; dwIndex < dwCount; dwIndex++) {
  1395. bpfdi = lcbGetBpfdi(hwndList, fListBox, dwIndex);
  1396. if (!IsSpecialBpfdi(bpfdi)) {
  1397. // bpfdi = (BPFDI)((DWORD)bpfdi + (DWORD)lpCache);
  1398. if (bpfdi->fdiWidthActual == lpFnt->cxFontActual &&
  1399. bpfdi->fdiHeightActual == lpFnt->cyFontActual &&
  1400. fCurFontIsTt == (bpfdi->fdiHeightReq != 0)) {
  1401. lcbSetCurSel(hwndList, fListBox, dwIndex);
  1402. return TRUE;
  1403. }
  1404. }
  1405. }
  1406. return FALSE;
  1407. }
  1408. /** AddRasterFontsToFontList
  1409. *
  1410. * Enumerate the available dimensions for our OEM raster font
  1411. * and add them to the list or combo box.
  1412. *
  1413. * Entry:
  1414. * hwndList = List box or combo box to fill with info
  1415. * fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
  1416. * lpszRasterFaceName
  1417. *
  1418. * Returns:
  1419. * TRUE if fonts were enumerated to completion.
  1420. * FALSE if enumeration failed. (Out of memory.)
  1421. *
  1422. */
  1423. BOOL AddRasterFontsToFontListA(HWND hwndList, BOOL fListBox,
  1424. LPCSTR lpszRasterFaceName, INT CodePage)
  1425. {
  1426. HDC hDC;
  1427. BOOL fSuccess;
  1428. FNTENUMINFO FntEnum;
  1429. hDC = GetDC(hwndList);
  1430. if (!hDC) return FALSE;
  1431. FntEnum.hwndList = hwndList;
  1432. FntEnum.fListBox = fListBox;
  1433. FntEnum.CodePage = CodePage;
  1434. fSuccess = EnumFontFamiliesA(hDC,
  1435. lpszRasterFaceName,
  1436. (FONTENUMPROCA)RasterFontEnum,
  1437. (LPARAM)&FntEnum);
  1438. ReleaseDC(hwndList, hDC);
  1439. return TRUE;
  1440. }
  1441. /** RasterFontEnum
  1442. *
  1443. * FONTENUMPROC for enumerating all available dimensions of the OEM
  1444. * raster font.
  1445. *
  1446. * This routine is used to load the logical and physical font
  1447. * dimensions cache with information about raster fonts.
  1448. *
  1449. * Entry:
  1450. * lpelf \
  1451. * lpntm > from EnumFonts (see SDK)
  1452. * nFontType /
  1453. * hwndList = List box or combo box to fill with info
  1454. * fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
  1455. *
  1456. * Returns:
  1457. * TRUE to continue enumeration.
  1458. * FALSE to stop enumeration. (Out of memory.)
  1459. */
  1460. int CALLBACK RasterFontEnum(ENUMLOGFONTA *lpelf, NEWTEXTMETRICA *lpntm, int nFontType, LPARAM lParam)
  1461. {
  1462. #define fListBox (((LPFNTENUMINFO)lParam)->fListBox)
  1463. #define hwndList (((LPFNTENUMINFO)lParam)->hwndList)
  1464. #define CodePage (((LPFNTENUMINFO)lParam)->CodePage)
  1465. #define lpLogFont (&(lpelf->elfLogFont))
  1466. /*
  1467. * We only care about OEM fixed-pitch fonts.
  1468. */
  1469. if (lpLogFont->lfCharSet != OEMCharsetFromCP(CodePage)
  1470. || (lpLogFont->lfPitchAndFamily & (TMPF_TRUETYPE | TMPF_FIXED_PITCH))
  1471. != TMPF_FIXED_PITCH)
  1472. return TRUE;
  1473. return AddToFontListCache(hwndList,
  1474. fListBox,
  1475. 0, 0,
  1476. lpLogFont->lfHeight,
  1477. lpLogFont->lfWidth,
  1478. CodePage) != BPFDI_CANCEL;
  1479. #undef lpLogFont
  1480. #undef fListBox
  1481. #undef hwndList
  1482. #undef CodePage
  1483. }
  1484. /** AddToFontListCache
  1485. *
  1486. * Adds an entry to the font dimension information cache,
  1487. * growing the cache if necessary.
  1488. *
  1489. * It also adds the entry to the indicated list box, provided
  1490. * the entry is not a duplicate.
  1491. *
  1492. * Returns:
  1493. * BPFDI of the recently-added font, or BPFDI_CANCEL if out of memory.
  1494. *
  1495. * Overview:
  1496. * (1) Grow the cache if necessary.
  1497. * (2) Add the information to the list/combo box.
  1498. * (3) Add the information to the cache.
  1499. */
  1500. BPFDI AddToFontListCache(HWND hwndList,
  1501. BOOL fListBox,
  1502. UINT uHeightReq,
  1503. UINT uWidthReq,
  1504. UINT uHeightActual,
  1505. UINT uWidthActual,
  1506. UINT uCodePage)
  1507. {
  1508. LPVOID hCache;
  1509. LONG_PTR lCacheSave;
  1510. DWORD dwIndex, ifdi;
  1511. BPFDI bpfdi;
  1512. TCHAR szBuf[MAXDIMENSTRING];
  1513. int idx;
  1514. ASSERT(!((uHeightReq==0) && (uWidthReq==0) && (uHeightActual==0) && (uWidthActual==0)));
  1515. /* Reject too-large fonts out of hand. */
  1516. if (uHeightActual > MAX_FONT_HEIGHT) {
  1517. return BPFDI_IGNORE;
  1518. }
  1519. /*
  1520. * FIRST, determine whether this font entry has already been cached
  1521. */
  1522. // we maintain two set of cache entries in case we have two code page
  1523. // to support
  1524. //
  1525. idx = IsBilingualCP(uCodePage) ? 1 : 0;
  1526. for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache + bpfdiStart[idx]); ifdi < cfdiCache[idx]; ++ifdi, ++bpfdi)
  1527. {
  1528. if (bpfdi->fdiWidthReq == uWidthReq &&
  1529. bpfdi->fdiHeightReq == uHeightReq &&
  1530. bpfdi->fdiWidthActual == uWidthActual &&
  1531. bpfdi->fdiHeightActual == uHeightActual)
  1532. goto UpdateListCombo;
  1533. }
  1534. /*
  1535. * Grow the cache if necessary.
  1536. */
  1537. if (cfdiCache[idx] >= cfdiCacheActual[idx]) {
  1538. /*
  1539. * save offset from beginning of cache
  1540. */
  1541. bpfdi = (BPFDI)((DWORD_PTR)bpfdi - (DWORD_PTR)lpCache);
  1542. /*
  1543. * save current lpCache value so can adjust entries in listbox
  1544. * when we're done...
  1545. */
  1546. lCacheSave = (LONG_PTR)lpCache;
  1547. hCache = LocalReAlloc(lpCache,
  1548. (cfdiCacheActual[0] + cfdiCacheActual[1] + FDI_TABLE_INC) *
  1549. sizeof(FONTDIMENINFO), LMEM_ZEROINIT|LMEM_MOVEABLE);
  1550. if (!hCache)
  1551. return BPFDI_CANCEL;
  1552. lpCache = hCache;
  1553. if (!idx && IsBilingualCP(g_uCodePage)) {
  1554. /*
  1555. * We need to shift 2nd cache before using expanded 1st chache
  1556. */
  1557. BPFDI bpfdi2;
  1558. for (ifdi = cfdiCache[1],
  1559. bpfdi2 = (BPFDI)((DWORD_PTR)lpCache + bpfdiStart[1]) + ifdi - 1 + FDI_TABLE_INC ;
  1560. ifdi ; ifdi--, bpfdi2--) {
  1561. *bpfdi2 = *(bpfdi2 - FDI_TABLE_INC);
  1562. }
  1563. bpfdiStart[1] += FDI_TABLE_INC;
  1564. }
  1565. /* restore bpfdi from saved offset */
  1566. bpfdi = (BPFDI)((DWORD_PTR)lpCache + (DWORD_PTR)bpfdi);
  1567. cfdiCacheActual[idx] += FDI_TABLE_INC;
  1568. /*
  1569. * Convert lCacheSave to an offset...
  1570. */
  1571. lCacheSave = (LONG_PTR)lpCache - lCacheSave;
  1572. if (lCacheSave)
  1573. {
  1574. /*
  1575. * Now, adjust each entry in the listbox to account for the new
  1576. * relocated cache position..
  1577. */
  1578. dwIndex = lcbGetCount(hwndList, fListBox);
  1579. for(ifdi = 0; ifdi < dwIndex; ifdi++)
  1580. {
  1581. LONG_PTR lBpfdi;
  1582. lBpfdi = (LONG_PTR)lcbGetItemDataPair(hwndList, fListBox, ifdi);
  1583. if (!IsSpecialBpfdi((BPFDI)lBpfdi))
  1584. {
  1585. lBpfdi += lCacheSave;
  1586. lcbSetItemDataPair(hwndList, fListBox, ifdi, lBpfdi, ((BPFDI)lBpfdi)->bTT);
  1587. }
  1588. }
  1589. }
  1590. }
  1591. /*
  1592. * Now add the information to the cache. All the casting on bpfdiCache
  1593. * is just to inhibit a bogus compiler complaint.
  1594. */
  1595. bpfdi->fdiWidthReq = uWidthReq;
  1596. bpfdi->fdiHeightReq = uHeightReq;
  1597. bpfdi->fdiWidthActual = uWidthActual;
  1598. bpfdi->fdiHeightActual = uHeightActual;
  1599. cfdiCache[idx]++;
  1600. UpdateListCombo:
  1601. if (hwndList) {
  1602. /*
  1603. * Add the string to the list/combo box if it isn't there already.
  1604. */
  1605. wsprintf(szBuf, TEXT("\t%2d\tx\t%2d"), uWidthActual, uHeightActual);
  1606. dwIndex = lcbFindStringExact(hwndList, fListBox, szBuf);
  1607. if (IsDlgError(dwIndex)) {
  1608. /*
  1609. * Not already on the list. Add it.
  1610. */
  1611. dwIndex = lcbAddString(hwndList, fListBox, szBuf);
  1612. if (IsDlgError(dwIndex)) {
  1613. return BPFDI_CANCEL;
  1614. }
  1615. lcbSetItemDataPair(hwndList, fListBox, dwIndex,
  1616. bpfdi, uHeightReq);
  1617. }
  1618. }
  1619. return bpfdi;
  1620. }
  1621. /** AddTrueTypeFontsToFontListA
  1622. *
  1623. * To avoid rasterizing all the fonts unnecessarily, we load the
  1624. * information from the szTTCacheSection font cache.
  1625. *
  1626. * Note that the cache information is not validated! We just
  1627. * assume that if the value is in the cache, it is valid.
  1628. *
  1629. * Entry:
  1630. * hwndList = List box or combo box to fill with info
  1631. * fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
  1632. * lpszTTFaceName
  1633. *
  1634. * Returns:
  1635. * TRUE if fonts were enumerated to completion.
  1636. * FALSE if enumeration failed. (Out of memory.)
  1637. *
  1638. * Caveats:
  1639. * The ParseIniWords call assumes that the values were written
  1640. * by AddOneNewTrueTypeFontToFontList, who wrote them out so
  1641. * that a single call to ParseIniWords will read the height and
  1642. * width directly into a dwHeightWidth.
  1643. *
  1644. * Similarly, the second ParseIniWords reads the item directly into
  1645. * a dwHeightWidth.
  1646. */
  1647. BOOL AddTrueTypeFontsToFontListA(HWND hwndList, BOOL fListBox,
  1648. LPSTR lpszTTFaceName, INT CodePage)
  1649. {
  1650. LPTSTR pszBuf;
  1651. LPTSTR pszBufNew;
  1652. LPTSTR psz;
  1653. LPTSTR lpszNext;
  1654. DWORD dwHWReq;
  1655. DWORD dwHWActual;
  1656. BOOL fSuccess;
  1657. DWORD cchBuf;
  1658. DWORD cchActual;
  1659. int i;
  1660. int idx = IsBilingualCP(CodePage) ? 1 : 0;
  1661. /*
  1662. * See if we can load everything out of the szTTCacheSection.
  1663. *
  1664. * There is no API to get the size of a profile string, so we
  1665. * have to fake it by reading, reallocing, and reading again
  1666. * until it all fits.
  1667. *
  1668. * The initial value of 1024 characters means that we can handle
  1669. * up to 128 font sizes. A comfortable number, we hope.
  1670. */
  1671. cchBuf = 1024;
  1672. cchActual = 0;
  1673. pszBufNew = (LPTSTR)LocalAlloc(LPTR, cchBuf*sizeof(TCHAR));
  1674. while (pszBufNew) {
  1675. pszBuf = pszBufNew;
  1676. cchActual = GetPrivateProfileString(szTTCacheSection[idx], NULL,
  1677. c_szNULL, pszBuf, cchBuf, szSystemINI);
  1678. if (cchActual < cchBuf - 5) goto Okay;
  1679. cchBuf += 512;
  1680. pszBufNew = (LPTSTR)LocalReAlloc(pszBuf, cchBuf*sizeof(TCHAR), LMEM_MOVEABLE|LMEM_ZEROINIT);
  1681. }
  1682. /* Bleargh. Too much stuff in the cache. Punt it and start anew. */
  1683. goto FreshStart;
  1684. Okay:
  1685. fSuccess = FALSE;
  1686. /*
  1687. * In the time between flushing the cache and reloading it here,
  1688. * a handful of fonts may have gotten added to the cache due to
  1689. * WinOldAp trying to realize the font it got back. So consider the
  1690. * font cache decent if there are at least ten fonts in it.
  1691. */
  1692. if (cchActual >= 4 * 10) {
  1693. /*
  1694. * We found cache information. Party away.
  1695. */
  1696. psz = pszBuf;
  1697. while (*psz) {
  1698. if (ParseIniWords(psz, (PWORD)&dwHWReq, 2, &lpszNext) != 2 ||
  1699. GetIniWords(szTTCacheSection[idx], psz,
  1700. (PWORD)&dwHWActual, 2, szSystemINI) != 2) {
  1701. /* Font cache looks bogus. Start with a new one. */
  1702. goto FreshStart;
  1703. }
  1704. if (AddToFontListCache(hwndList, fListBox,
  1705. (UINT)HIWORD(dwHWReq),
  1706. (UINT)LOWORD(dwHWReq),
  1707. (UINT)HIWORD(dwHWActual),
  1708. (UINT)LOWORD(dwHWActual),
  1709. CodePage) == BPFDI_CANCEL)
  1710. goto E0;
  1711. psz = (LPTSTR)(lpszNext + 1); /* Skip past the NUL */
  1712. }
  1713. }
  1714. else
  1715. {
  1716. FreshStart:
  1717. /* Blast the old cache, just make sure we have a clean slate */
  1718. WritePrivateProfileString(szTTCacheSection[idx], NULL, NULL, szSystemINI);
  1719. /* No cache available. Need to build one. */
  1720. for (i = 0; i < NUMINITIALTTHEIGHTS; i++)
  1721. {
  1722. if (rgwInitialTtHeights[i])
  1723. {
  1724. AddOneNewTrueTypeFontToFontListA(hwndList, fListBox,
  1725. 0, (UINT)rgwInitialTtHeights[i],
  1726. lpszTTFaceName, CodePage);
  1727. }
  1728. }
  1729. }
  1730. fSuccess = TRUE;
  1731. E0:
  1732. EVAL(LocalFree(pszBuf) == NULL);
  1733. return fSuccess;
  1734. }
  1735. /* Given height and width, synthesize a TrueType font with those
  1736. * dimensions and record the actual font height and width in
  1737. * the persistent font cache, as well as a FDI.
  1738. *
  1739. * Entry:
  1740. * hwndList = List box or combo box to fill with info
  1741. * fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
  1742. * wHeight = Desired font height
  1743. * wWidth = Desired font width (can be zero for "default")
  1744. * lpszTTFaceName
  1745. *
  1746. * Returns:
  1747. * BPFDI of font dimension info, or BPFDI_CANCEL on failure.
  1748. *
  1749. * Caveats:
  1750. * The wsprintf assumes that the fdiWidthReq and
  1751. * fdiHeightReq fields appear in the indicated order,
  1752. * because the values will be read into a dwHeightWidth later.
  1753. *
  1754. * Similarly for the WriteIniWords.
  1755. */
  1756. BPFDI AddOneNewTrueTypeFontToFontListA(HWND hwndList,
  1757. BOOL fListBox,
  1758. UINT uWidth, UINT uHeight,
  1759. LPSTR lpszTTFaceName, INT CodePage)
  1760. {
  1761. BPFDI bpfdi;
  1762. HDC hDC;
  1763. HFONT hFont;
  1764. SIZE sSize;
  1765. HFONT hFontPrev;
  1766. DWORD dwHeightWidth;
  1767. TCHAR szBuf[MAXDIMENSTRING];
  1768. int idx;
  1769. BYTE bCharset;
  1770. DWORD fdwClipPrecision;
  1771. bpfdi = BPFDI_CANCEL;
  1772. hDC = GetDC(NULL); /* Get a screen DC */
  1773. if (!hDC) goto E0;
  1774. // choose charset, clip precision based on codepage
  1775. // 0xFE is a hack for japanese platform
  1776. //
  1777. bCharset = (CodePage == CP_JPN? 0xFE: OEMCharsetFromCP(CodePage));
  1778. if (CodePage == CP_US)
  1779. fdwClipPrecision = CLIP_DEFAULT_PRECIS|(g_uCodePage == CP_WANSUNG? CLIP_DFA_OVERRIDE: 0);
  1780. else
  1781. fdwClipPrecision = CLIP_DEFAULT_PRECIS;
  1782. hFont = CreateFontA((INT)uHeight, (INT)uWidth, 0, 0, 0, 0, 0, 0,
  1783. bCharset, OUT_TT_PRECIS,
  1784. fdwClipPrecision, 0, FIXED_PITCH | FF_DONTCARE, lpszTTFaceName);
  1785. if (!hFont) goto E1;
  1786. hFontPrev = SelectObject(hDC, hFont);
  1787. if (!hFontPrev) goto E2;
  1788. if (GetTextExtentPoint32(hDC, szZero, 1, &sSize))
  1789. {
  1790. dwHeightWidth = (sSize.cy << 16) | (sSize.cx & 0x00FF);
  1791. }
  1792. else
  1793. {
  1794. dwHeightWidth = 0;
  1795. }
  1796. if (!dwHeightWidth) goto E3;
  1797. if (IsBilingualCP(CodePage) && (HIWORD(dwHeightWidth)%2))
  1798. goto E3;
  1799. wsprintf(szBuf, TEXT("%d %d"), uWidth, uHeight);
  1800. idx = IsBilingualCP(CodePage) ? 0 : 1;
  1801. WriteIniWords(szTTCacheSection[idx], szBuf, (PWORD)&dwHeightWidth, 2, szSystemINI);
  1802. bpfdi = AddToFontListCache(hwndList, fListBox, uHeight, uWidth,
  1803. (UINT)sSize.cy, (UINT)sSize.cx,
  1804. CodePage);
  1805. E3: SelectObject(hDC, hFontPrev);
  1806. E2: DeleteObject(hFont);
  1807. E1: ReleaseDC(0, hDC);
  1808. E0: return bpfdi;
  1809. }
  1810. /* Returns the BPFDI corresponding to the currently selected font in
  1811. * the indicated list or combo box, or BPFDI_CANCEL on error.
  1812. *
  1813. * Entry:
  1814. * hwndList == handle to listbox or combo box to fill
  1815. * if NULL, then AUTO font calculation is assumed
  1816. * fListBox == TRUE if hwndList is a listbox, FALSE if a combo box
  1817. * pfi -> FNTINFO structure
  1818. * if pfi is NULL, then AUTO font calculation is ignored
  1819. * Returns:
  1820. * BPFDI of the current selection, or BPFDI_CANCEL on error.
  1821. */
  1822. DWORD_PTR GetFont(HWND hwndList, BOOL fListBox, PFNTINFO pfi)
  1823. {
  1824. DWORD dwIndex = 0;
  1825. BPFDI bpfdi = BPFDI_CANCEL;
  1826. if (!hwndList) { // just do AUTO calculations
  1827. if (!pfi)
  1828. goto Exit; // whoops, can't even do those
  1829. goto ChooseBest;
  1830. }
  1831. dwIndex = lcbGetCurSel(hwndList, fListBox);
  1832. if (!IsDlgError(dwIndex)) {
  1833. if (pfi)
  1834. pfi->fntProposed.flFnt &= ~FNT_AUTOSIZE;
  1835. bpfdi = lcbGetBpfdi(hwndList, fListBox, dwIndex);
  1836. if (bpfdi == BPFDI_AUTO && pfi) {
  1837. pfi->fntProposed.flFnt |= FNT_AUTOSIZE;
  1838. ChooseBest:
  1839. bpfdi = ChooseBestFont((UINT)pfi->winOriginal.cxCells,
  1840. (UINT)pfi->winOriginal.cyCells,
  1841. (UINT)pfi->winOriginal.cxClient,
  1842. (UINT)pfi->winOriginal.cyClient,
  1843. (UINT)pfi->fntProposed.flFnt,
  1844. (INT)pfi->fntProposed.wCurrentCP);
  1845. }
  1846. // Set the index of the current selection (HIWORD
  1847. // of the return code) to LB_ERR if there's an error
  1848. if (bpfdi == BPFDI_CANCEL)
  1849. dwIndex = (DWORD)LB_ERR;
  1850. }
  1851. Exit:
  1852. if (!IsSpecialBpfdi(bpfdi))
  1853. {
  1854. bpfdi->Index = dwIndex;
  1855. }
  1856. return (DWORD_PTR)bpfdi;
  1857. }
  1858. /* Copies data from the given BPFDI to the given PROPFNT structure.
  1859. *
  1860. * Entry:
  1861. * lpFnt = pointer to PROPFNT structure
  1862. * bpfdi = based pointer to a FONTDIMENINFO structure;
  1863. * if a special BPFDI_* constant, no font info is changed
  1864. * Returns:
  1865. * Nothing
  1866. */
  1867. void SetFont(LPPROPFNT lpFnt, BPFDI bpfdi)
  1868. {
  1869. if (!IsSpecialBpfdi(bpfdi))
  1870. {
  1871. lpFnt->flFnt &= ~(FNT_RASTER | FNT_TT);
  1872. if (bpfdi->fdiHeightReq == 0)
  1873. {
  1874. /* Raster font */
  1875. lpFnt->flFnt |= FNT_RASTER;
  1876. lpFnt->cxFont = lpFnt->cxFontActual = (WORD) bpfdi->fdiWidthActual;
  1877. lpFnt->cyFont = lpFnt->cyFontActual = (WORD) bpfdi->fdiHeightActual;
  1878. }
  1879. else
  1880. {
  1881. /* TrueType font */
  1882. lpFnt->flFnt |= FNT_TT;
  1883. lpFnt->cxFont = (WORD) bpfdi->fdiWidthReq;
  1884. lpFnt->cyFont = (WORD) bpfdi->fdiHeightReq;
  1885. lpFnt->cxFontActual = (WORD) bpfdi->fdiWidthActual;
  1886. lpFnt->cyFontActual = (WORD) bpfdi->fdiHeightActual;
  1887. }
  1888. }
  1889. }
  1890. /* Performs the following calculation in LONG arithmetic to avoid
  1891. * overflow:
  1892. * return = n1 * m / n2
  1893. * This can be used to make an aspect ration calculation where n1/n2
  1894. * is the aspect ratio and m is a known value. The return value will
  1895. * be the value that corresponds to m with the correct apsect ratio.
  1896. */
  1897. //
  1898. // <This is defined as a macro for Win32 >
  1899. //
  1900. /* Scales a point to be preview-sized instead of screen-sized.
  1901. * Depends on the global vars cxScreen and cyScreen established at init.
  1902. */
  1903. void AspectPoint(LPRECT lprcPreview, LPPOINT lppt)
  1904. {
  1905. lppt->x = AspectScale(lprcPreview->right, cxScreen, lppt->x);
  1906. lppt->y = AspectScale(lprcPreview->bottom, cyScreen, lppt->y);
  1907. }
  1908. /* AspectRect
  1909. *
  1910. * Scales a rectangle to be preview-sized instead of screen-sized.
  1911. * Depends on the global vars cxScreen and cyScreen established at init.
  1912. */
  1913. void AspectRect(LPRECT lprcPreview, LPRECT lprc)
  1914. {
  1915. AspectPoint(lprcPreview, &((LPPOINT)lprc)[0]); /* Upper left corner */
  1916. AspectPoint(lprcPreview, &((LPPOINT)lprc)[1]); /* Lower right corner */
  1917. }
  1918. /* Given a BPFDI, create a font that corresponds to it.
  1919. *
  1920. * Entry:
  1921. * bpfdi -> FDI describing the font we want to create
  1922. * pfi -> proposed font info structure
  1923. *
  1924. * Returns:
  1925. * HFONT that was created.
  1926. */
  1927. HFONT CreateFontFromBpfdi(BPFDI bpfdi, PFNTINFO pfi)
  1928. {
  1929. HFONT hf;
  1930. int fdwClipPrecision;
  1931. BYTE bT2Charset;
  1932. // a hack for japanese charset
  1933. bT2Charset = (pfi->fntProposed.wCurrentCP == CP_JPN?
  1934. 0xFE: OEMCharsetFromCP(pfi->fntProposed.wCurrentCP));
  1935. if (pfi->fntProposed.wCurrentCP == CP_US)
  1936. fdwClipPrecision = CLIP_DEFAULT_PRECIS|(g_uCodePage == CP_WANSUNG? CLIP_DFA_OVERRIDE: 0);
  1937. else
  1938. fdwClipPrecision = CLIP_DEFAULT_PRECIS;
  1939. if (bpfdi->fdiHeightReq == 0) {
  1940. /* Raster font */
  1941. hf = CreateFontA(bpfdi->fdiHeightActual, bpfdi->fdiWidthActual,
  1942. 0, 0, 0, 0, 0, 0, (BYTE)OEMCharsetFromCP(pfi->fntProposed.wCurrentCP),
  1943. OUT_RASTER_PRECIS, fdwClipPrecision,
  1944. 0, FIXED_PITCH | FF_DONTCARE, pfi->fntProposed.achRasterFaceName);
  1945. } else {
  1946. /* a TrueType font */
  1947. hf = CreateFontA(bpfdi->fdiHeightReq, bpfdi->fdiWidthReq,
  1948. 0, 0, 0, 0, 0, 0, (BYTE)bT2Charset, OUT_TT_PRECIS, fdwClipPrecision,
  1949. 0, FIXED_PITCH | FF_DONTCARE, pfi->fntProposed.achTTFaceName);
  1950. }
  1951. return hf;
  1952. }
  1953. /** FontSelInit
  1954. *
  1955. * Obtain the various font selection penalties from SYSTEM.INI
  1956. * and force the values into range.
  1957. *
  1958. * Entry:
  1959. * rgwInitialTtHeights contains default values for sizes.
  1960. *
  1961. * Exit:
  1962. * rgwInitialTtHeights contains actual values for sizes.
  1963. */
  1964. void FontSelInit(void)
  1965. {
  1966. GetIniWords(szNonWinSection, szTTInitialSizes,
  1967. rgwInitialTtHeights, sizeof(rgwInitialTtHeights)/sizeof(WORD), szSystemINI);
  1968. }
  1969. /* Convert logical dimensions for a TrueType font into physical
  1970. * dimensions. If possible, we get this information from the
  1971. * font dimension cache, but in the case where this is not possible,
  1972. * we synthesize the font and measure him directly.
  1973. *
  1974. * Entry:
  1975. * dxWidth = logical font width
  1976. * dyHeight = logical font height
  1977. *
  1978. * Returns:
  1979. * BPFDI pointing to dimension information, or BPFDI_CANCEL on failure.
  1980. */
  1981. BPFDI GetTrueTypeFontTrueDimensions(UINT dxWidth, UINT dyHeight, INT CodePage)
  1982. {
  1983. IFDI ifdi;
  1984. BPFDI bpfdi;
  1985. int idx = IsBilingualCP(CodePage)? 1 : 0;
  1986. for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache + bpfdiStart[idx]);
  1987. ifdi < cfdiCache[idx]; ifdi++, bpfdi++)
  1988. {
  1989. if (bpfdi->fdiWidthReq == dxWidth &&
  1990. bpfdi->fdiHeightReq == dyHeight) {
  1991. return bpfdi;
  1992. }
  1993. }
  1994. /*
  1995. * The font dimensions have not been cached. We have to create it.
  1996. */
  1997. return (BPFDI)AddOneNewTrueTypeFontToFontListA(0, 0, dxWidth, dyHeight,
  1998. szTTFaceName[idx], CodePage);
  1999. }
  2000. /* Look for a font that matches the indicated dimensions, creating
  2001. * one if necessary.
  2002. *
  2003. * But we never create a font which is too narrow or too short.
  2004. * The limits are controlled by the ptNonAspectMin variable.
  2005. *
  2006. * Entry:
  2007. * dxWidth = desired font width
  2008. * dyHeight = desired font height
  2009. * fPerfect = see below
  2010. *
  2011. * If fPerfect is TRUE, then a perfect match is requested
  2012. * from the font cache (we should not try to synthesize a font).
  2013. * In which case, the sign of dyHeight determines whether a
  2014. * raster font (positive) or TrueType font (negative) is
  2015. * desired. If a perfect match cannot be found, then we
  2016. * return BPFDI_CANCEL.
  2017. *
  2018. * Returns:
  2019. * BPFDI of of the font that matches the best.
  2020. * BPFDI_CANCEL if no font could be found.
  2021. */
  2022. BPFDI FindFontMatch(UINT dxWidth, UINT dyHeight, LPINT lpfl, INT CodePage)
  2023. {
  2024. IFDI ifdi;
  2025. BPFDI bpfdi;
  2026. BPFDI bpfdiBest = BPFDI_CANCEL;
  2027. PENALTY pnlBest = SENTINELPENALTY;
  2028. int idx;
  2029. int fl = *lpfl;
  2030. /*
  2031. * First, see if a perfect match already exists.
  2032. */
  2033. idx = IsBilingualCP(CodePage) ? 1 : 0;
  2034. for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache+bpfdiStart[idx]);
  2035. ifdi < cfdiCache[idx]; ifdi++, bpfdi++)
  2036. {
  2037. if (fl & FFM_RESTRICTED) {
  2038. /* Deal with the restrictions.
  2039. * Reject the font if it is raster but we want TTONLY, or v.v.
  2040. *
  2041. * The condition below reads as
  2042. *
  2043. * If (is a raster font != want a raster font)
  2044. */
  2045. if (!bpfdi->fdiHeightReq != (fl == FFM_RASTERFONTS)) {
  2046. continue;
  2047. }
  2048. }
  2049. if (bpfdi->fdiHeightActual == dyHeight && bpfdi->fdiWidthActual == dxWidth) {
  2050. *lpfl = FFM_PERFECT;
  2051. return bpfdi;
  2052. } }
  2053. if (fl != FFM_TTFONTS)
  2054. return BPFDI_CANCEL;
  2055. /*
  2056. * We got here if we couldn't find a perfect match.
  2057. *
  2058. * Adjust the requested height and width for aspect ratio
  2059. * constraints. If adjustments are necessary, trust the height.
  2060. *
  2061. * Comparisons are as WORDs (unsigned) so that a setting of "-1 -1"
  2062. * lets the user forbid all non-aspect ratio fonts.
  2063. */
  2064. if (dyHeight < (UINT)ptNonAspectMin.y || dxWidth < (UINT)ptNonAspectMin.x) {
  2065. dxWidth = 0;
  2066. }
  2067. return GetTrueTypeFontTrueDimensions(dxWidth, dyHeight, CodePage);
  2068. }
  2069. /* We have decided whether the desired size is larger or smaller.
  2070. * Compute the penalty corresponding to the Initial and Scale.
  2071. *
  2072. * Entry:
  2073. * ppnlp -> PENALTYPAIR to apply
  2074. * dSmaller = the smaller dimension
  2075. * dLarger = the larger dimension
  2076. *
  2077. * Exit:
  2078. * Returns penalty to apply to the difference in dimensions.
  2079. */
  2080. PENALTY ComputePenaltyFromPair(PPENALTYPAIR ppnlp,
  2081. UINT dSmaller, UINT dLarger)
  2082. {
  2083. return (ppnlp->pnlInitial +
  2084. ppnlp->pnlScale - MulDiv(ppnlp->pnlScale, dSmaller, dLarger));
  2085. }
  2086. /* Compute the penalty depending on whether the desired size
  2087. * is smaller, equal to, or larger than the actual size.
  2088. *
  2089. * Entry:
  2090. * ppnll -> PENALTYLIST to apply
  2091. * dActual = the actual dimension
  2092. * dDesired = the desired dimension
  2093. *
  2094. * Exit:
  2095. * Returns penalty to apply to the difference in dimensions,
  2096. * choosing between the Overshoot and Shortfall PENALTYPAIRS,
  2097. * accordingly.
  2098. */
  2099. PENALTY ComputePenaltyFromList(PPENALTYLIST ppnll,
  2100. UINT dActual, UINT dDesired)
  2101. {
  2102. if (dActual == dDesired)
  2103. return 0;
  2104. if (dActual < dDesired)
  2105. return ComputePenaltyFromPair(&ppnll->pnlpOvershoot, dActual, dDesired);
  2106. return ComputePenaltyFromPair(&ppnll->pnlpShortfall, dDesired, dActual);
  2107. }
  2108. /** ComputePenalty
  2109. *
  2110. * Compute the total penalty associated to a window size.
  2111. *
  2112. * Entry:
  2113. * dxCells = width of window in cells
  2114. * dyCells = height of window in cells
  2115. * dxClient = actual horizontal size of window
  2116. * dyClient = actual vertical size of window
  2117. * dxFont = width of one character in the font
  2118. * dyFont = height of one character in the font
  2119. *
  2120. * Exit:
  2121. * Returns total penalty associated to a window of the indicated
  2122. * size with a font of the indicated dimensions.
  2123. */
  2124. PENALTY ComputePenalty(UINT cxCells, UINT cyCells,
  2125. UINT dxClient, UINT dyClient,
  2126. UINT dxFont, UINT dyFont)
  2127. {
  2128. return
  2129. (ComputePenaltyFromList(&pnllX, dxClient, dxFont * cxCells) +
  2130. ComputePenaltyFromList(&pnllY, dyClient, dyFont * cyCells));
  2131. }
  2132. /** ChooseBestFont
  2133. *
  2134. * Determine which font looks best for the specified window size
  2135. * by picking the one which has the smallest penalty.
  2136. *
  2137. * Entry:
  2138. * dxCells = width of window in cells
  2139. * dyCells = height of window in cells
  2140. * dxClient= width of window we want to fit into
  2141. * dyClient= height of window we want to fit into
  2142. * fl = font pool flags
  2143. *
  2144. * Returns:
  2145. * Word offset from lpFontTable of the font we've decided to use.
  2146. * BPFDI_CANCEL if no font could be found. (Should never happen.)
  2147. *
  2148. * NOTE!
  2149. * We do *not* FontEnum through all the fonts because that would be
  2150. * too slow. Instead, we inspect the cache of available font
  2151. * dimensions, and only after we've chosen the best font do we
  2152. * load all his other info.
  2153. *
  2154. * This means that if the user installs new fonts, we won't see
  2155. * them until the cache is updated on receipt of a WM_FONTCHANGEff
  2156. * message, or the user either (1) pulls down the font list box,
  2157. * or (2) calls up the font selection dialog box.
  2158. */
  2159. BPFDI ChooseBestFont(UINT cxCells, UINT cyCells, UINT dxClient, UINT dyClient,
  2160. INT fl, INT CodePage)
  2161. {
  2162. int flTemp;
  2163. DWORD ifdi;
  2164. BPFDI bpfdi;
  2165. PENALTY pnl;
  2166. UINT dxWidth, dyHeight;
  2167. BPFDI bpfdiBest = BPFDI_CANCEL;
  2168. PENALTY pnlBest = SENTINELPENALTY;
  2169. int idx;
  2170. static int prev_CodePage; // Only Japan is interested in prev_CodePage.
  2171. /*
  2172. * First, synthesize the theoretical best match.
  2173. */
  2174. if (!cxCells)
  2175. cxCells = 80; // if we get called with no real data,
  2176. if (!cyCells) // at least try to do something reasonable
  2177. cyCells = 25;
  2178. //
  2179. // In the case where the values passed in don't make sense,
  2180. // we default to raster 8x12.
  2181. //
  2182. dxWidth = (dxClient >= cxCells)? dxClient / cxCells : 8;
  2183. dyHeight = (dyClient >= cyCells)? dyClient / cyCells : 12;
  2184. //
  2185. // Now, if we bad values, make some sense out of bad values for
  2186. // dxClient & dyClient
  2187. //
  2188. if ((dxClient==0) || (dyClient==0))
  2189. {
  2190. dxClient = dxWidth * 80;
  2191. dyClient = dyHeight * 25;
  2192. }
  2193. flTemp = 0;
  2194. if ((fl & FNT_BOTHFONTS) != FNT_BOTHFONTS) {
  2195. flTemp = FFM_RASTERFONTS;
  2196. if (fl & FNT_TTFONTS)
  2197. flTemp = FFM_TTFONTS;
  2198. }
  2199. bpfdi = FindFontMatch(dxWidth, dyHeight, &flTemp, CodePage);
  2200. if (flTemp == FFM_PERFECT)
  2201. {
  2202. prev_CodePage = CodePage;
  2203. return bpfdi;
  2204. }
  2205. idx = IsBilingualCP(CodePage)? 1 : 0;
  2206. for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache+bpfdiStart[idx]);
  2207. ifdi < cfdiCache[idx]; ifdi++, bpfdi++)
  2208. {
  2209. // If the font pool is restricted, then only look at like fonts
  2210. if (flTemp)
  2211. if (!bpfdi->fdiHeightReq != (flTemp == FFM_RASTERFONTS))
  2212. continue;
  2213. // was ifdef JAPAN (hack)
  2214. // to prevent DOS_BOX shrinking which occurs toggling CP437 & CP932,
  2215. // just select one size bigger font when change CP437 to CP932
  2216. if (CodePage == 932 && prev_CodePage == 437) {
  2217. if (dxWidth < bpfdi->fdiWidthActual) {
  2218. if (bpfdiBest->fdiWidthActual > bpfdi->fdiWidthActual)
  2219. bpfdiBest = bpfdi;
  2220. else if (bpfdiBest->fdiWidthActual == bpfdi->fdiWidthActual &&
  2221. bpfdiBest->fdiHeightActual > bpfdi->fdiHeightActual)
  2222. bpfdiBest = bpfdi;
  2223. }
  2224. else {
  2225. if (dxWidth == bpfdi->fdiWidthActual) {
  2226. if (bpfdi->fdiHeightActual > dyHeight &&
  2227. bpfdiBest->fdiHeightActual > bpfdi->fdiHeightActual)
  2228. bpfdiBest = bpfdi;
  2229. }
  2230. }
  2231. }
  2232. else
  2233. // was the end of ifdef JAPAN
  2234. {
  2235. pnl = 0;
  2236. if (bpfdi->fdiHeightReq)
  2237. pnl = pnlTrueType;
  2238. pnl += ComputePenalty(cxCells, cyCells,
  2239. dxClient, dyClient,
  2240. bpfdi->fdiWidthActual,
  2241. bpfdi->fdiHeightActual);
  2242. if (pnl <= pnlBest) {
  2243. pnlBest = pnl;
  2244. bpfdiBest = bpfdi;
  2245. }
  2246. }
  2247. }
  2248. // was ifdef JAPAN
  2249. prev_CodePage = CodePage;
  2250. // was end of ifdef JAPAN
  2251. return bpfdiBest;
  2252. }