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 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 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 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 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 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 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 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 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 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 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 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 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 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