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

2484 lines
80 KiB

  1. /****************************************************************************\
  2. *
  3. * PROGRAM: fontview.c
  4. *
  5. * PURPOSE: Loads and displays fonts from the given filename
  6. *
  7. * COMMENTS:
  8. *
  9. * HISTORY:
  10. * 02-Oct-1995 JonPa Created It
  11. *
  12. \****************************************************************************/
  13. #include <windows.h> /* required for all Windows applications */
  14. #include <commdlg.h>
  15. #include <shellapi.h>
  16. #include <shlwapi.h>
  17. #include <strsafe.h>
  18. #include <wingdip.h> /* prototype for GetFontRsourceInfo */
  19. #include <objbase.h>
  20. #include "fontdefs.h" /* specific to this program */
  21. #include "fvmsg.h"
  22. #include "fvrc.h"
  23. #include "ttdefs.h"
  24. HANDLE hInst; /* current instance */
  25. HWND ghwndView = NULL;
  26. HWND ghwndFrame = NULL;
  27. BOOL gfPrint = FALSE;
  28. TCHAR gszFontPath[2 * MAX_PATH];
  29. LPTSTR gpszSampleText;
  30. LPTSTR gpszSampleAlph[3];
  31. FFTYPE gfftFontType;
  32. LOGFONT glfFont;
  33. DISPTEXT gdtDisplay;
  34. HBRUSH ghbr3DFace;
  35. HBRUSH ghbr3DShadow;
  36. int gyScroll = 0; // Vertical scroll offset in pels
  37. int gcyLine = 0;
  38. int gcxMinWinSize = CX_MIN_WINSIZE;
  39. int gcyMinWinSize = CY_MIN_WINSIZE;
  40. BOOL gbIsDBCS = FALSE; // Indicates whether system default langID is DBCS
  41. int gNumOfFonts = 0; // number of fonts in the file.
  42. int gIndexOfFonts = 0; // current index of the fonts.
  43. LPLOGFONT glpLogFonts; // get global data by GetFontResourceInfo()
  44. int apts[] = { 12, 18, 24, 36, 48, 60, 72 };
  45. #define C_POINTS_LIST (sizeof(apts) / sizeof(apts[0]))
  46. #define CPTS_BTN_AREA 28
  47. int gcyBtnArea = CPTS_BTN_AREA;
  48. BTNREC gabtCmdBtns[] = {
  49. { 6, 6, 36, 16, IDB_DONE, NULL, MSG_DONE, NULL },
  50. { -6, 6, 36, 16, IDB_PRINT, NULL, MSG_PRINT, NULL },
  51. { 68, 6, 20, 16, IDB_PREV_FONT, NULL, MSG_PREV_FONT, NULL }, // DBCS only.
  52. { -68, 6, 20, 16, IDB_NEXT_FONT, NULL, MSG_NEXT_FONT, NULL } // DBCS only.
  53. };
  54. #define C_DBCSBUTTONS 2 // Prev & Next font are DBCS specific.
  55. //
  56. // This may be recalculated in WinMain to adjust for a DBCS locale.
  57. //
  58. int C_BUTTONS = (sizeof(gabtCmdBtns) / sizeof(gabtCmdBtns[0]));
  59. #if DBG
  60. void DDPrint( LPTSTR sz, DWORD dw ) {
  61. TCHAR szBuff[246];
  62. StringCchPrintf( szBuff, ARRAYSIZE(szBuff), sz, dw );
  63. OutputDebugString( szBuff );
  64. }
  65. # define DDPRINT( s, d ) DDPrint( s, d )
  66. #else
  67. # define DDPRINT( s, d )
  68. #endif
  69. #define IsZeroFSig( fs ) ( (fs)->fsUsb[0] == 0 && (fs)->fsUsb[1] == 0 && (fs)->fsUsb[2] == 0 && \
  70. (fs)->fsUsb[3] == 0 && (fs)->fsCsb[0] == 0 && (fs)->fsCsb[1] == 0 )
  71. BOOL NativeCodePageSupported(LPLOGFONT lplf) {
  72. BOOL fRet = FALSE;
  73. HDC hdc = CreateCompatibleDC(NULL);
  74. if (hdc)
  75. {
  76. HFONT hf, hfOld;
  77. FONTSIGNATURE fsig;
  78. CHARSETINFO csi;
  79. DDPRINT( TEXT("System default code page: %d\n"), GetACP() );
  80. TranslateCharsetInfo( (LPDWORD)IntToPtr(GetACP()), &csi, TCI_SRCCODEPAGE );
  81. hf = CreateFontIndirect( lplf );
  82. hfOld = SelectObject( hdc, hf );
  83. GetTextCharsetInfo( hdc, &fsig, 0 );
  84. SelectObject( hdc, hfOld );
  85. DeleteObject(hf);
  86. if (IsZeroFSig( &fsig ) ) {
  87. // Font does not support GetTextCharsetInfo(), just go off of the lfCharSet value
  88. DDPRINT( TEXT("Font does not support GetTextCharsetInfo... \nTesting %d (font cs) against"), lplf->lfCharSet );
  89. DDPRINT( TEXT("%d (sys charset)\n"), csi.ciCharset );
  90. fRet = (lplf->lfCharSet == csi.ciCharset);
  91. } else {
  92. DDPRINT( TEXT("GTCI() worked...\nChecking font charset bits %08x"), fsig.fsCsb[0] );
  93. DDPRINT( TEXT(" %08x against"), fsig.fsCsb[1] );
  94. DDPRINT( TEXT(" system charset bits %08x "), csi.fs.fsCsb[0] );
  95. DDPRINT( TEXT(" %08x\n"), csi.fs.fsCsb[1] );
  96. fRet = ((csi.fs.fsCsb[0] & fsig.fsCsb[0]) || (csi.fs.fsCsb[1] & fsig.fsCsb[1]));
  97. }
  98. DeleteDC(hdc);
  99. }
  100. return fRet;
  101. }
  102. /****************************************************************************
  103. *
  104. * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
  105. *
  106. * PURPOSE: calls initialization function, processes message loop
  107. *
  108. *
  109. \****************************************************************************/
  110. int APIENTRY WinMain(
  111. HINSTANCE hInstance,
  112. HINSTANCE hPrevInstance,
  113. LPSTR lpstrCmdLine,
  114. int nCmdShow
  115. )
  116. {
  117. int i, iCpts;
  118. MSG msg;
  119. HACCEL hAccel;
  120. HICON hIcon;
  121. USHORT wLanguageId;
  122. BOOL bCoInitialized = FALSE;
  123. //
  124. // Initialize the gbIsDBCS flag based on the current default language.
  125. //
  126. wLanguageId = LANGIDFROMLCID(GetThreadLocale());
  127. gbIsDBCS = (LANG_JAPANESE == PRIMARYLANGID(wLanguageId)) ||
  128. (LANG_KOREAN == PRIMARYLANGID(wLanguageId)) ||
  129. (LANG_CHINESE == PRIMARYLANGID(wLanguageId));
  130. //
  131. // In a DBCS locale, exclude the Prev-Next font buttons.
  132. //
  133. if (!gbIsDBCS)
  134. C_BUTTONS -= C_DBCSBUTTONS;
  135. //
  136. // Need to initialize COM so that SHGetFileInfo will load the IExtractIcon handler
  137. // implemented in fontext.dll.
  138. //
  139. if (SUCCEEDED(CoInitialize(NULL)))
  140. bCoInitialized = TRUE;
  141. /*
  142. * Parse the Command Line
  143. *
  144. * Use GetCommandLine() here (instead of lpstrCmdLine) so the
  145. * command string will be in Unicode on NT
  146. */
  147. FillMemory( &gdtDisplay, sizeof(gdtDisplay), 0 );
  148. if (!ParseCommand( GetCommandLine(), gszFontPath, ARRAYSIZE(gszFontPath), &gfPrint ) ||
  149. (gfftFontType = LoadFontFile( gszFontPath, &gdtDisplay, &hIcon )) == FFT_BAD_FILE) {
  150. // Bad font file, inform user, and exit
  151. FmtMessageBox( NULL, MSG_APP_TITLE, NULL, MB_OK | MB_ICONSTOP,
  152. FALSE, MSG_BADFILENAME, gszFontPath );
  153. if (bCoInitialized)
  154. CoUninitialize();
  155. ExitProcess(1);
  156. }
  157. /*
  158. * Now finish initializing the display structure
  159. */
  160. gpszSampleAlph[0] = FmtSprintf(MSG_SAMPLEALPH_0);
  161. gpszSampleAlph[1] = FmtSprintf(MSG_SAMPLEALPH_1);
  162. gpszSampleAlph[2] = FmtSprintf(MSG_SAMPLEALPH_2);
  163. // find next line on display
  164. for( i = 0; i < CLINES_DISPLAY; i++ ) {
  165. if (gdtDisplay.atlDsp[i].dtyp == DTP_UNUSED)
  166. break;
  167. }
  168. // fill in sample alphabet
  169. gdtDisplay.atlDsp[i].pszText = gpszSampleAlph[0];
  170. gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleAlph[0]);
  171. gdtDisplay.atlDsp[i].dtyp = DTP_SHRINKTEXT;
  172. gdtDisplay.atlDsp[i].cptsSize = CPTS_SAMPLE_ALPHA;
  173. i++;
  174. gdtDisplay.atlDsp[i] = gdtDisplay.atlDsp[i-1];
  175. gdtDisplay.atlDsp[i].pszText = gpszSampleAlph[1];
  176. gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleAlph[1]);
  177. i++;
  178. gdtDisplay.atlDsp[i] = gdtDisplay.atlDsp[i-1];
  179. gdtDisplay.atlDsp[i].pszText = gpszSampleAlph[2];
  180. gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleAlph[2]);
  181. gdtDisplay.atlDsp[i].fLineUnder = TRUE;
  182. // now fill in sample Sentences
  183. iCpts = 0;
  184. if (gbIsDBCS)
  185. {
  186. //
  187. // Determine with string to use: the default or the language
  188. // specific.
  189. //
  190. switch (gdtDisplay.lfTestFont.lfCharSet) {
  191. case SYMBOL_CHARSET:
  192. case ANSI_CHARSET:
  193. case DEFAULT_CHARSET:
  194. case OEM_CHARSET:
  195. gpszSampleText = FmtSprintf(MSG_SAMPLETEXT);
  196. break;
  197. default:
  198. gpszSampleText = FmtSprintf(MSG_SAMPLETEXT_ALT);
  199. break;
  200. }
  201. }
  202. else
  203. {
  204. if(NativeCodePageSupported(&(gdtDisplay.lfTestFont))) {
  205. //
  206. // Native code page is supported, select that codepage
  207. // and print the localized string.
  208. //
  209. CHARSETINFO csi;
  210. TranslateCharsetInfo( (LPDWORD)IntToPtr(GetACP()), &csi, TCI_SRCCODEPAGE );
  211. gdtDisplay.lfTestFont.lfCharSet = (BYTE)csi.ciCharset;
  212. gpszSampleText = FmtSprintf(MSG_SAMPLETEXT);
  213. } else {
  214. //
  215. // Font does not support the local code page. Print
  216. // a random string up instead using the font's default charset.
  217. //
  218. gpszSampleText = FmtSprintf(MSG_ALTSAMPLE);
  219. }
  220. }
  221. for( i += 1; i < CLINES_DISPLAY && iCpts < C_POINTS_LIST; i++ ) {
  222. if (gdtDisplay.atlDsp[i].dtyp == DTP_UNUSED) {
  223. gdtDisplay.atlDsp[i].pszText = gpszSampleText;
  224. gdtDisplay.atlDsp[i].cchText = lstrlen(gpszSampleText);
  225. gdtDisplay.atlDsp[i].dtyp = DTP_TEXTOUT;
  226. gdtDisplay.atlDsp[i].cptsSize = apts[iCpts++];
  227. }
  228. }
  229. /*
  230. * Init the title font LOGFONT, and other variables
  231. */
  232. InitGlobals();
  233. if (!hPrevInstance) {
  234. if (!InitApplication(hInstance, hIcon)) {
  235. msg.wParam = FALSE;
  236. goto ExitProg;
  237. }
  238. }
  239. /* Perform initializations that apply to a specific instance */
  240. if (!InitInstance(hInstance, nCmdShow, gdtDisplay.atlDsp[0].pszText)) {
  241. msg.wParam = FALSE;
  242. goto ExitProg;
  243. }
  244. /* Acquire and dispatch messages until a WM_QUIT message is received. */
  245. hAccel = LoadAccelerators(hInstance, TEXT("fviewAccel"));
  246. while (GetMessage(&msg, NULL, 0L, 0L)) {
  247. if (!TranslateAccelerator(ghwndView, hAccel, &msg)) {
  248. TranslateMessage(&msg);
  249. DispatchMessage(&msg);
  250. }
  251. }
  252. ExitProg:
  253. for ( i = 0; i < C_BUTTONS; i++ )
  254. FmtFree( gabtCmdBtns[i].pszText );
  255. if (gbIsDBCS && glpLogFonts)
  256. FreeMem(glpLogFonts);
  257. RemoveFontResource( gszFontPath );
  258. if (bCoInitialized)
  259. CoUninitialize();
  260. return (int)(msg.wParam);
  261. }
  262. /****************************************************************************
  263. *
  264. * FUNCTION: InitApplication(HANDLE)
  265. *
  266. * PURPOSE: Initializes window data and registers window class
  267. *
  268. * COMMENTS:
  269. *
  270. * This function is called at initialization time only if no other
  271. * instances of the application are running. This function performs
  272. * initialization tasks that can be done once for any number of running
  273. * instances.
  274. *
  275. * In this case, we initialize a window class by filling out a data
  276. * structure of type WNDCLASS and calling the Windows RegisterClass()
  277. * function. Since all instances of this application use the same window
  278. * class, we only need to do this when the first instance is initialized.
  279. *
  280. *
  281. \****************************************************************************/
  282. BOOL InitApplication(HANDLE hInstance, HICON hIcon) /* current instance */
  283. {
  284. WNDCLASS wc;
  285. BOOL fRet = FALSE;
  286. /* Fill in window class structure with parameters that describe the */
  287. /* main window. */
  288. wc.style = CS_HREDRAW | CS_VREDRAW;
  289. wc.lpfnWndProc = FrameWndProc;
  290. wc.cbClsExtra = 0;
  291. wc.cbWndExtra = 0;
  292. wc.hInstance = hInstance; /* Application that owns the class. */
  293. wc.hIcon = hIcon ? hIcon : LoadIcon(NULL, IDI_APPLICATION);
  294. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  295. wc.hbrBackground = ghbr3DFace;
  296. wc.lpszMenuName = NULL;
  297. wc.lpszClassName = TEXT("FontViewWClass");
  298. /* Register the window class and return success/failure code. */
  299. if (RegisterClass(&wc)) {
  300. /* Fill in window class structure with parameters that describe the */
  301. /* main window. */
  302. wc.style = CS_HREDRAW | CS_VREDRAW;
  303. wc.lpfnWndProc = ViewWndProc;
  304. wc.cbClsExtra = 0;
  305. wc.cbWndExtra = 0;
  306. wc.hInstance = hInstance; /* Application that owns the class. */
  307. wc.hIcon = NULL;
  308. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  309. wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  310. wc.lpszMenuName = NULL;
  311. wc.lpszClassName = TEXT("FontDisplayClass");
  312. fRet = RegisterClass(&wc);
  313. }
  314. return fRet;
  315. }
  316. /****************************************************************************
  317. *
  318. * FUNCTION: InitInstance(HANDLE, int)
  319. *
  320. * PURPOSE: Saves instance handle and creates main window
  321. *
  322. * COMMENTS:
  323. *
  324. * This function is called at initialization time for every instance of
  325. * this application. This function performs initialization tasks that
  326. * cannot be shared by multiple instances.
  327. *
  328. * In this case, we save the instance handle in a static variable and
  329. * create and display the main program window.
  330. *
  331. \****************************************************************************/
  332. BOOL InitInstance( HANDLE hInstance, int nCmdShow, LPTSTR pszTitle)
  333. {
  334. /* Save the instance handle in static variable, which will be used in */
  335. /* many subsequence calls from this application to Windows. */
  336. hInst = hInstance;
  337. /* Create a main window for this application instance. */
  338. ghwndFrame = CreateWindow( TEXT("FontViewWClass"), pszTitle,
  339. WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
  340. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );
  341. /* If window could not be created, return "failure" */
  342. if (!ghwndFrame)
  343. return (FALSE);
  344. return (TRUE); /* Returns the value from PostQuitMessage */
  345. }
  346. /****************************************************************************
  347. *
  348. * FUNCTION: InitLogFont
  349. *
  350. \****************************************************************************/
  351. void InitGlobals( void ) {
  352. TCHAR szMsShellDlg2[LF_FACESIZE];
  353. INT cyDPI,i, cxFiller, cxMaxTxt, cxTxt, cxMax;
  354. HDC hdc;
  355. HFONT hfOld;
  356. RECT rc;
  357. FillMemory( &glfFont, sizeof(glfFont), 0 );
  358. glfFont.lfCharSet = DEFAULT_CHARSET;
  359. glfFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  360. glfFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  361. glfFont.lfQuality = DEFAULT_QUALITY;
  362. glfFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  363. if (LoadString(hInst, IDS_FONTFACE, szMsShellDlg2, ARRAYSIZE(szMsShellDlg2)))
  364. StringCchCopy(glfFont.lfFaceName, ARRAYSIZE(glfFont.lfFaceName), szMsShellDlg2);
  365. else
  366. StringCchCopy(glfFont.lfFaceName, ARRAYSIZE(glfFont.lfFaceName), TEXT("MS Shell Dlg2"));
  367. hdc = CreateCompatibleDC(NULL);
  368. cyDPI = GetDeviceCaps(hdc, LOGPIXELSY );
  369. hfOld = SelectObject( hdc, GetStockObject(DEFAULT_GUI_FONT));
  370. // Find out size of padding around text
  371. SetRect(&rc, 0, 0, 0, 0 );
  372. DrawText(hdc, TEXT("####"), -1, &rc, DT_CALCRECT | DT_CENTER);
  373. cxFiller = rc.right - rc.left;
  374. gcyBtnArea = MulDiv( gcyBtnArea, cyDPI, C_PTS_PER_INCH );
  375. cxMax = cxMaxTxt = 0;
  376. for( i = 0; i < C_BUTTONS; i++ ) {
  377. gabtCmdBtns[i].x = MulDiv( gabtCmdBtns[i].x, cyDPI, C_PTS_PER_INCH );
  378. gabtCmdBtns[i].y = MulDiv( gabtCmdBtns[i].y, cyDPI, C_PTS_PER_INCH );
  379. gabtCmdBtns[i].cx = MulDiv( gabtCmdBtns[i].cx, cyDPI, C_PTS_PER_INCH );
  380. gabtCmdBtns[i].cy = MulDiv( gabtCmdBtns[i].cy, cyDPI, C_PTS_PER_INCH );
  381. if (gabtCmdBtns[i].cx > cxMax)
  382. cxMax = gabtCmdBtns[i].cx;
  383. gabtCmdBtns[i].pszText = FmtSprintf( gabtCmdBtns[i].idText );
  384. SetRect(&rc, 0, 0, 0, 0 );
  385. DrawText(hdc, gabtCmdBtns[i].pszText, -1, &rc, DT_CALCRECT | DT_CENTER);
  386. cxTxt = rc.right - rc.left + cxFiller;
  387. if (cxMaxTxt < cxTxt) {
  388. cxMaxTxt = cxTxt;
  389. }
  390. }
  391. //
  392. // Make sure buttons are big enough for text! (So localizer's won't have
  393. // to change code.
  394. //
  395. if (cxMax < cxMaxTxt) {
  396. for( i = 0; i < C_BUTTONS; i++ ) {
  397. gabtCmdBtns[i].cx = gabtCmdBtns[i].cx * cxMaxTxt / cxMax;
  398. }
  399. }
  400. //
  401. // Make sure buttons don't overlap
  402. //
  403. i = C_BUTTONS - 1;
  404. cxMax = gabtCmdBtns[0].x + gabtCmdBtns[0].cx + gabtCmdBtns[0].x + gabtCmdBtns[i].cx + (-gabtCmdBtns[i].x) +
  405. (2 * GetSystemMetrics(SM_CXSIZEFRAME));
  406. if (cxMax > gcxMinWinSize)
  407. gcxMinWinSize = cxMax;
  408. SelectObject(hdc, hfOld);
  409. DeleteDC(hdc);
  410. gcyLine = MulDiv( CPTS_INFO_SIZE, cyDPI, C_PTS_PER_INCH );
  411. ghbr3DFace = GetSysColorBrush(COLOR_3DFACE);
  412. ghbr3DShadow = GetSysColorBrush(COLOR_3DSHADOW);
  413. }
  414. /****************************************************************************
  415. *
  416. * FUNCTION: SkipWhiteSpace
  417. *
  418. \****************************************************************************/
  419. LPTSTR SkipWhiteSpace( LPTSTR psz ) {
  420. while( *psz == TEXT(' ') || *psz == TEXT('\t') || *psz == TEXT('\n') ) {
  421. psz = CharNext( psz );
  422. }
  423. return psz;
  424. }
  425. /****************************************************************************
  426. *
  427. * FUNCTION: CloneString
  428. *
  429. \****************************************************************************/
  430. LPTSTR CloneString(LPTSTR psz) {
  431. int cch;
  432. LPTSTR pszRet;
  433. cch = (lstrlen( psz ) + 1);
  434. pszRet = AllocMem(cch * sizeof(TCHAR));
  435. StringCchCopy( pszRet, cch, psz );
  436. return pszRet;
  437. }
  438. /****************************************************************************
  439. *
  440. * FUNCTION: GetFileSizeFromName(pszFontPath)
  441. *
  442. \****************************************************************************/
  443. DWORD GetFileSizeFromName( LPCTSTR pszPath ) {
  444. HANDLE hfile;
  445. DWORD cb = 0;
  446. hfile = CreateFile( pszPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
  447. if (hfile != INVALID_HANDLE_VALUE) {
  448. cb = GetFileSize( hfile, NULL );
  449. CloseHandle(hfile);
  450. }
  451. return cb;
  452. }
  453. HRESULT FindPfb (LPCTSTR pszPFM, LPTSTR pszPFB, size_t cchPFB);
  454. HRESULT BuildType1FontSpec(LPCTSTR pszPFM, LPTSTR pszSpec, size_t cchSpec);
  455. /****************************************************************************
  456. *
  457. * FUNCTION: ParseCommand
  458. *
  459. \****************************************************************************/
  460. BOOL ParseCommand( LPTSTR lpstrCmdLine, LPTSTR pszFontPath, size_t cchFontPath, BOOL *pfPrint ) {
  461. LPTSTR psz;
  462. BOOL fInQuote = FALSE;
  463. TCHAR szPfmPfb[(2 * MAX_PATH) + 1]; // +1 for possible '|' delimiter.
  464. //
  465. // Skip program name
  466. //
  467. for( psz = SkipWhiteSpace(lpstrCmdLine);
  468. *psz != TEXT('\0') && (fInQuote || *psz != TEXT(' ')); psz = CharNext(psz) ) {
  469. if (*psz == TEXT('\"')) {
  470. fInQuote = !fInQuote;
  471. }
  472. }
  473. if (*psz == TEXT('\0')) {
  474. *pszFontPath = TEXT('\0');
  475. return FALSE;
  476. }
  477. psz = SkipWhiteSpace(psz);
  478. //
  479. // Check for "/p"
  480. //
  481. if (psz[0] == TEXT('/') && (psz[1] == TEXT('p') || psz[1] == TEXT('P'))) {
  482. *pfPrint = TRUE;
  483. psz += 2; // DBCS OK since we already verified that the
  484. // chars were '/' and 'p', they can't be lead bytes
  485. } else
  486. *pfPrint = FALSE;
  487. psz = SkipWhiteSpace(psz);
  488. //
  489. // If the string ends in ".PFM"...
  490. //
  491. if (0 == lstrcmpi(PathFindExtension(psz), TEXT(".PFM")))
  492. {
  493. if (SUCCEEDED(BuildType1FontSpec(psz, szPfmPfb, ARRAYSIZE(szPfmPfb))))
  494. {
  495. psz = szPfmPfb;
  496. }
  497. }
  498. StringCchCopy( pszFontPath, cchFontPath, psz );
  499. return *psz != TEXT('\0');
  500. }
  501. /****************************************************************************
  502. *
  503. * FUNCTION: GetGDILangID
  504. *
  505. * REVIEW! I believe this is how GDI determines the LangID, verify on
  506. * international builds.
  507. *
  508. \****************************************************************************/
  509. WORD GetGDILangID() {
  510. return (WORD)GetSystemDefaultLangID();
  511. }
  512. void ConvertTTStrToWinZStr( LPWSTR pwsz, LPVOID pvTTS, int cbMW ) {
  513. int i, cch;
  514. LPMWORD lpmw = pvTTS;
  515. cch = cbMW / sizeof(MWORD);
  516. for( i = 0; i < cch; i++ ) {
  517. *pwsz++ = MWORD2INT(*lpmw);
  518. lpmw++;
  519. }
  520. *pwsz = L'\0';
  521. }
  522. VOID ConvertDBCSTTStrToWinZStr( LPTSTR pwsz, LPCSTR pvTTS, ULONG cbMW ) {
  523. BYTE Name[256];
  524. WORD wordChar;
  525. BYTE *ansiName = Name;
  526. WORD *srcString = (WORD *)pvTTS;
  527. int length = 0;
  528. int cb = cbMW;
  529. for(;cb;cb-=2) {
  530. wordChar = *srcString;
  531. if(wordChar & 0x00FF) {
  532. *ansiName++ = (CHAR)((wordChar & 0x00FF));
  533. *ansiName++ = (CHAR)((wordChar & 0xFF00) >> 8);
  534. length += 2;
  535. } else {
  536. *ansiName++ = (CHAR)((wordChar & 0xFF00) >> 8);
  537. length++;
  538. }
  539. srcString++;
  540. }
  541. ansiName[length] = '\0';
  542. MultiByteToWideChar(CP_ACP,0,Name,length,pwsz,cbMW);
  543. }
  544. /****************************************************************************
  545. *
  546. * FUNCTION: FindNameString
  547. *
  548. * helper function for GetAlignedTTName
  549. *
  550. \****************************************************************************/
  551. LPTSTR FindNameString(PBYTE pbTTData, int cNameRec, int idName, WORD wLangID)
  552. {
  553. PTTNAMETBL ptnt;
  554. PTTNAMEREC ptnr;
  555. LPTSTR psz;
  556. int i;
  557. ptnt = (PTTNAMETBL)pbTTData;
  558. for( i = 0; i < cNameRec; i++ ) {
  559. LPVOID pvTTStr;
  560. ptnr = &(ptnt->anrNames[i]);
  561. if (MWORD2INT(ptnr->mwidPlatform) != TTID_PLATFORM_MS ||
  562. MWORD2INT(ptnr->mwidName) != idName ||
  563. MWORD2INT(ptnr->mwidLang) != wLangID) {
  564. continue;
  565. }
  566. pvTTStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings)
  567. + MWORD2INT(ptnr->mwoffString));
  568. psz = AllocMem((MWORD2INT(ptnr->mwcbString) + sizeof(TEXT('\0'))) * 2);
  569. if ((MWORD2INT(ptnr->mwidEncoding) == TTID_MS_GB) ||
  570. (MWORD2INT(ptnr->mwidEncoding) == TTID_MS_WANSUNG) ||
  571. (MWORD2INT(ptnr->mwidEncoding) == TTID_MS_BIG5)) {
  572. ConvertDBCSTTStrToWinZStr( psz, pvTTStr, MWORD2INT(ptnr->mwcbString) );
  573. } else {
  574. ConvertTTStrToWinZStr( psz, pvTTStr, MWORD2INT(ptnr->mwcbString) );
  575. }
  576. return psz;
  577. }
  578. return NULL;
  579. }
  580. /****************************************************************************
  581. *
  582. * FUNCTION: GetAlignedTTName
  583. *
  584. * NOTE: This function returns an allocated string that must be freed
  585. * after use.
  586. *
  587. * This function allocs a buffer to recopy the string into incase we are
  588. * running on a RISC machine with NT. Since the string will be UNICODE
  589. * (ie. each char is a WORD), those strings must be aligned on WORD
  590. * boundaries. Unfortunatly, TrueType files do not neccesarily align
  591. * the embedded unicode strings. Furthur more, on NT we can not simply
  592. * return a pointer to the data stored in the input buffer, since the
  593. * 'Unicode' strings stored in the TTF file are stored in Motorola (big
  594. * endian) format, and we need the unicode chars in Intel (little endian)
  595. * format. Last but not least, we need the returned string to be null terminated
  596. * so we need to either alloc the buffer for that case anyway.
  597. *
  598. \****************************************************************************/
  599. LPTSTR GetAlignedTTName( PBYTE pbTTData, int idName ) {
  600. PTTNAMEREC ptnr;
  601. PTTNAMETBL ptnt;
  602. int cNameRec,i;
  603. LPTSTR psz;
  604. BOOL bFirstRetry;
  605. WORD wLangID = GetGDILangID();
  606. LCID lcid = GetThreadLocale();
  607. ptnt = (PTTNAMETBL)pbTTData;
  608. cNameRec = MWORD2INT(ptnt->mwcNameRec);
  609. //
  610. // Look For Microsoft Platform ID's
  611. //
  612. if (gbIsDBCS)
  613. {
  614. if ((psz = FindNameString(pbTTData, cNameRec, idName, wLangID)) != NULL) {
  615. return psz;
  616. }
  617. //
  618. // If we didn't find it, try English if we haven't already.
  619. //
  620. if ( wLangID != 0x0409 ) {
  621. if ((psz = FindNameString(pbTTData, cNameRec, idName, 0x0409)) != NULL) {
  622. return psz;
  623. }
  624. }
  625. }
  626. else
  627. {
  628. bFirstRetry = TRUE;
  629. retry_lang:
  630. for( i = 0; i < cNameRec; i++ ) {
  631. LPVOID pvTTStr;
  632. ptnr = &(ptnt->anrNames[i]);
  633. if (MWORD2INT(ptnr->mwidPlatform) != TTID_PLATFORM_MS ||
  634. MWORD2INT(ptnr->mwidName) != idName ||
  635. MWORD2INT(ptnr->mwidLang) != wLangID) {
  636. continue;
  637. }
  638. pvTTStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings) + MWORD2INT(ptnr->mwoffString));
  639. psz = AllocMem(MWORD2INT(ptnr->mwcbString) + sizeof(TEXT('\0')));
  640. ConvertTTStrToWinZStr( psz, pvTTStr, MWORD2INT(ptnr->mwcbString) );
  641. return psz;
  642. }
  643. //
  644. // Give 0x409 a try if there is no specified MAC language.
  645. //
  646. if (bFirstRetry && wLangID != 0x0409) {
  647. bFirstRetry = FALSE;
  648. wLangID = 0x0409;
  649. goto retry_lang;
  650. }
  651. }
  652. //
  653. // Didn't find MS Platform, try Macintosh
  654. //
  655. for( i = 0; i < cNameRec; i++ ) {
  656. int cch;
  657. LPSTR pszMacStr;
  658. ptnr = &(ptnt->anrNames[i]);
  659. if (MWORD2INT(ptnr->mwidPlatform) != TTID_PLATFORM_MAC ||
  660. MWORD2INT(ptnr->mwidName) != idName ||
  661. MWORD2INT(ptnr->mwidLang) != wLangID) {
  662. continue;
  663. }
  664. pszMacStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings) + MWORD2INT(ptnr->mwoffString));
  665. cch = MultiByteToWideChar(CP_MACCP, 0, pszMacStr, MWORD2INT(ptnr->mwcbString), NULL, 0);
  666. if (cch == 0)
  667. continue;
  668. cch += 1; // for null
  669. psz = AllocMem(cch * sizeof(TCHAR));
  670. if (psz == NULL)
  671. continue;
  672. cch = MultiByteToWideChar(CP_MACCP, 0, pszMacStr, MWORD2INT(ptnr->mwcbString), psz, cch);
  673. if (cch == 0) {
  674. FreeMem(psz);
  675. continue;
  676. }
  677. return psz;
  678. }
  679. //
  680. // Didn't find MS Platform nor Macintosh
  681. // 1. Try change Thread Locale to data Locale
  682. // 2. MultiByteToWideChar with Thread code page CP_THREAD_ACP
  683. //
  684. for( i = 0; i < cNameRec; i++ ) {
  685. int cch;
  686. LPSTR pszStr;
  687. ptnr = &(ptnt->anrNames[i]);
  688. if (MWORD2INT(ptnr->mwidName) != idName ||
  689. MWORD2INT(ptnr->mwidLang) == 0) {
  690. continue;
  691. }
  692. if (LANGIDFROMLCID(lcid) != MWORD2INT(ptnr->mwidLang)) {
  693. lcid = MAKELCID(MWORD2INT(ptnr->mwidLang), SORT_DEFAULT);
  694. if (!SetThreadLocale(lcid)) {
  695. break;
  696. }
  697. }
  698. pszStr = (LPVOID)(pbTTData + MWORD2INT(ptnt->mwoffStrings) + MWORD2INT(ptnr->mwoffString));
  699. cch = MultiByteToWideChar(CP_THREAD_ACP, 0, pszStr, MWORD2INT(ptnr->mwcbString), NULL, 0);
  700. if (cch == 0)
  701. continue;
  702. cch += 1; // for null
  703. psz = AllocMem(cch * sizeof(TCHAR));
  704. if (psz == NULL)
  705. continue;
  706. cch = MultiByteToWideChar(CP_THREAD_ACP, 0, pszStr, MWORD2INT(ptnr->mwcbString), psz, cch);
  707. if (cch == 0) {
  708. FreeMem(psz);
  709. continue;
  710. }
  711. return psz;
  712. }
  713. return NULL;
  714. }
  715. /****************************************************************************
  716. *
  717. * FUNCTION: LoadFontFile
  718. *
  719. \****************************************************************************/
  720. FFTYPE LoadFontFile( LPTSTR pszFontPath, PDISPTEXT pdtSmpl, HICON *phIcon ) {
  721. int cFonts;
  722. FFTYPE fft = FFT_BAD_FILE;
  723. SHFILEINFO sfi;
  724. LPTSTR pszAdobe;
  725. TCHAR szFPBuf[MAX_PATH];
  726. cFonts = AddFontResource( pszFontPath );
  727. if (gbIsDBCS)
  728. {
  729. //
  730. // save cFonts value to global variable.
  731. //
  732. gNumOfFonts = cFonts;
  733. }
  734. if (cFonts != 0) {
  735. LPLOGFONT lplf;
  736. DWORD cb;
  737. DWORD cbCFF = 0, cbMMSD = 0, cbDSIG = 0; // for OpenType
  738. BYTE *pbDSIG = NULL; // for OpenType
  739. BOOL fIsTT;
  740. cb = sizeof(LOGFONT) * cFonts;
  741. if (gbIsDBCS)
  742. {
  743. //
  744. // save lplf to global variable.
  745. //
  746. glpLogFonts = lplf = AllocMem(cb);
  747. }
  748. else
  749. {
  750. lplf = AllocMem(cb);
  751. }
  752. // ?? Should this be GetFontResourceInfo (doesn't matter; but why force W)
  753. if (GetFontResourceInfoW( (LPTSTR)pszFontPath, &cb, lplf, GFRI_LOGFONTS )) {
  754. HDC hdc;
  755. HFONT hf, hfOld;
  756. LOGFONT lf;
  757. int nIndex;
  758. int cLoopReps = 1;
  759. BOOL fIsTrueTypeFont;
  760. DWORD dwSize = sizeof(BOOL);
  761. if(GetFontResourceInfoW((LPTSTR) pszFontPath, &dwSize, &fIsTrueTypeFont, GFRI_ISTRUETYPE)) {
  762. // If there is a raster & true type font on the system at the same time,
  763. // and the height/width requested is supported by both fonts, the
  764. // the font methods (which take the LOGFONT struct, *lplf) will select
  765. // the raster font (by design). THis causes a problem when the user wants
  766. // to view the true type font; so, an extra check needs to be done to see if
  767. // the font requested is a true type, and if so then specify in the LOGFONT
  768. // struct to only show the true type font
  769. if(fIsTrueTypeFont) {
  770. lplf->lfOutPrecision = OUT_TT_ONLY_PRECIS;
  771. }
  772. }
  773. //
  774. // This DBCS-aware code was originally placed within #ifdef DBCS
  775. // preprocessor statements. For single-binary, these had to be
  776. // replaced with runtime checks. The original code did some funky
  777. // things to execute a loop in DBCS builds but only a single iteration
  778. // in non-DBCS builds. To do this, the "for" statement and it's
  779. // closing brace were placed in #ifdef DBCS like this:
  780. //
  781. // #ifdef DBCS
  782. // for (nIndex = 0; nIndex < cFonts; nIndex++)
  783. // {
  784. // //
  785. // // Other DBCS-specific code.
  786. // //
  787. // #endif
  788. // //
  789. // // Code for both DBCS and non-DBCS systems
  790. // // executes only once.
  791. // //
  792. // #ifdef DBCS
  793. // }
  794. // #endif
  795. //
  796. // While effective in a multi-binary configuration, this doesn't
  797. // translate well to a single-binary build.
  798. // To preserve the original logic without having to do major
  799. // reconstruction, I've replaced the loop sentinel variable with
  800. // "cLoopReps". In non-DBCS locales, it is set to 1. In DBCS
  801. // locales, it is assigned the value in "cFonts".
  802. //
  803. // [BrianAu 5/4/97]
  804. //
  805. if (gbIsDBCS)
  806. cLoopReps = cFonts;
  807. for (nIndex = 0; nIndex < cLoopReps; nIndex++) {
  808. if (gbIsDBCS)
  809. {
  810. lf = *(lplf + nIndex);
  811. //
  812. // Skip vertical font
  813. //
  814. if (lf.lfFaceName[0] == TEXT('@')) {
  815. gNumOfFonts = (cFonts == 2) ? gNumOfFonts-1 : gNumOfFonts;
  816. continue;
  817. }
  818. hf = CreateFontIndirect(&lf);
  819. }
  820. else
  821. {
  822. hf = CreateFontIndirect(lplf);
  823. }
  824. hdc = CreateCompatibleDC(NULL);
  825. if (hdc)
  826. {
  827. hfOld = SelectObject(hdc, hf);
  828. // Only otf fonts will have CFF table, tag is ' FFC'.
  829. cbCFF = GetFontData(hdc,' FFC', 0, NULL, 0);
  830. cbDSIG = GetFontData(hdc,'GISD', 0, NULL, 0);
  831. if (cbDSIG != GDI_ERROR)
  832. {
  833. if ((pbDSIG = AllocMem(cbDSIG)) == NULL)
  834. {
  835. // Can't determine what's in the DSIG table.
  836. // Continue as though the DSIG table does not exist.
  837. cbDSIG = 0;
  838. }
  839. else
  840. {
  841. if (GetFontData (hdc, 'GISD', 0, pbDSIG, cbDSIG) == GDI_ERROR)
  842. {
  843. // Continue as though the DSIG table does not exist
  844. cbDSIG = 0;
  845. }
  846. FreeMem(pbDSIG);
  847. }
  848. }
  849. if (cbCFF == GDI_ERROR)
  850. cbCFF = 0;
  851. if (cbDSIG == GDI_ERROR)
  852. cbDSIG = 0;
  853. if (cbCFF || cbDSIG)
  854. {
  855. fft = FFT_OTF;
  856. if (cbCFF)
  857. {
  858. cbMMSD = GetFontData(hdc,'DSMM', 0, NULL, 0);
  859. if (cbMMSD == GDI_ERROR)
  860. cbMMSD = 0;
  861. }
  862. }
  863. cb = GetFontData(hdc, TT_TBL_NAME, 0, NULL, 0);
  864. if (fft != FFT_OTF)
  865. {
  866. fIsTT = (cb != 0 && cb != GDI_ERROR);
  867. fft = fIsTT ? FFT_TRUETYPE : FFT_BITMAP;
  868. }
  869. if ((fft == FFT_TRUETYPE) || (fft == FFT_OTF)) {
  870. int i;
  871. LPBYTE lpTTData;
  872. LPTSTR pszTmp;
  873. lpTTData = AllocMem(cb);
  874. GetFontData(hdc, TT_TBL_NAME, 0, lpTTData, cb);
  875. i = 0;
  876. //
  877. // Title String
  878. //
  879. pdtSmpl->atlDsp[i].dtyp = DTP_SHRINKDRAW;
  880. pdtSmpl->atlDsp[i].cptsSize = CPTS_TITLE_SIZE;
  881. pdtSmpl->atlDsp[i].fLineUnder = TRUE;
  882. pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_FULLFONTNM );
  883. if (pszTmp != NULL) {
  884. if (gbIsDBCS)
  885. {
  886. //
  887. // TTC Support.
  888. //
  889. if (nIndex == 0) {
  890. pdtSmpl->atlDsp[i].pszText = CloneString(pszTmp);
  891. } else {
  892. pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_TTC_CONCAT,
  893. pdtSmpl->atlDsp[i].pszText,
  894. pszTmp);
  895. }
  896. if (nIndex + 1 == cFonts) {
  897. //
  898. // If last this is last font, append "(True Type)"
  899. //
  900. pdtSmpl->atlDsp[i].pszText = FmtSprintf((fft == FFT_TRUETYPE) ? MSG_PTRUETYPEP : MSG_POPENTYPEP,
  901. pdtSmpl->atlDsp[i].pszText);
  902. }
  903. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  904. FreeMem(pszTmp);
  905. }
  906. else
  907. {
  908. pdtSmpl->atlDsp[i].pszText = FmtSprintf((fft == FFT_TRUETYPE) ? MSG_PTRUETYPEP : MSG_POPENTYPEP, pszTmp);
  909. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  910. FreeMem(pszTmp);
  911. }
  912. } else {
  913. if (gbIsDBCS)
  914. {
  915. //
  916. // TTC support
  917. //
  918. if (nIndex == 0) {
  919. pdtSmpl->atlDsp[i].pszText = CloneString(lf.lfFaceName);
  920. } else {
  921. pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_TTC_CONCAT,
  922. pdtSmpl->atlDsp[i].pszText,
  923. lf.lfFaceName);
  924. }
  925. if (nIndex + 1 == cFonts) {
  926. //
  927. // If last this is last font, append "(True Type)"
  928. //
  929. pdtSmpl->atlDsp[i].pszText = FmtSprintf((fft == FFT_TRUETYPE) ? MSG_PTRUETYPEP : MSG_POPENTYPEP,
  930. pdtSmpl->atlDsp[i].pszText);
  931. }
  932. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  933. }
  934. else
  935. {
  936. pdtSmpl->atlDsp[i].pszText = CloneString(lplf->lfFaceName);
  937. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[0].pszText);
  938. }
  939. }
  940. i++;
  941. pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
  942. //// insert an extra line to provide better description of the font
  943. if (fft == FFT_OTF)
  944. {
  945. LPTSTR pszTemp = NULL;
  946. WCHAR awcTmp[256];
  947. awcTmp[0] = 0; // zero init
  948. pdtSmpl->atlDsp[i].dtyp = DTP_NORMALDRAW;
  949. pdtSmpl->atlDsp[i].cptsSize = CPTS_INFO_SIZE;
  950. pdtSmpl->atlDsp[i].fLineUnder = FALSE;
  951. pdtSmpl->atlDsp[i].pszText = FmtSprintf(
  952. MSG_POTF,
  953. awcTmp);
  954. if (cbDSIG)
  955. {
  956. pszTemp = pdtSmpl->atlDsp[i].pszText;
  957. pdtSmpl->atlDsp[i].pszText = FmtSprintf(
  958. MSG_PDSIG,
  959. pdtSmpl->atlDsp[i].pszText);
  960. FmtFree(pszTemp);
  961. }
  962. pszTemp = pdtSmpl->atlDsp[i].pszText;
  963. pdtSmpl->atlDsp[i].pszText = FmtSprintf(
  964. cbCFF ? MSG_PPSGLYPHS : MSG_PTTGLYPHS,
  965. pdtSmpl->atlDsp[i].pszText);
  966. FmtFree(pszTemp);
  967. pszTemp = pdtSmpl->atlDsp[i].pszText;
  968. pdtSmpl->atlDsp[i].pszText = FmtSprintf(
  969. MSG_PINSTRUCTIONS,
  970. pdtSmpl->atlDsp[i].pszText);
  971. FmtFree(pszTemp);
  972. if (cbCFF)
  973. {
  974. pszTemp = pdtSmpl->atlDsp[i].pszText;
  975. pdtSmpl->atlDsp[i].pszText = FmtSprintf(
  976. cbMMSD ? MSG_PMULTIPLEMASTER : MSG_PSINGLEMASTER,
  977. pdtSmpl->atlDsp[i].pszText);
  978. FmtFree(pszTemp);
  979. }
  980. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  981. i++;
  982. pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
  983. }
  984. //
  985. // Typeface Name:
  986. //
  987. pdtSmpl->atlDsp[i].cptsSize = CPTS_INFO_SIZE;
  988. pdtSmpl->atlDsp[i].dtyp = DTP_NORMALDRAW;
  989. pdtSmpl->atlDsp[i].fLineUnder = FALSE;
  990. pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_FONTFAMILY );
  991. if (pszTmp != NULL) {
  992. pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_TYPEFACENAME, pszTmp);
  993. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  994. FreeMem(pszTmp);
  995. i++;
  996. pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
  997. }
  998. //
  999. // File size:
  1000. //
  1001. pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_FILESIZE,
  1002. ROUND_UP_DIV(GetFileSizeFromName(pszFontPath), CB_ONE_K));
  1003. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  1004. //
  1005. // Version:
  1006. //
  1007. pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_VERSIONSTR );
  1008. if (pszTmp != NULL) {
  1009. i++;
  1010. pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
  1011. pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_VERSION, pszTmp);
  1012. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  1013. FreeMem( pszTmp );
  1014. }
  1015. //
  1016. // Copyright string
  1017. //
  1018. pszTmp = GetAlignedTTName( lpTTData, TTID_NAME_COPYRIGHT );
  1019. if (pszTmp != NULL) {
  1020. i++;
  1021. pdtSmpl->atlDsp[i] = pdtSmpl->atlDsp[i-1];
  1022. pdtSmpl->atlDsp[i].cptsSize = CPTS_COPYRIGHT_SIZE;
  1023. pdtSmpl->atlDsp[i].dtyp = DTP_WRAPDRAW;
  1024. pdtSmpl->atlDsp[i].pszText = FmtSprintf(MSG_COPYRIGHT, pszTmp);
  1025. pdtSmpl->atlDsp[i].cchText = lstrlen(pdtSmpl->atlDsp[i].pszText);
  1026. FreeMem( pszTmp );
  1027. }
  1028. pdtSmpl->atlDsp[i].fLineUnder = TRUE;
  1029. if (gbIsDBCS)
  1030. {
  1031. //
  1032. // TTC Support.
  1033. //
  1034. FreeMem(lpTTData);
  1035. }
  1036. } else {
  1037. // Title String (Non TrueType case)
  1038. pdtSmpl->atlDsp[0].dtyp = DTP_SHRINKDRAW;
  1039. pdtSmpl->atlDsp[0].cptsSize = CPTS_TITLE_SIZE;
  1040. pdtSmpl->atlDsp[0].fLineUnder = TRUE;
  1041. pdtSmpl->atlDsp[0].pszText = CloneString(lplf->lfFaceName);
  1042. pdtSmpl->atlDsp[0].cchText = lstrlen(pdtSmpl->atlDsp[0].pszText);
  1043. // Use Default quality, so we can see GDI scaling of Bitmap Fonts
  1044. lplf->lfQuality = DEFAULT_QUALITY;
  1045. lplf->lfWidth = 0;
  1046. }
  1047. // If LPK is loaded then GetFontResourceInfo(GFRI_LOGFONTS) may return ANSI_CHARSET for some DBCS fonts.
  1048. // Get the native char set.
  1049. if (gbIsDBCS & NativeCodePageSupported(lplf)) {
  1050. //
  1051. // Native code page is supported, set that codepage
  1052. //
  1053. CHARSETINFO csi;
  1054. TranslateCharsetInfo( (LPDWORD)IntToPtr(GetACP()), &csi, TCI_SRCCODEPAGE );
  1055. lplf->lfCharSet = (BYTE)csi.ciCharset;
  1056. }
  1057. SelectObject(hdc, hfOld);
  1058. DeleteDC(hdc);
  1059. } // if (hdc)
  1060. if (hf)
  1061. {
  1062. DeleteObject(hf);
  1063. }
  1064. } // for
  1065. pdtSmpl->lfTestFont = *lplf;
  1066. }
  1067. if (!gbIsDBCS)
  1068. {
  1069. FreeMem(lplf);
  1070. }
  1071. }
  1072. //
  1073. // MAJOR HACK!
  1074. //
  1075. // Since ATM-Type1 fonts are split between two files, (*.PFM and *.PFB) we have done a hack
  1076. // earlier in the code to find the missing filename and concatinate them together in
  1077. // the form "FOO.PFM|FOO.PFB", so we can then call AddFontResource() with only one string.
  1078. //
  1079. // Since SHGetFileInfo does not understand this hacked filename format, we must split ATM-Type1
  1080. // names appart here and then reconcat them after we call the shell api.
  1081. //
  1082. pszAdobe = pszFontPath;
  1083. while( *pszAdobe && *pszAdobe != TEXT('|') )
  1084. pszAdobe = CharNext(pszAdobe);
  1085. if ( *pszAdobe ) {
  1086. *pszAdobe = TEXT('\0');
  1087. pdtSmpl->atlDsp[0].pszText = FmtSprintf(MSG_PTYPE1, pdtSmpl->atlDsp[0].pszText);
  1088. pdtSmpl->atlDsp[0].cchText = lstrlen(pdtSmpl->atlDsp[0].pszText);
  1089. } else {
  1090. pszAdobe = NULL;
  1091. }
  1092. // end of HACK
  1093. //
  1094. // Get the associated icon for this font file type
  1095. //
  1096. if ( fft != FFT_BAD_FILE && SHGetFileInfo( pszFontPath, 0, &sfi, sizeof(sfi), SHGFI_ICON )) {
  1097. *phIcon = sfi.hIcon;
  1098. } else
  1099. *phIcon = NULL;
  1100. //
  1101. // HACK - restore the '|' we nuked above
  1102. //
  1103. if ( pszAdobe != NULL ) {
  1104. *pszAdobe = TEXT('|');
  1105. }
  1106. // end of HACK
  1107. return fft;
  1108. }
  1109. /****************************************************************************
  1110. *
  1111. * FUNCTION: DrawFontSample
  1112. *
  1113. * Parameters:
  1114. *
  1115. * lprcPage Size of the page in pels. A page is either a printed
  1116. * sheet (on a printer) or the Window.
  1117. *
  1118. * cyOffset Offset into the virtual sample text. Used to "scroll" the
  1119. * window up and down. Positive number means start further
  1120. * down in the virtual sample text as the top line in the
  1121. * lprcPage.
  1122. *
  1123. * lprcPaint Rectangle to draw. It is in the same coord space as
  1124. * lprcPage. Used to optimize window repaints, and to
  1125. * support banding to printers.
  1126. *
  1127. *
  1128. \****************************************************************************/
  1129. int DrawFontSample( HDC hdc, LPRECT lprcPage, int cyOffset, LPRECT lprcPaint, BOOL fReallyDraw ) {
  1130. int cyDPI;
  1131. HFONT hfOld, hfText, hfDesk;
  1132. LOGFONT lfTmp;
  1133. int yBaseline = -cyOffset;
  1134. int taOld,i;
  1135. TCHAR szNumber[10];
  1136. int cyShkTxt = -1, cptsShkTxt = -1;
  1137. SIZE sz;
  1138. int cxPage;
  1139. DPRINT((DBTX("PAINTING")));
  1140. cyDPI = GetDeviceCaps(hdc, LOGPIXELSY );
  1141. taOld = SetTextAlign(hdc, TA_BASELINE);
  1142. glfFont.lfHeight = MulDiv( -CPTS_COPYRIGHT_SIZE, cyDPI, C_PTS_PER_INCH );
  1143. hfDesk = CreateFontIndirect(&glfFont);
  1144. // Get hfOld for later
  1145. hfOld = SelectObject(hdc, hfDesk);
  1146. if (gbIsDBCS)
  1147. {
  1148. //
  1149. // if two or more fonts exist, set correct typeface name
  1150. //
  1151. if (gNumOfFonts > 1 && gfftFontType == FFT_TRUETYPE) {
  1152. gdtDisplay.atlDsp[INDEX_TYPEFACENAME].pszText =
  1153. FmtSprintf(MSG_TYPEFACENAME, gdtDisplay.lfTestFont.lfFaceName);
  1154. gdtDisplay.atlDsp[INDEX_TYPEFACENAME].cchText =
  1155. lstrlen(gdtDisplay.atlDsp[INDEX_TYPEFACENAME].pszText);
  1156. }
  1157. }
  1158. //
  1159. // Find the longest shrinktext line so we can make sure they will fit
  1160. // on the screen
  1161. //
  1162. cxPage = lprcPage->right - lprcPage->left;
  1163. for( i = 0; i < CLINES_DISPLAY && gdtDisplay.atlDsp[i].dtyp != DTP_UNUSED; i++ ) {
  1164. PTXTLN ptlCurrent = &(gdtDisplay.atlDsp[i]);
  1165. if (ptlCurrent->dtyp == DTP_SHRINKTEXT) {
  1166. lfTmp = gdtDisplay.lfTestFont;
  1167. if (cptsShkTxt == -1)
  1168. cptsShkTxt = ptlCurrent->cptsSize;
  1169. cyShkTxt = MulDiv( -cptsShkTxt, cyDPI, C_PTS_PER_INCH );
  1170. lfTmp.lfHeight = cyShkTxt;
  1171. hfText = CreateFontIndirect( &lfTmp );
  1172. SelectObject(hdc, hfText);
  1173. GetTextExtentPoint32(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &sz );
  1174. SelectObject(hdc, hfOld);
  1175. DeleteObject(hfText);
  1176. // Make sure shrink lines are not too long
  1177. if (sz.cx > cxPage) {
  1178. DPRINT((DBTX(">>>Old lfH:%d sz.cx:%d cxPage:%d"), lfTmp.lfHeight, sz.cx, cxPage));
  1179. cptsShkTxt = cptsShkTxt * cxPage / sz.cx;
  1180. cyShkTxt = MulDiv( -cptsShkTxt, cyDPI, C_PTS_PER_INCH );
  1181. DPRINT((DBTX(">>>New lfH:%d"),lfTmp.lfHeight));
  1182. }
  1183. }
  1184. }
  1185. //
  1186. // Paint the screen/page
  1187. //
  1188. for( i = 0; i < CLINES_DISPLAY && gdtDisplay.atlDsp[i].dtyp != DTP_UNUSED; i++ ) {
  1189. TEXTMETRIC tm;
  1190. PTXTLN ptlCurrent = &(gdtDisplay.atlDsp[i]);
  1191. // Create and select the font for this line
  1192. if (ptlCurrent->dtyp == DTP_TEXTOUT || ptlCurrent->dtyp == DTP_SHRINKTEXT )
  1193. lfTmp = gdtDisplay.lfTestFont;
  1194. else
  1195. lfTmp = glfFont;
  1196. if (ptlCurrent->dtyp == DTP_SHRINKTEXT) {
  1197. DPRINT((DBTX("PAINT:Creating ShrinkText Font:%s height:%d"), lfTmp.lfFaceName, lfTmp.lfHeight ));
  1198. lfTmp.lfHeight = cyShkTxt;
  1199. }
  1200. else
  1201. lfTmp.lfHeight = MulDiv( -ptlCurrent->cptsSize, cyDPI, C_PTS_PER_INCH );
  1202. hfText = CreateFontIndirect( &lfTmp );
  1203. SelectObject(hdc, hfText);
  1204. // Get size characteristics for this line in the selected font
  1205. if (ptlCurrent->dtyp == DTP_SHRINKDRAW) {
  1206. GetTextExtentPoint32(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &sz );
  1207. // Make sure shrink lines are not too long
  1208. if (sz.cx > cxPage) {
  1209. SelectObject(hdc, hfOld);
  1210. DeleteObject(hfText);
  1211. DPRINT((DBTX("===Old lfH:%d sz.cx:%d cxPage:%d"), lfTmp.lfHeight, sz.cx, cxPage));
  1212. lfTmp.lfHeight = MulDiv( -ptlCurrent->cptsSize * cxPage / sz.cx, cyDPI, C_PTS_PER_INCH );
  1213. DPRINT((DBTX("===New lfH:%d"),lfTmp.lfHeight));
  1214. hfText = CreateFontIndirect( &lfTmp );
  1215. SelectObject(hdc, hfText);
  1216. }
  1217. }
  1218. GetTextMetrics(hdc, &tm);
  1219. yBaseline += (tm.tmAscent + tm.tmExternalLeading);
  1220. DPRINT((DBTX("tmH:%d tmA:%d tmD:%d tmIL:%d tmEL:%d"), tm.tmHeight, tm.tmAscent, tm.tmDescent, tm.tmInternalLeading, tm.tmExternalLeading));
  1221. // Draw the text
  1222. switch(ptlCurrent->dtyp) {
  1223. case DTP_NORMALDRAW:
  1224. case DTP_SHRINKDRAW:
  1225. case DTP_SHRINKTEXT:
  1226. if (fReallyDraw) {
  1227. ExtTextOut(hdc, lprcPage->left, yBaseline, ETO_CLIPPED, lprcPaint,
  1228. ptlCurrent->pszText, ptlCurrent->cchText, NULL);
  1229. }
  1230. //
  1231. // Bob says "This looks nice!" (Adding a little extra white space before the underline)
  1232. //
  1233. if (ptlCurrent->fLineUnder)
  1234. yBaseline += tm.tmDescent;
  1235. break;
  1236. case DTP_WRAPDRAW: {
  1237. RECT rc;
  1238. int cy;
  1239. yBaseline += tm.tmDescent;
  1240. SetRect(&rc, lprcPage->left, yBaseline - tm.tmHeight, lprcPage->right, yBaseline );
  1241. DPRINT((DBTX("**** Org RC:(%d, %d, %d, %d) tmH:%d"), rc.left, rc.top, rc.right, rc.bottom, tm.tmHeight));
  1242. cy = DrawText(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &rc,
  1243. DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT);
  1244. DPRINT((DBTX("**** Cmp RC:(%d, %d, %d, %d) cy:%d"), rc.left, rc.top, rc.right, rc.bottom, cy));
  1245. if( cy > tm.tmHeight )
  1246. yBaseline = rc.bottom = rc.top + cy;
  1247. if (fReallyDraw) {
  1248. SetTextAlign(hdc, taOld);
  1249. DrawText(hdc, ptlCurrent->pszText, ptlCurrent->cchText, &rc, DT_NOPREFIX | DT_WORDBREAK);
  1250. SetTextAlign(hdc, TA_BASELINE);
  1251. }
  1252. break;
  1253. }
  1254. case DTP_TEXTOUT:
  1255. if (fReallyDraw) {
  1256. SIZE szNum;
  1257. int cchNum;
  1258. SelectObject(hdc, hfDesk );
  1259. StringCchPrintf( szNumber, ARRAYSIZE(szNumber), TEXT("%d"), ptlCurrent->cptsSize );
  1260. cchNum = lstrlen(szNumber);
  1261. ExtTextOut(hdc, lprcPage->left, yBaseline, ETO_CLIPPED, lprcPaint, szNumber, cchNum, NULL);
  1262. GetTextExtentPoint32(hdc, szNumber, cchNum, &szNum);
  1263. SelectObject(hdc, hfText);
  1264. ExtTextOut(hdc, lprcPage->left + szNum.cx * 2, yBaseline, ETO_CLIPPED, lprcPaint,
  1265. ptlCurrent->pszText, ptlCurrent->cchText, NULL);
  1266. }
  1267. break;
  1268. }
  1269. yBaseline += tm.tmDescent;
  1270. if (fReallyDraw && ptlCurrent->fLineUnder) {
  1271. MoveToEx( hdc, lprcPage->left, yBaseline, NULL);
  1272. LineTo( hdc, lprcPage->right, yBaseline );
  1273. // Leave space for the line we just drew
  1274. yBaseline += 1;
  1275. }
  1276. SelectObject( hdc, hfOld );
  1277. DeleteObject( hfText );
  1278. }
  1279. SelectObject(hdc, hfOld);
  1280. SetTextAlign(hdc, taOld);
  1281. DeleteObject(hfDesk);
  1282. return yBaseline;
  1283. }
  1284. /****************************************************************************
  1285. *
  1286. * FUNCTION: PaintSampleWindow
  1287. *
  1288. \****************************************************************************/
  1289. void PaintSampleWindow( HWND hwnd, HDC hdc, PAINTSTRUCT *pps ) {
  1290. RECT rcClient;
  1291. GetClientRect(hwnd, &rcClient);
  1292. DrawFontSample( hdc, &rcClient, gyScroll, &(pps->rcPaint), TRUE );
  1293. }
  1294. /****************************************************************************
  1295. *
  1296. * FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
  1297. *
  1298. * PURPOSE: Processes messages
  1299. *
  1300. * MESSAGES:
  1301. *
  1302. * WM_COMMAND - application menu (About dialog box)
  1303. * WM_DESTROY - destroy window
  1304. *
  1305. * COMMENTS:
  1306. *
  1307. * To process the IDM_ABOUT message, call MakeProcInstance() to get the
  1308. * current instance address of the About() function. Then call Dialog
  1309. * box which will create the box according to the information in your
  1310. * fontview.rc file and turn control over to the About() function. When
  1311. * it returns, free the intance address.
  1312. *
  1313. \****************************************************************************/
  1314. LRESULT APIENTRY FrameWndProc(
  1315. HWND hwnd, /* window handle */
  1316. UINT message, /* type of message */
  1317. WPARAM wParam, /* additional information */
  1318. LPARAM lParam) /* additional information */
  1319. {
  1320. static SIZE szWindow = {0, 0};
  1321. switch (message) {
  1322. case WM_PAINT: {
  1323. HDC hdc;
  1324. RECT rc;
  1325. PAINTSTRUCT ps;
  1326. int x;
  1327. hdc = BeginPaint(hwnd, &ps);
  1328. // get the window rect
  1329. GetClientRect(hwnd, &rc);
  1330. // extend only down by gcyBtnArea
  1331. rc.bottom = rc.top + gcyBtnArea;
  1332. // Fill rect with button face color (handled by class background brush)
  1333. // FillRect(hdc, &rc, ghbr3DFace);
  1334. // Fill small rect at bottom with edge color
  1335. rc.top = rc.bottom - 2;
  1336. FillRect(hdc, &rc, ghbr3DShadow);
  1337. ReleaseDC(hwnd, hdc);
  1338. EndPaint(hwnd, &ps);
  1339. break;
  1340. }
  1341. case WM_CREATE: {
  1342. HDC hdc;
  1343. RECT rc;
  1344. int i;
  1345. GetClientRect(hwnd, &rc);
  1346. szWindow.cx = rc.right - rc.left;
  1347. szWindow.cy = rc.bottom - rc.top;
  1348. for( i = 0; i < C_BUTTONS; i++ ) {
  1349. int x = gabtCmdBtns[i].x;
  1350. HWND hwndBtn;
  1351. if (gbIsDBCS)
  1352. {
  1353. DWORD dwStyle = 0;
  1354. //
  1355. // If font is not TrueType font or not TTC font,
  1356. // AND button id is previous/next,
  1357. // then just continue.
  1358. //
  1359. if ((gfftFontType != FFT_TRUETYPE ||
  1360. gNumOfFonts <= 1) &&
  1361. (gabtCmdBtns[i].id == IDB_PREV_FONT ||
  1362. gabtCmdBtns[i].id == IDB_NEXT_FONT)) {
  1363. continue;
  1364. }
  1365. //
  1366. // Set x potision for each button.
  1367. //
  1368. switch (gabtCmdBtns[i].id) {
  1369. case IDB_PREV_FONT:
  1370. x = szWindow.cx / 2 - gabtCmdBtns[i].cx - 5;
  1371. dwStyle = WS_DISABLED; // initially disabled.
  1372. break;
  1373. case IDB_NEXT_FONT:
  1374. x = szWindow.cx / 2 + 5;
  1375. break;
  1376. default:
  1377. if (x < 0)
  1378. x = szWindow.cx + x - gabtCmdBtns[i].cx;
  1379. }
  1380. gabtCmdBtns[i].hwnd = hwndBtn = CreateWindow( TEXT("button"),
  1381. gabtCmdBtns[i].pszText,
  1382. BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | dwStyle,
  1383. x, gabtCmdBtns[i].y,
  1384. gabtCmdBtns[i].cx, gabtCmdBtns[i].cy,
  1385. hwnd, (HMENU)IntToPtr(gabtCmdBtns[i].id),
  1386. hInst, NULL);
  1387. }
  1388. else
  1389. {
  1390. if (x < 0)
  1391. x = szWindow.cx + x - gabtCmdBtns[i].cx;
  1392. gabtCmdBtns[i].hwnd = hwndBtn = CreateWindow( TEXT("button"),
  1393. gabtCmdBtns[i].pszText, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE,
  1394. x, gabtCmdBtns[i].y,
  1395. gabtCmdBtns[i].cx, gabtCmdBtns[i].cy,
  1396. hwnd, (HMENU)IntToPtr(gabtCmdBtns[i].id),
  1397. hInst, NULL);
  1398. }
  1399. if (hwndBtn != NULL) {
  1400. SendMessage(hwndBtn,
  1401. WM_SETFONT,
  1402. (WPARAM)GetStockObject(DEFAULT_GUI_FONT),
  1403. MAKELPARAM(TRUE, 0));
  1404. }
  1405. }
  1406. ghwndView = CreateWindow( TEXT("FontDisplayClass"), NULL, WS_CHILD | WS_VSCROLL | WS_VISIBLE,
  1407. 0, gcyBtnArea, szWindow.cx, szWindow.cy - gcyBtnArea, hwnd, 0, hInst, NULL );
  1408. break;
  1409. }
  1410. case WM_GETMINMAXINFO: {
  1411. LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
  1412. lpmmi->ptMinTrackSize.x = gcxMinWinSize;
  1413. lpmmi->ptMinTrackSize.y = gcyMinWinSize;
  1414. break;
  1415. }
  1416. case WM_SIZE: {
  1417. int cxNew, cyNew;
  1418. HDC hdc;
  1419. RECT rc;
  1420. SCROLLINFO sci;
  1421. cxNew = LOWORD(lParam);
  1422. cyNew = HIWORD(lParam);
  1423. if (cyNew != szWindow.cy || cxNew != szWindow.cx) {
  1424. int i;
  1425. if (gbIsDBCS)
  1426. {
  1427. for( i = 0; i < C_BUTTONS; i++ ) {
  1428. int x = gabtCmdBtns[i].x;
  1429. //
  1430. // If font is not TrueType font or not TTC font,
  1431. // AND button id is previous/next,
  1432. // then just continue.
  1433. //
  1434. if ((gfftFontType != FFT_TRUETYPE ||
  1435. gNumOfFonts <= 1) &&
  1436. (gabtCmdBtns[i].id == IDB_PREV_FONT ||
  1437. gabtCmdBtns[i].id == IDB_NEXT_FONT)) {
  1438. continue;
  1439. }
  1440. //
  1441. // Set x potision for each button.
  1442. //
  1443. switch (gabtCmdBtns[i].id) {
  1444. case IDB_PREV_FONT:
  1445. SetWindowPos(gabtCmdBtns[i].hwnd,
  1446. NULL,
  1447. cxNew / 2 - gabtCmdBtns[i].cx - 5,
  1448. gabtCmdBtns[i].y,
  1449. 0,
  1450. 0,
  1451. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  1452. break;
  1453. case IDB_NEXT_FONT:
  1454. SetWindowPos(gabtCmdBtns[i].hwnd,
  1455. NULL,
  1456. cxNew /2 + 5,
  1457. gabtCmdBtns[i].y,
  1458. 0,
  1459. 0,
  1460. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  1461. break;
  1462. default:
  1463. if (x < 0) {
  1464. SetWindowPos(gabtCmdBtns[i].hwnd,
  1465. NULL,
  1466. cxNew + x - gabtCmdBtns[i].cx,
  1467. gabtCmdBtns[i].y,
  1468. 0,
  1469. 0,
  1470. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  1471. }
  1472. }
  1473. }
  1474. }
  1475. else // !DBCS
  1476. {
  1477. for( i = 0; i < C_BUTTONS; i++ ) {
  1478. int x = gabtCmdBtns[i].x;
  1479. if (x < 0) {
  1480. SetWindowPos(gabtCmdBtns[i].hwnd, NULL, cxNew + x - gabtCmdBtns[i].cx, gabtCmdBtns[i].y, 0, 0,
  1481. SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  1482. }
  1483. }
  1484. } // DBCS
  1485. szWindow.cx = cxNew;
  1486. szWindow.cy = cyNew;
  1487. SetWindowPos(ghwndView, NULL, 0, gcyBtnArea, szWindow.cx, szWindow.cy - gcyBtnArea,
  1488. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
  1489. }
  1490. break;
  1491. }
  1492. case WM_COMMAND: /* message: command from application menu */
  1493. if (LOWORD(wParam) != IDB_DONE)
  1494. return SendMessage(ghwndView, message, wParam, lParam);
  1495. PostMessage(ghwndFrame, WM_CLOSE, 0, 0);
  1496. break;
  1497. case WM_DESTROY: {
  1498. int i;
  1499. DestroyWindow(ghwndView);
  1500. for( i = 0; i < C_BUTTONS; i++ ) {
  1501. DestroyWindow(gabtCmdBtns[i].hwnd);
  1502. }
  1503. PostQuitMessage(0);
  1504. break;
  1505. }
  1506. default: /* Passes it on if unproccessed */
  1507. return (DefWindowProc(hwnd, message, wParam, lParam));
  1508. }
  1509. return (0L);
  1510. }
  1511. /****************************************************************************
  1512. *
  1513. * FUNCTION: ViewWndProc(HWND, unsigned, WORD, LONG)
  1514. *
  1515. * PURPOSE: Processes messages
  1516. *
  1517. * MESSAGES:
  1518. *
  1519. * WM_COMMAND - application menu (About dialog box)
  1520. * WM_DESTROY - destroy window
  1521. *
  1522. * COMMENTS:
  1523. *
  1524. * To process the IDM_ABOUT message, call MakeProcInstance() to get the
  1525. * current instance address of the About() function. Then call Dialog
  1526. * box which will create the box according to the information in your
  1527. * fontview.rc file and turn control over to the About() function. When
  1528. * it returns, free the intance address.
  1529. *
  1530. \****************************************************************************/
  1531. LRESULT APIENTRY ViewWndProc(
  1532. HWND hwnd, /* window handle */
  1533. UINT message, /* type of message */
  1534. WPARAM wParam, /* additional information */
  1535. LPARAM lParam) /* additional information */
  1536. {
  1537. static SIZE szWindow = {0, 0};
  1538. static int cyVirtPage = 0;
  1539. switch (message) {
  1540. case WM_CREATE: {
  1541. HDC hdc;
  1542. RECT rc;
  1543. SCROLLINFO sci;
  1544. int i;
  1545. GetClientRect(hwnd, &rc);
  1546. szWindow.cx = rc.right - rc.left;
  1547. szWindow.cy = rc.bottom - rc.top;
  1548. hdc = CreateCompatibleDC(NULL);
  1549. cyVirtPage = DrawFontSample(hdc, &rc, 0, NULL, FALSE);
  1550. DeleteDC(hdc);
  1551. gyScroll = 0;
  1552. sci.cbSize = sizeof(sci);
  1553. sci.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
  1554. sci.nMin = 0;
  1555. sci.nMax = cyVirtPage;
  1556. sci.nPage = szWindow.cy;
  1557. sci.nPos = gyScroll;
  1558. SetScrollInfo(hwnd, SB_VERT, &sci, TRUE );
  1559. if (gfPrint)
  1560. PostMessage(hwnd, WM_COMMAND, IDB_PRINT, 0);
  1561. break;
  1562. }
  1563. case WM_SIZE: {
  1564. int cxNew, cyNew;
  1565. HDC hdc;
  1566. RECT rc;
  1567. SCROLLINFO sci;
  1568. cxNew = LOWORD(lParam);
  1569. cyNew = HIWORD(lParam);
  1570. if (cyNew != szWindow.cy || cxNew != szWindow.cx) {
  1571. int i;
  1572. szWindow.cx = cxNew;
  1573. szWindow.cy = cyNew;
  1574. hdc = CreateCompatibleDC(NULL);
  1575. SetRect(&rc, 0, 0, szWindow.cx, szWindow.cy);
  1576. cyVirtPage = DrawFontSample(hdc, &rc, 0, NULL, FALSE);
  1577. DeleteDC(hdc);
  1578. if (cyVirtPage <= cyNew) {
  1579. // Disable the scrollbar
  1580. gyScroll = 0;
  1581. }
  1582. if (cyVirtPage > szWindow.cy && gyScroll > cyVirtPage - szWindow.cy)
  1583. gyScroll = cyVirtPage - szWindow.cy;
  1584. sci.cbSize = sizeof(sci);
  1585. sci.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
  1586. sci.nMin = 0;
  1587. sci.nMax = cyVirtPage;
  1588. sci.nPage = cyNew;
  1589. sci.nPos = gyScroll;
  1590. SetScrollInfo(hwnd, SB_VERT, &sci, TRUE );
  1591. }
  1592. break;
  1593. }
  1594. case WM_VSCROLL: {
  1595. int iCode = (int)LOWORD(wParam);
  1596. int yPos = (int)HIWORD(wParam);
  1597. int yNewScroll = gyScroll;
  1598. switch( iCode ) {
  1599. case SB_THUMBPOSITION:
  1600. case SB_THUMBTRACK:
  1601. if (yPos != yNewScroll)
  1602. yNewScroll = yPos;
  1603. break;
  1604. case SB_LINEUP:
  1605. yNewScroll -= gcyLine;
  1606. break;
  1607. case SB_PAGEUP:
  1608. yNewScroll -= szWindow.cy;
  1609. break;
  1610. case SB_LINEDOWN:
  1611. yNewScroll += gcyLine;
  1612. break;
  1613. case SB_PAGEDOWN:
  1614. yNewScroll += szWindow.cy;
  1615. break;
  1616. case SB_TOP:
  1617. yNewScroll = 0;
  1618. break;
  1619. case SB_BOTTOM:
  1620. yNewScroll = cyVirtPage;
  1621. break;
  1622. }
  1623. if (yNewScroll < 0)
  1624. yNewScroll = 0;
  1625. if (yNewScroll > cyVirtPage - szWindow.cy)
  1626. yNewScroll = cyVirtPage - szWindow.cy;
  1627. if (yNewScroll < 0)
  1628. yNewScroll = 0;
  1629. if (gyScroll != yNewScroll) {
  1630. SCROLLINFO sci;
  1631. int dyScroll;
  1632. dyScroll = gyScroll - yNewScroll;
  1633. if (ABS(dyScroll) < szWindow.cy) {
  1634. ScrollWindowEx(hwnd, 0, dyScroll, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE);
  1635. } else
  1636. InvalidateRect(hwnd, NULL, TRUE);
  1637. gyScroll = yNewScroll;
  1638. sci.cbSize = sizeof(sci);
  1639. sci.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
  1640. sci.nMin = 0;
  1641. sci.nMax = cyVirtPage;
  1642. sci.nPage = szWindow.cy;
  1643. sci.nPos = gyScroll;
  1644. SetScrollInfo(hwnd, SB_VERT, &sci, TRUE );
  1645. }
  1646. break;
  1647. }
  1648. case WM_COMMAND: /* message: command from application menu */
  1649. if( !DoCommand( hwnd, wParam, lParam ) )
  1650. return (DefWindowProc(hwnd, message, wParam, lParam));
  1651. break;
  1652. case WM_PAINT: {
  1653. HDC hdc;
  1654. PAINTSTRUCT ps;
  1655. hdc = BeginPaint( hwnd, &ps );
  1656. PaintSampleWindow( hwnd, hdc, &ps );
  1657. EndPaint( hwnd, &ps );
  1658. break;
  1659. }
  1660. default: /* Passes it on if unproccessed */
  1661. return (DefWindowProc(hwnd, message, wParam, lParam));
  1662. }
  1663. return (0L);
  1664. }
  1665. /*********************************************\
  1666. *
  1667. * PRINT DLGS
  1668. *
  1669. *
  1670. \*********************************************/
  1671. HDC PromptForPrinter(HWND hwnd, HINSTANCE hInst, int *pcCopies ) {
  1672. PRINTDLG pd;
  1673. FillMemory(&pd, sizeof(pd), 0);
  1674. pd.lStructSize = sizeof(pd);
  1675. pd.hwndOwner = hwnd;
  1676. pd.Flags = PD_RETURNDC | PD_NOSELECTION;
  1677. pd.nCopies = 1;
  1678. pd.hInstance = hInst;
  1679. if (PrintDlg(&pd)) {
  1680. *pcCopies = pd.nCopies;
  1681. return pd.hDC;
  1682. } else
  1683. return NULL;
  1684. }
  1685. /****************************************************************************\
  1686. *
  1687. * FUNCTION: PrintSampleWindow(hwnd)
  1688. *
  1689. * Prompts for a printer and then draws the sample text to the printer
  1690. *
  1691. \****************************************************************************/
  1692. void PrintSampleWindow(HWND hwnd) {
  1693. HDC hdc;
  1694. DOCINFO di;
  1695. int cxDPI, cyDPI, iPage, cCopies;
  1696. RECT rcPage;
  1697. HCURSOR hcur;
  1698. hdc = PromptForPrinter(hwnd, hInst, &cCopies);
  1699. if (hdc == NULL)
  1700. return;
  1701. hcur = SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)));
  1702. cyDPI = GetDeviceCaps(hdc, LOGPIXELSY );
  1703. cxDPI = GetDeviceCaps(hdc, LOGPIXELSX );
  1704. /*
  1705. * Set a one inch margine around the page
  1706. */
  1707. SetRect(&rcPage, 0, 0, GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES));
  1708. rcPage.left += cxDPI;
  1709. rcPage.right -= cxDPI;
  1710. di.cbSize = sizeof(di);
  1711. di.lpszDocName = gdtDisplay.atlDsp[0].pszText;
  1712. di.lpszOutput = NULL;
  1713. di.lpszDatatype = NULL;
  1714. di.fwType = 0;
  1715. StartDoc(hdc, &di);
  1716. for( iPage = 0; iPage < cCopies; iPage++ ) {
  1717. StartPage(hdc);
  1718. DrawFontSample( hdc, &rcPage, -cyDPI, &rcPage, TRUE );
  1719. EndPage(hdc);
  1720. }
  1721. EndDoc(hdc);
  1722. DeleteDC(hdc);
  1723. SetCursor(hcur);
  1724. }
  1725. /****************************************************************************\
  1726. *
  1727. * FUNCTION: EnableCommandButtons(id, bEnable)
  1728. *
  1729. * Enable/disable command button.
  1730. *
  1731. \****************************************************************************/
  1732. BOOL EnableCommandButton(int id, BOOL bEnable)
  1733. {
  1734. int i;
  1735. HWND hwnd = NULL;
  1736. for( i = 0; i < C_BUTTONS; i++ ) {
  1737. if (gabtCmdBtns[i].id == id) {
  1738. hwnd = gabtCmdBtns[i].hwnd;
  1739. break;
  1740. }
  1741. }
  1742. return (hwnd == NULL) ? FALSE: EnableWindow(hwnd, bEnable);
  1743. }
  1744. /****************************************************************************\
  1745. *
  1746. * FUNCTION: ViewNextFont(iInc)
  1747. *
  1748. * Show the previous/next font.
  1749. *
  1750. \****************************************************************************/
  1751. void ViewNextFont(int iInc)
  1752. {
  1753. int index = gIndexOfFonts + iInc;
  1754. while (1) {
  1755. if ( index < 0 || index >= gNumOfFonts ) {
  1756. //
  1757. // if out of range, then return.
  1758. //
  1759. MessageBeep(MB_OK);
  1760. return;
  1761. }
  1762. else if ((*(glpLogFonts + index)).lfFaceName[0] == TEXT('@')) {
  1763. //
  1764. // if the font is vertical font, skip this font and
  1765. // try next/previous font.
  1766. //
  1767. index += iInc;
  1768. }
  1769. else {
  1770. break;
  1771. }
  1772. }
  1773. //
  1774. // Enable/Disable Prev/Next buttons.
  1775. //
  1776. if (index == 0) {
  1777. // first font
  1778. EnableCommandButton(IDB_PREV_FONT, FALSE);
  1779. EnableCommandButton(IDB_NEXT_FONT, TRUE);
  1780. }
  1781. else if (index == gNumOfFonts - 1) {
  1782. // last font
  1783. EnableCommandButton(IDB_PREV_FONT, TRUE);
  1784. EnableCommandButton(IDB_NEXT_FONT, FALSE);
  1785. }
  1786. else {
  1787. // other
  1788. EnableCommandButton(IDB_PREV_FONT, TRUE);
  1789. EnableCommandButton(IDB_NEXT_FONT, TRUE);
  1790. }
  1791. //
  1792. // Show the new font.
  1793. //
  1794. gIndexOfFonts = index;
  1795. gdtDisplay.lfTestFont = *(glpLogFonts + index);
  1796. InvalidateRect(ghwndView, NULL, TRUE);
  1797. }
  1798. /****************************************************************************\
  1799. *
  1800. * FUNCTION: DoCommand(HWND, unsigned, WORD, LONG)
  1801. *
  1802. * PURPOSE: Processes messages for "About" dialog box
  1803. *
  1804. * MESSAGES:
  1805. *
  1806. * WM_INITDIALOG - initialize dialog box
  1807. * WM_COMMAND - Input received
  1808. *
  1809. * COMMENTS:
  1810. *
  1811. * No initialization is needed for this particular dialog box, but TRUE
  1812. * must be returned to Windows.
  1813. *
  1814. * Wait for user to click on "Ok" button, then close the dialog box.
  1815. *
  1816. \****************************************************************************/
  1817. BOOL DoCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
  1818. {
  1819. switch(LOWORD(wParam)){
  1820. case IDB_PRINT: {
  1821. PrintSampleWindow(hWnd);
  1822. break;
  1823. }
  1824. case IDB_DONE: {
  1825. PostMessage(ghwndFrame, WM_CLOSE, 0, 0);
  1826. break;
  1827. }
  1828. case IDK_UP: {
  1829. SendMessage(hWnd, WM_VSCROLL, SB_LINEUP, (LPARAM)NULL );
  1830. break;
  1831. }
  1832. case IDK_DOWN: {
  1833. SendMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)NULL );
  1834. break;
  1835. }
  1836. case IDK_PGUP: {
  1837. SendMessage(hWnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)NULL );
  1838. break;
  1839. }
  1840. case IDK_PGDWN: {
  1841. SendMessage(hWnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)NULL );
  1842. break;
  1843. }
  1844. case IDB_PREV_FONT: {
  1845. ViewNextFont(-1);
  1846. break;
  1847. }
  1848. case IDB_NEXT_FONT: {
  1849. ViewNextFont(1);
  1850. break;
  1851. }
  1852. default: {
  1853. return FALSE;
  1854. }
  1855. }
  1856. return TRUE;
  1857. }
  1858. BOOL bFileExists(TCHAR*pszFile)
  1859. {
  1860. HANDLE hf;
  1861. if ((hf = CreateFile(pszFile,
  1862. GENERIC_READ,
  1863. FILE_SHARE_READ,
  1864. NULL,
  1865. OPEN_EXISTING,
  1866. FILE_ATTRIBUTE_NORMAL,
  1867. NULL)) != INVALID_HANDLE_VALUE)
  1868. {
  1869. CloseHandle(hf);
  1870. return TRUE;
  1871. }
  1872. return FALSE;
  1873. }
  1874. /******************************Public*Routine******************************\
  1875. *
  1876. * FindPfb, given pfm file, see if pfb file exists in the same dir or in the
  1877. * parent directory of the pfm file
  1878. *
  1879. * Given: c:\foo\bar\font.pfm
  1880. * Check: c:\foo\bar\font.pfb
  1881. * c:\foo\font.pfb
  1882. *
  1883. * Given: font.pfm
  1884. * Check: font.pfb
  1885. * ..\font.pfb
  1886. *
  1887. * History:
  1888. * 14-Jun-1994 -by- Bodin Dresevic [BodinD]
  1889. * Wrote it.
  1890. *
  1891. * 28-Feb-2002 -by- Brian Aust [BrianAu]
  1892. * Replaced all of Bodin's character manipulations with calls to
  1893. * shlwapi path functions and strsafe helpers.
  1894. *
  1895. * Returns:
  1896. * S_OK - PFB file found. Full path to PFB written to pszPFB buffer.
  1897. * S_FALSE - PFB file not found.
  1898. * Other - Error HRESULT.
  1899. *
  1900. \**************************************************************************/
  1901. HRESULT FindPfb (LPCTSTR pszPFM, LPTSTR pszPFB, size_t cchPFB)
  1902. {
  1903. TCHAR szPath[MAX_PATH]; // Working 'scratch' buffer.
  1904. HRESULT hr;
  1905. if (0 != lstrcmpi(PathFindExtension(pszPFM), TEXT(".PFM")))
  1906. {
  1907. //
  1908. // Caller didn't provide a PFM file path.
  1909. //
  1910. return E_INVALIDARG;
  1911. }
  1912. //
  1913. // Copy input path to our scratch buffer so we can modify it.
  1914. //
  1915. hr = StringCchCopy(szPath, ARRAYSIZE(szPath), pszPFM);
  1916. if (SUCCEEDED(hr))
  1917. {
  1918. //
  1919. // Does a PFB file exist in the same directory as the PFM file?
  1920. //
  1921. PathRenameExtension(szPath, TEXT(".PFB"));
  1922. if (bFileExists(szPath))
  1923. {
  1924. hr = S_OK; // Found a match!
  1925. }
  1926. else
  1927. {
  1928. LPCTSTR pszFileName = PathFindFileName(pszPFM);
  1929. //
  1930. // PFB doesn't exist in same directory.
  1931. // Try the parent directory.
  1932. // Remove the file name so we have only a directory path.
  1933. //
  1934. if (!PathRemoveFileSpec(szPath))
  1935. {
  1936. //
  1937. // This shouldn't happen. We've already tested earlier
  1938. // for content in the path string.
  1939. //
  1940. hr = E_FAIL;
  1941. }
  1942. else
  1943. {
  1944. if (0 == szPath[0])
  1945. {
  1946. //
  1947. // Removing the file spec left us with an empty string.
  1948. // That means a bare "font.pfm" name was passed in.
  1949. // Build a relative path to the parent directory.
  1950. //
  1951. hr = StringCchPrintf(szPath, ARRAYSIZE(szPath), TEXT("..\\%s"), pszFileName);
  1952. }
  1953. else
  1954. {
  1955. //
  1956. // Remove the containing directory so we have a path
  1957. // to the parent directory.
  1958. //
  1959. if (PathRemoveFileSpec(szPath))
  1960. {
  1961. //
  1962. // We're now at the parent directory.
  1963. // Build a full file path here.
  1964. //
  1965. if (PathAppend(szPath, pszFileName))
  1966. {
  1967. hr = S_OK; // We have a path to test.
  1968. }
  1969. else
  1970. {
  1971. hr = E_FAIL;
  1972. }
  1973. }
  1974. else
  1975. {
  1976. //
  1977. // No parent directory exists in the path. That
  1978. // means, the PFM file is in the root of the path.
  1979. // We've already tested for a PFB in the same
  1980. // directory so our search is over. No match.
  1981. //
  1982. hr = S_FALSE;
  1983. }
  1984. }
  1985. }
  1986. if (S_OK == hr)
  1987. {
  1988. //
  1989. // We have a valid path to search. Replace the extension
  1990. // with .PFB and see if the file exists.
  1991. //
  1992. PathRenameExtension(szPath, TEXT(".PFB"));
  1993. if (!bFileExists(szPath))
  1994. {
  1995. hr = S_FALSE; // No match.
  1996. }
  1997. }
  1998. }
  1999. if (S_OK == hr)
  2000. {
  2001. //
  2002. // Found matching PFB file. Return the path to the caller.
  2003. //
  2004. hr = StringCchCopy(pszPFB, cchPFB, szPath);
  2005. }
  2006. }
  2007. return hr;
  2008. }
  2009. //
  2010. // Given the path for a PFM file, try to locate a matching
  2011. // PFB file. If one is found, the two paths are concatenated together
  2012. // and returned with a '|' character as a delimiter. If a PFB file is
  2013. // not found, the path to the PFM file is returned unaltered.
  2014. //
  2015. HRESULT BuildType1FontSpec(LPCTSTR pszPFM, LPTSTR pszSpec, size_t cchSpec)
  2016. {
  2017. TCHAR szPFB[MAX_PATH];
  2018. HRESULT hr = FindPfb(pszPFM, szPFB, ARRAYSIZE(szPFB));
  2019. if (S_OK == hr)
  2020. {
  2021. //
  2022. // PFB file found. Build the concatenated PFM|PFB path string.
  2023. //
  2024. hr = StringCchPrintf(pszSpec, cchSpec, TEXT("%s|%s"), pszPFM, szPFB);
  2025. }
  2026. else if (S_FALSE == hr)
  2027. {
  2028. //
  2029. // No PFB found. Return the original PFM file path.
  2030. //
  2031. hr = StringCchCopy(pszSpec, cchSpec, pszPFM);
  2032. }
  2033. return hr;
  2034. }