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.
2569 lines
79 KiB
2569 lines
79 KiB
/*
|
|
* Microsoft Confidential
|
|
* Copyright (C) Microsoft Corporation 1991
|
|
* All Rights Reserved.
|
|
*
|
|
*
|
|
* PIFFNT.C
|
|
* User interface dialogs for GROUP_FNT
|
|
*
|
|
* History:
|
|
* Created 04-Jan-1993 1:10pm by Jeff Parsons
|
|
* Changed 05-May-1993 5:10pm by Raymond Chen -- New Chicago-look preview
|
|
* Changed 12-Aug-1993 4:14pm by Raymond Chen -- Remove font inc and dec
|
|
*
|
|
* All font dialog code taken from font*.c in vmdosapp, 01-Apr-93
|
|
*/
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef _X86_
|
|
|
|
#define REGSTR_MSDOSEMU_DISPLAYPARAMS TEXT("DisplayParams")
|
|
|
|
#define REGSTR_PATH_MSDOSEMU "Software\\Microsoft\\Windows\\CurrentVersion\\MS-DOS Emulation"
|
|
|
|
const TCHAR szWndPreviewClass[] = TEXT("WOAWinPreview");
|
|
const TCHAR szFontPreviewClass[] = TEXT("WOAFontPreview");
|
|
|
|
// The preview strings for bilingual dosbox.
|
|
// We'll load this from our resource that will be properly
|
|
// localized. We'll give up if it fails and use above sample
|
|
// instead.
|
|
|
|
UINT cxScreen, cyScreen, dyChar, dyItem;
|
|
|
|
// Macro definitions that handle codepages
|
|
//
|
|
#define OEMCharsetFromCP(cp) \
|
|
((cp)==CP_JPN? SHIFTJIS_CHARSET : ((cp)==CP_WANSUNG? HANGEUL_CHARSET : OEM_CHARSET))
|
|
/*
|
|
* Font cache information. Note that this cache, being in PIFMGR,
|
|
* is now global, which will make support for per-VM font files/faces
|
|
* more problematic, if we even decide that's an interesting feature.
|
|
*
|
|
*/
|
|
DWORD bpfdiStart[2] = { 0 }; /* strage for the offset to cache */
|
|
UINT cfdiCache[2]; /* # used entries in fdi cache */
|
|
UINT cfdiCacheActual[2]; /* Total # entries in fdi cache */
|
|
LPVOID lpCache = NULL;
|
|
|
|
|
|
/*
|
|
* Owner-draw list box information.
|
|
*
|
|
*/
|
|
HBITMAP hbmFont; /* Handle to "TrueType" logo */
|
|
DWORD dwTimeCheck;
|
|
COLORREF clrChecksum;
|
|
|
|
HCURSOR hcursorWait;
|
|
|
|
#define MAXDIMENSTRING 80
|
|
|
|
/*
|
|
* Initial font heights for TT fonts
|
|
*
|
|
* This is read from an INI file, so it must remain writeable.
|
|
*
|
|
* We don't try generating TT fonts below 12pt by default because
|
|
* they just look crappy. Frosting setup will put a different
|
|
* table into place because Lucida Console looks good down to 4pt.
|
|
*
|
|
* On NT, Lucida Console is installed be default, though.
|
|
*
|
|
* The Frosting table is
|
|
* 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22
|
|
*/
|
|
WORD rgwInitialTtHeights[] = { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22 };
|
|
|
|
|
|
|
|
/*
|
|
* rgpnlPenalties -- Initialize penalty array to default values
|
|
*/
|
|
INT rgpnlPenalties[] =
|
|
{ 5000, 1000, 0, 1000, 5000, 1000, 0, 1000, 1 };
|
|
|
|
|
|
POINT ptNonAspectMin = { -1, -1 };
|
|
|
|
// Context-sensitive help ids
|
|
|
|
const static DWORD rgdwHelp[] = {
|
|
IDC_FONTGRP, IDH_COMM_GROUPBOX,
|
|
IDC_RASTERFONTS, IDH_DOS_AVAIL_FONTS,
|
|
IDC_TTFONTS, IDH_DOS_AVAIL_FONTS,
|
|
IDC_BOTHFONTS, IDH_DOS_AVAIL_FONTS,
|
|
IDC_FONTSIZELBL, IDH_DOS_FONT_SIZE,
|
|
IDC_FONTSIZE, IDH_DOS_FONT_SIZE,
|
|
IDC_WNDPREVIEWLBL, IDH_DOS_FONT_WINDOW_PREVIEW,
|
|
IDC_FONTPREVIEWLBL, IDH_DOS_FONT_FONT_PREVIEW,
|
|
IDC_WNDPREVIEW, IDH_DOS_FONT_WINDOW_PREVIEW,
|
|
IDC_FONTPREVIEW, IDH_DOS_FONT_FONT_PREVIEW,
|
|
IDC_REALMODEDISABLE, IDH_DOS_REALMODEPROPS,
|
|
0, 0
|
|
};
|
|
|
|
|
|
BOOL_PTR CALLBACK DlgFntProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PFNTINFO pfi = (PFNTINFO)GetWindowLongPtr(hDlg, DWLP_USER);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// allocate dialog instance data
|
|
if (NULL != (pfi = (PFNTINFO)LocalAlloc(LPTR, sizeof(FNTINFO))))
|
|
{
|
|
pfi->ppl = (PPROPLINK)((LPPROPSHEETPAGE)lParam)->lParam;
|
|
SetWindowLongPtr(hDlg, DWLP_USER, (LPARAM)pfi);
|
|
InitFntDlg(hDlg, pfi);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
EndDialog(hDlg, FALSE); // fail the dialog create
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
// free any allocations/resources inside the pfi first!
|
|
if (pfi)
|
|
{
|
|
if (pfi->hFontPreview)
|
|
{
|
|
DeleteObject(pfi->hFontPreview);
|
|
pfi->hFontPreview = NULL;
|
|
}
|
|
// ok, NOW we can free the pfi
|
|
EVAL(LocalFree(pfi) == NULL);
|
|
SetWindowLongPtr(hDlg, DWLP_USER, 0);
|
|
}
|
|
break;
|
|
|
|
HELP_CASES(rgdwHelp) // Handle help messages
|
|
|
|
case WM_COMMAND:
|
|
if (LOWORD(lParam) == 0)
|
|
break; // message not from a control
|
|
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_RASTERFONTS:
|
|
case IDC_TTFONTS:
|
|
case IDC_BOTHFONTS:
|
|
|
|
/*
|
|
* Rebuild the font list based on the user's selection of
|
|
* which fonts to include/exclude.
|
|
*/
|
|
pfi->fntProposed.flFnt &= ~FNT_BOTHFONTS;
|
|
pfi->fntProposed.flFnt |= FNTFLAGSFROMID(wParam);
|
|
CreateFontList(GetDlgItem(hDlg, IDC_FONTSIZE), TRUE, &pfi->fntProposed);
|
|
PreviewUpdate(GetDlgItem(hDlg, IDC_FONTSIZE), pfi);
|
|
|
|
if (HIWORD(wParam) == BN_CLICKED)
|
|
SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
|
|
|
|
return FALSE;
|
|
|
|
case IDC_FONTSIZE:
|
|
|
|
if (HIWORD(wParam) == LBN_SELCHANGE)
|
|
{
|
|
PreviewUpdate(GetDlgItem(hDlg, IDC_FONTSIZE), pfi);
|
|
SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
|
|
return TRUE;
|
|
}
|
|
if (HIWORD(wParam) == LBN_DBLCLK)
|
|
ApplyFntDlg(hDlg, pfi);
|
|
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR *)lParam)->code) {
|
|
case PSN_SETACTIVE:
|
|
AdjustRealModeControls(pfi->ppl, hDlg);
|
|
break;
|
|
|
|
case PSN_KILLACTIVE:
|
|
// This gives the current page a chance to validate itself
|
|
// SetWindowLong(hDlg, DWL_MSGRESULT, ValidFntDlg(hDlg, pfi));
|
|
break;
|
|
|
|
case PSN_APPLY:
|
|
// This happens on OK....
|
|
ApplyFntDlg(hDlg, pfi);
|
|
break;
|
|
|
|
case PSN_RESET:
|
|
// This happens on Cancel....
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* For WM_MEASUREITEM and WM_DRAWITEM, since there is only one
|
|
* owner-draw list box in the entire dialog box, we don't have
|
|
* to do a GetDlgItem to figure out who he is.
|
|
*/
|
|
|
|
case WM_MEASUREITEM:
|
|
// measure the owner draw listbox
|
|
MeasureItemFontList((LPMEASUREITEMSTRUCT)lParam);
|
|
break;
|
|
|
|
case WM_DRAWITEM:
|
|
DrawItemFontList(TRUE, (LPDRAWITEMSTRUCT)lParam);
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
UpdateTTBitmap();
|
|
break;
|
|
|
|
default:
|
|
return FALSE; // return 0 when not processing
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/** InitFntDlg
|
|
*
|
|
* Create the list of appropriate fonts.
|
|
*
|
|
* This routine is broken out of FontDlgProc because it chew
|
|
* up lots of stack for the message buffer, and we don't want to
|
|
* eat that much stack on every entry to FontDlgProc.
|
|
*
|
|
* Note that we must defer CreateFontList until WM_INITDIALOG
|
|
* time because it is not until then that we have a list box that
|
|
* we can shove the data into.
|
|
*/
|
|
|
|
void InitFntDlg(HWND hDlg, register PFNTINFO pfi)
|
|
{
|
|
HWND hwndList; /* The listbox of fonts */
|
|
PPROPLINK ppl = pfi->ppl;
|
|
WINDOWPLACEMENT wp;
|
|
|
|
ASSERTTRUE(ppl->iSig == PROP_SIG);
|
|
|
|
if (!PifMgr_GetProperties(ppl, MAKELP(0,GROUP_FNT),
|
|
&pfi->fntProposed, sizeof(pfi->fntProposed), GETPROPS_NONE)
|
|
||
|
|
!PifMgr_GetProperties(ppl, MAKELP(0,GROUP_WIN),
|
|
&pfi->winOriginal, sizeof(pfi->winOriginal), GETPROPS_NONE)) {
|
|
Warning(hDlg, IDS_QUERY_ERROR, MB_ICONEXCLAMATION | MB_OK);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Set up instance variables for the window preview window.
|
|
*/
|
|
|
|
/* Show preview maximized if window is maximized or restores to max'd.
|
|
* Also if it is open restored and has no scrollbars.
|
|
* (Determined by comparing the client window size against the cell
|
|
* size and font size.)
|
|
*/
|
|
|
|
pfi->fMax = FALSE;
|
|
|
|
/*
|
|
* Preload winOriginal with up-to-the-minute goodies, if we have
|
|
* them.
|
|
*/
|
|
|
|
#define HasScrollbars(z) \
|
|
(pfi->winOriginal.c##z##Cells * pfi->fntProposed.c##z##FontActual > \
|
|
pfi->winOriginal.c##z##Client)
|
|
|
|
if (ppl->hwndTty) {
|
|
wp.length = sizeof(WINDOWPLACEMENT);
|
|
VERIFYTRUE(GetWindowPlacement(ppl->hwndTty, &wp));
|
|
|
|
// Convert/Copy to 16-bit structure
|
|
pfi->winOriginal.wLength = (WORD)wp.length;
|
|
pfi->winOriginal.wShowFlags = (WORD)wp.flags;
|
|
pfi->winOriginal.wShowCmd = (WORD)wp.showCmd;
|
|
pfi->winOriginal.xMinimize = (WORD)wp.ptMinPosition.x;
|
|
pfi->winOriginal.yMinimize = (WORD)wp.ptMinPosition.y;
|
|
pfi->winOriginal.xMaximize = (WORD)wp.ptMaxPosition.x;
|
|
pfi->winOriginal.yMaximize = (WORD)wp.ptMaxPosition.y;
|
|
pfi->winOriginal.rcNormal.left = (WORD)wp.rcNormalPosition.left;
|
|
pfi->winOriginal.rcNormal.top = (WORD)wp.rcNormalPosition.top;
|
|
pfi->winOriginal.rcNormal.right = (WORD)wp.rcNormalPosition.right;
|
|
pfi->winOriginal.rcNormal.bottom = (WORD)wp.rcNormalPosition.bottom;
|
|
|
|
if (!IsIconic(ppl->hwndTty) &&
|
|
!HasScrollbars(x) && !HasScrollbars(y)) {
|
|
pfi->fMax = TRUE;
|
|
}
|
|
}
|
|
|
|
if ((pfi->winOriginal.wShowCmd == SW_SHOWMAXIMIZED) ||
|
|
(pfi->winOriginal.wShowFlags & WPF_RESTORETOMAXIMIZED)) {
|
|
pfi->fMax = TRUE;
|
|
}
|
|
|
|
if (pfi->winOriginal.wShowCmd == SW_SHOWMAXIMIZED) {
|
|
pfi->ptCorner.x = (LONG)pfi->winOriginal.xMaximize;
|
|
pfi->ptCorner.y = (LONG)pfi->winOriginal.yMaximize;
|
|
} else {
|
|
if (pfi->winOriginal.rcNormal.left==0)
|
|
{
|
|
pfi->ptCorner.x = -1;
|
|
}
|
|
else
|
|
{
|
|
pfi->ptCorner.x = (LONG)pfi->winOriginal.rcNormal.left;
|
|
}
|
|
pfi->ptCorner.y = (LONG)pfi->winOriginal.rcNormal.top;
|
|
}
|
|
|
|
/*
|
|
* First, check which fonts the user wants to see.
|
|
*
|
|
*/
|
|
CheckDlgButton(hDlg, IDFROMFNTFLAGS(pfi->fntProposed.flFnt), TRUE);
|
|
|
|
hwndList = GetDlgItem(hDlg, IDC_FONTSIZE);
|
|
// SendMessage(hwndList, WM_SETFONT, (WPARAM)GetStockObject(SYSTEM_FIXED_FONT), FALSE);
|
|
|
|
if (CreateFontList(hwndList, TRUE, &pfi->fntProposed) == LB_ERR) {
|
|
MemoryWarning(hDlg);
|
|
EndDialog(hDlg, PtrToLong(BPFDI_CANCEL)); /* Get out of the dialog */
|
|
return;
|
|
}
|
|
|
|
/* Initialize the preview windows */
|
|
PreviewInit(hDlg, pfi);
|
|
PreviewUpdate(GetDlgItem(hDlg, IDC_FONTSIZE), pfi);
|
|
}
|
|
|
|
|
|
void ApplyFntDlg(HWND hDlg, register PFNTINFO pfi)
|
|
{
|
|
PPROPLINK ppl = pfi->ppl;
|
|
|
|
ASSERTTRUE(ppl->iSig == PROP_SIG);
|
|
|
|
if (!PifMgr_SetProperties(ppl, MAKELP(0,GROUP_FNT),
|
|
&pfi->fntProposed, sizeof(pfi->fntProposed), SETPROPS_NONE))
|
|
Warning(hDlg, IDS_UPDATE_ERROR, MB_ICONEXCLAMATION | MB_OK);
|
|
else
|
|
if (ppl->hwndNotify) {
|
|
ppl->flProp |= PROP_NOTIFY;
|
|
PostMessage(ppl->hwndNotify, ppl->uMsgNotify, sizeof(pfi->fntProposed), (LPARAM)MAKELP(0,GROUP_FNT));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Retrieves the name of the font to use for true-type DOS box
|
|
* in a window given a registry tree root.
|
|
*
|
|
* Entry:
|
|
*
|
|
* hkRoot -> registry tree root to search
|
|
* pszFaceSbcs -> LF_FACESIZE buffer for SBCS font
|
|
* pszFaceDbcs -> LF_FACESIZE buffer for DBCS font (may be null)
|
|
*
|
|
* Exit:
|
|
*
|
|
* Buffers filled with new font names, or left unchanged if nothing
|
|
* found in registry.
|
|
*
|
|
*/
|
|
|
|
#define REGSTR_MSDOSEMU_FONT "Font"
|
|
#define REGSTR_MSDOSEMU_FONTDBCS "FontDBCS"
|
|
|
|
// assumes caller passes LF_FACESIZE buffers
|
|
void GetDosBoxTtFontsHkA(HKEY hkRoot, LPSTR pszFaceSbcs, LPSTR pszFaceDbcs)
|
|
{
|
|
static CHAR const szMsdosemu[] = REGSTR_PATH_MSDOSEMU;
|
|
HKEY hk;
|
|
DWORD cb;
|
|
|
|
if (RegOpenKeyExA(hkRoot, szMsdosemu, 0, KEY_READ, &hk) == ERROR_SUCCESS)
|
|
{
|
|
static CHAR const szFont[] = REGSTR_MSDOSEMU_FONT;
|
|
cb = LF_FACESIZE;
|
|
RegQueryValueExA(hk, szFont, 0, 0, (LPBYTE)pszFaceSbcs, &cb);
|
|
|
|
if (pszFaceDbcs)
|
|
{
|
|
static CHAR const szDbcsFont[] = REGSTR_MSDOSEMU_FONTDBCS;
|
|
cb = LF_FACESIZE;
|
|
RegQueryValueExA(hk, szDbcsFont, 0, 0, (LPBYTE)pszFaceDbcs, &cb);
|
|
}
|
|
RegCloseKey(hk);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Retrieves the name of the font to use for true-type DOS box
|
|
* in a window.
|
|
*
|
|
* This routine consults the appropriate registry keys.
|
|
*
|
|
* The DOS box font comes first from HKLM, to establish a
|
|
* machine-wide default, but can in turn be overridden by
|
|
* HKCU for each user to override.
|
|
*
|
|
* Entry:
|
|
*
|
|
* pszFaceSbcs -> LF_FACESIZE buffer for SBCS font
|
|
* pszFaceDbcs -> LF_FACESIZE buffer for DBCS font (may be null)
|
|
*
|
|
* Exit:
|
|
*
|
|
* Buffers filled with new font names, or left unchange if nothing
|
|
* found in registry.
|
|
*
|
|
*/
|
|
|
|
void CoolGetDosBoxTtFontsA(LPSTR pszFaceSbcs, LPSTR pszFaceDbcs)
|
|
{
|
|
GetDosBoxTtFontsHkA(HKEY_LOCAL_MACHINE, pszFaceSbcs, pszFaceDbcs);
|
|
GetDosBoxTtFontsHkA(HKEY_CURRENT_USER, pszFaceSbcs, pszFaceDbcs);
|
|
}
|
|
|
|
/** BroadcastFontChange
|
|
*
|
|
* HACK! for MS PowerPoint 4.0. These wallys, for some reason, will go
|
|
* off and eat up reams of CPU time if they receive a WM_FONTCHANGE
|
|
* message that was *posted*. But if the message is *sent*, they do
|
|
* the right thing. The puzzling thing is that they never call
|
|
* InSendMessage(), so how do they know? What's more, why do they care?
|
|
* This was true in 3.1 also. What's their problem?
|
|
*
|
|
* The problem is that sending a broadcast risks deadlock city; see the
|
|
* various hacks in winoldap for places where DDE broadcasting is bypassed.
|
|
* In addition, since BroadcastFontChange is also called during the WEP,
|
|
* multi-threaded apps will deadlock if we SendMessage back to a window
|
|
* on a different thread in the app, because Kernel takes a process
|
|
* critical section during DLL unload.
|
|
*
|
|
* So if PowerPig is running, we just don't tell anybody that we dorked
|
|
* with the fonts.
|
|
*
|
|
* Returns:
|
|
*
|
|
* None.
|
|
*
|
|
*/
|
|
|
|
void BroadcastFontChange(void)
|
|
{
|
|
if (!GetModuleHandle(szPP4)) {
|
|
PostMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0L);
|
|
}
|
|
}
|
|
|
|
/** LoadGlobalFontData
|
|
*
|
|
* Get the name of the DOS box raster font and load it.
|
|
*
|
|
* Get the name of the TT font. (CheckDisplayParameters needs this.)
|
|
*
|
|
* Check the display parameters.
|
|
*
|
|
* Initialize the fdi cache. The cache remains in GlobalLock'd
|
|
* memory throughout its lifetime. This is not a problem because
|
|
* we are guaranteed to be in protected mode.
|
|
*
|
|
* We also load things necessary for the font combo/list boxes.
|
|
*
|
|
* And compute the height of the owner-draw list box item.
|
|
*
|
|
* Returns:
|
|
*
|
|
* TRUE on success. In which case the FDI cache and hbmFont
|
|
* are ready to use.
|
|
*
|
|
* FALSE on failure. In which case there is insufficient memory
|
|
* to complete the operation.
|
|
*/
|
|
|
|
typedef void (WINAPI *LPFNGDBTF)(LPTSTR, LPTSTR); /* GetDosBoxTtFonts */
|
|
|
|
BOOL LoadGlobalFontData(void)
|
|
{
|
|
HDC hDC;
|
|
TEXTMETRIC tm;
|
|
TCHAR szBuffer[MAXPATHNAME];
|
|
|
|
cxScreen = GetSystemMetrics(SM_CXSCREEN);
|
|
cyScreen = GetSystemMetrics(SM_CYSCREEN);
|
|
|
|
/*
|
|
* Get the system char size and save it away for later use.
|
|
*/
|
|
hDC = GetDC(NULL);
|
|
SelectObject(hDC, GetStockObject(SYSTEM_FONT));
|
|
GetTextMetrics(hDC, &tm);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
dyChar = tm.tmHeight + tm.tmExternalLeading;
|
|
dyItem = max(tm.tmHeight, DY_TTBITMAP);
|
|
|
|
/*
|
|
* Chicago's AddFontResource looks in the FONTS directory first, which
|
|
* is great because it saves us the trouble of doing goofy disk access
|
|
* optimizations.
|
|
*/
|
|
GetPrivateProfileString(sz386EnhSection, szWOAFontKey,
|
|
c_szNULL, szBuffer, ARRAYSIZE(szBuffer), szSystemINI);
|
|
if (szBuffer[0] && AddFontResource(szBuffer)) {
|
|
BroadcastFontChange();
|
|
}
|
|
|
|
/*
|
|
* Add DBCS native font if it is present.
|
|
*/
|
|
GetPrivateProfileString(sz386EnhSection, szWOADBCSFontKey,
|
|
c_szNULL, szBuffer, ARRAYSIZE(szBuffer), szSystemINI);
|
|
if (szBuffer[0] && AddFontResource(szBuffer)) {
|
|
BroadcastFontChange();
|
|
}
|
|
|
|
/*
|
|
* Load default TT font name(s) and TT cache section names from resource
|
|
*/
|
|
LoadStringA(g_hinst, IDS_TTFACENAME_SBCS, szTTFaceName[0], ARRAYSIZE(szTTFaceName[0]));
|
|
LoadString(g_hinst,IDS_TTCACHESEC_SBCS, szTTCacheSection[0], ARRAYSIZE(szTTCacheSection[0]));
|
|
|
|
if (IsBilingualCP(g_uCodePage))
|
|
{
|
|
LoadStringA(g_hinst, IDS_TTFACENAME_DBCS, szTTFaceName[1], ARRAYSIZE(szTTFaceName[1]));
|
|
LoadString(g_hinst, IDS_TTCACHESEC_DBCS, szTTCacheSection[1], ARRAYSIZE(szTTCacheSection[1]));
|
|
}
|
|
|
|
CoolGetDosBoxTtFontsA(szTTFaceName[0], szTTFaceName[1]);
|
|
|
|
CheckDisplayParameters();
|
|
|
|
// alloc needed # of cache
|
|
//
|
|
lpCache = (LPVOID)LocalAlloc(LPTR,
|
|
FDI_TABLE_START * sizeof(FONTDIMENINFO) * (IsBilingualCP(g_uCodePage)? 2:1));
|
|
|
|
if (!lpCache)
|
|
return FALSE;
|
|
|
|
hcursorWait = LoadCursor(NULL, IDC_WAIT);
|
|
|
|
UpdateTTBitmap();
|
|
if (!hbmFont)
|
|
goto E0;
|
|
|
|
// set initial value of # of cache entries which depends on whether we have
|
|
// two codepage to handle
|
|
//
|
|
cfdiCacheActual[0] = FDI_TABLE_START;
|
|
|
|
if (IsBilingualCP(g_uCodePage))
|
|
{
|
|
cfdiCacheActual[1] = FDI_TABLE_START;
|
|
bpfdiStart[1] += FDI_TABLE_START;
|
|
}
|
|
|
|
FontSelInit();
|
|
|
|
return TRUE;
|
|
|
|
E0:
|
|
EVAL(LocalFree(lpCache) == NULL);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL LoadGlobalFontEditData()
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
// Set up the window preview class for piffnt.c
|
|
|
|
wc.style = 0L;
|
|
wc.lpfnWndProc = WndPreviewWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(PFNTINFO);
|
|
wc.hInstance = g_hinst;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = szWndPreviewClass;
|
|
|
|
// Don't go through RegisterClassD because we manually unregister
|
|
// this class ourselves.
|
|
if (!RealRegisterClass(&wc))
|
|
return FALSE;
|
|
|
|
// Set up the font preview class for piffnt.c
|
|
|
|
wc.style = 0L;
|
|
wc.lpfnWndProc = FontPreviewWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(PFNTINFO);
|
|
wc.hInstance = g_hinst;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = GetStockObject(BLACK_BRUSH);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = szFontPreviewClass;
|
|
|
|
// Don't go through RegisterClassD because we manually unregister
|
|
// this class ourselves.
|
|
if (!RealRegisterClass(&wc))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void FreeGlobalFontEditData()
|
|
{
|
|
UnregisterClass(szWndPreviewClass, g_hinst);
|
|
UnregisterClass(szFontPreviewClass, g_hinst);
|
|
}
|
|
|
|
|
|
/*
|
|
* Make sure that the display parameters have not changed, including
|
|
* the name of the TT font(s).
|
|
*
|
|
* If they have, we BLAST OUR CACHE since it is no longer any good.
|
|
*
|
|
* Entry:
|
|
* szTTFaceName contains the name of the TrueType font to use.
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*/
|
|
|
|
void CheckDisplayParameters(void)
|
|
{
|
|
HDC hIC;
|
|
HKEY hk;
|
|
DISPLAYPARAMETERS dpTrue, dpStored;
|
|
|
|
hIC = CreateIC(szDisplay, 0, 0, 0);
|
|
|
|
if (!hIC) {
|
|
/*
|
|
* If things are really screwy, stay conservative and assume
|
|
* that all is well.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
dpTrue.dpHorzSize = GetDeviceCaps(hIC, HORZSIZE);
|
|
dpTrue.dpVertSize = GetDeviceCaps(hIC, VERTSIZE);
|
|
dpTrue.dpHorzRes = GetDeviceCaps(hIC, HORZRES);
|
|
dpTrue.dpVertRes = GetDeviceCaps(hIC, VERTRES);
|
|
dpTrue.dpLogPixelsX = GetDeviceCaps(hIC, LOGPIXELSX);
|
|
dpTrue.dpLogPixelsY = GetDeviceCaps(hIC, LOGPIXELSY);
|
|
dpTrue.dpAspectX = GetDeviceCaps(hIC, ASPECTX);
|
|
dpTrue.dpAspectY = GetDeviceCaps(hIC, ASPECTY);
|
|
dpTrue.dpBitsPerPixel = GetDeviceCaps(hIC, BITSPIXEL);
|
|
DeleteDC(hIC);
|
|
|
|
/*
|
|
* Since szTTFaceName is pre-initialized to "Courier New" padded
|
|
* with nulls, we can rely on the garbage after the end of the
|
|
* string always to be the same, so that a pure memory comparison
|
|
* will work.
|
|
*/
|
|
MultiByteToWideChar(CP_ACP, 0, szTTFaceName[0], -1, dpTrue.szTTFace[0], ARRAYSIZE(dpTrue.szTTFace[0]));
|
|
if (IsBilingualCP(g_uCodePage))
|
|
MultiByteToWideChar(CP_ACP, 0, szTTFaceName[1], -1, dpTrue.szTTFace[1], ARRAYSIZE(dpTrue.szTTFace[1]));
|
|
|
|
/*
|
|
* We must store the dimension information in the registry because
|
|
* the install program for Omar Sharif Bridge will ERASE! your
|
|
* SYSTEM.INI if it contains a line greater than 78 characters.
|
|
* (I am not making this up. How could I?)
|
|
*/
|
|
|
|
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT(REGSTR_PATH_MSDOSEMU), 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hk, NULL) == 0) {
|
|
DWORD cb = sizeof(DISPLAYPARAMETERS);
|
|
if (SHQueryValueEx(hk, REGSTR_MSDOSEMU_DISPLAYPARAMS, 0, 0, (LPVOID)&dpStored, &cb) != 0 || cb != sizeof(DISPLAYPARAMETERS) || IsBufferDifferent(&dpTrue, &dpStored, sizeof(DISPLAYPARAMETERS))) {
|
|
/*
|
|
* Not much we can do if the write fails, so don't check.
|
|
*/
|
|
VERIFYTRUE(RegSetValueEx(hk, REGSTR_MSDOSEMU_DISPLAYPARAMS, 0, REG_BINARY, (LPVOID)&dpTrue, cb) == 0);
|
|
|
|
/* Blast the font dimension cache */
|
|
WritePrivateProfileString(szTTCacheSection[1], NULL, NULL, szSystemINI);
|
|
if (IsBilingualCP(g_uCodePage))
|
|
WritePrivateProfileString(szTTCacheSection[0], NULL, NULL, szSystemINI);
|
|
}
|
|
VERIFYTRUE(RegCloseKey(hk) == 0);
|
|
} else {
|
|
/*
|
|
* Couldn't access registry. Oh well.
|
|
*/
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* When the dialog box is created, we create the Window
|
|
* Preview child window, as well as the Font Preview window.
|
|
*
|
|
* The creation is deferred until the actual dialog box creation
|
|
* because the size and shape of the Window Preview window depends
|
|
* on the current video driver.
|
|
*/
|
|
|
|
void PreviewInit(HWND hDlg, PFNTINFO pfi)
|
|
{
|
|
HWND hwnd;
|
|
RECT rectLabel, rcPreview;
|
|
|
|
/*
|
|
* Compute the size of our preview window.
|
|
*
|
|
* The top is aligned with the top of IDC_WNDPREVIEWLBL,
|
|
* minus a top margin of 3/2 dyChar.
|
|
* The left edge is aligned with the left edge of IDC_WNDPREVIEWLBL.
|
|
* The maximum width is the width of IDC_WNDPREVIEWLBL.
|
|
* The bottom edge can go as far down as the bottom of the dialog,
|
|
* minus a bottom margin of 3/2 dyChar.
|
|
* And the shape of the preview window is determined by the screen
|
|
* dimensions.
|
|
*
|
|
* We make the preview window as large as possible, given these
|
|
* constraints.
|
|
*
|
|
*/
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_WNDPREVIEWLBL), &rectLabel);
|
|
ScreenToClient(hDlg, (LPPOINT)&rectLabel);
|
|
ScreenToClient(hDlg, (LPPOINT)&rectLabel.right);
|
|
|
|
/*
|
|
* This GetWindowRect/ScreenToClient sets rcPreview.top.
|
|
*/
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_WNDPREVIEWLBL), &rcPreview);
|
|
ScreenToClient(hDlg, (LPPOINT)&rcPreview);
|
|
|
|
/*
|
|
* Compute height based on width.
|
|
*/
|
|
rcPreview.top += 3 * dyChar / 2;
|
|
rcPreview.left = rectLabel.left;
|
|
rcPreview.right = rectLabel.right - rectLabel.left;
|
|
rcPreview.bottom = AspectScale(cyScreen, cxScreen, rcPreview.right);
|
|
|
|
/*
|
|
* Phew. Now we can create the preview window.
|
|
*/
|
|
hwnd = CreateWindowEx(
|
|
WS_EX_CLIENTEDGE,
|
|
szWndPreviewClass, NULL,
|
|
WS_CHILD | WS_VISIBLE,
|
|
rcPreview.left, rcPreview.top,
|
|
rcPreview.right, rcPreview.bottom,
|
|
hDlg, (HMENU)IDC_WNDPREVIEW, g_hinst, NULL);
|
|
|
|
if (hwnd)
|
|
SetWindowLongPtr(hwnd, 0, (LONG_PTR)pfi);
|
|
|
|
/*
|
|
* Compute the size of the font preview. This is easier.
|
|
*/
|
|
GetWindowRect(GetDlgItem(hDlg, IDC_FONTPREVIEWLBL), &rectLabel);
|
|
ScreenToClient(hDlg, (LPPOINT)&rectLabel.left);
|
|
ScreenToClient(hDlg, (LPPOINT)&rectLabel.right);
|
|
|
|
hwnd = CreateWindowEx(
|
|
WS_EX_CLIENTEDGE,
|
|
szFontPreviewClass, NULL,
|
|
WS_CHILD | WS_VISIBLE,
|
|
rectLabel.left,
|
|
rectLabel.top + 3 * dyChar / 2,
|
|
rectLabel.right - rectLabel.left,
|
|
rcPreview.bottom,
|
|
hDlg, (HMENU)IDC_FONTPREVIEW, g_hinst, NULL);
|
|
|
|
if (hwnd)
|
|
SetWindowLongPtr(hwnd, 0, (LONG_PTR)pfi);
|
|
}
|
|
|
|
|
|
/* PreviewUpdate
|
|
*
|
|
* Does the preview of the selected font.
|
|
*/
|
|
|
|
void PreviewUpdate(HWND hwndList, PFNTINFO pfi)
|
|
{
|
|
HWND hDlg;
|
|
BPFDI bpfdi;
|
|
|
|
/* Delete the old font if necessary */
|
|
if (pfi->hFontPreview)
|
|
{
|
|
DeleteObject(pfi->hFontPreview);
|
|
pfi->hFontPreview = NULL;
|
|
}
|
|
|
|
/* When we select a font, we do the font preview by setting it
|
|
* into the appropriate list box
|
|
*/
|
|
bpfdi = (BPFDI)GetFont(hwndList, TRUE, pfi);
|
|
if (IsSpecialBpfdi(bpfdi))
|
|
return;
|
|
|
|
/* Update our internal font structure so that preview window
|
|
* will actually change
|
|
*/
|
|
pfi->bpfdi = bpfdi;
|
|
SetFont(&pfi->fntProposed, bpfdi);
|
|
|
|
/* Make the new font */
|
|
pfi->hFontPreview = CreateFontFromBpfdi(bpfdi, pfi);
|
|
|
|
/* Force the preview windows to repaint */
|
|
hDlg = GetParent(hwndList);
|
|
InvalidateRect(GetDlgItem(hDlg, IDC_WNDPREVIEW), NULL, TRUE);
|
|
InvalidateRect(GetDlgItem(hDlg, IDC_FONTPREVIEW), NULL, TRUE);
|
|
}
|
|
|
|
|
|
/* WndPreviewWndProc
|
|
*
|
|
* Handles the window preview window.
|
|
*/
|
|
|
|
LRESULT WndPreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
WndPreviewPaint(GetParent(hwnd), hwnd);
|
|
break;
|
|
|
|
case WM_HELP: // Handles title bar help button message
|
|
WinHelp(hwnd, NULL, HELP_CONTEXTPOPUP, IDH_DOS_FONT_WINDOW_PREVIEW);
|
|
break;
|
|
|
|
case WM_RBUTTONUP:
|
|
case WM_NCRBUTTONUP: // Equivalent of WM_CONTEXTMENU
|
|
OnWmContextMenu((WPARAM)hwnd, &rgdwHelp[0]);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Swiped from Control Panel / Metrics.
|
|
*
|
|
* Draws the frame *and* modifies the rectangle to contain the
|
|
* shrunk coordinates.
|
|
*/
|
|
void _DrawFrame(HDC hdc, int clr, LPRECT lprc, int cx, int cy)
|
|
{
|
|
HBRUSH hbr;
|
|
RECT rcT;
|
|
|
|
CopyRect(&rcT, lprc);
|
|
hbr = SelectObject(hdc, GetSysColorBrush(clr));
|
|
|
|
/* Left */
|
|
PatBlt(hdc, rcT.left, rcT.top, cx, rcT.bottom-rcT.top, PATCOPY);
|
|
rcT.left += cx;
|
|
|
|
/* Top */
|
|
PatBlt(hdc, rcT.left, rcT.top, rcT.right-rcT.left, cy, PATCOPY);
|
|
rcT.top += cy;
|
|
|
|
/* Right */
|
|
rcT.right -= cx;
|
|
PatBlt(hdc, rcT.right, rcT.top, cx, rcT.bottom-rcT.top, PATCOPY);
|
|
|
|
/* Bottom */
|
|
rcT.bottom -= cy;
|
|
PatBlt(hdc, rcT.left, rcT.bottom, rcT.right-rcT.left, cy, PATCOPY);
|
|
|
|
SelectObject(hdc, hbr);
|
|
CopyRect(lprc, &rcT);
|
|
}
|
|
|
|
|
|
/* WndPreviewPaint
|
|
*
|
|
* Paints the window preview window. This is called from its
|
|
* paint message handler.
|
|
*
|
|
*/
|
|
|
|
void WndPreviewPaint(HWND hDlg, HWND hwnd)
|
|
{
|
|
PPROPLINK ppl;
|
|
PFNTINFO pfi;
|
|
RECT rcPreview;
|
|
RECT rcWin;
|
|
RECT rcClient;
|
|
RECT rcT;
|
|
POINT ptButton;
|
|
#define cxButton ptButton.x
|
|
#define cyButton ptButton.y
|
|
POINT ptCorner;
|
|
POINT ptFrame;
|
|
#define cxFrame ptFrame.x
|
|
#define cyFrame ptFrame.y
|
|
BPFDI bpfdi;
|
|
int cxBorder, cyBorder;
|
|
int dyToolbar;
|
|
PAINTSTRUCT ps;
|
|
BOOL bCenter;
|
|
|
|
BeginPaint(hwnd, &ps);
|
|
|
|
pfi = (PFNTINFO)GetWindowLongPtr(hwnd, 0);
|
|
|
|
ppl = pfi->ppl;
|
|
ASSERTTRUE(ppl->iSig == PROP_SIG);
|
|
|
|
bpfdi = pfi->bpfdi;
|
|
|
|
/* If we don't have a font, get out */
|
|
if (!pfi->hFontPreview)
|
|
return;
|
|
|
|
/* Get the width of the preview "screen" */
|
|
GetClientRect(hwnd, &rcPreview);
|
|
|
|
/* Figure out how large we would be as a result of the change.
|
|
* This isn't perfect, but it'll probably be close enough.
|
|
* (Imperfection if we chose AUTO as the font.)
|
|
*/
|
|
|
|
/* Assume maximized */
|
|
rcClient.left = rcClient.top = 0;
|
|
if (pfi->winOriginal.cxCells) {
|
|
rcClient.right = pfi->winOriginal.cxCells * bpfdi->fdiWidthActual;
|
|
} else {
|
|
rcClient.right = 80 * bpfdi->fdiWidthActual;
|
|
}
|
|
|
|
if (pfi->winOriginal.cyCells) {
|
|
rcClient.bottom = pfi->winOriginal.cyCells * bpfdi->fdiHeightActual;
|
|
} else {
|
|
PROPVID vid;
|
|
|
|
// set default value
|
|
rcClient.bottom = 25 * bpfdi->fdiHeightActual;
|
|
|
|
// now see if there is a value in the pif file for size of window...
|
|
if (PifMgr_GetProperties(ppl, MAKELP(0,GROUP_VID),
|
|
&vid, sizeof(vid), GETPROPS_NONE))
|
|
{
|
|
if (vid.cScreenLines > 0)
|
|
rcClient.bottom = vid.cScreenLines * bpfdi->fdiHeightActual;
|
|
|
|
}
|
|
}
|
|
if (!pfi->fMax && pfi->winOriginal.cxClient && pfi->winOriginal.cyClient) {
|
|
/* Shrink down to window actual */
|
|
if (rcClient.right > (int)pfi->winOriginal.cxClient)
|
|
rcClient.right = (int)pfi->winOriginal.cxClient;
|
|
if (rcClient.bottom > (int)pfi->winOriginal.cyClient)
|
|
rcClient.bottom = (int)pfi->winOriginal.cyClient;
|
|
}
|
|
|
|
/* Get some more metrics */
|
|
cxBorder = GetSystemMetrics(SM_CXBORDER);
|
|
cyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
|
|
cxButton = GetSystemMetrics(SM_CXSIZE);
|
|
cyButton = GetSystemMetrics(SM_CYSIZE);
|
|
// cyButton *= 2; /* Double the height for "looks" */
|
|
|
|
cxFrame = GetSystemMetrics(SM_CXFRAME);
|
|
cyFrame = GetSystemMetrics(SM_CYFRAME);
|
|
|
|
/* FLAG DAY! Convert everything from desktop coordinates to
|
|
* aspect ratio-scaled preview coordinates
|
|
*
|
|
* Do **not** convert cxBorder and cyBorder!
|
|
*
|
|
* ptCorner must not be modified in-place since its value is used at
|
|
* the next go-round.
|
|
*
|
|
* After translation, cxFrame and cyFrame are adjusted so that the
|
|
* cxBorder counts against them. This allows for users who set
|
|
* really wide frames, but doesn't penalize the users who have
|
|
* narrow frames.
|
|
*/
|
|
|
|
ptCorner = pfi->ptCorner;
|
|
bCenter = (ptCorner.x == -1);
|
|
AspectPoint(&rcPreview, &ptCorner);
|
|
AspectPoint(&rcPreview, &ptFrame);
|
|
AspectRect(&rcPreview, &rcClient);
|
|
AspectPoint(&rcPreview, &ptButton);
|
|
|
|
/*
|
|
* The height of a toolbar is hard-coded at 30 pixels.
|
|
*/
|
|
if (pfi->winOriginal.flWin & WIN_TOOLBAR) {
|
|
dyToolbar = (int)AspectScale(rcPreview.bottom, cyScreen, 30);
|
|
} else {
|
|
dyToolbar = 0;
|
|
}
|
|
|
|
/* Make sure the buttons are nonzero in dimension */
|
|
if (cxButton == 0) cxButton = 1;
|
|
if (cyButton == 0) cyButton = 1;
|
|
|
|
/*
|
|
* Don't penalize people who have thin frames.
|
|
*/
|
|
if (cxFrame < cxBorder) cxFrame = cxBorder;
|
|
if (cyFrame < cyBorder) cyFrame = cyBorder;
|
|
|
|
/*
|
|
* Convert from client rectangle back to window rectangle.
|
|
*
|
|
* We must do this *AFTER* the flag day, because we need to use the
|
|
* post-flag day cxBorder and cyBorder.
|
|
*/
|
|
|
|
/* Put a (scaled-down) toolbar into place. We'll expand the client
|
|
* region to accomodate it. (We'll subtract the toolbar off before
|
|
* painting the client region.)
|
|
*/
|
|
rcClient.bottom += dyToolbar;
|
|
|
|
/* Shove the client region down to make room for the caption. */
|
|
OffsetRect(&rcClient, 0, cyButton);
|
|
|
|
rcWin = rcClient;
|
|
rcWin.top = 0;
|
|
InflateRect(&rcWin, cxFrame, cyFrame);
|
|
|
|
/*
|
|
* Now put it in the proper position on the (shrunk-down) desktop.
|
|
* We cannot do this until rcWin's value is finalized.
|
|
*/
|
|
if (bCenter)
|
|
{
|
|
ptCorner.x = ((rcPreview.right - rcPreview.left) -
|
|
(rcWin.right - rcWin.left)
|
|
) / 2;
|
|
if (ptCorner.x < 0)
|
|
ptCorner.x = 0;
|
|
|
|
ptCorner.y = ((rcPreview.bottom - rcPreview.top) -
|
|
(rcWin.bottom - rcWin.top)
|
|
) / 5;
|
|
if (ptCorner.y < 0)
|
|
ptCorner.y = 0;
|
|
|
|
}
|
|
OffsetRect(&rcWin, ptCorner.x, ptCorner.y);
|
|
OffsetRect(&rcClient, ptCorner.x, ptCorner.y);
|
|
|
|
/* It's party time! */
|
|
|
|
/* The outer border */
|
|
DrawEdge(ps.hdc, &rcWin, BDR_RAISEDINNER, BF_RECT | BF_ADJUST);
|
|
|
|
/* The sizing frame */
|
|
_DrawFrame(ps.hdc, COLOR_ACTIVEBORDER,
|
|
&rcWin, cxFrame - cxBorder, cyFrame - cyBorder);
|
|
|
|
/* rcWin has now shrunk to its inner edge */
|
|
|
|
/* Move its bottom edge upwards to meet the top of the client region.
|
|
* This turns rcWin into the caption area.
|
|
*/
|
|
rcWin.bottom = rcClient.top;
|
|
FillRect(ps.hdc, &rcWin, (HBRUSH)(COLOR_ACTIVECAPTION+1));
|
|
|
|
/* Next comes the toolbar */
|
|
rcT= rcClient;
|
|
rcT.bottom = rcT.top + dyToolbar;
|
|
FillRect(ps.hdc, &rcT, (HBRUSH)(COLOR_BTNFACE+1));
|
|
|
|
/* Next, draw the client region */
|
|
rcClient.top += dyToolbar;
|
|
DrawEdge(ps.hdc, &rcClient, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
|
|
FillRect(ps.hdc, &rcClient, (HBRUSH)GetStockObject(BLACK_BRUSH));
|
|
|
|
/*
|
|
* Now draw the three caption buttons.
|
|
*/
|
|
|
|
/*
|
|
* The system menu.
|
|
*/
|
|
rcT = rcWin;
|
|
rcT.right = rcT.left + cxButton;
|
|
//DrawFrameControl(ps.hdc, &rcT, DFC_SYSMENU, DFCS_SYSMENUMAIN);
|
|
DrawFrameControl(ps.hdc, &rcT, DFC_CAPTION, DFCS_CAPTIONCLOSE);
|
|
|
|
/*
|
|
* The maximize menu.
|
|
*/
|
|
rcWin.left = rcWin.right - cxButton;
|
|
//DrawFrameControl(ps.hdc, &rcWin, DFC_SIZE, DFCS_SIZEMAX);
|
|
DrawFrameControl(ps.hdc, &rcWin, DFC_CAPTION, DFCS_CAPTIONMAX);
|
|
|
|
/*
|
|
* The minimize menu.
|
|
*/
|
|
rcWin.left -= cxButton;
|
|
rcWin.right -= cxButton;
|
|
//DrawFrameControl(ps.hdc, &rcWin, DFC_SIZE, DFCS_SIZEMIN);
|
|
DrawFrameControl(ps.hdc, &rcWin, DFC_CAPTION, DFCS_CAPTIONMIN);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
#undef cxButton
|
|
#undef cyButton
|
|
|
|
#undef cxFrame
|
|
#undef cyFrame
|
|
|
|
LRESULT FontPreviewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
RECT rect;
|
|
PFNTINFO pfi;
|
|
PAINTSTRUCT ps;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
BeginPaint(hwnd, &ps);
|
|
|
|
pfi = (PFNTINFO)GetWindowLongPtr(hwnd, 0);
|
|
|
|
/* Draw the font sample */
|
|
SelectObject(ps.hdc, pfi->hFontPreview);
|
|
SetTextColor(ps.hdc, RGB(192, 192, 192));
|
|
SetBkColor(ps.hdc, RGB(0, 0, 0));
|
|
GetClientRect(hwnd, &rect);
|
|
InflateRect(&rect, -2, -2);
|
|
|
|
{
|
|
TCHAR szPreviewText[300];
|
|
LoadString(g_hinst, IsBilingualCP(pfi->fntProposed.wCurrentCP) ? IDS_PREVIEWTEXT_BILNG : IDS_PREVIEWTEXT, szPreviewText, ARRAYSIZE(szPreviewText));
|
|
// load a sample for their native codepage
|
|
DrawText(ps.hdc, szPreviewText, -1, &rect, 0);
|
|
}
|
|
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
|
|
case WM_HELP: // Handles title bar help button message
|
|
WinHelp(hwnd, NULL, HELP_CONTEXTPOPUP, IDH_DOS_FONT_FONT_PREVIEW);
|
|
break;
|
|
|
|
case WM_RBUTTONUP:
|
|
case WM_NCRBUTTONUP: // Equivalent of WM_CONTEXTMENU
|
|
OnWmContextMenu((WPARAM)hwnd, &rgdwHelp[0]);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Loads the dialog control hwndList with all available font
|
|
* dimensions for raster fonts, and a selected collection of
|
|
* dimensions for TrueType fonts.
|
|
*
|
|
* The reference data for each control is an index into lpfniCache.
|
|
*
|
|
* The hourglass cursor is displayed during the font list build.
|
|
*
|
|
* Entry:
|
|
* hwndList == handle to listbox or combo box to fill
|
|
* fListBox == TRUE if hwndList is a listbox, FALSE if a combo box
|
|
* lpFnt -> PROPFNT structure
|
|
*
|
|
* If HIWORD(lpFnt) is NULL, then LOWORD(lpFnt) is used as an hProps
|
|
* to get obtain property info for that handle.
|
|
*
|
|
* Returns:
|
|
* >= 0 on success, indicating the current selection.
|
|
* In which case the FDI cache is valid and hwndList has been filled
|
|
* with font information, and the currently-selected font has been
|
|
* made the current selection.
|
|
*
|
|
* LB_ERR/CB_ERR on failure. The list box hwndList is left in an
|
|
* indeterminate state.
|
|
*/
|
|
|
|
int WINAPI CreateFontList(HWND hwndList, BOOL fListBox, LPPROPFNT lpFnt)
|
|
{
|
|
DWORD dwIndex;
|
|
HCURSOR hcursor;
|
|
PROPFNT fntTemp;
|
|
int iReturn = LB_ERR;
|
|
TCHAR szBuf[MAXDIMENSTRING];
|
|
|
|
if (IS_INTRESOURCE(lpFnt))
|
|
{
|
|
if (!PifMgr_GetProperties(lpFnt, MAKELP(0,GROUP_FNT),
|
|
&fntTemp, sizeof(fntTemp), GETPROPS_NONE))
|
|
goto Exit2;
|
|
|
|
lpFnt = &fntTemp;
|
|
}
|
|
|
|
/*
|
|
* Put up an hourglass while the font list build is taking place,
|
|
* since it might take a long time if we have to re-rasterize
|
|
* TrueType fonts.
|
|
*
|
|
* NOTE! That we do not do a ShowCursor. Why?
|
|
*
|
|
* If the user is on a mouseless system, then he can't access his
|
|
* toolbar, and hence the only time this code can get called is
|
|
* during the creation of the font selection dialog box. In which
|
|
* case, DialogBox has already done a ShowCursor for us.
|
|
*
|
|
*/
|
|
hcursor = SetCursor(hcursorWait);
|
|
|
|
/*
|
|
* Initialize the list box.
|
|
*/
|
|
if (hwndList) {
|
|
SendMessage(hwndList, WM_SETREDRAW, FALSE, 0L);
|
|
SendMessage(hwndList, fListBox ? LB_RESETCONTENT : CB_RESETCONTENT, 0, 0L);
|
|
}
|
|
|
|
/*
|
|
* Add the fonts.
|
|
*/
|
|
if ((lpFnt->flFnt & FNT_RASTERFONTS) &&
|
|
!AddRasterFontsToFontListA(hwndList, fListBox,
|
|
lpFnt->achRasterFaceName, lpFnt->wCurrentCP))
|
|
goto Exit;
|
|
|
|
if ((lpFnt->flFnt & FNT_TTFONTS) &&
|
|
!AddTrueTypeFontsToFontListA(hwndList, fListBox,
|
|
lpFnt->achTTFaceName, lpFnt->wCurrentCP))
|
|
goto Exit;
|
|
|
|
/*
|
|
* And the magical "Auto" font size.
|
|
*/
|
|
|
|
/*
|
|
* Beyond this point, success is assured, so at the very least,
|
|
* DON'T return LB_ERR; we may optionally set the return code to
|
|
* the current selection, below, too...
|
|
*/
|
|
iReturn = 0;
|
|
|
|
if (hwndList) {
|
|
/*
|
|
* No error checking here because if anything fails, then the
|
|
* end result will be merely that the "Auto" option either
|
|
* (1) exists but is invisible, or (2) doesn't appear at all.
|
|
*/
|
|
LoadString(g_hinst, IDS_AUTO, szBuf, ARRAYSIZE(szBuf));
|
|
dwIndex = lcbInsertString(hwndList, fListBox, szBuf, 0);
|
|
lcbSetItemDataPair(hwndList, fListBox, dwIndex, BPFDI_AUTO, 0);
|
|
|
|
/*
|
|
* Make yet another pass through the list to find the current
|
|
* font and select it. Thanks to an intentional flakiness
|
|
* in USER, we can't do this check at the point that the
|
|
* font is added, because the selection does not move with the
|
|
* item when a new item is inserted above the selection.
|
|
*
|
|
* Bleah.
|
|
*/
|
|
if (!MatchCurrentFont(hwndList, fListBox, lpFnt)) {
|
|
/*
|
|
* If no font matched the current font, and we are a list box,
|
|
* then make the first font the current selection.
|
|
*
|
|
* We don't want to make any default selection if we are a
|
|
* combo box, because that would make the user think that the
|
|
* current font was something it wasn't.
|
|
*/
|
|
if (fListBox) {
|
|
/*
|
|
* SORTING-SENSITIVE! This assumes that "Auto" is at the top
|
|
* of the list.
|
|
*/
|
|
lcbSetCurSel(hwndList, TRUE, 0);
|
|
lpFnt->flFnt |= FNT_AUTOSIZE;
|
|
}
|
|
}
|
|
SendMessage(hwndList, WM_SETREDRAW, TRUE, 0L);
|
|
|
|
iReturn = lcbGetCurSel(hwndList, fListBox);
|
|
}
|
|
Exit:
|
|
/*
|
|
* Reset the mouse cursor.
|
|
*/
|
|
SetCursor(hcursor);
|
|
|
|
Exit2:
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
/** UpdateTTBitmap
|
|
*
|
|
* Recompute the colors for the TrueType bitmap hbmFont.
|
|
*
|
|
* Since we may receive this several times for a single WM_SYSCOLORCHANGE,
|
|
* we update our colors under the following conditions:
|
|
*
|
|
* 1. More than one second has elapsed since the previous call, or
|
|
* 2. A crude checksum fails.
|
|
*
|
|
* Entry:
|
|
* None.
|
|
*
|
|
* Returns:
|
|
* hbmFont recomputed.
|
|
*/
|
|
|
|
VOID WINAPI UpdateTTBitmap(void)
|
|
{
|
|
COLORREF clr;
|
|
|
|
/*
|
|
* Note that the checksum should not be a symmetric function,
|
|
* because a common color alteration is to exchange or permute
|
|
* the colors.
|
|
*/
|
|
clr = + GetSysColor(COLOR_BTNTEXT)
|
|
- GetSysColor(COLOR_BTNSHADOW)
|
|
+ (GetSysColor(COLOR_BTNFACE) ^ 1)
|
|
- (GetSysColor(COLOR_BTNHIGHLIGHT) ^ 2)
|
|
^ GetSysColor(COLOR_WINDOW);
|
|
|
|
if (!hbmFont || clr != clrChecksum || GetTickCount() - dwTimeCheck < 1000) {
|
|
clrChecksum = clr;
|
|
dwTimeCheck = GetTickCount();
|
|
if (hbmFont) DeleteObject(hbmFont);
|
|
hbmFont = CreateMappedBitmap(g_hinst, IDB_TTBITMAP, 0, NULL, 0);
|
|
}
|
|
}
|
|
|
|
|
|
/** DrawItemFontList
|
|
*
|
|
* Answer the WM_DRAWITEM message sent from the font list box or
|
|
* font combo box.
|
|
*
|
|
* This code was originally lifted from FONT.C in sdk\commdlg.
|
|
*
|
|
* See fontutil.h for an explanation of the \1 hack.
|
|
*
|
|
* Entry:
|
|
* fListBox = TRUE if the item is a list box, FALSE if a combo box
|
|
* lpdis -> DRAWITEMSTRUCT describing object to be drawn
|
|
*
|
|
* Returns:
|
|
* None.
|
|
*
|
|
* The object is drawn.
|
|
*/
|
|
|
|
#define cTabsList 3
|
|
|
|
typedef struct DIFLINFO {
|
|
LPTSTR di_lpsz;
|
|
PINT di_pTabs;
|
|
} DIFLINFO, *LPDIFLINFO;
|
|
|
|
#define lpdi ((LPDIFLINFO)lp)
|
|
BOOL CALLBACK diflGrayStringProc(HDC hdc, LPARAM lp, int cch)
|
|
{
|
|
return (BOOL)TabbedTextOut(hdc, 0, 0,
|
|
lpdi->di_lpsz, lstrlen(lpdi->di_lpsz),
|
|
cTabsList, lpdi->di_pTabs, 0);
|
|
|
|
}
|
|
#undef lpdi
|
|
|
|
VOID WINAPI DrawItemFontList(BOOL fListBox, const LPDRAWITEMSTRUCT lpdis)
|
|
{
|
|
HDC hDC, hdcMem;
|
|
DWORD rgbBack, rgbText;
|
|
int iColorBack;
|
|
COLORREF clrText;
|
|
COLORREF clrBack;
|
|
TCHAR szDimen[MAXDIMENSTRING];
|
|
HBITMAP hOld;
|
|
int dy;
|
|
DIFLINFO di;
|
|
static int rgTabsList[cTabsList] = {0, 0, 0};
|
|
static int rgTabsCombo[cTabsList] = {0, 0, 0};
|
|
#define lpsz di.di_lpsz
|
|
#define pTabs di.di_pTabs
|
|
|
|
if ((int)lpdis->itemID < 0)
|
|
return;
|
|
|
|
hDC = lpdis->hDC;
|
|
|
|
if (lpdis->itemAction & ODA_FOCUS) {
|
|
if (lpdis->itemState & ODS_SELECTED) {
|
|
DrawFocusRect(hDC, &lpdis->rcItem);
|
|
}
|
|
} else {
|
|
if (lpdis->itemState & ODS_SELECTED) {
|
|
clrBack = GetSysColor(iColorBack = COLOR_HIGHLIGHT);
|
|
clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
|
|
} else {
|
|
clrBack = GetSysColor(iColorBack = COLOR_WINDOW);
|
|
clrText = GetSysColor(IsWindowEnabled(lpdis->hwndItem) ?
|
|
COLOR_WINDOWTEXT : COLOR_GRAYTEXT);
|
|
}
|
|
rgbText = SetTextColor(hDC, clrText);
|
|
rgbBack = SetBkColor(hDC, clrBack);
|
|
|
|
// draw selection background
|
|
FillRect(hDC, &lpdis->rcItem, (HBRUSH)UIntToPtr((iColorBack + 1)));
|
|
|
|
// get the string
|
|
SendMessage(lpdis->hwndItem, fListBox ? LB_GETTEXT : CB_GETLBTEXT, lpdis->itemID, (LPARAM)(LPTSTR)szDimen);
|
|
|
|
lpsz = szDimen;
|
|
if (szDimen[0] == TEXT('\1')) // hack for "Auto" string
|
|
lpsz++;
|
|
|
|
if (fListBox)
|
|
pTabs = rgTabsList;
|
|
else
|
|
pTabs = rgTabsCombo;
|
|
|
|
if (pTabs[0] == 0) { /* Never seen this font before */
|
|
/* Assumes GetTextExtent(hDC, ANSI_TIMES, 1) < 2 * dxChar */
|
|
SIZE sSize;
|
|
GetTextExtentPoint32(hDC, szZero, 1, &sSize); // size of '0'
|
|
/* A negative # for tab stop right aligns the tabs... */
|
|
pTabs[0] = -sSize.cx * 3;
|
|
pTabs[1] = -sSize.cx * 5;
|
|
pTabs[2] = -sSize.cx * 8;
|
|
}
|
|
|
|
// draw the text
|
|
//
|
|
// Note that the SDK dox for GrayString says that you can detect
|
|
// whether GrayString is needed by saying
|
|
//
|
|
// if (GetSysColor(COLOR_GRAYTEXT) == 0) {
|
|
// GrayString(...);
|
|
// } else {
|
|
// TextOut(...);
|
|
// }
|
|
//
|
|
// This is incorrect. The correct test is the one below, which
|
|
// also catches bad color combinations on color devices.
|
|
//
|
|
if (clrText == clrBack) {
|
|
SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
|
|
GrayString(hDC, GetStockObject(GRAY_BRUSH), diflGrayStringProc ,
|
|
(LPARAM)(LPVOID)&di, 0,
|
|
lpdis->rcItem.left + DX_TTBITMAP,
|
|
lpdis->rcItem.top,
|
|
lpdis->rcItem.right - lpdis->rcItem.left - DX_TTBITMAP,
|
|
lpdis->rcItem.bottom - lpdis->rcItem.top);
|
|
} else {
|
|
TabbedTextOut(hDC, lpdis->rcItem.left + DX_TTBITMAP, lpdis->rcItem.top, lpsz, lstrlen(lpsz), cTabsList, pTabs, DX_TTBITMAP);
|
|
}
|
|
|
|
// and the bitmap if needed
|
|
if (!IsSpecialBpfdi((BPFDI)lpdis->itemData))
|
|
{
|
|
if (((BPFDI)(lpdis->itemData))->bTT) {
|
|
hdcMem = CreateCompatibleDC(hDC);
|
|
if (hdcMem) {
|
|
hOld = SelectObject(hdcMem, hbmFont);
|
|
|
|
dy = ((lpdis->rcItem.bottom - lpdis->rcItem.top) - DY_TTBITMAP) / 2;
|
|
|
|
BitBlt(hDC, lpdis->rcItem.left, lpdis->rcItem.top + dy,
|
|
DX_TTBITMAP, DY_TTBITMAP, hdcMem, 0,
|
|
lpdis->itemState & ODS_SELECTED ? 0 : DY_TTBITMAP, SRCCOPY);
|
|
|
|
if (hOld)
|
|
SelectObject(hdcMem, hOld);
|
|
DeleteDC(hdcMem);
|
|
}
|
|
}
|
|
}
|
|
|
|
SetTextColor(hDC, rgbText);
|
|
SetBkColor(hDC, rgbBack);
|
|
|
|
if (lpdis->itemState & ODS_FOCUS) {
|
|
DrawFocusRect(hDC, &lpdis->rcItem);
|
|
}
|
|
}
|
|
}
|
|
#undef lpsz
|
|
#undef pTabs
|
|
|
|
|
|
/** MeasureItemFontList
|
|
*
|
|
* Answer the WM_MEASUREITEM message sent from the font list box or
|
|
* font combo box. shared between the toolbar combo box code and
|
|
* the font preview property sheet
|
|
*
|
|
* Entry:
|
|
* lpmi -> LPMEASUREITEMSTRUCT describing object to be measured
|
|
*
|
|
* Returns:
|
|
* TRUE.
|
|
*
|
|
* lpmi->itemHeight filled with actual item height.
|
|
*/
|
|
|
|
LONG WINAPI MeasureItemFontList(LPMEASUREITEMSTRUCT lpmi)
|
|
{
|
|
lpmi->itemHeight = dyItem;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/** MatchCurrentFont
|
|
*
|
|
* Locates the current font in the indicated list box and
|
|
* makes him the current selection.
|
|
*
|
|
* If we are in auto-mode, then "Auto" is selected.
|
|
*
|
|
* Entry:
|
|
* hwndList == handle to listbox or combo box
|
|
* fListBox == TRUE if hwndList is a listbox, FALSE if a combo box
|
|
* lpFnt -> PROPFNT structure
|
|
*
|
|
* Returns:
|
|
* TRUE if the current font was found and selected.
|
|
*/
|
|
BOOL WINAPI MatchCurrentFont(HWND hwndList, BOOL fListBox, LPPROPFNT lpFnt)
|
|
{
|
|
BPFDI bpfdi;
|
|
DWORD dwCount, dwIndex;
|
|
BOOL fCurFontIsTt = !!(lpFnt->flFnt & FNT_TT);
|
|
|
|
if (lpFnt->flFnt & FNT_AUTOSIZE) {
|
|
/*
|
|
* SORTING-SENSITIVE! This assumes that "Auto" is at the top
|
|
* of the list.
|
|
*/
|
|
lcbSetCurSel(hwndList, fListBox, 0);
|
|
return TRUE;
|
|
}
|
|
dwCount = lcbGetCount(hwndList, fListBox);
|
|
for (dwIndex = 0; dwIndex < dwCount; dwIndex++) {
|
|
|
|
bpfdi = lcbGetBpfdi(hwndList, fListBox, dwIndex);
|
|
|
|
if (!IsSpecialBpfdi(bpfdi)) {
|
|
// bpfdi = (BPFDI)((DWORD)bpfdi + (DWORD)lpCache);
|
|
if (bpfdi->fdiWidthActual == lpFnt->cxFontActual &&
|
|
bpfdi->fdiHeightActual == lpFnt->cyFontActual &&
|
|
fCurFontIsTt == (bpfdi->fdiHeightReq != 0)) {
|
|
|
|
lcbSetCurSel(hwndList, fListBox, dwIndex);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/** AddRasterFontsToFontList
|
|
*
|
|
* Enumerate the available dimensions for our OEM raster font
|
|
* and add them to the list or combo box.
|
|
*
|
|
* Entry:
|
|
* hwndList = List box or combo box to fill with info
|
|
* fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
|
|
* lpszRasterFaceName
|
|
*
|
|
* Returns:
|
|
* TRUE if fonts were enumerated to completion.
|
|
* FALSE if enumeration failed. (Out of memory.)
|
|
*
|
|
*/
|
|
BOOL AddRasterFontsToFontListA(HWND hwndList, BOOL fListBox,
|
|
LPCSTR lpszRasterFaceName, INT CodePage)
|
|
{
|
|
HDC hDC;
|
|
BOOL fSuccess;
|
|
FNTENUMINFO FntEnum;
|
|
|
|
hDC = GetDC(hwndList);
|
|
if (!hDC) return FALSE;
|
|
|
|
FntEnum.hwndList = hwndList;
|
|
FntEnum.fListBox = fListBox;
|
|
FntEnum.CodePage = CodePage;
|
|
fSuccess = EnumFontFamiliesA(hDC,
|
|
lpszRasterFaceName,
|
|
(FONTENUMPROCA)RasterFontEnum,
|
|
(LPARAM)&FntEnum);
|
|
ReleaseDC(hwndList, hDC);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/** RasterFontEnum
|
|
*
|
|
* FONTENUMPROC for enumerating all available dimensions of the OEM
|
|
* raster font.
|
|
*
|
|
* This routine is used to load the logical and physical font
|
|
* dimensions cache with information about raster fonts.
|
|
*
|
|
* Entry:
|
|
* lpelf \
|
|
* lpntm > from EnumFonts (see SDK)
|
|
* nFontType /
|
|
* hwndList = List box or combo box to fill with info
|
|
* fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
|
|
*
|
|
* Returns:
|
|
* TRUE to continue enumeration.
|
|
* FALSE to stop enumeration. (Out of memory.)
|
|
*/
|
|
|
|
int CALLBACK RasterFontEnum(ENUMLOGFONTA *lpelf, NEWTEXTMETRICA *lpntm, int nFontType, LPARAM lParam)
|
|
{
|
|
#define fListBox (((LPFNTENUMINFO)lParam)->fListBox)
|
|
#define hwndList (((LPFNTENUMINFO)lParam)->hwndList)
|
|
#define CodePage (((LPFNTENUMINFO)lParam)->CodePage)
|
|
#define lpLogFont (&(lpelf->elfLogFont))
|
|
|
|
/*
|
|
* We only care about OEM fixed-pitch fonts.
|
|
*/
|
|
if (lpLogFont->lfCharSet != OEMCharsetFromCP(CodePage)
|
|
|| (lpLogFont->lfPitchAndFamily & (TMPF_TRUETYPE | TMPF_FIXED_PITCH))
|
|
!= TMPF_FIXED_PITCH)
|
|
return TRUE;
|
|
|
|
return AddToFontListCache(hwndList,
|
|
fListBox,
|
|
0, 0,
|
|
lpLogFont->lfHeight,
|
|
lpLogFont->lfWidth,
|
|
CodePage) != BPFDI_CANCEL;
|
|
#undef lpLogFont
|
|
#undef fListBox
|
|
#undef hwndList
|
|
#undef CodePage
|
|
}
|
|
|
|
/** AddToFontListCache
|
|
*
|
|
* Adds an entry to the font dimension information cache,
|
|
* growing the cache if necessary.
|
|
*
|
|
* It also adds the entry to the indicated list box, provided
|
|
* the entry is not a duplicate.
|
|
*
|
|
* Returns:
|
|
* BPFDI of the recently-added font, or BPFDI_CANCEL if out of memory.
|
|
*
|
|
* Overview:
|
|
* (1) Grow the cache if necessary.
|
|
* (2) Add the information to the list/combo box.
|
|
* (3) Add the information to the cache.
|
|
*/
|
|
BPFDI AddToFontListCache(HWND hwndList,
|
|
BOOL fListBox,
|
|
UINT uHeightReq,
|
|
UINT uWidthReq,
|
|
UINT uHeightActual,
|
|
UINT uWidthActual,
|
|
UINT uCodePage)
|
|
{
|
|
LPVOID hCache;
|
|
LONG_PTR lCacheSave;
|
|
DWORD dwIndex, ifdi;
|
|
BPFDI bpfdi;
|
|
TCHAR szBuf[MAXDIMENSTRING];
|
|
int idx;
|
|
|
|
ASSERT(!((uHeightReq==0) && (uWidthReq==0) && (uHeightActual==0) && (uWidthActual==0)));
|
|
/* Reject too-large fonts out of hand. */
|
|
if (uHeightActual > MAX_FONT_HEIGHT) {
|
|
return BPFDI_IGNORE;
|
|
}
|
|
|
|
/*
|
|
* FIRST, determine whether this font entry has already been cached
|
|
*/
|
|
|
|
// we maintain two set of cache entries in case we have two code page
|
|
// to support
|
|
//
|
|
idx = IsBilingualCP(uCodePage) ? 1 : 0;
|
|
|
|
for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache + bpfdiStart[idx]); ifdi < cfdiCache[idx]; ++ifdi, ++bpfdi)
|
|
{
|
|
if (bpfdi->fdiWidthReq == uWidthReq &&
|
|
bpfdi->fdiHeightReq == uHeightReq &&
|
|
bpfdi->fdiWidthActual == uWidthActual &&
|
|
bpfdi->fdiHeightActual == uHeightActual)
|
|
goto UpdateListCombo;
|
|
}
|
|
|
|
/*
|
|
* Grow the cache if necessary.
|
|
*/
|
|
if (cfdiCache[idx] >= cfdiCacheActual[idx]) {
|
|
|
|
/*
|
|
* save offset from beginning of cache
|
|
*/
|
|
bpfdi = (BPFDI)((DWORD_PTR)bpfdi - (DWORD_PTR)lpCache);
|
|
|
|
/*
|
|
* save current lpCache value so can adjust entries in listbox
|
|
* when we're done...
|
|
*/
|
|
lCacheSave = (LONG_PTR)lpCache;
|
|
hCache = LocalReAlloc(lpCache,
|
|
(cfdiCacheActual[0] + cfdiCacheActual[1] + FDI_TABLE_INC) *
|
|
sizeof(FONTDIMENINFO), LMEM_ZEROINIT|LMEM_MOVEABLE);
|
|
if (!hCache)
|
|
return BPFDI_CANCEL;
|
|
lpCache = hCache;
|
|
|
|
if (!idx && IsBilingualCP(g_uCodePage)) {
|
|
/*
|
|
* We need to shift 2nd cache before using expanded 1st chache
|
|
*/
|
|
BPFDI bpfdi2;
|
|
for (ifdi = cfdiCache[1],
|
|
bpfdi2 = (BPFDI)((DWORD_PTR)lpCache + bpfdiStart[1]) + ifdi - 1 + FDI_TABLE_INC ;
|
|
ifdi ; ifdi--, bpfdi2--) {
|
|
*bpfdi2 = *(bpfdi2 - FDI_TABLE_INC);
|
|
}
|
|
bpfdiStart[1] += FDI_TABLE_INC;
|
|
}
|
|
/* restore bpfdi from saved offset */
|
|
bpfdi = (BPFDI)((DWORD_PTR)lpCache + (DWORD_PTR)bpfdi);
|
|
cfdiCacheActual[idx] += FDI_TABLE_INC;
|
|
|
|
/*
|
|
* Convert lCacheSave to an offset...
|
|
*/
|
|
lCacheSave = (LONG_PTR)lpCache - lCacheSave;
|
|
|
|
if (lCacheSave)
|
|
{
|
|
/*
|
|
* Now, adjust each entry in the listbox to account for the new
|
|
* relocated cache position..
|
|
*/
|
|
|
|
dwIndex = lcbGetCount(hwndList, fListBox);
|
|
for(ifdi = 0; ifdi < dwIndex; ifdi++)
|
|
{
|
|
LONG_PTR lBpfdi;
|
|
|
|
lBpfdi = (LONG_PTR)lcbGetItemDataPair(hwndList, fListBox, ifdi);
|
|
if (!IsSpecialBpfdi((BPFDI)lBpfdi))
|
|
{
|
|
lBpfdi += lCacheSave;
|
|
lcbSetItemDataPair(hwndList, fListBox, ifdi, lBpfdi, ((BPFDI)lBpfdi)->bTT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Now add the information to the cache. All the casting on bpfdiCache
|
|
* is just to inhibit a bogus compiler complaint.
|
|
*/
|
|
bpfdi->fdiWidthReq = uWidthReq;
|
|
bpfdi->fdiHeightReq = uHeightReq;
|
|
|
|
bpfdi->fdiWidthActual = uWidthActual;
|
|
bpfdi->fdiHeightActual = uHeightActual;
|
|
|
|
cfdiCache[idx]++;
|
|
|
|
UpdateListCombo:
|
|
|
|
if (hwndList) {
|
|
/*
|
|
* Add the string to the list/combo box if it isn't there already.
|
|
*/
|
|
StringCchPrintf(szBuf, ARRAYSIZE(szBuf), TEXT("\t%2d\tx\t%2d"), uWidthActual, uHeightActual);
|
|
|
|
dwIndex = lcbFindStringExact(hwndList, fListBox, szBuf);
|
|
|
|
if (IsDlgError(dwIndex)) {
|
|
/*
|
|
* Not already on the list. Add it.
|
|
*/
|
|
dwIndex = lcbAddString(hwndList, fListBox, szBuf);
|
|
|
|
if (IsDlgError(dwIndex)) {
|
|
return BPFDI_CANCEL;
|
|
}
|
|
lcbSetItemDataPair(hwndList, fListBox, dwIndex,
|
|
bpfdi, uHeightReq);
|
|
}
|
|
}
|
|
return bpfdi;
|
|
}
|
|
|
|
|
|
/** AddTrueTypeFontsToFontListA
|
|
*
|
|
* To avoid rasterizing all the fonts unnecessarily, we load the
|
|
* information from the szTTCacheSection font cache.
|
|
*
|
|
* Note that the cache information is not validated! We just
|
|
* assume that if the value is in the cache, it is valid.
|
|
*
|
|
* Entry:
|
|
* hwndList = List box or combo box to fill with info
|
|
* fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
|
|
* lpszTTFaceName
|
|
*
|
|
* Returns:
|
|
* TRUE if fonts were enumerated to completion.
|
|
* FALSE if enumeration failed. (Out of memory.)
|
|
*
|
|
* Caveats:
|
|
* The ParseIniWords call assumes that the values were written
|
|
* by AddOneNewTrueTypeFontToFontList, who wrote them out so
|
|
* that a single call to ParseIniWords will read the height and
|
|
* width directly into a dwHeightWidth.
|
|
*
|
|
* Similarly, the second ParseIniWords reads the item directly into
|
|
* a dwHeightWidth.
|
|
*/
|
|
|
|
BOOL AddTrueTypeFontsToFontListA(HWND hwndList, BOOL fListBox,
|
|
LPSTR lpszTTFaceName, INT CodePage)
|
|
{
|
|
LPTSTR pszBuf;
|
|
LPTSTR pszBufNew;
|
|
LPTSTR psz;
|
|
LPTSTR lpszNext;
|
|
DWORD dwHWReq;
|
|
DWORD dwHWActual;
|
|
BOOL fSuccess;
|
|
DWORD cchBuf;
|
|
DWORD cchActual;
|
|
int i;
|
|
int idx = IsBilingualCP(CodePage) ? 1 : 0;
|
|
|
|
/*
|
|
* See if we can load everything out of the szTTCacheSection.
|
|
*
|
|
* There is no API to get the size of a profile string, so we
|
|
* have to fake it by reading, reallocing, and reading again
|
|
* until it all fits.
|
|
*
|
|
* The initial value of 1024 characters means that we can handle
|
|
* up to 128 font sizes. A comfortable number, we hope.
|
|
*/
|
|
|
|
cchBuf = 1024;
|
|
cchActual = 0;
|
|
pszBufNew = (LPTSTR)LocalAlloc(LPTR, cchBuf*sizeof(TCHAR));
|
|
|
|
while (pszBufNew) {
|
|
pszBuf = pszBufNew;
|
|
cchActual = GetPrivateProfileString(szTTCacheSection[idx], NULL,
|
|
c_szNULL, pszBuf, cchBuf, szSystemINI);
|
|
if (cchActual < cchBuf - 5) goto Okay;
|
|
|
|
cchBuf += 512;
|
|
pszBufNew = (LPTSTR)LocalReAlloc(pszBuf, cchBuf*sizeof(TCHAR), LMEM_MOVEABLE|LMEM_ZEROINIT);
|
|
}
|
|
|
|
/* Bleargh. Too much stuff in the cache. Punt it and start anew. */
|
|
goto FreshStart;
|
|
|
|
Okay:
|
|
|
|
fSuccess = FALSE;
|
|
|
|
/*
|
|
* In the time between flushing the cache and reloading it here,
|
|
* a handful of fonts may have gotten added to the cache due to
|
|
* WinOldAp trying to realize the font it got back. So consider the
|
|
* font cache decent if there are at least ten fonts in it.
|
|
*/
|
|
if (cchActual >= 4 * 10) {
|
|
|
|
/*
|
|
* We found cache information. Party away.
|
|
*/
|
|
|
|
psz = pszBuf;
|
|
while (*psz) {
|
|
|
|
if (ParseIniWords(psz, (PWORD)&dwHWReq, 2, &lpszNext) != 2 ||
|
|
GetIniWords(szTTCacheSection[idx], psz,
|
|
(PWORD)&dwHWActual, 2, szSystemINI) != 2) {
|
|
/* Font cache looks bogus. Start with a new one. */
|
|
goto FreshStart;
|
|
}
|
|
|
|
if (AddToFontListCache(hwndList, fListBox,
|
|
(UINT)HIWORD(dwHWReq),
|
|
(UINT)LOWORD(dwHWReq),
|
|
(UINT)HIWORD(dwHWActual),
|
|
(UINT)LOWORD(dwHWActual),
|
|
CodePage) == BPFDI_CANCEL)
|
|
goto E0;
|
|
|
|
psz = (LPTSTR)(lpszNext + 1); /* Skip past the NUL */
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
FreshStart:
|
|
/* Blast the old cache, just make sure we have a clean slate */
|
|
WritePrivateProfileString(szTTCacheSection[idx], NULL, NULL, szSystemINI);
|
|
|
|
/* No cache available. Need to build one. */
|
|
for (i = 0; i < NUMINITIALTTHEIGHTS; i++)
|
|
{
|
|
if (rgwInitialTtHeights[i])
|
|
{
|
|
AddOneNewTrueTypeFontToFontListA(hwndList, fListBox,
|
|
0, (UINT)rgwInitialTtHeights[i],
|
|
lpszTTFaceName, CodePage);
|
|
}
|
|
}
|
|
}
|
|
|
|
fSuccess = TRUE;
|
|
E0:
|
|
EVAL(LocalFree(pszBuf) == NULL);
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
/* Given height and width, synthesize a TrueType font with those
|
|
* dimensions and record the actual font height and width in
|
|
* the persistent font cache, as well as a FDI.
|
|
*
|
|
* Entry:
|
|
* hwndList = List box or combo box to fill with info
|
|
* fListBox = TRUE if hwndList is a listbox, FALSE if a combo box
|
|
* wHeight = Desired font height
|
|
* wWidth = Desired font width (can be zero for "default")
|
|
* lpszTTFaceName
|
|
*
|
|
* Returns:
|
|
* BPFDI of font dimension info, or BPFDI_CANCEL on failure.
|
|
*
|
|
* Caveats:
|
|
* The wsprintf assumes that the fdiWidthReq and
|
|
* fdiHeightReq fields appear in the indicated order,
|
|
* because the values will be read into a dwHeightWidth later.
|
|
*
|
|
* Similarly for the WriteIniWords.
|
|
*/
|
|
|
|
BPFDI AddOneNewTrueTypeFontToFontListA(HWND hwndList,
|
|
BOOL fListBox,
|
|
UINT uWidth, UINT uHeight,
|
|
LPSTR lpszTTFaceName, INT CodePage)
|
|
{
|
|
BPFDI bpfdi;
|
|
HDC hDC;
|
|
HFONT hFont;
|
|
SIZE sSize;
|
|
HFONT hFontPrev;
|
|
DWORD dwHeightWidth;
|
|
TCHAR szBuf[MAXDIMENSTRING];
|
|
|
|
int idx;
|
|
BYTE bCharset;
|
|
DWORD fdwClipPrecision;
|
|
|
|
bpfdi = BPFDI_CANCEL;
|
|
|
|
hDC = GetDC(NULL); /* Get a screen DC */
|
|
if (!hDC) goto E0;
|
|
|
|
// choose charset, clip precision based on codepage
|
|
// 0xFE is a hack for japanese platform
|
|
//
|
|
bCharset = (CodePage == CP_JPN? 0xFE: OEMCharsetFromCP(CodePage));
|
|
|
|
if (CodePage == CP_US)
|
|
fdwClipPrecision = CLIP_DEFAULT_PRECIS|(g_uCodePage == CP_WANSUNG? CLIP_DFA_OVERRIDE: 0);
|
|
else
|
|
fdwClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
|
|
hFont = CreateFontA((INT)uHeight, (INT)uWidth, 0, 0, 0, 0, 0, 0,
|
|
bCharset, OUT_TT_PRECIS,
|
|
fdwClipPrecision, 0, FIXED_PITCH | FF_DONTCARE, lpszTTFaceName);
|
|
|
|
if (!hFont) goto E1;
|
|
|
|
hFontPrev = SelectObject(hDC, hFont);
|
|
if (!hFontPrev) goto E2;
|
|
|
|
if (GetTextExtentPoint32(hDC, szZero, 1, &sSize))
|
|
{
|
|
dwHeightWidth = (sSize.cy << 16) | (sSize.cx & 0x00FF);
|
|
}
|
|
else
|
|
{
|
|
dwHeightWidth = 0;
|
|
}
|
|
|
|
if (!dwHeightWidth) goto E3;
|
|
|
|
if (IsBilingualCP(CodePage) && (HIWORD(dwHeightWidth)%2))
|
|
goto E3;
|
|
|
|
StringCchPrintf(szBuf, ARRAYSIZE(szBuf), TEXT("%d %d"), uWidth, uHeight);
|
|
|
|
idx = IsBilingualCP(CodePage) ? 0 : 1;
|
|
|
|
WriteIniWords(szTTCacheSection[idx], szBuf, (PWORD)&dwHeightWidth, 2, szSystemINI);
|
|
|
|
bpfdi = AddToFontListCache(hwndList, fListBox, uHeight, uWidth,
|
|
(UINT)sSize.cy, (UINT)sSize.cx,
|
|
CodePage);
|
|
|
|
E3: SelectObject(hDC, hFontPrev);
|
|
E2: DeleteObject(hFont);
|
|
E1: ReleaseDC(0, hDC);
|
|
E0: return bpfdi;
|
|
|
|
}
|
|
|
|
|
|
/* Returns the BPFDI corresponding to the currently selected font in
|
|
* the indicated list or combo box, or BPFDI_CANCEL on error.
|
|
*
|
|
* Entry:
|
|
* hwndList == handle to listbox or combo box to fill
|
|
* if NULL, then AUTO font calculation is assumed
|
|
* fListBox == TRUE if hwndList is a listbox, FALSE if a combo box
|
|
* pfi -> FNTINFO structure
|
|
* if pfi is NULL, then AUTO font calculation is ignored
|
|
* Returns:
|
|
* BPFDI of the current selection, or BPFDI_CANCEL on error.
|
|
*/
|
|
DWORD_PTR GetFont(HWND hwndList, BOOL fListBox, PFNTINFO pfi)
|
|
{
|
|
DWORD dwIndex = 0;
|
|
BPFDI bpfdi = BPFDI_CANCEL;
|
|
|
|
if (!hwndList) { // just do AUTO calculations
|
|
if (!pfi)
|
|
goto Exit; // whoops, can't even do those
|
|
goto ChooseBest;
|
|
}
|
|
dwIndex = lcbGetCurSel(hwndList, fListBox);
|
|
if (!IsDlgError(dwIndex)) {
|
|
|
|
if (pfi)
|
|
pfi->fntProposed.flFnt &= ~FNT_AUTOSIZE;
|
|
|
|
bpfdi = lcbGetBpfdi(hwndList, fListBox, dwIndex);
|
|
|
|
if (bpfdi == BPFDI_AUTO && pfi) {
|
|
pfi->fntProposed.flFnt |= FNT_AUTOSIZE;
|
|
|
|
ChooseBest:
|
|
bpfdi = ChooseBestFont((UINT)pfi->winOriginal.cxCells,
|
|
(UINT)pfi->winOriginal.cyCells,
|
|
(UINT)pfi->winOriginal.cxClient,
|
|
(UINT)pfi->winOriginal.cyClient,
|
|
(UINT)pfi->fntProposed.flFnt,
|
|
(INT)pfi->fntProposed.wCurrentCP);
|
|
}
|
|
// Set the index of the current selection (HIWORD
|
|
// of the return code) to LB_ERR if there's an error
|
|
|
|
if (bpfdi == BPFDI_CANCEL)
|
|
dwIndex = (DWORD)LB_ERR;
|
|
}
|
|
Exit:
|
|
if (!IsSpecialBpfdi(bpfdi))
|
|
{
|
|
bpfdi->Index = dwIndex;
|
|
}
|
|
|
|
return (DWORD_PTR)bpfdi;
|
|
}
|
|
|
|
|
|
/* Copies data from the given BPFDI to the given PROPFNT structure.
|
|
*
|
|
* Entry:
|
|
* lpFnt = pointer to PROPFNT structure
|
|
* bpfdi = based pointer to a FONTDIMENINFO structure;
|
|
* if a special BPFDI_* constant, no font info is changed
|
|
* Returns:
|
|
* Nothing
|
|
*/
|
|
void SetFont(LPPROPFNT lpFnt, BPFDI bpfdi)
|
|
{
|
|
if (!IsSpecialBpfdi(bpfdi))
|
|
{
|
|
lpFnt->flFnt &= ~(FNT_RASTER | FNT_TT);
|
|
|
|
if (bpfdi->fdiHeightReq == 0)
|
|
{
|
|
/* Raster font */
|
|
lpFnt->flFnt |= FNT_RASTER;
|
|
lpFnt->cxFont = lpFnt->cxFontActual = (WORD) bpfdi->fdiWidthActual;
|
|
lpFnt->cyFont = lpFnt->cyFontActual = (WORD) bpfdi->fdiHeightActual;
|
|
}
|
|
else
|
|
{
|
|
/* TrueType font */
|
|
lpFnt->flFnt |= FNT_TT;
|
|
lpFnt->cxFont = (WORD) bpfdi->fdiWidthReq;
|
|
lpFnt->cyFont = (WORD) bpfdi->fdiHeightReq;
|
|
lpFnt->cxFontActual = (WORD) bpfdi->fdiWidthActual;
|
|
lpFnt->cyFontActual = (WORD) bpfdi->fdiHeightActual;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Performs the following calculation in LONG arithmetic to avoid
|
|
* overflow:
|
|
* return = n1 * m / n2
|
|
* This can be used to make an aspect ration calculation where n1/n2
|
|
* is the aspect ratio and m is a known value. The return value will
|
|
* be the value that corresponds to m with the correct apsect ratio.
|
|
*/
|
|
|
|
//
|
|
// <This is defined as a macro for Win32 >
|
|
//
|
|
|
|
/* Scales a point to be preview-sized instead of screen-sized.
|
|
* Depends on the global vars cxScreen and cyScreen established at init.
|
|
*/
|
|
|
|
void AspectPoint(LPRECT lprcPreview, LPPOINT lppt)
|
|
{
|
|
lppt->x = AspectScale(lprcPreview->right, cxScreen, lppt->x);
|
|
lppt->y = AspectScale(lprcPreview->bottom, cyScreen, lppt->y);
|
|
}
|
|
|
|
/* AspectRect
|
|
*
|
|
* Scales a rectangle to be preview-sized instead of screen-sized.
|
|
* Depends on the global vars cxScreen and cyScreen established at init.
|
|
*/
|
|
|
|
void AspectRect(LPRECT lprcPreview, LPRECT lprc)
|
|
{
|
|
AspectPoint(lprcPreview, &((LPPOINT)lprc)[0]); /* Upper left corner */
|
|
AspectPoint(lprcPreview, &((LPPOINT)lprc)[1]); /* Lower right corner */
|
|
}
|
|
|
|
/* Given a BPFDI, create a font that corresponds to it.
|
|
*
|
|
* Entry:
|
|
* bpfdi -> FDI describing the font we want to create
|
|
* pfi -> proposed font info structure
|
|
*
|
|
* Returns:
|
|
* HFONT that was created.
|
|
*/
|
|
HFONT CreateFontFromBpfdi(BPFDI bpfdi, PFNTINFO pfi)
|
|
{
|
|
HFONT hf;
|
|
int fdwClipPrecision;
|
|
BYTE bT2Charset;
|
|
|
|
// a hack for japanese charset
|
|
bT2Charset = (pfi->fntProposed.wCurrentCP == CP_JPN?
|
|
0xFE: OEMCharsetFromCP(pfi->fntProposed.wCurrentCP));
|
|
|
|
if (pfi->fntProposed.wCurrentCP == CP_US)
|
|
fdwClipPrecision = CLIP_DEFAULT_PRECIS|(g_uCodePage == CP_WANSUNG? CLIP_DFA_OVERRIDE: 0);
|
|
else
|
|
fdwClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
|
|
if (bpfdi->fdiHeightReq == 0) {
|
|
/* Raster font */
|
|
hf = CreateFontA(bpfdi->fdiHeightActual, bpfdi->fdiWidthActual,
|
|
0, 0, 0, 0, 0, 0, (BYTE)OEMCharsetFromCP(pfi->fntProposed.wCurrentCP),
|
|
OUT_RASTER_PRECIS, fdwClipPrecision,
|
|
0, FIXED_PITCH | FF_DONTCARE, pfi->fntProposed.achRasterFaceName);
|
|
} else {
|
|
/* a TrueType font */
|
|
hf = CreateFontA(bpfdi->fdiHeightReq, bpfdi->fdiWidthReq,
|
|
0, 0, 0, 0, 0, 0, (BYTE)bT2Charset, OUT_TT_PRECIS, fdwClipPrecision,
|
|
0, FIXED_PITCH | FF_DONTCARE, pfi->fntProposed.achTTFaceName);
|
|
}
|
|
|
|
return hf;
|
|
}
|
|
|
|
|
|
/** FontSelInit
|
|
*
|
|
* Obtain the various font selection penalties from SYSTEM.INI
|
|
* and force the values into range.
|
|
*
|
|
* Entry:
|
|
* rgwInitialTtHeights contains default values for sizes.
|
|
*
|
|
* Exit:
|
|
* rgwInitialTtHeights contains actual values for sizes.
|
|
*/
|
|
|
|
void FontSelInit(void)
|
|
{
|
|
GetIniWords(szNonWinSection, szTTInitialSizes,
|
|
rgwInitialTtHeights, sizeof(rgwInitialTtHeights)/sizeof(WORD), szSystemINI);
|
|
}
|
|
|
|
|
|
/* Convert logical dimensions for a TrueType font into physical
|
|
* dimensions. If possible, we get this information from the
|
|
* font dimension cache, but in the case where this is not possible,
|
|
* we synthesize the font and measure him directly.
|
|
*
|
|
* Entry:
|
|
* dxWidth = logical font width
|
|
* dyHeight = logical font height
|
|
*
|
|
* Returns:
|
|
* BPFDI pointing to dimension information, or BPFDI_CANCEL on failure.
|
|
*/
|
|
|
|
BPFDI GetTrueTypeFontTrueDimensions(UINT dxWidth, UINT dyHeight, INT CodePage)
|
|
{
|
|
IFDI ifdi;
|
|
BPFDI bpfdi;
|
|
int idx = IsBilingualCP(CodePage)? 1 : 0;
|
|
for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache + bpfdiStart[idx]);
|
|
ifdi < cfdiCache[idx]; ifdi++, bpfdi++)
|
|
{
|
|
if (bpfdi->fdiWidthReq == dxWidth &&
|
|
bpfdi->fdiHeightReq == dyHeight) {
|
|
return bpfdi;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The font dimensions have not been cached. We have to create it.
|
|
*/
|
|
return (BPFDI)AddOneNewTrueTypeFontToFontListA(0, 0, dxWidth, dyHeight,
|
|
szTTFaceName[idx], CodePage);
|
|
}
|
|
|
|
|
|
/* Look for a font that matches the indicated dimensions, creating
|
|
* one if necessary.
|
|
*
|
|
* But we never create a font which is too narrow or too short.
|
|
* The limits are controlled by the ptNonAspectMin variable.
|
|
*
|
|
* Entry:
|
|
* dxWidth = desired font width
|
|
* dyHeight = desired font height
|
|
* fPerfect = see below
|
|
*
|
|
* If fPerfect is TRUE, then a perfect match is requested
|
|
* from the font cache (we should not try to synthesize a font).
|
|
* In which case, the sign of dyHeight determines whether a
|
|
* raster font (positive) or TrueType font (negative) is
|
|
* desired. If a perfect match cannot be found, then we
|
|
* return BPFDI_CANCEL.
|
|
*
|
|
* Returns:
|
|
* BPFDI of of the font that matches the best.
|
|
* BPFDI_CANCEL if no font could be found.
|
|
*/
|
|
BPFDI FindFontMatch(UINT dxWidth, UINT dyHeight, LPINT lpfl, INT CodePage)
|
|
{
|
|
IFDI ifdi;
|
|
BPFDI bpfdi;
|
|
BPFDI bpfdiBest = BPFDI_CANCEL;
|
|
PENALTY pnlBest = SENTINELPENALTY;
|
|
int idx;
|
|
|
|
int fl = *lpfl;
|
|
/*
|
|
* First, see if a perfect match already exists.
|
|
*/
|
|
idx = IsBilingualCP(CodePage) ? 1 : 0;
|
|
for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache+bpfdiStart[idx]);
|
|
ifdi < cfdiCache[idx]; ifdi++, bpfdi++)
|
|
{
|
|
|
|
if (fl & FFM_RESTRICTED) {
|
|
/* Deal with the restrictions.
|
|
* Reject the font if it is raster but we want TTONLY, or v.v.
|
|
*
|
|
* The condition below reads as
|
|
*
|
|
* If (is a raster font != want a raster font)
|
|
*/
|
|
if (!bpfdi->fdiHeightReq != (fl == FFM_RASTERFONTS)) {
|
|
continue;
|
|
}
|
|
}
|
|
if (bpfdi->fdiHeightActual == dyHeight && bpfdi->fdiWidthActual == dxWidth) {
|
|
*lpfl = FFM_PERFECT;
|
|
return bpfdi;
|
|
} }
|
|
|
|
if (fl != FFM_TTFONTS)
|
|
return BPFDI_CANCEL;
|
|
/*
|
|
* We got here if we couldn't find a perfect match.
|
|
*
|
|
* Adjust the requested height and width for aspect ratio
|
|
* constraints. If adjustments are necessary, trust the height.
|
|
*
|
|
* Comparisons are as WORDs (unsigned) so that a setting of "-1 -1"
|
|
* lets the user forbid all non-aspect ratio fonts.
|
|
*/
|
|
if (dyHeight < (UINT)ptNonAspectMin.y || dxWidth < (UINT)ptNonAspectMin.x) {
|
|
dxWidth = 0;
|
|
}
|
|
return GetTrueTypeFontTrueDimensions(dxWidth, dyHeight, CodePage);
|
|
}
|
|
|
|
/* We have decided whether the desired size is larger or smaller.
|
|
* Compute the penalty corresponding to the Initial and Scale.
|
|
*
|
|
* Entry:
|
|
* ppnlp -> PENALTYPAIR to apply
|
|
* dSmaller = the smaller dimension
|
|
* dLarger = the larger dimension
|
|
*
|
|
* Exit:
|
|
* Returns penalty to apply to the difference in dimensions.
|
|
*/
|
|
PENALTY ComputePenaltyFromPair(PPENALTYPAIR ppnlp,
|
|
UINT dSmaller, UINT dLarger)
|
|
{
|
|
return (ppnlp->pnlInitial +
|
|
ppnlp->pnlScale - MulDiv(ppnlp->pnlScale, dSmaller, dLarger));
|
|
}
|
|
|
|
|
|
/* Compute the penalty depending on whether the desired size
|
|
* is smaller, equal to, or larger than the actual size.
|
|
*
|
|
* Entry:
|
|
* ppnll -> PENALTYLIST to apply
|
|
* dActual = the actual dimension
|
|
* dDesired = the desired dimension
|
|
*
|
|
* Exit:
|
|
* Returns penalty to apply to the difference in dimensions,
|
|
* choosing between the Overshoot and Shortfall PENALTYPAIRS,
|
|
* accordingly.
|
|
*/
|
|
PENALTY ComputePenaltyFromList(PPENALTYLIST ppnll,
|
|
UINT dActual, UINT dDesired)
|
|
{
|
|
if (dActual == dDesired)
|
|
return 0;
|
|
|
|
if (dActual < dDesired)
|
|
return ComputePenaltyFromPair(&ppnll->pnlpOvershoot, dActual, dDesired);
|
|
|
|
return ComputePenaltyFromPair(&ppnll->pnlpShortfall, dDesired, dActual);
|
|
}
|
|
|
|
|
|
/** ComputePenalty
|
|
*
|
|
* Compute the total penalty associated to a window size.
|
|
*
|
|
* Entry:
|
|
* dxCells = width of window in cells
|
|
* dyCells = height of window in cells
|
|
* dxClient = actual horizontal size of window
|
|
* dyClient = actual vertical size of window
|
|
* dxFont = width of one character in the font
|
|
* dyFont = height of one character in the font
|
|
*
|
|
* Exit:
|
|
* Returns total penalty associated to a window of the indicated
|
|
* size with a font of the indicated dimensions.
|
|
*/
|
|
PENALTY ComputePenalty(UINT cxCells, UINT cyCells,
|
|
UINT dxClient, UINT dyClient,
|
|
UINT dxFont, UINT dyFont)
|
|
{
|
|
return
|
|
(ComputePenaltyFromList(&pnllX, dxClient, dxFont * cxCells) +
|
|
ComputePenaltyFromList(&pnllY, dyClient, dyFont * cyCells));
|
|
}
|
|
|
|
|
|
/** ChooseBestFont
|
|
*
|
|
* Determine which font looks best for the specified window size
|
|
* by picking the one which has the smallest penalty.
|
|
*
|
|
* Entry:
|
|
* dxCells = width of window in cells
|
|
* dyCells = height of window in cells
|
|
* dxClient= width of window we want to fit into
|
|
* dyClient= height of window we want to fit into
|
|
* fl = font pool flags
|
|
*
|
|
* Returns:
|
|
* Word offset from lpFontTable of the font we've decided to use.
|
|
* BPFDI_CANCEL if no font could be found. (Should never happen.)
|
|
*
|
|
* NOTE!
|
|
* We do *not* FontEnum through all the fonts because that would be
|
|
* too slow. Instead, we inspect the cache of available font
|
|
* dimensions, and only after we've chosen the best font do we
|
|
* load all his other info.
|
|
*
|
|
* This means that if the user installs new fonts, we won't see
|
|
* them until the cache is updated on receipt of a WM_FONTCHANGEff
|
|
* message, or the user either (1) pulls down the font list box,
|
|
* or (2) calls up the font selection dialog box.
|
|
*/
|
|
|
|
BPFDI ChooseBestFont(UINT cxCells, UINT cyCells, UINT dxClient, UINT dyClient,
|
|
INT fl, INT CodePage)
|
|
{
|
|
int flTemp;
|
|
DWORD ifdi;
|
|
BPFDI bpfdi;
|
|
PENALTY pnl;
|
|
UINT dxWidth, dyHeight;
|
|
BPFDI bpfdiBest = BPFDI_CANCEL;
|
|
PENALTY pnlBest = SENTINELPENALTY;
|
|
int idx;
|
|
static int prev_CodePage; // Only Japan is interested in prev_CodePage.
|
|
|
|
/*
|
|
* First, synthesize the theoretical best match.
|
|
*/
|
|
if (!cxCells)
|
|
cxCells = 80; // if we get called with no real data,
|
|
if (!cyCells) // at least try to do something reasonable
|
|
cyCells = 25;
|
|
|
|
//
|
|
// In the case where the values passed in don't make sense,
|
|
// we default to raster 8x12.
|
|
//
|
|
dxWidth = (dxClient >= cxCells)? dxClient / cxCells : 8;
|
|
dyHeight = (dyClient >= cyCells)? dyClient / cyCells : 12;
|
|
|
|
//
|
|
// Now, if we bad values, make some sense out of bad values for
|
|
// dxClient & dyClient
|
|
//
|
|
|
|
if ((dxClient==0) || (dyClient==0))
|
|
{
|
|
dxClient = dxWidth * 80;
|
|
dyClient = dyHeight * 25;
|
|
}
|
|
|
|
flTemp = 0;
|
|
if ((fl & FNT_BOTHFONTS) != FNT_BOTHFONTS) {
|
|
flTemp = FFM_RASTERFONTS;
|
|
if (fl & FNT_TTFONTS)
|
|
flTemp = FFM_TTFONTS;
|
|
}
|
|
bpfdi = FindFontMatch(dxWidth, dyHeight, &flTemp, CodePage);
|
|
if (flTemp == FFM_PERFECT)
|
|
{
|
|
prev_CodePage = CodePage;
|
|
return bpfdi;
|
|
}
|
|
|
|
idx = IsBilingualCP(CodePage)? 1 : 0;
|
|
for (ifdi = 0, bpfdi = (BPFDI)((DWORD_PTR)lpCache+bpfdiStart[idx]);
|
|
ifdi < cfdiCache[idx]; ifdi++, bpfdi++)
|
|
{
|
|
// If the font pool is restricted, then only look at like fonts
|
|
|
|
if (flTemp)
|
|
if (!bpfdi->fdiHeightReq != (flTemp == FFM_RASTERFONTS))
|
|
continue;
|
|
|
|
// was ifdef JAPAN (hack)
|
|
// to prevent DOS_BOX shrinking which occurs toggling CP437 & CP932,
|
|
// just select one size bigger font when change CP437 to CP932
|
|
if (CodePage == 932 && prev_CodePage == 437) {
|
|
if (dxWidth < bpfdi->fdiWidthActual) {
|
|
if (bpfdiBest->fdiWidthActual > bpfdi->fdiWidthActual)
|
|
bpfdiBest = bpfdi;
|
|
else if (bpfdiBest->fdiWidthActual == bpfdi->fdiWidthActual &&
|
|
bpfdiBest->fdiHeightActual > bpfdi->fdiHeightActual)
|
|
bpfdiBest = bpfdi;
|
|
}
|
|
else {
|
|
if (dxWidth == bpfdi->fdiWidthActual) {
|
|
if (bpfdi->fdiHeightActual > dyHeight &&
|
|
bpfdiBest->fdiHeightActual > bpfdi->fdiHeightActual)
|
|
bpfdiBest = bpfdi;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
// was the end of ifdef JAPAN
|
|
{
|
|
pnl = 0;
|
|
if (bpfdi->fdiHeightReq)
|
|
pnl = pnlTrueType;
|
|
|
|
pnl += ComputePenalty(cxCells, cyCells,
|
|
dxClient, dyClient,
|
|
bpfdi->fdiWidthActual,
|
|
bpfdi->fdiHeightActual);
|
|
|
|
if (pnl <= pnlBest) {
|
|
pnlBest = pnl;
|
|
bpfdiBest = bpfdi;
|
|
}
|
|
}
|
|
}
|
|
// was ifdef JAPAN
|
|
prev_CodePage = CodePage;
|
|
// was end of ifdef JAPAN
|
|
return bpfdiBest;
|
|
}
|
|
|
|
#endif
|