2485 lines
78 KiB
C
2485 lines
78 KiB
C
/****************************************************************************\
|
|
*
|
|
* PROGRAM: fontview.c
|
|
*
|
|
* PURPOSE: Loads and displays fonts from the given filename
|
|
*
|
|
* COMMENTS:
|
|
*
|
|
* HISTORY:
|
|
* 02-Oct-1995 JonPa Created It
|
|
*
|
|
\****************************************************************************/
|
|
|
|
#include <windows.h> /* required for all Windows applications */
|
|
#include <commdlg.h>
|
|
#include <shellapi.h>
|
|
#include <shlwapi.h>
|
|
#include <strsafe.h>
|
|
#include <wingdip.h> /* prototype for GetFontRsourceInfo */
|
|
#include <objbase.h>
|
|
#include "fontdefs.h" /* specific to this program */
|
|
#include "fvmsg.h"
|
|
#include "fvrc.h"
|
|
#include "ttdefs.h"
|
|
|
|
|
|
|
|
HANDLE hInst; /* current instance */
|
|
HWND ghwndView = NULL;
|
|
HWND ghwndFrame = NULL;
|
|
BOOL gfPrint = FALSE;
|
|
TCHAR gszFontPath[2 * MAX_PATH];
|
|
LPTSTR gpszSampleText;
|
|
LPTSTR gpszSampleAlph[3];
|
|
FFTYPE gfftFontType;
|
|
LOGFONT glfFont;
|
|
DISPTEXT gdtDisplay;
|
|
HBRUSH ghbr3DFace;
|
|
HBRUSH ghbr3DShadow;
|
|
|
|
|
|
int gyScroll = 0; // Vertical scroll offset in pels
|
|
int gcyLine = 0;
|
|
|
|
int gcxMinWinSize = CX_MIN_WINSIZE;
|
|
int gcyMinWinSize = CY_MIN_WINSIZE;
|
|
|
|
BOOL gbIsDBCS = FALSE; // Indicates whether system default langID is DBCS
|
|
int gNumOfFonts = 0; // number of fonts in the file.
|
|
int gIndexOfFonts = 0; // current index of the fonts.
|
|
LPLOGFONT glpLogFonts; // get global data by GetFontResourceInfo()
|
|
|
|
int apts[] = { 12, 18, 24, 36, 48, 60, 72 };
|
|
#define C_POINTS_LIST (sizeof(apts) / sizeof(apts[0]))
|
|
|
|
#define CPTS_BTN_AREA 28
|
|
int gcyBtnArea = CPTS_BTN_AREA;
|
|
BTNREC gabtCmdBtns[] = {
|
|
{ 6, 6, 36, 16, IDB_DONE, NULL, MSG_DONE, NULL },
|
|
{ -6, 6, 36, 16, IDB_PRINT, NULL, MSG_PRINT, NULL },
|
|
{ 68, 6, 20, 16, IDB_PREV_FONT, NULL, MSG_PREV_FONT, NULL }, // DBCS only.
|
|
{ -68, 6, 20, 16, IDB_NEXT_FONT, NULL, MSG_NEXT_FONT, NULL } // DBCS only.
|
|
};
|
|
|
|
#define C_DBCSBUTTONS 2 // Prev & Next font are DBCS specific.
|
|
//
|
|
// This may be recalculated in WinMain to adjust for a DBCS locale.
|
|
//
|
|
int C_BUTTONS = (sizeof(gabtCmdBtns) / sizeof(gabtCmdBtns[0]));
|
|
|
|
|
|
#if DBG
|
|
void DDPrint( LPTSTR sz, DWORD dw ) {
|
|
TCHAR szBuff[246];
|
|
StringCchPrintf( szBuff, ARRAYSIZE(szBuff), sz, dw );
|
|
|
|
OutputDebugString( szBuff );
|
|
}
|
|
|
|
# define DDPRINT( s, d ) DDPrint( s, d )
|
|
#else
|
|
# define DDPRINT( s, d )
|
|
#endif
|
|
|
|
|
|
#define IsZeroFSig( fs ) ( (fs)->fsUsb[0] == 0 && (fs)->fsUsb[1] == 0 && (fs)->fsUsb[2] == 0 && \
|
|
(fs)->fsUsb[3] == 0 && (fs)->fsCsb[0] == 0 && (fs)->fsCsb[1] == 0 )
|
|
|
|
BOOL NativeCodePageSupported(LPLOGFONT lplf) {
|
|
BOOL fRet = FALSE;
|
|
HDC hdc = CreateCompatibleDC(NULL);
|
|
if (hdc)
|
|
{
|
|
HFONT hf, hfOld;
|
|
FONTSIGNATURE fsig;
|
|
CHARSETINFO csi;
|
|
|
|
DDPRINT( TEXT("System default code page: %d\n"), GetACP() );
|
|
|
|
TranslateCharsetInfo( (LPDWORD)IntToPtr(GetACP()), &csi, TCI_SRCCODEPAGE );
|
|
|
|
hf = CreateFontIndirect( lplf );
|
|
|
|
hfOld = SelectObject( hdc, hf );
|
|
|
|
GetTextCharsetInfo( hdc, &fsig, 0 );
|
|
|
|
SelectObject( hdc, hfOld );
|
|
|
|
DeleteObject(hf);
|
|
|
|
if (IsZeroFSig( &fsig ) ) {
|
|
// Font does not support GetTextCharsetInfo(), just go off of the lfCharSet value
|
|
|
|
DDPRINT( TEXT("Font does not support GetTextCharsetInfo... \nTesting %d (font cs) against"), lplf->lfCharSet );
|
|
DDPRINT( TEXT("%d (sys charset)\n"), csi.ciCharset );
|
|
|
|
fRet = (lplf->lfCharSet == csi.ciCharset);
|
|
|
|
} else {
|
|
DDPRINT( TEXT("GTCI() worked...\nChecking font charset bits %08x"), fsig.fsCsb[0] );
|
|
DDPRINT( TEXT(" %08x against"), fsig.fsCsb[1] );
|
|
DDPRINT( TEXT(" system charset bits %08x "), csi.fs.fsCsb[0] );
|
|
DDPRINT( TEXT(" %08x\n"), csi.fs.fsCsb[1] );
|
|
|
|
fRet = ((csi.fs.fsCsb[0] & fsig.fsCsb[0]) || (csi.fs.fsCsb[1] & fsig.fsCsb[1]));
|
|
}
|
|
|
|
DeleteDC(hdc);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
|
|
*
|
|
* PURPOSE: calls initialization function, processes message loop
|
|
*
|
|
*
|
|
\****************************************************************************/
|
|
int APIENTRY WinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPSTR lpstrCmdLine,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
int i, iCpts;
|
|
MSG msg;
|
|
HACCEL hAccel;
|
|
HICON hIcon;
|
|
USHORT wLanguageId;
|
|
BOOL bCoInitialized = FALSE;
|
|
|
|
//
|
|
// Initialize the gbIsDBCS flag based on the current default language.
|
|
//
|
|
wLanguageId = LANGIDFROMLCID(GetThreadLocale());
|
|
|
|
gbIsDBCS = (LANG_JAPANESE == PRIMARYLANGID(wLanguageId)) ||
|
|
(LANG_KOREAN == PRIMARYLANGID(wLanguageId)) ||
|
|
(LANG_CHINESE == PRIMARYLANGID(wLanguageId));
|
|
|
|
//
|
|
// In a DBCS locale, exclude the Prev-Next font buttons.
|
|
//
|
|
if (!gbIsDBCS)
|
|
C_BUTTONS -= C_DBCSBUTTONS;
|
|
//
|
|
// Need to initialize COM so that SHGetFileInfo will load the IExtractIcon handler
|
|
// implemented in fontext.dll.
|
|
//
|
|
if (SUCCEEDED(CoInitialize(NULL)))
|
|
bCoInitialized = TRUE;
|
|
|
|
/*
|
|
* Parse the Command Line
|
|
*
|
|
* Use GetCommandLine() here (instead of lpstrCmdLine) so the
|
|
* command string will be in Unicode on NT
|
|
*/
|
|
FillMemory( &gdtDisplay, sizeof(gdtDisplay), 0 );
|
|
|
|
if (!ParseCommand( GetCommandLine(), gszFontPath, ARRAYSIZE(gszFontPath), &gfPrint ) ||
|
|
(gfftFontType = LoadFontFile( gszFontPath, &gdtDisplay, &hIcon )) == FFT_BAD_FILE) {
|
|
|
|
// Bad font file, inform user, and exit
|
|
|
|
FmtMessageBox( NULL, MSG_APP_TITLE, NULL, MB_OK | MB_ICONSTOP,
|
|
FALSE, MSG_BADFILENAME, gszFontPath );
|
|
|
|
if (bCoInitialized)
|
|
CoUninitialize();
|
|
|
|
ExitProcess(1);
|
|
}
|
|
|
|
/*
|
|
* Now finish initializing the display structure
|
|
*/
|
|
gpszSampleAlph[0] = FmtSprintf(MSG_SAMPLEALPH_0);
|
|
gpszSampleAlph[1] = FmtSprintf(MSG_SAMPLEALPH_1);
|
|
gpszSampleAlph[2] = FmtSprintf(MSG_SAMPLEALPH_2);
|
|
|
|
// find next line on display
|
|
for( i = 0; i < CLINES_DISPLAY; i++ ) {
|
|
if (gdtDisplay.atlDsp[i].dtyp == DTP_UNUSED)
|
|
break;
|
|
}
|
|
|
|
// fill in sample alphabet
|
|
gdtDisplay.atlDsp[i].pszText = gpszSampleAlph[0];
|
|
gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleAlph[0]);
|
|
gdtDisplay.atlDsp[i].dtyp = DTP_SHRINKTEXT;
|
|
gdtDisplay.atlDsp[i].cptsSize = CPTS_SAMPLE_ALPHA;
|
|
|
|
i++;
|
|
gdtDisplay.atlDsp[i] = gdtDisplay.atlDsp[i-1];
|
|
gdtDisplay.atlDsp[i].pszText = gpszSampleAlph[1];
|
|
gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleAlph[1]);
|
|
|
|
i++;
|
|
gdtDisplay.atlDsp[i] = gdtDisplay.atlDsp[i-1];
|
|
gdtDisplay.atlDsp[i].pszText = gpszSampleAlph[2];
|
|
gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleAlph[2]);
|
|
gdtDisplay.atlDsp[i].fLineUnder = TRUE;
|
|
|
|
|
|
// now fill in sample Sentences
|
|
iCpts = 0;
|
|
|
|
if (gbIsDBCS)
|
|
{
|
|
//
|
|
// Determine with string to use: the default or the language
|
|
// specific.
|
|
//
|
|
switch (gdtDisplay.lfTestFont.lfCharSet) {
|
|
case SYMBOL_CHARSET:
|
|
case ANSI_CHARSET:
|
|
case DEFAULT_CHARSET:
|
|
case OEM_CHARSET:
|
|
gpszSampleText = FmtSprintf(MSG_SAMPLETEXT);
|
|
break;
|
|
|
|
default:
|
|
gpszSampleText = FmtSprintf(MSG_SAMPLETEXT_ALT);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(NativeCodePageSupported(&(gdtDisplay.lfTestFont))) {
|
|
//
|
|
// Native code page is supported, select that codepage
|
|
// and print the localized string.
|
|
//
|
|
CHARSETINFO csi;
|
|
|
|
TranslateCharsetInfo( (LPDWORD)IntToPtr(GetACP()), &csi, TCI_SRCCODEPAGE );
|
|
|
|
gdtDisplay.lfTestFont.lfCharSet = (BYTE)csi.ciCharset;
|
|
|
|
gpszSampleText = FmtSprintf(MSG_SAMPLETEXT);
|
|
|
|
} else {
|
|
//
|
|
// Font does not support the local code page. Print
|
|
// a random string up instead using the font's default charset.
|
|
//
|
|
gpszSampleText = FmtSprintf(MSG_ALTSAMPLE);
|
|
}
|
|
}
|
|
|
|
for( i += 1; i < CLINES_DISPLAY && iCpts < C_POINTS_LIST; i++ ) {
|
|
if (gdtDisplay.atlDsp[i].dtyp == DTP_UNUSED) {
|
|
gdtDisplay.atlDsp[i].pszText = gpszSampleText;
|
|
gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleText);
|
|
gdtDisplay.atlDsp[i].dtyp = DTP_TEXTOUT;
|
|
gdtDisplay.atlDsp[i].cptsSize = apts[iCpts++];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Init the title font LOGFONT, and other variables
|
|
*/
|
|
InitGlobals();
|
|
|
|
if (!hPrevInstance) {
|
|
if (!InitApplication(hInstance, hIcon)) {
|
|
msg.wParam = FALSE;
|
|
goto ExitProg;
|
|
}
|
|
}
|
|
|
|
/* Perform initializations that apply to a specific instance */
|
|
|
|
if (!InitInstance(hInstance, nCmdShow, gdtDisplay.atlDsp[0].pszText)) {
|
|
msg.wParam = FALSE;
|
|
goto ExitProg;
|
|
}
|
|
|
|
/* Acquire and dispatch messages until a WM_QUIT message is received. */
|
|
hAccel = LoadAccelerators(hInstance, TEXT("fviewAccel"));
|
|
|
|
while (GetMessage(&msg, NULL, 0L, 0L)) {
|
|
if (!TranslateAccelerator(ghwndView, hAccel, &msg)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
ExitProg:
|
|
for ( i = 0; i < C_BUTTONS; i++ )
|
|
FmtFree( gabtCmdBtns[i].pszText );
|
|
|
|
if (gbIsDBCS && glpLogFonts)
|
|
FreeMem(glpLogFonts);
|
|
|
|
RemoveFontResource( gszFontPath );
|
|
|
|
if (bCoInitialized)
|
|
CoUninitialize();
|
|
|
|
return (int)(msg.wParam);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: InitApplication(HANDLE)
|
|
*
|
|
* PURPOSE: Initializes window data and registers window class
|
|
*
|
|
* COMMENTS:
|
|
*
|
|
* This function is called at initialization time only if no other
|
|
* instances of the application are running. This function performs
|
|
* initialization tasks that can be done once for any number of running
|
|
* instances.
|
|
*
|
|
* In this case, we initialize a window class by filling out a data
|
|
* structure of type WNDCLASS and calling the Windows RegisterClass()
|
|
* function. Since all instances of this application use the same window
|
|
* class, we only need to do this when the first instance is initialized.
|
|
*
|
|
*
|
|
\****************************************************************************/
|
|
|
|
BOOL InitApplication(HANDLE hInstance, HICON hIcon) /* current instance */
|
|
{
|
|
WNDCLASS wc;
|
|
BOOL fRet = FALSE;
|
|
|
|
/* Fill in window class structure with parameters that describe the */
|
|
/* main window. */
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = FrameWndProc;
|
|
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance; /* Application that owns the class. */
|
|
wc.hIcon = hIcon ? hIcon : LoadIcon(NULL, IDI_APPLICATION);
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = ghbr3DFace;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = TEXT("FontViewWClass");
|
|
|
|
/* Register the window class and return success/failure code. */
|
|
|
|
if (RegisterClass(&wc)) {
|
|
/* Fill in window class structure with parameters that describe the */
|
|
/* main window. */
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = ViewWndProc;
|
|
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance; /* Application that owns the class. */
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = TEXT("FontDisplayClass");
|
|
|
|
fRet = RegisterClass(&wc);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: InitInstance(HANDLE, int)
|
|
*
|
|
* PURPOSE: Saves instance handle and creates main window
|
|
*
|
|
* COMMENTS:
|
|
*
|
|
* This function is called at initialization time for every instance of
|
|
* this application. This function performs initialization tasks that
|
|
* cannot be shared by multiple instances.
|
|
*
|
|
* In this case, we save the instance handle in a static variable and
|
|
* create and display the main program window.
|
|
*
|
|
\****************************************************************************/
|
|
|
|
BOOL InitInstance( HANDLE hInstance, int nCmdShow, LPTSTR pszTitle)
|
|
{
|
|
|
|
/* Save the instance handle in static variable, which will be used in */
|
|
/* many subsequence calls from this application to Windows. */
|
|
|
|
hInst = hInstance;
|
|
|
|
/* Create a main window for this application instance. */
|
|
|
|
ghwndFrame = CreateWindow( TEXT("FontViewWClass"), pszTitle,
|
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
|
|
|
|
/* If window could not be created, return "failure" */
|
|
|
|
if (!ghwndFrame)
|
|
return (FALSE);
|
|
|
|
return (TRUE); /* Returns the value from PostQuitMessage */
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: InitLogFont
|
|
*
|
|
\****************************************************************************/
|
|
void InitGlobals( void ) {
|
|
TCHAR szMsShellDlg2[LF_FACESIZE];
|
|
INT cyDPI,i, cxFiller, cxMaxTxt, cxTxt, cxMax;
|
|
HDC hdc;
|
|
HFONT hfOld;
|
|
RECT rc;
|
|
|
|
FillMemory( &glfFont, sizeof(glfFont), 0 );
|
|
|
|
glfFont.lfCharSet = DEFAULT_CHARSET;
|
|
glfFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
glfFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
glfFont.lfQuality = DEFAULT_QUALITY;
|
|
glfFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
|
|
|
if (LoadString(hInst, IDS_FONTFACE, szMsShellDlg2, ARRAYSIZE(szMsShellDlg2)))
|
|
StringCchCopy(glfFont.lfFaceName, ARRAYSIZE(glfFont.lfFaceName), szMsShellDlg2);
|
|
else
|
|
StringCchCopy(glfFont.lfFaceName, ARRAYSIZE(glfFont.lfFaceName), TEXT("MS Shell Dlg2"));
|
|
|
|
hdc = CreateCompatibleDC(NULL);
|
|
cyDPI = GetDeviceCaps(hdc, LOGPIXELSY );
|
|
|
|
hfOld = SelectObject( hdc, GetStockObject(DEFAULT_GUI_FONT));
|
|
|
|
// Find out size of padding around text
|
|
SetRect(&rc, 0, 0, 0, 0 );
|
|
DrawText(hdc, TEXT("####"), -1, &rc, DT_CALCRECT | DT_CENTER);
|
|
cxFiller = rc.right - rc.left;
|
|
|
|
gcyBtnArea = MulDiv( gcyBtnArea, cyDPI, C_PTS_PER_INCH );
|
|
cxMax = cxMaxTxt = 0;
|
|
for( i = 0; i < C_BUTTONS; i++ ) {
|
|
gabtCmdBtns[i].x = MulDiv( gabtCmdBtns[i].x, cyDPI, C_PTS_PER_INCH );
|
|
gabtCmdBtns[i].y = MulDiv( gabtCmdBtns[i].y, cyDPI, C_PTS_PER_INCH );
|
|
gabtCmdBtns[i].cx = MulDiv( gabtCmdBtns[i].cx, cyDPI, C_PTS_PER_INCH );
|
|
gabtCmdBtns[i].cy = MulDiv( gabtCmdBtns[i].cy, cyDPI, C_PTS_PER_INCH );
|
|
|
|
if (gabtCmdBtns[i].cx > cxMax)
|
|
cxMax = gabtCmdBtns[i].cx;
|
|
|
|
gabtCmdBtns[i].pszText = FmtSprintf( gabtCmdBtns[i].idText );
|
|
SetRect(&rc, 0, 0, 0, 0 );
|
|
DrawText(hdc, gabtCmdBtns[i].pszText, -1, &rc, DT_CALCRECT | DT_CENTER);
|
|
|
|
cxTxt = rc.right - rc.left + cxFiller;
|
|
|
|
if (cxMaxTxt < cxTxt) {
|
|
cxMaxTxt = cxTxt;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure buttons are big enough for text! (So localizer's won't have
|
|
// to change code.
|
|
//
|
|
if (cxMax < cxMaxTxt) {
|
|
for( i = 0; i < C_BUTTONS; i++ ) {
|
|
gabtCmdBtns[i].cx = gabtCmdBtns[i].cx * cxMaxTxt / cxMax;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure buttons don't overlap
|
|
//
|
|
i = C_BUTTONS - 1;
|
|
cxMax = gabtCmdBtns[0].x + gabtCmdBtns[0].cx + gabtCmdBtns[0].x + gabtCmdBtns[i].cx + (-gabtCmdBtns[i].x) +
|
|
(2 * GetSystemMetrics(SM_CXSIZEFRAME));
|
|
|
|
if (cxMax > gcxMinWinSize)
|
|
gcxMinWinSize = cxMax;
|
|
|
|
SelectObject(hdc, hfOld);
|
|
DeleteDC(hdc);
|
|
|
|
gcyLine = MulDiv( CPTS_INFO_SIZE, cyDPI, C_PTS_PER_INCH );
|
|
|
|
ghbr3DFace = GetSysColorBrush(COLOR_3DFACE);
|
|
ghbr3DShadow = GetSysColorBrush(COLOR_3DSHADOW);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: SkipWhiteSpace
|
|
*
|
|
\****************************************************************************/
|
|
LPTSTR SkipWhiteSpace( LPTSTR psz ) {
|
|
|
|
while( *psz == TEXT(' ') || *psz == TEXT('\t') || *psz == TEXT('\n') ) {
|
|
psz = CharNext( psz );
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: CloneString
|
|
*
|
|
\****************************************************************************/
|
|
LPTSTR CloneString(LPTSTR psz) {
|
|
int cch;
|
|
LPTSTR pszRet;
|
|
cch = (lstrlen( psz ) + 1);
|
|
|
|
pszRet = AllocMem(cch * sizeof(TCHAR));
|
|
StringCchCopy( pszRet, cch, psz );
|
|
return pszRet;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: GetFileSizeFromName(pszFontPath)
|
|
*
|
|
\****************************************************************************/
|
|
DWORD GetFileSizeFromName( LPCTSTR pszPath ) {
|
|
HANDLE hfile;
|
|
DWORD cb = 0;
|
|
|
|
hfile = CreateFile( pszPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
|
|
if (hfile != INVALID_HANDLE_VALUE) {
|
|
cb = GetFileSize( hfile, NULL );
|
|
CloseHandle(hfile);
|
|
}
|
|
|
|
return cb;
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT FindPfb (LPCTSTR pszPFM, LPTSTR pszPFB, size_t cchPFB);
|
|
HRESULT BuildType1FontSpec(LPCTSTR pszPFM, LPTSTR pszSpec, size_t cchSpec);
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: ParseCommand
|
|
*
|
|
\****************************************************************************/
|
|
|
|
|
|
BOOL ParseCommand( LPTSTR lpstrCmdLine, LPTSTR pszFontPath, size_t cchFontPath, BOOL *pfPrint ) {
|
|
LPTSTR psz;
|
|
BOOL fInQuote = FALSE;
|
|
TCHAR szPfmPfb[(2 * MAX_PATH) + 1]; // +1 for possible '|' delimiter.
|
|
|
|
//
|
|
// Skip program name
|
|
//
|
|
for( psz = SkipWhiteSpace(lpstrCmdLine);
|
|
*psz != TEXT('\0') && (fInQuote || *psz != TEXT(' ')); psz = CharNext(psz) ) {
|
|
|
|
if (*psz == TEXT('\"')) {
|
|
fInQuote = !fInQuote;
|
|
}
|
|
}
|
|
|
|
if (*psz == TEXT('\0')) {
|
|
*pszFontPath = TEXT('\0');
|
|
return FALSE;
|
|
}
|
|
|
|
psz = SkipWhiteSpace(psz);
|
|
|
|
//
|
|
// Check for "/p"
|
|
//
|
|
if (psz[0] == TEXT('/') && (psz[1] == TEXT('p') || psz[1] == TEXT('P'))) {
|
|
*pfPrint = TRUE;
|
|
psz += 2; // DBCS OK since we already verified that the
|
|
// chars were '/' and 'p', they can't be lead bytes
|
|
} else
|
|
*pfPrint = FALSE;
|
|
|
|
psz = SkipWhiteSpace(psz);
|
|
|
|
//
|
|
// If the string ends in ".PFM"...
|
|
//
|
|
if (0 == lstrcmpi(PathFindExtension(psz), TEXT(".PFM")))
|
|
{
|
|
if (SUCCEEDED(BuildType1FontSpec(psz, szPfmPfb, ARRAYSIZE(szPfmPfb))))
|
|
{
|
|
psz = szPfmPfb;
|
|
}
|
|
}
|
|
StringCchCopy( pszFontPath, cchFontPath, psz );
|
|
return *psz != TEXT('\0');
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: GetGDILangID
|
|
*
|
|
* REVIEW! I believe this is how GDI determines the LangID, verify on
|
|
* international builds.
|
|
*
|
|
\****************************************************************************/
|
|
WORD GetGDILangID() {
|
|
return (WORD)GetSystemDefaultLangID();
|
|
}
|
|
|
|
|
|
|
|
void ConvertTTStrToWinZStr( LPWSTR pwsz, LPVOID pvTTS, int cbMW ) {
|
|
int i, cch;
|
|
LPMWORD lpmw = pvTTS;
|
|
|
|
cch = cbMW / sizeof(MWORD);
|
|
|
|
for( i = 0; i < cch; i++ ) {
|
|
*pwsz++ = MWORD2INT(*lpmw);
|
|
lpmw++;
|
|
}
|
|
|
|
*pwsz = L'\0';
|
|
}
|
|
|
|
|
|
VOID ConvertDBCSTTStrToWinZStr( LPTSTR pwsz, LPCSTR pvTTS, ULONG cbMW ) {
|
|
BYTE Name[256];
|
|
WORD wordChar;
|
|
BYTE *ansiName = Name;
|
|
WORD *srcString = (WORD *)pvTTS;
|
|
int length = 0;
|
|
int cb = cbMW;
|
|
|
|
for(;cb;cb-=2) {
|
|
wordChar = *srcString;
|
|
if(wordChar & 0x00FF) {
|
|
*ansiName++ = (CHAR)((wordChar & 0x00FF));
|
|
*ansiName++ = (CHAR)((wordChar & 0xFF00) >> 8);
|
|
length += 2;
|
|
} else {
|
|
*ansiName++ = (CHAR)((wordChar & 0xFF00) >> 8);
|
|
length++;
|
|
}
|
|
srcString++;
|
|
}
|
|
|
|
ansiName[length] = '\0';
|
|
|
|
MultiByteToWideChar(CP_ACP,0,Name,length,pwsz,cbMW);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: FindNameString
|
|
*
|
|
* helper function for GetAlignedTTName
|
|
*
|
|
\****************************************************************************/
|
|
LPTSTR FindNameString(PBYTE pbTTData, int cNameRec, int idName, WORD wLangID)
|
|
{
|
|
PTTNAMETBL ptnt;
|
|
PTTNAMEREC ptnr;
|
|
LPTSTR psz;
|
|
int i;
|
|
|
|
ptnt = (PTTNAMETBL)pbTTData;
|
|
|
|
for( i = 0; i < cNameRec; i++ ) {
|
|
LPVOID pvTTStr;
|
|
|
|
ptnr = &(ptnt->anrNames[i]);
|
|
if (MWORD2INT(ptnr->mwidPlatform) != TTID_PLATFORM_MS ||
|
|
MWORD2INT(ptnr->mwidName) != idName ||
|
|
MWORD2INT(ptnr->mwidLang) != wLangID) {
|
|
continue;
|
|
}
|
|
|
|
pvTTStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings)
|
|
+ MWORD2INT(ptnr->mwoffString));
|
|
|
|
psz = AllocMem((MWORD2INT(ptnr->mwcbString) + sizeof(TEXT('\0'))) * 2);
|
|
|
|
if ((MWORD2INT(ptnr->mwidEncoding) == TTID_MS_GB) ||
|
|
(MWORD2INT(ptnr->mwidEncoding) == TTID_MS_WANSUNG) ||
|
|
(MWORD2INT(ptnr->mwidEncoding) == TTID_MS_BIG5)) {
|
|
ConvertDBCSTTStrToWinZStr( psz, pvTTStr, MWORD2INT(ptnr->mwcbString) );
|
|
} else {
|
|
ConvertTTStrToWinZStr( psz, pvTTStr, MWORD2INT(ptnr->mwcbString) );
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: GetAlignedTTName
|
|
*
|
|
* NOTE: This function returns an allocated string that must be freed
|
|
* after use.
|
|
*
|
|
* This function allocs a buffer to recopy the string into incase we are
|
|
* running on a RISC machine with NT. Since the string will be UNICODE
|
|
* (ie. each char is a WORD), those strings must be aligned on WORD
|
|
* boundaries. Unfortunatly, TrueType files do not neccesarily align
|
|
* the embedded unicode strings. Furthur more, on NT we can not simply
|
|
* return a pointer to the data stored in the input buffer, since the
|
|
* 'Unicode' strings stored in the TTF file are stored in Motorola (big
|
|
* endian) format, and we need the unicode chars in Intel (little endian)
|
|
* format. Last but not least, we need the returned string to be null terminated
|
|
* so we need to either alloc the buffer for that case anyway.
|
|
*
|
|
\****************************************************************************/
|
|
LPTSTR GetAlignedTTName( PBYTE pbTTData, int idName ) {
|
|
PTTNAMEREC ptnr;
|
|
PTTNAMETBL ptnt;
|
|
int cNameRec,i;
|
|
LPTSTR psz;
|
|
BOOL bFirstRetry;
|
|
WORD wLangID = GetGDILangID();
|
|
LCID lcid = GetThreadLocale();
|
|
|
|
ptnt = (PTTNAMETBL)pbTTData;
|
|
cNameRec = MWORD2INT(ptnt->mwcNameRec);
|
|
|
|
//
|
|
// Look For Microsoft Platform ID's
|
|
//
|
|
if (gbIsDBCS)
|
|
{
|
|
if ((psz = FindNameString(pbTTData, cNameRec, idName, wLangID)) != NULL) {
|
|
return psz;
|
|
}
|
|
//
|
|
// If we didn't find it, try English if we haven't already.
|
|
//
|
|
if ( wLangID != 0x0409 ) {
|
|
if ((psz = FindNameString(pbTTData, cNameRec, idName, 0x0409)) != NULL) {
|
|
return psz;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bFirstRetry = TRUE;
|
|
|
|
retry_lang:
|
|
|
|
for( i = 0; i < cNameRec; i++ ) {
|
|
LPVOID pvTTStr;
|
|
ptnr = &(ptnt->anrNames[i]);
|
|
if (MWORD2INT(ptnr->mwidPlatform) != TTID_PLATFORM_MS ||
|
|
MWORD2INT(ptnr->mwidName) != idName ||
|
|
MWORD2INT(ptnr->mwidLang) != wLangID) {
|
|
continue;
|
|
}
|
|
|
|
pvTTStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings) + MWORD2INT(ptnr->mwoffString));
|
|
psz = AllocMem(MWORD2INT(ptnr->mwcbString) + sizeof(TEXT('\0')));
|
|
|
|
ConvertTTStrToWinZStr( psz, pvTTStr, MWORD2INT(ptnr->mwcbString) );
|
|
return psz;
|
|
}
|
|
|
|
//
|
|
// Give 0x409 a try if there is no specified MAC language.
|
|
//
|
|
if (bFirstRetry && wLangID != 0x0409) {
|
|
bFirstRetry = FALSE;
|
|
wLangID = 0x0409;
|
|
goto retry_lang;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Didn't find MS Platform, try Macintosh
|
|
//
|
|
for( i = 0; i < cNameRec; i++ ) {
|
|
int cch;
|
|
LPSTR pszMacStr;
|
|
|
|
ptnr = &(ptnt->anrNames[i]);
|
|
if (MWORD2INT(ptnr->mwidPlatform) != TTID_PLATFORM_MAC ||
|
|
MWORD2INT(ptnr->mwidName) != idName ||
|
|
MWORD2INT(ptnr->mwidLang) != wLangID) {
|
|
continue;
|
|
}
|
|
|
|
pszMacStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings) + MWORD2INT(ptnr->mwoffString));
|
|
|
|
cch = MultiByteToWideChar(CP_MACCP, 0, pszMacStr, MWORD2INT(ptnr->mwcbString), NULL, 0);
|
|
if (cch == 0)
|
|
continue;
|
|
|
|
cch += 1; // for null
|
|
psz = AllocMem(cch * sizeof(TCHAR));
|
|
if (psz == NULL)
|
|
continue;
|
|
|
|
cch = MultiByteToWideChar(CP_MACCP, 0, pszMacStr, MWORD2INT(ptnr->mwcbString), psz, cch);
|
|
if (cch == 0) {
|
|
FreeMem(psz);
|
|
continue;
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
//
|
|
// Didn't find MS Platform nor Macintosh
|
|
// 1. Try change Thread Locale to data Locale
|
|
// 2. MultiByteToWideChar with Thread code page CP_THREAD_ACP
|
|
//
|
|
for( i = 0; i < cNameRec; i++ ) {
|
|
int cch;
|
|
LPSTR pszStr;
|
|
|
|
ptnr = &(ptnt->anrNames[i]);
|
|
if (MWORD2INT(ptnr->mwidName) != idName ||
|
|
MWORD2INT(ptnr->mwidLang) == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (LANGIDFROMLCID(lcid) != MWORD2INT(ptnr->mwidLang)) {
|
|
lcid = MAKELCID(MWORD2INT(ptnr->mwidLang), SORT_DEFAULT);
|
|
if (!SetThreadLocale(lcid)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
pszStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings) + MWORD2INT(ptnr->mwoffString));
|
|
|
|
cch = MultiByteToWideChar(CP_THREAD_ACP, 0, pszStr, MWORD2INT(ptnr->mwcbString), NULL, 0);
|
|
if (cch == 0)
|
|
continue;
|
|
|
|
cch += 1; // for null
|
|
psz = AllocMem(cch * sizeof(TCHAR));
|
|
if (psz == NULL)
|
|
continue;
|
|
|
|
cch = MultiByteToWideChar(CP_THREAD_ACP, 0, pszStr, MWORD2INT(ptnr->mwcbString), psz, cch);
|
|
if (cch == 0) {
|
|
FreeMem(psz);
|
|
continue;
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: LoadFontFile
|
|
*
|
|
\****************************************************************************/
|
|
FFTYPE LoadFontFile( LPTSTR pszFontPath, PDISPTEXT pdtSmpl, HICON *phIcon ) {
|
|
int cFonts;
|
|
FFTYPE fft = FFT_BAD_FILE;
|
|
SHFILEINFO sfi;
|
|
LPTSTR pszAdobe;
|
|
TCHAR szFPBuf[MAX_PATH];
|
|
|
|
cFonts = AddFontResource( pszFontPath );
|
|
|
|
if (gbIsDBCS)
|
|
{
|
|
//
|
|
// save cFonts value to global variable.
|
|
//
|
|
gNumOfFonts = cFonts;
|
|
}
|
|
|
|
if (cFonts != 0) {
|
|
LPLOGFONT lplf;
|
|
DWORD cb;
|
|
DWORD cbCFF = 0, cbMMSD = 0, cbDSIG = 0; // for OpenType
|
|
BYTE *pbDSIG = NULL; // for OpenType
|
|
BOOL fIsTT;
|
|
|
|
cb = sizeof(LOGFONT) * cFonts;
|
|
|
|
if (gbIsDBCS)
|
|
{
|
|
//
|
|
// save lplf to global variable.
|
|
//
|
|
glpLogFonts = lplf = AllocMem(cb);
|
|
}
|
|
else
|
|
{
|
|
lplf = AllocMem(cb);
|
|
}
|
|
|
|
// ?? Should this be GetFontResourceInfo (doesn't matter; but why force W)
|
|
if (GetFontResourceInfoW( (LPTSTR)pszFontPath, &cb, lplf, GFRI_LOGFONTS )) {
|
|
HDC hdc;
|
|
HFONT hf, hfOld;
|
|
LOGFONT lf;
|
|
int nIndex;
|
|
int cLoopReps = 1;
|
|
|
|
BOOL fIsTrueTypeFont;
|
|
DWORD dwSize = sizeof(BOOL);
|
|
|
|
if(GetFontResourceInfoW((LPTSTR) pszFontPath, &dwSize, &fIsTrueTypeFont, GFRI_ISTRUETYPE)) {
|
|
// If there is a raster & true type font on the system at the same time,
|
|
// and the height/width requested is supported by both fonts, the
|
|
// the font methods (which take the LOGFONT struct, *lplf) will select
|
|
// the raster font (by design). THis causes a problem when the user wants
|
|
// to view the true type font; so, an extra check needs to be done to see if
|
|
// the font requested is a true type, and if so then specify in the LOGFONT
|
|
// struct to only show the true type font
|
|
if(fIsTrueTypeFont) {
|
|
lplf->lfOutPrecision = OUT_TT_ONLY_PRECIS;
|
|
}
|
|
}
|
|
|
|
//
|
|
// This DBCS-aware code was originally placed within #ifdef DBCS
|
|
// preprocessor statements. For single-binary, these had to be
|
|
// replaced with runtime checks. The original code did some funky
|
|
// things to execute a loop in DBCS builds but only a single iteration
|
|
// in non-DBCS builds. To do this, the "for" statement and it's
|
|
// closing brace were placed in #ifdef DBCS like this:
|
|
//
|
|
// #ifdef DBCS
|
|
// for (nIndex = 0; nIndex < cFonts; nIndex++)
|
|
// {
|
|
// //
|
|
// // Other DBCS-specific code.
|
|
// //
|
|
// #endif
|
|
// //
|
|
// // Code for both DBCS and non-DBCS systems
|
|
// // executes only once.
|
|
// //
|
|
// #ifdef DBCS
|
|
// }
|
|
// #endif
|
|
//
|
|
// While effective in a multi-binary configuration, this doesn't
|
|
// translate well to a single-binary build.
|
|
// To preserve the original logic without having to do major
|
|
// reconstruction, I've replaced the loop sentinel variable with
|
|
// "cLoopReps". In non-DBCS locales, it is set to 1. In DBCS
|
|
// locales, it is assigned the value in "cFonts".
|
|
//
|
|
// [BrianAu 5/4/97]
|
|
//
|
|
|
|
if (gbIsDBCS)
|
|
cLoopReps = cFonts;
|
|
|
|
for (nIndex = 0; nIndex < cLoopReps; nIndex++) {
|
|
if (gbIsDBCS)
|
|
{
|
|
lf = *(lplf + nIndex);
|
|
|
|
//
|
|
// Skip vertical font
|
|
//
|
|
if (lf.lfFaceName[0] == TEXT('@')) {
|
|
gNumOfFonts = (cFonts == 2) ? gNumOfFonts-1 : gNumOfFonts;
|
|
continue;
|
|
}
|
|
|
|
hf = CreateFontIndirect(&lf);
|
|
}
|
|
else
|
|
{
|
|
hf = CreateFontIndirect(lplf);
|
|
}
|
|
|
|
hdc = CreateCompatibleDC(NULL);
|
|
|
|
if (hdc)
|
|
{
|
|
hfOld = SelectObject(hdc, hf);
|
|
|
|
// Only otf fonts will have CFF table, tag is ' FFC'.
|
|
|
|
cbCFF = GetFontData(hdc,' FFC', 0, NULL, 0);
|
|
cbDSIG = GetFontData(hdc,'GISD', 0, NULL, 0);
|
|
|
|
if (cbDSIG != GDI_ERROR)
|
|
{
|
|
if ((pbDSIG = AllocMem(cbDSIG)) == NULL)
|
|
{
|
|
// Can't determine what's in the DSIG table.
|
|
// Continue as though the DSIG table does not exist.
|
|
cbDSIG = 0;
|
|
}
|
|
else
|
|
{
|
|
if (GetFontData (hdc, 'GISD', 0, pbDSIG, cbDSIG) == GDI_ERROR)
|
|
{
|
|
// Continue as though the DSIG table does not exist
|
|
cbDSIG = 0;
|
|
}
|
|
FreeMem(pbDSIG);
|
|
}
|
|
}
|
|
|
|
|
|
if (cbCFF == GDI_ERROR)
|
|
cbCFF = 0;
|
|
|
|
if (cbDSIG == GDI_ERROR)
|
|
cbDSIG = 0;
|
|
|
|
if (cbCFF || cbDSIG)
|
|
{
|
|
fft = FFT_OTF;
|
|
if (cbCFF)
|
|
{
|
|
cbMMSD = GetFontData(hdc,'DSMM', 0, NULL, 0);
|
|
if (cbMMSD == GDI_ERROR)
|
|
cbMMSD = 0;
|
|
}
|
|
}
|
|
|
|
cb = GetFontData(hdc, TT_TBL_NAME, 0, NULL, 0);
|
|
|
|
if (fft != FFT_OTF)
|
|
{
|
|
fIsTT = (cb != 0 && cb != GDI_ERROR);
|
|
fft = fIsTT ? FFT_TRUETYPE : FFT_BITMAP;
|
|
}
|
|
|
|
if ((fft == FFT_TRUETYPE) || (fft == FFT_OTF)) {
|
|
int i;
|
|
LPBYTE lpTTData;
|
|
LPTSTR pszTmp;
|
|
|
|
lpTTData = AllocMem(cb);
|
|
GetFontData(hdc, TT_TBL_NAME, 0, lpTTData, cb);
|
|
|
|
i = 0;
|
|
|
|
//
|
|
// Title String
|
|
//
|
|
pdtSmpl->atlDsp[i].dtyp = DTP_SHRINKDRAW;
|
|
pdtSmpl->atlDsp[i].cptsSize = CPTS_TITLE_SIZE;
|
|
pdtSmpl->atlDsp[i].fLineUnder = TRUE;
|
|
|
|
pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_FULLFONTNM );
|
|
if (pszTmp != NULL) {
|
|
if (gbIsDBCS)
|
|
{
|
|
//
|
|
// TTC Support.
|
|
//
|
|
if (nIndex == 0) {
|
|
pdtSmpl->atlDsp[i].pszText = CloneString(pszTmp);
|
|
} else {
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_TTC_CONCAT,
|
|
pdtSmpl->atlDsp[i].pszText,
|
|
pszTmp);
|
|
}
|
|
|
|
if (nIndex + 1 == cFonts) {
|
|
//
|
|
// If last this is last font, append "(True Type)"
|
|
//
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf((fft == FFT_TRUETYPE) ? MSG_PTRUETYPEP : MSG_POPENTYPEP,
|
|
pdtSmpl->atlDsp[i].pszText);
|
|
}
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
FreeMem(pszTmp);
|
|
}
|
|
else
|
|
{
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf((fft == FFT_TRUETYPE) ? MSG_PTRUETYPEP : MSG_POPENTYPEP, pszTmp);
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
FreeMem(pszTmp);
|
|
}
|
|
} else {
|
|
if (gbIsDBCS)
|
|
{
|
|
//
|
|
// TTC support
|
|
//
|
|
if (nIndex == 0) {
|
|
pdtSmpl->atlDsp[i].pszText = CloneString(lf.lfFaceName);
|
|
} else {
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_TTC_CONCAT,
|
|
pdtSmpl->atlDsp[i].pszText,
|
|
lf.lfFaceName);
|
|
}
|
|
|
|
if (nIndex + 1 == cFonts) {
|
|
//
|
|
// If last this is last font, append "(True Type)"
|
|
//
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf((fft == FFT_TRUETYPE) ? MSG_PTRUETYPEP : MSG_POPENTYPEP,
|
|
pdtSmpl->atlDsp[i].pszText);
|
|
}
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
}
|
|
else
|
|
{
|
|
pdtSmpl->atlDsp[i].pszText = CloneString(lplf->lfFaceName);
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[0].pszText);
|
|
}
|
|
}
|
|
i++;
|
|
pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
|
|
|
|
//// insert an extra line to provide better description of the font
|
|
|
|
if (fft == FFT_OTF)
|
|
{
|
|
LPTSTR pszTemp = NULL;
|
|
WCHAR awcTmp[256];
|
|
awcTmp[0] = 0; // zero init
|
|
|
|
pdtSmpl->atlDsp[i].dtyp = DTP_NORMALDRAW;
|
|
pdtSmpl->atlDsp[i].cptsSize = CPTS_INFO_SIZE;
|
|
pdtSmpl->atlDsp[i].fLineUnder = FALSE;
|
|
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(
|
|
MSG_POTF,
|
|
awcTmp);
|
|
|
|
if (cbDSIG)
|
|
{
|
|
pszTemp = pdtSmpl->atlDsp[i].pszText;
|
|
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(
|
|
MSG_PDSIG,
|
|
pdtSmpl->atlDsp[i].pszText);
|
|
|
|
FmtFree(pszTemp);
|
|
}
|
|
|
|
pszTemp = pdtSmpl->atlDsp[i].pszText;
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(
|
|
cbCFF ? MSG_PPSGLYPHS : MSG_PTTGLYPHS,
|
|
pdtSmpl->atlDsp[i].pszText);
|
|
FmtFree(pszTemp);
|
|
|
|
pszTemp = pdtSmpl->atlDsp[i].pszText;
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(
|
|
MSG_PINSTRUCTIONS,
|
|
pdtSmpl->atlDsp[i].pszText);
|
|
FmtFree(pszTemp);
|
|
|
|
if (cbCFF)
|
|
{
|
|
pszTemp = pdtSmpl->atlDsp[i].pszText;
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(
|
|
cbMMSD ? MSG_PMULTIPLEMASTER : MSG_PSINGLEMASTER,
|
|
pdtSmpl->atlDsp[i].pszText);
|
|
FmtFree(pszTemp);
|
|
}
|
|
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
|
|
i++;
|
|
pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
|
|
}
|
|
|
|
//
|
|
// Typeface Name:
|
|
//
|
|
pdtSmpl->atlDsp[i].cptsSize = CPTS_INFO_SIZE;
|
|
pdtSmpl->atlDsp[i].dtyp = DTP_NORMALDRAW;
|
|
pdtSmpl->atlDsp[i].fLineUnder = FALSE;
|
|
pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_FONTFAMILY );
|
|
if (pszTmp != NULL) {
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_TYPEFACENAME, pszTmp);
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
FreeMem(pszTmp);
|
|
i++;
|
|
pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
|
|
}
|
|
|
|
//
|
|
// File size:
|
|
//
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_FILESIZE,
|
|
ROUND_UP_DIV(GetFileSizeFromName(pszFontPath), CB_ONE_K));
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
|
|
//
|
|
// Version:
|
|
//
|
|
pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_VERSIONSTR );
|
|
if (pszTmp != NULL) {
|
|
i++;
|
|
pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_VERSION, pszTmp);
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
FreeMem( pszTmp );
|
|
}
|
|
|
|
//
|
|
// Copyright string
|
|
//
|
|
pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_COPYRIGHT );
|
|
if (pszTmp != NULL) {
|
|
i++;
|
|
pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
|
|
pdtSmpl->atlDsp[i].cptsSize = CPTS_COPYRIGHT_SIZE;
|
|
pdtSmpl->atlDsp[i].dtyp = DTP_WRAPDRAW;
|
|
pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_COPYRIGHT, pszTmp);
|
|
pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
|
|
FreeMem( pszTmp );
|
|
}
|
|
|
|
pdtSmpl->atlDsp[i].fLineUnder = TRUE;
|
|
|
|
if (gbIsDBCS)
|
|
{
|
|
//
|
|
// TTC Support.
|
|
//
|
|
FreeMem(lpTTData);
|
|
}
|
|
} else {
|
|
|
|
// Title String (Non TrueType case)
|
|
|
|
pdtSmpl->atlDsp[0].dtyp = DTP_SHRINKDRAW;
|
|
pdtSmpl->atlDsp[0].cptsSize = CPTS_TITLE_SIZE;
|
|
pdtSmpl->atlDsp[0].fLineUnder = TRUE;
|
|
pdtSmpl->atlDsp[0].pszText = CloneString(lplf->lfFaceName);
|
|
pdtSmpl->atlDsp[0].cchText = lstrlen(pdtSmpl->atlDsp[0].pszText);
|
|
|
|
// Use Default quality, so we can see GDI scaling of Bitmap Fonts
|
|
lplf->lfQuality = DEFAULT_QUALITY;
|
|
lplf->lfWidth = 0;
|
|
}
|
|
|
|
// If LPK is loaded then GetFontResourceInfo(GFRI_LOGFONTS) may return ANSI_CHARSET for some DBCS fonts.
|
|
// Get the native char set.
|
|
if (gbIsDBCS & NativeCodePageSupported(lplf)) {
|
|
//
|
|
// Native code page is supported, set that codepage
|
|
//
|
|
CHARSETINFO csi;
|
|
|
|
TranslateCharsetInfo( (LPDWORD)IntToPtr(GetACP()), &csi, TCI_SRCCODEPAGE );
|
|
|
|
lplf->lfCharSet = (BYTE)csi.ciCharset;
|
|
}
|
|
|
|
SelectObject(hdc, hfOld);
|
|
DeleteDC(hdc);
|
|
} // if (hdc)
|
|
|
|
if (hf)
|
|
{
|
|
DeleteObject(hf);
|
|
}
|
|
|
|
} // for
|
|
pdtSmpl->lfTestFont = *lplf;
|
|
}
|
|
|
|
if (!gbIsDBCS)
|
|
{
|
|
FreeMem(lplf);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// MAJOR HACK!
|
|
//
|
|
// Since ATM-Type1 fonts are split between two files, (*.PFM and *.PFB) we have done a hack
|
|
// earlier in the code to find the missing filename and concatinate them together in
|
|
// the form "FOO.PFM|FOO.PFB", so we can then call AddFontResource() with only one string.
|
|
//
|
|
// Since SHGetFileInfo does not understand this hacked filename format, we must split ATM-Type1
|
|
// names appart here and then reconcat them after we call the shell api.
|
|
//
|
|
pszAdobe = pszFontPath;
|
|
|
|
while( *pszAdobe && *pszAdobe != TEXT('|') )
|
|
pszAdobe = CharNext(pszAdobe);
|
|
|
|
if ( *pszAdobe ) {
|
|
|
|
*pszAdobe = TEXT('\0');
|
|
|
|
pdtSmpl->atlDsp[0].pszText = FmtSprintf(MSG_PTYPE1, pdtSmpl->atlDsp[0].pszText);
|
|
pdtSmpl->atlDsp[0].cchText = lstrlen(pdtSmpl->atlDsp[0].pszText);
|
|
|
|
} else {
|
|
pszAdobe = NULL;
|
|
}
|
|
// end of HACK
|
|
|
|
|
|
//
|
|
// Get the associated icon for this font file type
|
|
//
|
|
if ( fft != FFT_BAD_FILE && SHGetFileInfo( pszFontPath, 0, &sfi, sizeof(sfi), SHGFI_ICON )) {
|
|
*phIcon = sfi.hIcon;
|
|
} else
|
|
*phIcon = NULL;
|
|
|
|
//
|
|
// HACK - restore the '|' we nuked above
|
|
//
|
|
if ( pszAdobe != NULL ) {
|
|
*pszAdobe = TEXT('|');
|
|
}
|
|
// end of HACK
|
|
|
|
return fft;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: DrawFontSample
|
|
*
|
|
* Parameters:
|
|
*
|
|
* lprcPage Size of the page in pels. A page is either a printed
|
|
* sheet (on a printer) or the Window.
|
|
*
|
|
* cyOffset Offset into the virtual sample text. Used to "scroll" the
|
|
* window up and down. Positive number means start further
|
|
* down in the virtual sample text as the top line in the
|
|
* lprcPage.
|
|
*
|
|
* lprcPaint Rectangle to draw. It is in the same coord space as
|
|
* lprcPage. Used to optimize window repaints, and to
|
|
* support banding to printers.
|
|
*
|
|
*
|
|
\****************************************************************************/
|
|
int DrawFontSample( HDC hdc, LPRECT lprcPage, int cyOffset, LPRECT lprcPaint, BOOL fReallyDraw ) {
|
|
int cyDPI;
|
|
HFONT hfOld, hfText, hfDesk;
|
|
LOGFONT lfTmp;
|
|
int yBaseline = -cyOffset;
|
|
int taOld,i;
|
|
TCHAR szNumber[10];
|
|
int cyShkTxt = -1, cptsShkTxt = -1;
|
|
SIZE sz;
|
|
int cxPage;
|
|
|
|
DPRINT((DBTX("PAINTING")));
|
|
|
|
cyDPI = GetDeviceCaps(hdc, LOGPIXELSY );
|
|
taOld = SetTextAlign(hdc, TA_BASELINE);
|
|
|
|
glfFont.lfHeight = MulDiv( -CPTS_COPYRIGHT_SIZE, cyDPI, C_PTS_PER_INCH );
|
|
hfDesk = CreateFontIndirect(&glfFont);
|
|
|
|
// Get hfOld for later
|
|
hfOld = SelectObject(hdc, hfDesk);
|
|
|
|
|
|
if (gbIsDBCS)
|
|
{
|
|
//
|
|
// if two or more fonts exist, set correct typeface name
|
|
//
|
|
if (gNumOfFonts > 1 && gfftFontType == FFT_TRUETYPE) {
|
|
gdtDisplay.atlDsp[INDEX_TYPEFACENAME].pszText =
|
|
FmtSprintf(MSG_TYPEFACENAME, gdtDisplay.lfTestFont.lfFaceName);
|
|
gdtDisplay.atlDsp[INDEX_TYPEFACENAME].cchText =
|
|
lstrlen(gdtDisplay.atlDsp[INDEX_TYPEFACENAME].pszText);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find the longest shrinktext line so we can make sure they will fit
|
|
// on the screen
|
|
//
|
|
cxPage = lprcPage->right - lprcPage->left;
|
|
for( i = 0; i < CLINES_DISPLAY && gdtDisplay.atlDsp[i].dtyp != DTP_UNUSED; i++ ) {
|
|
PTXTLN ptlCurrent = &(gdtDisplay.atlDsp[i]);
|
|
|
|
if (ptlCurrent->dtyp == DTP_SHRINKTEXT) {
|
|
lfTmp = gdtDisplay.lfTestFont;
|
|
|
|
if (cptsShkTxt == -1)
|
|
cptsShkTxt = ptlCurrent->cptsSize;
|
|
|
|
cyShkTxt = MulDiv( -cptsShkTxt, cyDPI, C_PTS_PER_INCH );
|
|
|
|
lfTmp.lfHeight = cyShkTxt;
|
|
|
|
hfText = CreateFontIndirect( &lfTmp );
|
|
SelectObject(hdc, hfText);
|
|
|
|
GetTextExtentPoint32(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &sz );
|
|
|
|
SelectObject(hdc, hfOld);
|
|
DeleteObject(hfText);
|
|
|
|
// Make sure shrink lines are not too long
|
|
if (sz.cx > cxPage) {
|
|
|
|
DPRINT((DBTX(">>>Old lfH:%d sz.cx:%d cxPage:%d"), lfTmp.lfHeight, sz.cx, cxPage));
|
|
|
|
cptsShkTxt = cptsShkTxt * cxPage / sz.cx;
|
|
cyShkTxt = MulDiv( -cptsShkTxt, cyDPI, C_PTS_PER_INCH );
|
|
|
|
DPRINT((DBTX(">>>New lfH:%d"),lfTmp.lfHeight));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Paint the screen/page
|
|
//
|
|
for( i = 0; i < CLINES_DISPLAY && gdtDisplay.atlDsp[i].dtyp != DTP_UNUSED; i++ ) {
|
|
TEXTMETRIC tm;
|
|
PTXTLN ptlCurrent = &(gdtDisplay.atlDsp[i]);
|
|
|
|
// Create and select the font for this line
|
|
|
|
if (ptlCurrent->dtyp == DTP_TEXTOUT || ptlCurrent->dtyp == DTP_SHRINKTEXT )
|
|
lfTmp = gdtDisplay.lfTestFont;
|
|
else
|
|
lfTmp = glfFont;
|
|
|
|
if (ptlCurrent->dtyp == DTP_SHRINKTEXT) {
|
|
DPRINT((DBTX("PAINT:Creating ShrinkText Font:%s height:%d"), lfTmp.lfFaceName, lfTmp.lfHeight ));
|
|
lfTmp.lfHeight = cyShkTxt;
|
|
}
|
|
else
|
|
lfTmp.lfHeight = MulDiv( -ptlCurrent->cptsSize, cyDPI, C_PTS_PER_INCH );
|
|
|
|
hfText = CreateFontIndirect( &lfTmp );
|
|
SelectObject(hdc, hfText);
|
|
|
|
|
|
// Get size characteristics for this line in the selected font
|
|
if (ptlCurrent->dtyp == DTP_SHRINKDRAW) {
|
|
|
|
GetTextExtentPoint32(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &sz );
|
|
|
|
// Make sure shrink lines are not too long
|
|
if (sz.cx > cxPage) {
|
|
|
|
SelectObject(hdc, hfOld);
|
|
DeleteObject(hfText);
|
|
|
|
DPRINT((DBTX("===Old lfH:%d sz.cx:%d cxPage:%d"), lfTmp.lfHeight, sz.cx, cxPage));
|
|
|
|
lfTmp.lfHeight = MulDiv( -ptlCurrent->cptsSize * cxPage / sz.cx, cyDPI, C_PTS_PER_INCH );
|
|
|
|
DPRINT((DBTX("===New lfH:%d"),lfTmp.lfHeight));
|
|
|
|
hfText = CreateFontIndirect( &lfTmp );
|
|
SelectObject(hdc, hfText);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
GetTextMetrics(hdc, &tm);
|
|
|
|
yBaseline += (tm.tmAscent + tm.tmExternalLeading);
|
|
DPRINT((DBTX("tmH:%d tmA:%d tmD:%d tmIL:%d tmEL:%d"), tm.tmHeight, tm.tmAscent, tm.tmDescent, tm.tmInternalLeading, tm.tmExternalLeading));
|
|
|
|
// Draw the text
|
|
switch(ptlCurrent->dtyp) {
|
|
case DTP_NORMALDRAW:
|
|
case DTP_SHRINKDRAW:
|
|
case DTP_SHRINKTEXT:
|
|
if (fReallyDraw) {
|
|
ExtTextOut(hdc, lprcPage->left, yBaseline, ETO_CLIPPED, lprcPaint,
|
|
ptlCurrent->pszText, ptlCurrent->cchText, NULL);
|
|
}
|
|
|
|
//
|
|
// Bob says "This looks nice!" (Adding a little extra white space before the underline)
|
|
//
|
|
if (ptlCurrent->fLineUnder)
|
|
yBaseline += tm.tmDescent;
|
|
|
|
break;
|
|
|
|
case DTP_WRAPDRAW: {
|
|
RECT rc;
|
|
int cy;
|
|
|
|
yBaseline += tm.tmDescent;
|
|
SetRect(&rc, lprcPage->left, yBaseline - tm.tmHeight, lprcPage->right, yBaseline );
|
|
|
|
DPRINT((DBTX("**** Org RC:(%d, %d, %d, %d) tmH:%d"), rc.left, rc.top, rc.right, rc.bottom, tm.tmHeight));
|
|
cy = DrawText(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &rc,
|
|
DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
|
|
|
|
|
|
DPRINT((DBTX("**** Cmp RC:(%d, %d, %d, %d) cy:%d"), rc.left, rc.top, rc.right, rc.bottom, cy));
|
|
if( cy > tm.tmHeight )
|
|
yBaseline = rc.bottom = rc.top + cy;
|
|
|
|
if (fReallyDraw) {
|
|
SetTextAlign(hdc, taOld);
|
|
DrawText(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &rc, DT_NOPREFIX | DT_WORDBREAK);
|
|
SetTextAlign(hdc, TA_BASELINE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case DTP_TEXTOUT:
|
|
if (fReallyDraw) {
|
|
SIZE szNum;
|
|
int cchNum;
|
|
SelectObject(hdc, hfDesk );
|
|
StringCchPrintf( szNumber, ARRAYSIZE(szNumber), TEXT("%d"), ptlCurrent->cptsSize );
|
|
cchNum = lstrlen(szNumber);
|
|
ExtTextOut(hdc, lprcPage->left, yBaseline, ETO_CLIPPED, lprcPaint, szNumber, cchNum, NULL);
|
|
|
|
|
|
GetTextExtentPoint32(hdc, szNumber, cchNum, &szNum);
|
|
|
|
SelectObject(hdc, hfText);
|
|
ExtTextOut(hdc, lprcPage->left + szNum.cx * 2, yBaseline, ETO_CLIPPED, lprcPaint,
|
|
ptlCurrent->pszText, ptlCurrent->cchText, NULL);
|
|
}
|
|
break;
|
|
}
|
|
|
|
yBaseline += tm.tmDescent;
|
|
|
|
if (fReallyDraw && ptlCurrent->fLineUnder) {
|
|
MoveToEx( hdc, lprcPage->left, yBaseline, NULL);
|
|
LineTo( hdc, lprcPage->right, yBaseline );
|
|
|
|
// Leave space for the line we just drew
|
|
yBaseline += 1;
|
|
}
|
|
|
|
SelectObject( hdc, hfOld );
|
|
DeleteObject( hfText );
|
|
}
|
|
|
|
SelectObject(hdc, hfOld);
|
|
SetTextAlign(hdc, taOld);
|
|
DeleteObject(hfDesk);
|
|
|
|
return yBaseline;
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: PaintSampleWindow
|
|
*
|
|
\****************************************************************************/
|
|
void PaintSampleWindow( HWND hwnd, HDC hdc, PAINTSTRUCT *pps ) {
|
|
RECT rcClient;
|
|
|
|
GetClientRect(hwnd, &rcClient);
|
|
|
|
DrawFontSample( hdc, &rcClient, gyScroll, &(pps->rcPaint), TRUE );
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
|
|
*
|
|
* PURPOSE: Processes messages
|
|
*
|
|
* MESSAGES:
|
|
*
|
|
* WM_COMMAND - application menu (About dialog box)
|
|
* WM_DESTROY - destroy window
|
|
*
|
|
* COMMENTS:
|
|
*
|
|
* To process the IDM_ABOUT message, call MakeProcInstance() to get the
|
|
* current instance address of the About() function. Then call Dialog
|
|
* box which will create the box according to the information in your
|
|
* fontview.rc file and turn control over to the About() function. When
|
|
* it returns, free the intance address.
|
|
*
|
|
\****************************************************************************/
|
|
|
|
LRESULT APIENTRY FrameWndProc(
|
|
HWND hwnd, /* window handle */
|
|
UINT message, /* type of message */
|
|
WPARAM wParam, /* additional information */
|
|
LPARAM lParam) /* additional information */
|
|
{
|
|
static SIZE szWindow = {0, 0};
|
|
|
|
switch (message) {
|
|
|
|
case WM_PAINT: {
|
|
HDC hdc;
|
|
RECT rc;
|
|
PAINTSTRUCT ps;
|
|
int x;
|
|
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
|
|
// get the window rect
|
|
GetClientRect(hwnd, &rc);
|
|
|
|
// extend only down by gcyBtnArea
|
|
rc.bottom = rc.top + gcyBtnArea;
|
|
|
|
// Fill rect with button face color (handled by class background brush)
|
|
// FillRect(hdc, &rc, ghbr3DFace);
|
|
|
|
// Fill small rect at bottom with edge color
|
|
rc.top = rc.bottom - 2;
|
|
FillRect(hdc, &rc, ghbr3DShadow);
|
|
|
|
ReleaseDC(hwnd, hdc);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
}
|
|
|
|
case WM_CREATE: {
|
|
HDC hdc;
|
|
RECT rc;
|
|
int i;
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
szWindow.cx = rc.right - rc.left;
|
|
szWindow.cy = rc.bottom - rc.top;
|
|
|
|
for( i = 0; i < C_BUTTONS; i++ ) {
|
|
int x = gabtCmdBtns[i].x;
|
|
HWND hwndBtn;
|
|
|
|
if (gbIsDBCS)
|
|
{
|
|
DWORD dwStyle = 0;
|
|
|
|
//
|
|
// If font is not TrueType font or not TTC font,
|
|
// AND button id is previous/next,
|
|
// then just continue.
|
|
//
|
|
if ((gfftFontType != FFT_TRUETYPE ||
|
|
gNumOfFonts <= 1) &&
|
|
(gabtCmdBtns[i].id == IDB_PREV_FONT ||
|
|
gabtCmdBtns[i].id == IDB_NEXT_FONT)) {
|
|
continue;
|
|
}
|
|
//
|
|
// Set x potision for each button.
|
|
//
|
|
switch (gabtCmdBtns[i].id) {
|
|
case IDB_PREV_FONT:
|
|
x = szWindow.cx / 2 - gabtCmdBtns[i].cx - 5;
|
|
dwStyle = WS_DISABLED; // initially disabled.
|
|
break;
|
|
case IDB_NEXT_FONT:
|
|
x = szWindow.cx / 2 + 5;
|
|
break;
|
|
default:
|
|
if (x < 0)
|
|
x = szWindow.cx + x - gabtCmdBtns[i].cx;
|
|
}
|
|
gabtCmdBtns[i].hwnd = hwndBtn = CreateWindow( TEXT("button"),
|
|
gabtCmdBtns[i].pszText,
|
|
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | dwStyle,
|
|
x, gabtCmdBtns[i].y,
|
|
gabtCmdBtns[i].cx, gabtCmdBtns[i].cy,
|
|
hwnd, (HMENU)IntToPtr(gabtCmdBtns[i].id),
|
|
hInst, NULL);
|
|
}
|
|
else
|
|
{
|
|
if (x < 0)
|
|
x = szWindow.cx + x - gabtCmdBtns[i].cx;
|
|
|
|
gabtCmdBtns[i].hwnd = hwndBtn = CreateWindow( TEXT("button"),
|
|
gabtCmdBtns[i].pszText, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
|
|
x, gabtCmdBtns[i].y,
|
|
gabtCmdBtns[i].cx, gabtCmdBtns[i].cy,
|
|
hwnd, (HMENU)IntToPtr(gabtCmdBtns[i].id),
|
|
hInst, NULL);
|
|
|
|
}
|
|
if (hwndBtn != NULL) {
|
|
SendMessage(hwndBtn,
|
|
WM_SETFONT,
|
|
(WPARAM)GetStockObject(DEFAULT_GUI_FONT),
|
|
MAKELPARAM(TRUE, 0));
|
|
}
|
|
}
|
|
|
|
ghwndView = CreateWindow( TEXT("FontDisplayClass"), NULL, WS_CHILD | WS_VSCROLL | WS_VISIBLE,
|
|
0, gcyBtnArea, szWindow.cx, szWindow.cy - gcyBtnArea, hwnd, 0, hInst, NULL );
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_GETMINMAXINFO: {
|
|
LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
|
|
|
|
lpmmi->ptMinTrackSize.x = gcxMinWinSize;
|
|
lpmmi->ptMinTrackSize.y = gcyMinWinSize;
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_SIZE: {
|
|
int cxNew, cyNew;
|
|
HDC hdc;
|
|
RECT rc;
|
|
SCROLLINFO sci;
|
|
|
|
cxNew = LOWORD(lParam);
|
|
cyNew = HIWORD(lParam);
|
|
|
|
if (cyNew != szWindow.cy || cxNew != szWindow.cx) {
|
|
int i;
|
|
|
|
if (gbIsDBCS)
|
|
{
|
|
for( i = 0; i < C_BUTTONS; i++ ) {
|
|
int x = gabtCmdBtns[i].x;
|
|
|
|
//
|
|
// If font is not TrueType font or not TTC font,
|
|
// AND button id is previous/next,
|
|
// then just continue.
|
|
//
|
|
if ((gfftFontType != FFT_TRUETYPE ||
|
|
gNumOfFonts <= 1) &&
|
|
(gabtCmdBtns[i].id == IDB_PREV_FONT ||
|
|
gabtCmdBtns[i].id == IDB_NEXT_FONT)) {
|
|
continue;
|
|
}
|
|
//
|
|
// Set x potision for each button.
|
|
//
|
|
switch (gabtCmdBtns[i].id) {
|
|
case IDB_PREV_FONT:
|
|
SetWindowPos(gabtCmdBtns[i].hwnd,
|
|
NULL,
|
|
cxNew / 2 - gabtCmdBtns[i].cx - 5,
|
|
gabtCmdBtns[i].y,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
break;
|
|
case IDB_NEXT_FONT:
|
|
SetWindowPos(gabtCmdBtns[i].hwnd,
|
|
NULL,
|
|
cxNew /2 + 5,
|
|
gabtCmdBtns[i].y,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
break;
|
|
default:
|
|
if (x < 0) {
|
|
SetWindowPos(gabtCmdBtns[i].hwnd,
|
|
NULL,
|
|
cxNew + x - gabtCmdBtns[i].cx,
|
|
gabtCmdBtns[i].y,
|
|
0,
|
|
0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // !DBCS
|
|
{
|
|
for( i = 0; i < C_BUTTONS; i++ ) {
|
|
int x = gabtCmdBtns[i].x;
|
|
|
|
if (x < 0) {
|
|
SetWindowPos(gabtCmdBtns[i].hwnd, NULL, cxNew + x - gabtCmdBtns[i].cx, gabtCmdBtns[i].y, 0, 0,
|
|
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
}
|
|
}
|
|
} // DBCS
|
|
|
|
szWindow.cx = cxNew;
|
|
szWindow.cy = cyNew;
|
|
|
|
SetWindowPos(ghwndView, NULL, 0, gcyBtnArea, szWindow.cx, szWindow.cy - gcyBtnArea,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND: /* message: command from application menu */
|
|
if (LOWORD(wParam) != IDB_DONE)
|
|
return SendMessage(ghwndView, message, wParam, lParam);
|
|
|
|
PostMessage(ghwndFrame, WM_CLOSE, 0, 0);
|
|
break;
|
|
|
|
case WM_DESTROY: {
|
|
int i;
|
|
|
|
DestroyWindow(ghwndView);
|
|
for( i = 0; i < C_BUTTONS; i++ ) {
|
|
DestroyWindow(gabtCmdBtns[i].hwnd);
|
|
}
|
|
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
|
|
default: /* Passes it on if unproccessed */
|
|
return (DefWindowProc(hwnd, message, wParam, lParam));
|
|
}
|
|
return (0L);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* FUNCTION: ViewWndProc(HWND, unsigned, WORD, LONG)
|
|
*
|
|
* PURPOSE: Processes messages
|
|
*
|
|
* MESSAGES:
|
|
*
|
|
* WM_COMMAND - application menu (About dialog box)
|
|
* WM_DESTROY - destroy window
|
|
*
|
|
* COMMENTS:
|
|
*
|
|
* To process the IDM_ABOUT message, call MakeProcInstance() to get the
|
|
* current instance address of the About() function. Then call Dialog
|
|
* box which will create the box according to the information in your
|
|
* fontview.rc file and turn control over to the About() function. When
|
|
* it returns, free the intance address.
|
|
*
|
|
\****************************************************************************/
|
|
|
|
LRESULT APIENTRY ViewWndProc(
|
|
HWND hwnd, /* window handle */
|
|
UINT message, /* type of message */
|
|
WPARAM wParam, /* additional information */
|
|
LPARAM lParam) /* additional information */
|
|
{
|
|
static SIZE szWindow = {0, 0};
|
|
static int cyVirtPage = 0;
|
|
|
|
switch (message) {
|
|
|
|
case WM_CREATE: {
|
|
HDC hdc;
|
|
RECT rc;
|
|
SCROLLINFO sci;
|
|
int i;
|
|
|
|
GetClientRect(hwnd, &rc);
|
|
szWindow.cx = rc.right - rc.left;
|
|
szWindow.cy = rc.bottom - rc.top;
|
|
|
|
hdc = CreateCompatibleDC(NULL);
|
|
cyVirtPage = DrawFontSample(hdc, &rc, 0, NULL, FALSE);
|
|
DeleteDC(hdc);
|
|
|
|
|
|
gyScroll = 0;
|
|
|
|
sci.cbSize = sizeof(sci);
|
|
sci.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
|
|
sci.nMin = 0;
|
|
sci.nMax = cyVirtPage;
|
|
sci.nPage = szWindow.cy;
|
|
sci.nPos = gyScroll;
|
|
|
|
SetScrollInfo(hwnd, SB_VERT, &sci, TRUE );
|
|
|
|
if (gfPrint)
|
|
PostMessage(hwnd, WM_COMMAND, IDB_PRINT, 0);
|
|
break;
|
|
}
|
|
|
|
case WM_SIZE: {
|
|
int cxNew, cyNew;
|
|
HDC hdc;
|
|
RECT rc;
|
|
SCROLLINFO sci;
|
|
|
|
cxNew = LOWORD(lParam);
|
|
cyNew = HIWORD(lParam);
|
|
|
|
if (cyNew != szWindow.cy || cxNew != szWindow.cx) {
|
|
int i;
|
|
|
|
szWindow.cx = cxNew;
|
|
szWindow.cy = cyNew;
|
|
|
|
hdc = CreateCompatibleDC(NULL);
|
|
SetRect(&rc, 0, 0, szWindow.cx, szWindow.cy);
|
|
cyVirtPage = DrawFontSample(hdc, &rc, 0, NULL, FALSE);
|
|
DeleteDC(hdc);
|
|
|
|
if (cyVirtPage <= cyNew) {
|
|
// Disable the scrollbar
|
|
gyScroll = 0;
|
|
}
|
|
|
|
if (cyVirtPage > szWindow.cy && gyScroll > cyVirtPage - szWindow.cy)
|
|
gyScroll = cyVirtPage - szWindow.cy;
|
|
|
|
sci.cbSize = sizeof(sci);
|
|
sci.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
|
|
sci.nMin = 0;
|
|
sci.nMax = cyVirtPage;
|
|
sci.nPage = cyNew;
|
|
sci.nPos = gyScroll;
|
|
|
|
SetScrollInfo(hwnd, SB_VERT, &sci, TRUE );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_VSCROLL: {
|
|
int iCode = (int)LOWORD(wParam);
|
|
int yPos = (int)HIWORD(wParam);
|
|
int yNewScroll = gyScroll;
|
|
|
|
switch( iCode ) {
|
|
|
|
case SB_THUMBPOSITION:
|
|
case SB_THUMBTRACK:
|
|
if (yPos != yNewScroll)
|
|
yNewScroll = yPos;
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
yNewScroll -= gcyLine;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
yNewScroll -= szWindow.cy;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
yNewScroll += gcyLine;
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
yNewScroll += szWindow.cy;
|
|
break;
|
|
|
|
case SB_TOP:
|
|
yNewScroll = 0;
|
|
break;
|
|
|
|
case SB_BOTTOM:
|
|
yNewScroll = cyVirtPage;
|
|
break;
|
|
}
|
|
|
|
if (yNewScroll < 0)
|
|
yNewScroll = 0;
|
|
|
|
if (yNewScroll > cyVirtPage - szWindow.cy)
|
|
yNewScroll = cyVirtPage - szWindow.cy;
|
|
|
|
if (yNewScroll < 0)
|
|
yNewScroll = 0;
|
|
|
|
if (gyScroll != yNewScroll) {
|
|
SCROLLINFO sci;
|
|
int dyScroll;
|
|
|
|
dyScroll = gyScroll - yNewScroll;
|
|
|
|
if (ABS(dyScroll) < szWindow.cy) {
|
|
ScrollWindowEx(hwnd, 0, dyScroll, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
|
|
} else
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
|
|
gyScroll = yNewScroll;
|
|
|
|
sci.cbSize = sizeof(sci);
|
|
sci.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
|
|
sci.nMin = 0;
|
|
sci.nMax = cyVirtPage;
|
|
sci.nPage = szWindow.cy;
|
|
sci.nPos = gyScroll;
|
|
|
|
SetScrollInfo(hwnd, SB_VERT, &sci, TRUE );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
|
|
case WM_COMMAND: /* message: command from application menu */
|
|
if( !DoCommand( hwnd, wParam, lParam ) )
|
|
return (DefWindowProc(hwnd, message, wParam, lParam));
|
|
break;
|
|
|
|
case WM_PAINT: {
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
|
|
hdc = BeginPaint( hwnd, &ps );
|
|
PaintSampleWindow( hwnd, hdc, &ps );
|
|
EndPaint( hwnd, &ps );
|
|
break;
|
|
}
|
|
|
|
default: /* Passes it on if unproccessed */
|
|
return (DefWindowProc(hwnd, message, wParam, lParam));
|
|
}
|
|
return (0L);
|
|
}
|
|
|
|
/*********************************************\
|
|
*
|
|
* PRINT DLGS
|
|
*
|
|
*
|
|
\*********************************************/
|
|
HDC PromptForPrinter(HWND hwnd, HINSTANCE hInst, int *pcCopies ) {
|
|
PRINTDLG pd;
|
|
|
|
FillMemory(&pd, sizeof(pd), 0);
|
|
|
|
pd.lStructSize = sizeof(pd);
|
|
pd.hwndOwner = hwnd;
|
|
pd.Flags = PD_RETURNDC | PD_NOSELECTION;
|
|
pd.nCopies = 1;
|
|
pd.hInstance = hInst;
|
|
|
|
if (PrintDlg(&pd)) {
|
|
*pcCopies = pd.nCopies;
|
|
return pd.hDC;
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: PrintSampleWindow(hwnd)
|
|
*
|
|
* Prompts for a printer and then draws the sample text to the printer
|
|
*
|
|
\****************************************************************************/
|
|
void PrintSampleWindow(HWND hwnd) {
|
|
HDC hdc;
|
|
DOCINFO di;
|
|
int cxDPI, cyDPI, iPage, cCopies;
|
|
RECT rcPage;
|
|
HCURSOR hcur;
|
|
|
|
hdc = PromptForPrinter(hwnd, hInst, &cCopies);
|
|
if (hdc == NULL)
|
|
return;
|
|
|
|
hcur = SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)));
|
|
|
|
cyDPI = GetDeviceCaps(hdc, LOGPIXELSY );
|
|
cxDPI = GetDeviceCaps(hdc, LOGPIXELSX );
|
|
|
|
/*
|
|
* Set a one inch margine around the page
|
|
*/
|
|
SetRect(&rcPage, 0, 0, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES));
|
|
|
|
rcPage.left += cxDPI;
|
|
rcPage.right -= cxDPI;
|
|
|
|
|
|
di.cbSize = sizeof(di);
|
|
di.lpszDocName = gdtDisplay.atlDsp[0].pszText;
|
|
di.lpszOutput = NULL;
|
|
di.lpszDatatype = NULL;
|
|
di.fwType = 0;
|
|
|
|
StartDoc(hdc, &di);
|
|
|
|
for( iPage = 0; iPage < cCopies; iPage++ ) {
|
|
StartPage(hdc);
|
|
|
|
DrawFontSample( hdc, &rcPage, -cyDPI, &rcPage, TRUE );
|
|
|
|
EndPage(hdc);
|
|
}
|
|
|
|
EndDoc(hdc);
|
|
|
|
DeleteDC(hdc);
|
|
|
|
SetCursor(hcur);
|
|
}
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: EnableCommandButtons(id, bEnable)
|
|
*
|
|
* Enable/disable command button.
|
|
*
|
|
\****************************************************************************/
|
|
BOOL EnableCommandButton(int id, BOOL bEnable)
|
|
{
|
|
int i;
|
|
HWND hwnd = NULL;
|
|
|
|
for( i = 0; i < C_BUTTONS; i++ ) {
|
|
if (gabtCmdBtns[i].id == id) {
|
|
hwnd = gabtCmdBtns[i].hwnd;
|
|
break;
|
|
}
|
|
}
|
|
return (hwnd == NULL) ? FALSE: EnableWindow(hwnd, bEnable);
|
|
}
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: ViewNextFont(iInc)
|
|
*
|
|
* Show the previous/next font.
|
|
*
|
|
\****************************************************************************/
|
|
void ViewNextFont(int iInc)
|
|
{
|
|
int index = gIndexOfFonts + iInc;
|
|
|
|
while (1) {
|
|
if ( index < 0 || index >= gNumOfFonts ) {
|
|
//
|
|
// if out of range, then return.
|
|
//
|
|
MessageBeep(MB_OK);
|
|
return;
|
|
}
|
|
else if ((*(glpLogFonts + index)).lfFaceName[0] == TEXT('@')) {
|
|
//
|
|
// if the font is vertical font, skip this font and
|
|
// try next/previous font.
|
|
//
|
|
index += iInc;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enable/Disable Prev/Next buttons.
|
|
//
|
|
if (index == 0) {
|
|
// first font
|
|
EnableCommandButton(IDB_PREV_FONT, FALSE);
|
|
EnableCommandButton(IDB_NEXT_FONT, TRUE);
|
|
}
|
|
else if (index == gNumOfFonts - 1) {
|
|
// last font
|
|
EnableCommandButton(IDB_PREV_FONT, TRUE);
|
|
EnableCommandButton(IDB_NEXT_FONT, FALSE);
|
|
}
|
|
else {
|
|
// other
|
|
EnableCommandButton(IDB_PREV_FONT, TRUE);
|
|
EnableCommandButton(IDB_NEXT_FONT, TRUE);
|
|
}
|
|
|
|
//
|
|
// Show the new font.
|
|
//
|
|
gIndexOfFonts = index;
|
|
gdtDisplay.lfTestFont = *(glpLogFonts + index);
|
|
InvalidateRect(ghwndView, NULL, TRUE);
|
|
}
|
|
|
|
|
|
/****************************************************************************\
|
|
*
|
|
* FUNCTION: DoCommand(HWND, unsigned, WORD, LONG)
|
|
*
|
|
* PURPOSE: Processes messages for "About" dialog box
|
|
*
|
|
* MESSAGES:
|
|
*
|
|
* WM_INITDIALOG - initialize dialog box
|
|
* WM_COMMAND - Input received
|
|
*
|
|
* COMMENTS:
|
|
*
|
|
* No initialization is needed for this particular dialog box, but TRUE
|
|
* must be returned to Windows.
|
|
*
|
|
* Wait for user to click on "Ok" button, then close the dialog box.
|
|
*
|
|
\****************************************************************************/
|
|
BOOL DoCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
|
|
{
|
|
|
|
switch(LOWORD(wParam)){
|
|
case IDB_PRINT: {
|
|
PrintSampleWindow(hWnd);
|
|
break;
|
|
}
|
|
|
|
case IDB_DONE: {
|
|
PostMessage(ghwndFrame, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
|
|
case IDK_UP: {
|
|
SendMessage(hWnd, WM_VSCROLL, SB_LINEUP, (LPARAM)NULL );
|
|
break;
|
|
}
|
|
|
|
case IDK_DOWN: {
|
|
SendMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)NULL );
|
|
break;
|
|
}
|
|
|
|
case IDK_PGUP: {
|
|
SendMessage(hWnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)NULL );
|
|
break;
|
|
}
|
|
|
|
case IDK_PGDWN: {
|
|
SendMessage(hWnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)NULL );
|
|
break;
|
|
}
|
|
|
|
case IDB_PREV_FONT: {
|
|
ViewNextFont(-1);
|
|
break;
|
|
}
|
|
|
|
case IDB_NEXT_FONT: {
|
|
ViewNextFont(1);
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL bFileExists(TCHAR*pszFile)
|
|
{
|
|
HANDLE hf;
|
|
|
|
if ((hf = CreateFile(pszFile,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(hf);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* FindPfb, given pfm file, see if pfb file exists in the same dir or in the
|
|
* parent directory of the pfm file
|
|
*
|
|
* Given: c:\foo\bar\font.pfm
|
|
* Check: c:\foo\bar\font.pfb
|
|
* c:\foo\font.pfb
|
|
*
|
|
* Given: font.pfm
|
|
* Check: font.pfb
|
|
* ..\font.pfb
|
|
*
|
|
* History:
|
|
* 14-Jun-1994 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
*
|
|
* 28-Feb-2002 -by- Brian Aust [BrianAu]
|
|
* Replaced all of Bodin's character manipulations with calls to
|
|
* shlwapi path functions and strsafe helpers.
|
|
*
|
|
* Returns:
|
|
* S_OK - PFB file found. Full path to PFB written to pszPFB buffer.
|
|
* S_FALSE - PFB file not found.
|
|
* Other - Error HRESULT.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT FindPfb (LPCTSTR pszPFM, LPTSTR pszPFB, size_t cchPFB)
|
|
{
|
|
TCHAR szPath[MAX_PATH]; // Working 'scratch' buffer.
|
|
HRESULT hr;
|
|
|
|
if (0 != lstrcmpi(PathFindExtension(pszPFM), TEXT(".PFM")))
|
|
{
|
|
//
|
|
// Caller didn't provide a PFM file path.
|
|
//
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Copy input path to our scratch buffer so we can modify it.
|
|
//
|
|
hr = StringCchCopy(szPath, ARRAYSIZE(szPath), pszPFM);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Does a PFB file exist in the same directory as the PFM file?
|
|
//
|
|
PathRenameExtension(szPath, TEXT(".PFB"));
|
|
if (bFileExists(szPath))
|
|
{
|
|
hr = S_OK; // Found a match!
|
|
}
|
|
else
|
|
{
|
|
LPCTSTR pszFileName = PathFindFileName(pszPFM);
|
|
//
|
|
// PFB doesn't exist in same directory.
|
|
// Try the parent directory.
|
|
// Remove the file name so we have only a directory path.
|
|
//
|
|
if (!PathRemoveFileSpec(szPath))
|
|
{
|
|
//
|
|
// This shouldn't happen. We've already tested earlier
|
|
// for content in the path string.
|
|
//
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
if (0 == szPath[0])
|
|
{
|
|
//
|
|
// Removing the file spec left us with an empty string.
|
|
// That means a bare "font.pfm" name was passed in.
|
|
// Build a relative path to the parent directory.
|
|
//
|
|
hr = StringCchPrintf(szPath, ARRAYSIZE(szPath), TEXT("..\\%s"), pszFileName);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remove the containing directory so we have a path
|
|
// to the parent directory.
|
|
//
|
|
if (PathRemoveFileSpec(szPath))
|
|
{
|
|
//
|
|
// We're now at the parent directory.
|
|
// Build a full file path here.
|
|
//
|
|
if (PathAppend(szPath, pszFileName))
|
|
{
|
|
hr = S_OK; // We have a path to test.
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No parent directory exists in the path. That
|
|
// means, the PFM file is in the root of the path.
|
|
// We've already tested for a PFB in the same
|
|
// directory so our search is over. No match.
|
|
//
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// We have a valid path to search. Replace the extension
|
|
// with .PFB and see if the file exists.
|
|
//
|
|
PathRenameExtension(szPath, TEXT(".PFB"));
|
|
if (!bFileExists(szPath))
|
|
{
|
|
hr = S_FALSE; // No match.
|
|
}
|
|
}
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// Found matching PFB file. Return the path to the caller.
|
|
//
|
|
hr = StringCchCopy(pszPFB, cchPFB, szPath);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Given the path for a PFM file, try to locate a matching
|
|
// PFB file. If one is found, the two paths are concatenated together
|
|
// and returned with a '|' character as a delimiter. If a PFB file is
|
|
// not found, the path to the PFM file is returned unaltered.
|
|
//
|
|
HRESULT BuildType1FontSpec(LPCTSTR pszPFM, LPTSTR pszSpec, size_t cchSpec)
|
|
{
|
|
TCHAR szPFB[MAX_PATH];
|
|
HRESULT hr = FindPfb(pszPFM, szPFB, ARRAYSIZE(szPFB));
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// PFB file found. Build the concatenated PFM|PFB path string.
|
|
//
|
|
hr = StringCchPrintf(pszSpec, cchSpec, TEXT("%s|%s"), pszPFM, szPFB);
|
|
}
|
|
else if (S_FALSE == hr)
|
|
{
|
|
//
|
|
// No PFB found. Return the original PFM file path.
|
|
//
|
|
hr = StringCchCopy(pszSpec, cchSpec, pszPFM);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|