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

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