1 /*
2 * PROJECT: ReactOS Font Viewer
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Display class
5 * COPYRIGHT: Copyright 2007 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 #include <stdio.h>
11 #include <malloc.h>
12
13 #define SPACING1 8
14 #define SPACING2 5
15
16 extern INT g_NumFonts;
17 extern WCHAR g_FontTitle[];
18
19 const WCHAR g_szFontDisplayClassName[] = L"FontDisplayClass";
20 LRESULT CALLBACK DisplayProc(HWND, UINT, WPARAM, LPARAM);
21
22 /* Internal data storage type */
23 typedef struct
24 {
25 int nPageHeight;
26 WCHAR szTypeFaceName[LF_FULLFACESIZE];
27 WCHAR szFormat[MAX_FORMAT];
28 WCHAR szString[MAX_STRING];
29
30 HFONT hCaptionFont;
31 HFONT hCharSetFont;
32 HFONT hSizeFont;
33 HFONT hFonts[MAX_SIZES];
34 int nSizes[MAX_SIZES];
35 int nHeights[MAX_SIZES];
36 } DISPLAYDATA;
37
38 /* This is the only public function, it registers the class */
39 BOOL
Display_InitClass(HINSTANCE hInstance)40 Display_InitClass(HINSTANCE hInstance)
41 {
42 WNDCLASSEXW wincl;
43
44 /* Set the fontdisplay window class structure */
45 wincl.cbSize = sizeof(WNDCLASSEX);
46 wincl.style = CS_DBLCLKS;
47 wincl.lpfnWndProc = DisplayProc;
48 wincl.cbClsExtra = 0;
49 wincl.cbWndExtra = 0;
50 wincl.hInstance = hInstance;
51 wincl.hIcon = NULL;
52 wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
53 wincl.hbrBackground = GetStockObject(WHITE_BRUSH);
54 wincl.lpszMenuName = NULL;
55 wincl.lpszClassName = g_szFontDisplayClassName;
56 wincl.hIconSm = NULL;
57
58 /* Register the window class, and if it fails return FALSE */
59 if (!RegisterClassExW (&wincl))
60 {
61 return FALSE;
62 }
63 return TRUE;
64 }
65
66 static int
Display_DrawText(HDC hDC,DISPLAYDATA * pData,int nYPos)67 Display_DrawText(HDC hDC, DISPLAYDATA* pData, int nYPos)
68 {
69 HFONT hOldFont;
70 TEXTMETRIC tm;
71 int i, y;
72 WCHAR szSize[5];
73 WCHAR szCaption[LF_FULLFACESIZE + 20];
74
75 /* This is the location on the DC where we draw */
76 y = -nYPos;
77
78 hOldFont = SelectObject(hDC, pData->hCaptionFont);
79 GetTextMetrics(hDC, &tm);
80
81 swprintf(szCaption, L"%s%s", pData->szTypeFaceName, pData->szFormat);
82 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
83 y += tm.tmHeight + SPACING1;
84
85 /* Draw a separation Line */
86 SelectObject(hDC, GetStockObject(BLACK_PEN));
87 MoveToEx(hDC, 0, y, NULL);
88 LineTo(hDC, 10000, y);
89 y += SPACING2;
90
91 /* TODO: Output font info */
92
93 /* Output Character set */
94 SelectObject(hDC, pData->hCharSetFont);
95 GetTextMetrics(hDC, &tm);
96 swprintf(szCaption, L"abcdefghijklmnopqrstuvwxyz");
97 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
98 y += tm.tmHeight + 1;
99
100 swprintf(szCaption, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
101 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
102 y += tm.tmHeight + 1;
103
104 swprintf(szCaption, L"0123456789.:,;(\"~!@#$%%^&*')");
105 TextOutW(hDC, 0, y, szCaption, (INT)wcslen(szCaption));
106 y += tm.tmHeight + 1;
107
108 /* Draw a separation Line */
109 SelectObject(hDC, GetStockObject(BLACK_PEN));
110 MoveToEx(hDC, 0, y, NULL);
111 LineTo(hDC, 10000, y);
112 y += SPACING2;
113
114 /* Output the strings for different sizes */
115 for (i = 0; i < MAX_SIZES; i++)
116 {
117 SelectObject(hDC, pData->hFonts[i]);
118 TextOutW(hDC, 20, y, pData->szString, (INT)wcslen(pData->szString));
119 GetTextMetrics(hDC, &tm);
120 y += tm.tmHeight + 1;
121 SelectObject(hDC, pData->hSizeFont);
122 swprintf(szSize, L"%d", pData->nSizes[i]);
123 TextOutW(hDC, 0, y - 13 - tm.tmDescent, szSize, (INT)wcslen(szSize));
124 }
125 SelectObject(hDC, hOldFont);
126
127 return y;
128 }
129
130 static int
131 CALLBACK
EnumFontFamProcW(const LOGFONTW * lpelfe,const TEXTMETRICW * lptm,DWORD FontType,LPARAM lParam)132 EnumFontFamProcW(
133 const LOGFONTW *lpelfe,
134 const TEXTMETRICW *lptm,
135 DWORD FontType,
136 LPARAM lParam)
137 {
138 PNEWTEXTMETRICW pntmw = (PNEWTEXTMETRICW)lptm;
139 PBOOL pfOpenType = (PBOOL)lParam;
140
141 if (FontType & TRUETYPE_FONTTYPE)
142 {
143 if (pntmw->ntmFlags & (NTM_TT_OPENTYPE | NTM_PS_OPENTYPE))
144 {
145 *pfOpenType = TRUE;
146 return FALSE;
147 }
148 }
149 return TRUE;
150 }
151
152 static LRESULT
Display_SetTypeFace(HWND hwnd,PLOGFONTW pLogFont)153 Display_SetTypeFace(HWND hwnd, PLOGFONTW pLogFont)
154 {
155 DISPLAYDATA* pData;
156 TEXTMETRIC tm;
157 HDC hDC;
158 RECT rect;
159 SCROLLINFO si;
160 int i;
161 LOGFONTW logfont;
162 BOOL fOpenType;
163 BYTE Buffer[512];
164 LPOUTLINETEXTMETRICW pOTM = (LPOUTLINETEXTMETRICW)Buffer;
165 LPWSTR pch;
166
167 /* Set the new type face name */
168 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
169 lstrcpynW(pData->szTypeFaceName, pLogFont->lfFaceName,
170 ARRAYSIZE(pData->szTypeFaceName));
171
172 /* Create the new fonts */
173 hDC = GetDC(hwnd);
174 DeleteObject(pData->hCharSetFont);
175
176 logfont = *pLogFont;
177 logfont.lfHeight = -MulDiv(16, GetDeviceCaps(GetDC(NULL), LOGPIXELSY), 72);
178 pData->hCharSetFont = CreateFontIndirectW(&logfont);
179
180 /* Get font format */
181 SelectObject(hDC, pData->hCharSetFont);
182 GetTextMetrics(hDC, &tm);
183 if (tm.tmPitchAndFamily & TMPF_TRUETYPE)
184 {
185 if (GetOutlineTextMetricsW(hDC, sizeof(Buffer), pOTM))
186 {
187 LPBYTE pb = Buffer;
188 pb += (WORD)(DWORD_PTR)pOTM->otmpStyleName;
189 pch = (LPWSTR)pb;
190 if (*pch)
191 {
192 lstrcatW(pData->szTypeFaceName, L" ");
193 lstrcatW(pData->szTypeFaceName, pch);
194 }
195 }
196
197 fOpenType = FALSE;
198 EnumFontFamiliesExW(hDC, &logfont,
199 EnumFontFamProcW, (LPARAM)&fOpenType, 0);
200
201 if (fOpenType)
202 swprintf(pData->szFormat, L" (OpenType)");
203 else
204 swprintf(pData->szFormat, L" (TrueType)");
205 }
206 else if (tm.tmPitchAndFamily & TMPF_VECTOR)
207 {
208 swprintf(pData->szFormat, L" (Vector)");
209 }
210 else
211 {
212 swprintf(pData->szFormat, L" (Raster)");
213 }
214
215 for (i = 0; i < MAX_SIZES; i++)
216 {
217 DeleteObject(pData->hFonts[i]);
218 logfont.lfHeight = -MulDiv(pData->nSizes[i], GetDeviceCaps(hDC, LOGPIXELSY), 72);
219 pData->hFonts[i] = CreateFontIndirectW(&logfont);
220 }
221
222 /* Calculate new page dimensions */
223 pData->nPageHeight = Display_DrawText(hDC, pData, 0);
224 ReleaseDC(hwnd, hDC);
225
226 /* Set the vertical scrolling range and page size */
227 GetClientRect(hwnd, &rect);
228 si.cbSize = sizeof(si);
229 si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
230 si.nMin = 0;
231 si.nMax = pData->nPageHeight;
232 si.nPage = rect.bottom;
233 si.nPos = 0;
234 si.nTrackPos = 0;
235 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
236
237 return 0;
238 }
239
240 static LRESULT
Display_SetString(HWND hwnd,LPCWSTR pszString)241 Display_SetString(HWND hwnd, LPCWSTR pszString)
242 {
243 DISPLAYDATA* pData;
244
245 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
246 lstrcpynW(pData->szString, pszString, ARRAYSIZE(pData->szString));
247
248 InvalidateRect(hwnd, NULL, TRUE);
249
250 return 0;
251 }
252
253 static LRESULT
Display_OnCreate(HWND hwnd)254 Display_OnCreate(HWND hwnd)
255 {
256 DISPLAYDATA* pData;
257 const int nSizes[MAX_SIZES] = {8, 12, 18, 24, 36, 48, 60, 72};
258 int i;
259 LOGFONTW LogFont = {50, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
260 ANSI_CHARSET, OUT_DEFAULT_PRECIS,
261 CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
262 DEFAULT_PITCH , L"MS Shell Dlg"};
263
264 /* Create data structure */
265 pData = malloc(sizeof(DISPLAYDATA));
266 ZeroMemory(pData, sizeof(DISPLAYDATA));
267
268 /* Set the window's GWLP_USERDATA to our data structure */
269 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pData);
270
271 for (i = 0; i < MAX_SIZES; i++)
272 {
273 pData->nSizes[i] = nSizes[i];
274 }
275
276 pData->hCaptionFont = CreateFontIndirectW(&LogFont);
277 LogFont.lfHeight = 12;
278 pData->hSizeFont = CreateFontIndirectW(&LogFont);
279
280 Display_SetString(hwnd,
281 L"Jackdaws love my big sphinx of quartz. 1234567890");
282
283 Display_SetTypeFace(hwnd, &LogFont);
284
285 return 0;
286 }
287
288 static LRESULT
Display_OnPaint(HWND hwnd)289 Display_OnPaint(HWND hwnd)
290 {
291 DISPLAYDATA* pData;
292 PAINTSTRUCT ps;
293 SCROLLINFO si;
294
295 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
296
297 /* Get the Scroll position */
298 si.cbSize = sizeof(si);
299 si.fMask = SIF_POS;
300 GetScrollInfo(hwnd, SB_VERT, &si);
301
302 BeginPaint(hwnd, &ps);
303
304 /* Erase background */
305 FillRect(ps.hdc, &ps.rcPaint, GetStockObject(WHITE_BRUSH));
306
307 /* Draw the text */
308 Display_DrawText(ps.hdc, pData, si.nPos);
309
310 EndPaint(hwnd, &ps);
311
312 return 0;
313 }
314
315 static LRESULT
Display_OnSize(HWND hwnd)316 Display_OnSize(HWND hwnd)
317 {
318 RECT rect;
319 SCROLLINFO si;
320 int nOldPos;
321
322 GetClientRect(hwnd, &rect);
323
324 /* Get the old scroll pos */
325 si.cbSize = sizeof(si);
326 si.fMask = SIF_POS;
327 GetScrollInfo(hwnd, SB_VERT, &si);
328 nOldPos = si.nPos;
329
330 /* Set the new page size */
331 si.fMask = SIF_PAGE;
332 si.nPage = rect.bottom;
333 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
334
335 /* Get the new scroll pos */
336 si.fMask = SIF_POS;
337 GetScrollInfo(hwnd, SB_VERT, &si);
338
339 /* If they don't match ... */
340 if (nOldPos != si.nPos)
341 {
342 /* ... scroll the window */
343 ScrollWindowEx(hwnd, 0, nOldPos - si.nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE);
344 UpdateWindow(hwnd);
345 }
346
347 return 0;
348 }
349
350 static LRESULT
Display_OnVScroll(HWND hwnd,WPARAM wParam)351 Display_OnVScroll(HWND hwnd, WPARAM wParam)
352 {
353 SCROLLINFO si;
354 int nPos;
355
356 si.cbSize = sizeof(si);
357 si.fMask = SIF_POS | SIF_RANGE | SIF_TRACKPOS;
358 GetScrollInfo(hwnd, SB_VERT, &si);
359
360 switch(LOWORD(wParam))
361 {
362 case SB_PAGEUP:
363 nPos = si.nPos - 50;
364 break;
365 case SB_PAGEDOWN:
366 nPos = si.nPos + 50;
367 break;
368 case SB_LINEUP:
369 nPos = si.nPos - 10;
370 break;
371 case SB_LINEDOWN:
372 nPos = si.nPos + 10;
373 break;
374 case SB_THUMBTRACK:
375 case SB_THUMBPOSITION:
376 nPos = si.nTrackPos;
377 break;
378 default:
379 nPos = si.nPos;
380 }
381
382 nPos = max(nPos, si.nMin);
383 nPos = min(nPos, si.nMax);
384 if (nPos != si.nPos)
385 {
386 ScrollWindowEx(hwnd, 0, si.nPos - nPos, NULL, NULL, NULL, NULL, SW_INVALIDATE);
387 si.cbSize = sizeof(si);
388 si.nPos = nPos;
389 si.fMask = SIF_POS;
390 SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
391 UpdateWindow(hwnd);
392 }
393
394 return 0;
395 }
396
397 static LRESULT
Display_OnDestroy(HWND hwnd)398 Display_OnDestroy(HWND hwnd)
399 {
400 DISPLAYDATA* pData;
401 int i;
402
403 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
404
405 /* Delete the fonts */
406 DeleteObject(pData->hCaptionFont);
407 DeleteObject(pData->hCharSetFont);
408 DeleteObject(pData->hSizeFont);
409
410 for (i = 0; i < MAX_SIZES; i++)
411 {
412 DeleteObject(pData->hFonts[i]);
413 }
414
415 /* Free the data structure */
416 free(pData);
417
418 return 0;
419 }
420
421 LRESULT
Display_OnPrint(HWND hwnd)422 Display_OnPrint(HWND hwnd)
423 {
424 PRINTDLG pfont;
425 TEXTMETRIC tm;
426 int copies, yPos;
427
428 /* Clears the memory before using it */
429 ZeroMemory(&pfont, sizeof(pfont));
430
431 pfont.lStructSize = sizeof(pfont);
432 pfont.hwndOwner = hwnd;
433 pfont.hDevMode = NULL;
434 pfont.hDevNames = NULL;
435 pfont.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
436 pfont.nCopies = 1;
437 pfont.nFromPage = 0xFFFF;
438 pfont.nToPage = 0xFFFF;
439 pfont.nMinPage = 1;
440 pfont.nMaxPage = 0xFFFF;
441
442 /* Opens up the print dialog box */
443 if (PrintDlg(&pfont))
444 {
445 DOCINFO docinfo;
446 #if 0
447 DISPLAYDATA* pData;
448
449 pData = malloc(sizeof(DISPLAYDATA));
450 ZeroMemory(pData, sizeof(DISPLAYDATA));
451
452 /* Sets up the font layout */
453 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
454 #endif
455 docinfo.cbSize = sizeof(DOCINFO);
456 docinfo.lpszDocName = L"Printing Font";
457 docinfo.lpszOutput = NULL;
458 docinfo.lpszDatatype = NULL;
459 docinfo.fwType = 0;
460
461 /* We start printing */
462 StartDoc(pfont.hDC, &docinfo);
463
464 /* Grabs the text metrics for the printer */
465 GetTextMetrics(pfont.hDC, &tm);
466
467 /* Start out with 0 for the y position for the page */
468 yPos = 0;
469
470 /* Starts out with the current page */
471 StartPage(pfont.hDC);
472
473 /* Used when printing for more than one copy */
474 for (copies = 0; copies < pfont.nCopies; copies++)
475 {
476 /* Test output */
477 TextOutW(pfont.hDC, 10, yPos, L"Testing...1...2...3", 19);
478
479 /* TODO: Determine if using Display_DrawText() will work for both rendering out to the
480 window and to the printer output */
481 #if 0
482 Display_DrawText(pfont.hDC, pData, yPos);
483 #endif
484
485 /* Ends the current page */
486 EndPage(pfont.hDC);
487
488 /* If we are making more than one copy, start a new page */
489 if (copies != pfont.nCopies)
490 {
491 yPos = 0;
492 StartPage(pfont.hDC);
493 }
494 }
495
496 /* The printing is now over */
497 EndDoc(pfont.hDC);
498
499 DeleteDC(pfont.hDC);
500 #if 0
501 /* Frees the memory since we no longer need it for now */
502 free(pData);
503 #endif
504 }
505
506 return 0;
507 }
508
509 LRESULT
Display_GetFullName(HWND hwnd,INT length,PWSTR ptr)510 Display_GetFullName(HWND hwnd, INT length, PWSTR ptr)
511 {
512 DISPLAYDATA *pData;
513 INT len;
514
515 pData = (DISPLAYDATA*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
516
517 len = wcslen(pData->szTypeFaceName) + wcslen(pData->szFormat) + 2;
518
519 if (ptr != NULL && length >= len)
520 {
521 swprintf(ptr, L"%s%s", pData->szTypeFaceName, pData->szFormat);
522 }
523
524 return (LRESULT)len;
525 }
526
527 LRESULT CALLBACK
DisplayProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)528 DisplayProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
529 {
530 switch (message)
531 {
532 case WM_CREATE:
533 return Display_OnCreate(hwnd);
534
535 case WM_PAINT:
536 return Display_OnPaint(hwnd);
537
538 case WM_SIZE:
539 return Display_OnSize(hwnd);
540
541 case WM_VSCROLL:
542 return Display_OnVScroll(hwnd, wParam);
543
544 case FVM_SETTYPEFACE:
545 return Display_SetTypeFace(hwnd, (PLOGFONTW)lParam);
546
547 case FVM_SETSTRING:
548 return Display_SetString(hwnd, (WCHAR *)lParam);
549
550 case FVM_GETFULLNAME:
551 return Display_GetFullName(hwnd, (INT)wParam, (PWSTR)lParam);
552
553 case WM_DESTROY:
554 return Display_OnDestroy(hwnd);
555
556 default:
557 return DefWindowProcW(hwnd, message, wParam, lParam);
558 }
559
560 return 0;
561 }
562