Reactos

[CONSOLE][CONCFG][CONSRV] Provide support for specified additional TrueType fonts + bugfixes. CORE-12451 CORE-13182 CORE-13196

- CONSOLE: Initialize the additional TrueType fonts cache.
* Fix the font preview when a TrueType font has been selected.
* Refresh the available fonts and the font preview when the selected
code page is changed (Work In Progress), or when the OS pool of
font resources has changed (WM_FONTCHANGE message).

- CONCFG: Implement support for the additional TrueType fonts cache:
the contents of the cache is enumerated under the registry key
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont

* Add helper functions and macros.
* In CreateConsoleFontEx(), set the mandatory font pitch&family flags
and remove those that we do not support.
* In IsValidConsoleFont2(), update the validity checks and the
documentation links.

- CONSRV: Load/refresh the additional TrueType fonts cache when needed.

+497 -108
+5 -7
dll/cpl/console/console.c
··· 227 227 InitDefaultConsoleInfo(ConInfo); 228 228 } 229 229 230 - /* Initialize the font support */ 231 - FontPreview.hFont = CreateConsoleFont(ConInfo); 232 - if (FontPreview.hFont == NULL) 233 - DPRINT1("InitApplet: CreateConsoleFont() failed\n"); 234 - GetFontCellSize(NULL, FontPreview.hFont, &FontPreview.CharHeight, &FontPreview.CharWidth); 230 + /* Initialize the font support -- additional TrueType fonts cache and current preview font */ 231 + InitTTFontCache(); 232 + RefreshFontPreview(&FontPreview, ConInfo); 235 233 236 234 /* Initialize the property sheet structure */ 237 235 ZeroMemory(&psh, sizeof(psh)); ··· 274 272 UnRegisterWinPrevClass(hApplet); 275 273 276 274 /* Clear the font support */ 277 - if (FontPreview.hFont) DeleteObject(FontPreview.hFont); 278 - FontPreview.hFont = NULL; 275 + ResetFontPreview(&FontPreview); 276 + ClearTTFontCache(); 279 277 280 278 /* Save the console settings */ 281 279 if (SetConsoleInfo)
+17
dll/cpl/console/console.h
··· 49 49 50 50 VOID ApplyConsoleInfo(HWND hwndDlg); 51 51 52 + 53 + VOID 54 + RefreshFontPreview( 55 + IN FONT_PREVIEW* Preview, 56 + IN PCONSOLE_STATE_INFO pConInfo); 57 + 58 + VOID 59 + UpdateFontPreview( 60 + IN FONT_PREVIEW* Preview, 61 + IN HFONT hFont, 62 + IN UINT CharWidth, 63 + IN UINT CharHeight); 64 + 65 + #define ResetFontPreview(Preview) \ 66 + UpdateFontPreview((Preview), NULL, 0, 0) 67 + 68 + 52 69 /* Preview Windows */ 53 70 BOOL 54 71 RegisterWinPrevClass(
+122 -47
dll/cpl/console/font.c
··· 45 45 static DWORD CurrentFontType = (DWORD)-1; // Invalid font type 46 46 47 47 48 + VOID 49 + RefreshFontPreview( 50 + IN FONT_PREVIEW* Preview, 51 + IN PCONSOLE_STATE_INFO pConInfo) 52 + { 53 + if (Preview->hFont) DeleteObject(Preview->hFont); 54 + Preview->hFont = CreateConsoleFont(pConInfo); 55 + if (Preview->hFont == NULL) 56 + DPRINT1("RefreshFontPreview: CreateConsoleFont() failed\n"); 57 + GetFontCellSize(NULL, Preview->hFont, &Preview->CharHeight, &Preview->CharWidth); 58 + } 59 + 60 + VOID 61 + UpdateFontPreview( 62 + IN FONT_PREVIEW* Preview, 63 + IN HFONT hFont, 64 + IN UINT CharWidth, 65 + IN UINT CharHeight) 66 + { 67 + if (Preview->hFont) DeleteObject(Preview->hFont); 68 + Preview->hFont = hFont; 69 + Preview->CharWidth = CharWidth; 70 + Preview->CharHeight = CharHeight; 71 + } 72 + 48 73 // PLIST_GETCOUNT 49 74 static INT 50 75 RasterSizeList_GetCount( ··· 284 309 { 285 310 PFACE_NAMES_PROC_PARAM Param = (PFACE_NAMES_PROC_PARAM)lParam; 286 311 287 - /* 288 - * To install additional TrueType fonts to be available for the console, 289 - * add entries of type REG_SZ named "0", "00" etc... in: 290 - * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont 291 - * The names of the fonts listed there should match those in: 292 - * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts 293 - */ 294 312 if (IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage)) 295 313 { 296 314 /* Add the font to the list */ ··· 374 392 375 393 ZeroMemory(&lf, sizeof(lf)); 376 394 lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(CodePage); 377 - // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; 395 + // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN; 378 396 379 397 hDC = GetDC(NULL); 380 398 EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFaceNamesProc, (LPARAM)&Param, 0); ··· 397 415 } 398 416 399 417 static VOID 400 - FaceNameList_SelectFaceName( 418 + FaceNameList_SelectFont( 419 + IN HWND hDlg, 401 420 IN HWND hWndList, 402 - IN LPCWSTR FaceName) 421 + IN PFONTSIZE_LIST_CTL SizeList, 422 + IN LPCWSTR FaceName, 423 + IN ULONG FontFamily, 424 + IN ULONG FontWeight, 425 + IN COORD FontSize) 403 426 { 404 427 INT iItem; 405 428 ··· 410 433 iItem = 0; 411 434 SendMessageW(hWndList, LB_SETCURSEL, (WPARAM)iItem, 0); 412 435 436 + if (FontWeight >= FW_BOLD) 437 + CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_CHECKED); 438 + else 439 + CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_UNCHECKED); 440 + 441 + /* Select the current font size */ 442 + /* 443 + * Format: 444 + * Width = FontSize.X = LOWORD(FontSize); 445 + * Height = FontSize.Y = HIWORD(FontSize); 446 + */ 447 + SizeList->CurrentRasterSize = MAKELONG(FontSize.X, FontSize.Y); 448 + SizeList->CurrentTTSize = FontSize.Y; 449 + // FontSizeList_SelectFontSize(SizeList, SizeList->CurrentRasterSize); 450 + 413 451 // return iItem; 414 452 } 415 453 ··· 486 524 { 487 525 HWND hListBox = GetDlgItem(hDlg, IDC_LBOX_FONTTYPE); 488 526 INT Length, nSel; 489 - LOGFONTW lf; 490 527 LPWSTR FaceName; 491 528 DWORD FontType; 492 529 LPCWSTR FontGrpBoxLabelTpl = NULL; ··· 518 555 FaceName[Length] = L'\0'; 519 556 520 557 StringCchCopyW(pConInfo->FaceName, ARRAYSIZE(pConInfo->FaceName), FaceName); 521 - DPRINT1("pConInfo->FaceName = '%S'\n", pConInfo->FaceName); 522 - 523 - ZeroMemory(&lf, sizeof(lf)); 524 - lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(pConInfo->CodePage); 525 - // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; 526 - StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), FaceName); 558 + DPRINT("pConInfo->FaceName = '%S'\n", pConInfo->FaceName); 527 559 528 560 /* 529 561 * Retrieve the read-only font group box label string template, ··· 560 592 if ((CurrentFontType != FontType) || 561 593 (FontType == RASTER_FONTTYPE && CurrentSelFont != nSel)) 562 594 { 595 + LOGFONTW lf; 563 596 HDC hDC; 564 597 565 598 if (SizeList->UseRasterOrTTList) ··· 567 600 else 568 601 SendMessageW(SizeList->hWndTTSizeList, CB_RESETCONTENT, 0, 0); 569 602 603 + ZeroMemory(&lf, sizeof(lf)); 604 + lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(pConInfo->CodePage); 605 + // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN; 606 + StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), pConInfo->FaceName); 607 + 570 608 hDC = GetDC(NULL); 571 609 EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontSizesProc, (LPARAM)SizeList, 0); 572 610 ReleaseDC(NULL, hDC); ··· 597 635 IN PFONTSIZE_LIST_CTL SizeList, 598 636 IN OUT PCONSOLE_STATE_INFO pConInfo) 599 637 { 600 - LONG FontSize, CharWidth, CharHeight; 638 + LONG FontSize; 639 + UINT CharWidth, CharHeight; 640 + HFONT hFont; 601 641 WCHAR szFontSize[100]; 602 642 603 643 /* ··· 610 650 if (FontSize == 0) 611 651 return FALSE; // We have got an invalid font size... 612 652 613 - CharHeight = (SizeList->UseRasterOrTTList ? (LONG)HIWORD(FontSize) : FontSize); 614 - CharWidth = (SizeList->UseRasterOrTTList ? (LONG)LOWORD(FontSize) : 0); 653 + /* 654 + * For TrueType fonts we set the requested width to zero 655 + * so as to obtain a default aspect-ratio width. 656 + */ 657 + CharHeight = (UINT)(SizeList->UseRasterOrTTList ? HIWORD(FontSize) : FontSize); 658 + CharWidth = (UINT)(SizeList->UseRasterOrTTList ? LOWORD(FontSize) : 0); 615 659 616 - if (FontPreview.hFont) DeleteObject(FontPreview.hFont); 617 - FontPreview.hFont = CreateConsoleFont2(CharHeight, CharWidth, pConInfo); 618 - if (FontPreview.hFont == NULL) 660 + hFont = CreateConsoleFont2((LONG)CharHeight, (LONG)CharWidth, pConInfo); 661 + if (hFont == NULL) 619 662 DPRINT1("FontSizeChange: CreateConsoleFont2() failed\n"); 620 663 621 664 /* Retrieve the real character size in pixels */ 622 - GetFontCellSize(NULL, FontPreview.hFont, &FontPreview.CharHeight, &FontPreview.CharWidth); 665 + GetFontCellSize(NULL, hFont, &CharHeight, &CharWidth); 666 + 667 + /* 668 + * Update the font preview as well, and store the font handle. It will be 669 + * freed at later update or when the font preview is refreshed or reset. 670 + * For TrueType fonts, the preview will show the actual character width. 671 + */ 672 + UpdateFontPreview(&FontPreview, hFont, CharWidth, CharHeight); 623 673 624 674 /* 625 675 * Format: 626 676 * Width = FontSize.X = LOWORD(FontSize); 627 677 * Height = FontSize.Y = HIWORD(FontSize); 628 678 */ 629 - pConInfo->FontSize.X = (SHORT)(SizeList->UseRasterOrTTList ? FontPreview.CharWidth : 0); 630 - pConInfo->FontSize.Y = (SHORT)FontPreview.CharHeight; 679 + pConInfo->FontSize.X = (SHORT)(SizeList->UseRasterOrTTList ? CharWidth : 0); 680 + pConInfo->FontSize.Y = (SHORT)CharHeight; 631 681 632 - DPRINT1("pConInfo->FontSize = (%d x %d) ; (CharWidth x CharHeight) = (%d x %d)\n", 633 - pConInfo->FontSize.X, pConInfo->FontSize.Y, 634 - FontPreview.CharWidth, FontPreview.CharHeight); 682 + DPRINT("pConInfo->FontSize = (%d x %d) ; (CharWidth x CharHeight) = (%d x %d)\n", 683 + pConInfo->FontSize.X, pConInfo->FontSize.Y, CharWidth, CharHeight); 635 684 636 685 InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE); 637 686 InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE); 638 687 639 - StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", FontPreview.CharWidth); 688 + StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", CharWidth); 640 689 SetDlgItemText(hDlg, IDC_FONT_SIZE_X, szFontSize); 641 - StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", FontPreview.CharHeight); 690 + StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", CharHeight); 642 691 SetDlgItemText(hDlg, IDC_FONT_SIZE_Y, szFontSize); 643 692 644 693 return TRUE; ··· 689 738 690 739 /* Select the current font */ 691 740 DPRINT1("ConInfo->FaceName = '%S'\n", ConInfo->FaceName); 692 - FaceNameList_SelectFaceName(hFontList, ConInfo->FaceName); 693 - 694 - if (ConInfo->FontWeight >= FW_BOLD) 695 - CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_CHECKED); 696 - else 697 - CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_UNCHECKED); 698 - 699 - /* Select the current font size */ 700 - /* 701 - * Format: 702 - * Width = FontSize.X = LOWORD(FontSize); 703 - * Height = FontSize.Y = HIWORD(FontSize); 704 - */ 705 - SizeList->CurrentRasterSize = MAKELONG(ConInfo->FontSize.X, ConInfo->FontSize.Y); 706 - SizeList->CurrentTTSize = ConInfo->FontSize.Y; 707 - // FontSizeList_SelectFontSize(SizeList, SizeList->CurrentRasterSize); 741 + FaceNameList_SelectFont(hDlg, hFontList, 742 + SizeList, 743 + ConInfo->FaceName, 744 + ConInfo->FontFamily, 745 + ConInfo->FontWeight, 746 + ConInfo->FontSize); 708 747 709 748 /* Refresh everything */ 710 749 FontTypeChange(hDlg, SizeList, ConInfo); ··· 734 773 /* Retransmit to the preview window */ 735 774 SendDlgItemMessageW(hDlg, IDC_STATIC_FONT_WINDOW_PREVIEW, 736 775 WM_DISPLAYCHANGE, wParam, lParam); 776 + break; 777 + } 778 + 779 + #if 0 780 + case PSM_QUERYSIBLINGS: 781 + { 782 + /* 783 + * If this is a notification from the "Options" dialog because we 784 + * changed the code page, treat it using the WM_FONTCHANGE case, 785 + * otherwise ignore it. 786 + */ 787 + if (wParam != IDL_CODEPAGE) 788 + return FALSE; 789 + 790 + /* Fall through */ 791 + } 792 + #endif 793 + 794 + case WM_FONTCHANGE: 795 + { 796 + /* The pool of font resources has changed, re-enumerate the fonts */ 797 + HWND hFontList = GetDlgItem(hDlg, IDC_LBOX_FONTTYPE); 798 + 799 + /* Initialize the font list */ 800 + FaceNameList_Initialize(hFontList, ConInfo->CodePage); 801 + 802 + /* Select the current font */ 803 + FaceNameList_SelectFont(hDlg, hFontList, 804 + SizeList, 805 + ConInfo->FaceName, 806 + ConInfo->FontFamily, 807 + ConInfo->FontWeight, 808 + ConInfo->FontSize); 809 + 810 + /* Refresh everything */ 811 + FontTypeChange(hDlg, SizeList, ConInfo); 737 812 break; 738 813 } 739 814
+6
dll/cpl/console/layout.c
··· 203 203 * Compute the console window layout 204 204 */ 205 205 206 + if (FontPreview.hFont == NULL) 207 + RefreshFontPreview(&FontPreview, pConInfo); 208 + 206 209 /* We start with the console client area, rescaled for the preview */ 207 210 SetRect(&rcWin, 0, 0, 208 211 pConInfo->WindowSize.X * FontPreview.CharWidth, ··· 488 491 489 492 hBrush = CreateSolidBrush(nbkColor); 490 493 if (!hBrush) return; 494 + 495 + if (FontPreview.hFont == NULL) 496 + RefreshFontPreview(&FontPreview, pConInfo); 491 497 492 498 hOldFont = SelectObject(drawItem->hDC, FontPreview.hFont); 493 499 //if (hOldFont == NULL)
+13 -7
dll/cpl/console/options.c
··· 72 72 73 73 static VOID 74 74 BuildCodePageList( 75 - IN HWND hDlg) 75 + IN HWND hDlg, 76 + IN UINT CurrentCodePage) 76 77 { 77 78 LIST_CTL ListCtl; 78 79 HKEY hKey; ··· 126 127 AddCodePage(&ListCtl, CP_UTF8); 127 128 128 129 /* Find and select the current code page in the sorted list */ 129 - if (BisectListSortedByValue(&ListCtl, ConInfo->CodePage, &CodePage, FALSE) == CB_ERR || 130 + if (BisectListSortedByValue(&ListCtl, CurrentCodePage, &CodePage, FALSE) == CB_ERR || 130 131 CodePage == CB_ERR) 131 132 { 132 133 /* Not found, select the first element */ ··· 212 213 { 213 214 case WM_INITDIALOG: 214 215 { 215 - BuildCodePageList(hDlg); 216 + BuildCodePageList(hDlg, ConInfo->CodePage); 216 217 UpdateDialogElements(hDlg, ConInfo); 217 218 return TRUE; 218 219 } ··· 332 333 } 333 334 } 334 335 else 336 + // (HIWORD(wParam) == CBN_KILLFOCUS) 335 337 if ((HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_SELENDOK) && 336 338 (LOWORD(wParam) == IDL_CODEPAGE)) 337 339 { ··· 347 349 if (CodePage == CB_ERR) 348 350 break; 349 351 350 - ConInfo->CodePage = CodePage; 351 - 352 - /* Change the property sheet state only if the user validated */ 353 - if (HIWORD(wParam) == CBN_SELENDOK) 352 + /* If the user validated a different code page... */ 353 + if ((HIWORD(wParam) == CBN_SELENDOK) && (CodePage != ConInfo->CodePage)) 354 + { 355 + /* ... update the code page, notify the siblings and change the property sheet state */ 356 + ConInfo->CodePage = CodePage; 357 + // PropSheet_QuerySiblings(GetParent(hDlg), IDL_CODEPAGE, 0); 358 + ResetFontPreview(&FontPreview); 354 359 PropSheet_Changed(GetParent(hDlg), hDlg); 360 + } 355 361 } 356 362 357 363 break;
+254 -37
win32ss/user/winsrv/concfg/font.c
··· 20 20 #include <debug.h> 21 21 22 22 23 + /* GLOBALS ********************************************************************/ 24 + 25 + // RTL_STATIC_LIST_HEAD(TTFontCache); 26 + LIST_ENTRY TTFontCache = {&TTFontCache, &TTFontCache}; 27 + 23 28 /* FUNCTIONS ******************************************************************/ 24 29 25 30 /* Retrieves the character set associated with a given code page */ ··· 58 63 lf.lfOutPrecision = OUT_DEFAULT_PRECIS; 59 64 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 60 65 lf.lfQuality = DEFAULT_QUALITY; 61 - lf.lfPitchAndFamily = (BYTE)(FIXED_PITCH | FontFamily); 66 + 67 + /* Set the mandatory flags and remove those that we do not support */ 68 + lf.lfPitchAndFamily = (BYTE)( (FIXED_PITCH | FF_MODERN | FontFamily) & 69 + ~(VARIABLE_PITCH | FF_DECORATIVE | FF_ROMAN | FF_SCRIPT | FF_SWISS)); 62 70 63 71 if (!IsValidConsoleFont(FaceName, CodePage)) 64 72 StringCchCopyW(FaceName, LF_FACESIZE, L"Terminal"); ··· 179 187 { 180 188 LPCWSTR FaceName = lplf->lfFaceName; 181 189 182 - /* Record the font's attributes (Fixedwidth and Truetype) */ 183 - // BOOL fFixed = ((lplf->lfPitchAndFamily & 0x03) == FIXED_PITCH); 184 - // BOOL fTrueType = (lplf->lfOutPrecision == OUT_STROKE_PRECIS); 185 - 186 190 /* 187 - * According to: http://support.microsoft.com/kb/247815 188 - * the criteria for console-eligible fonts are: 191 + * According to: https://web.archive.org/web/20140901124501/http://support.microsoft.com/kb/247815 192 + * "Necessary criteria for fonts to be available in a command window", 193 + * the criteria for console-eligible fonts are as follows: 189 194 * - The font must be a fixed-pitch font. 190 195 * - The font cannot be an italic font. 191 196 * - The font cannot have a negative A or C space. ··· 198 203 * - If it is not a TrueType font, the face name must be "Terminal". 199 204 * - If it is an Asian TrueType font, it must also be an Asian character set. 200 205 * 206 + * See also Raymond Chen's blog: https://devblogs.microsoft.com/oldnewthing/?p=26843 207 + * and MIT-licensed Microsoft Terminal source code: https://github.com/microsoft/Terminal/blob/master/src/propsheet/misc.cpp 208 + * for other details. 209 + * 201 210 * To install additional TrueType fonts to be available for the console, 202 211 * add entries of type REG_SZ named "0", "00" etc... in: 203 212 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont ··· 205 214 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts 206 215 */ 207 216 208 - /* 209 - * In ReactOS we relax some of the criteria: 210 - * - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts 211 - * that can be italic or have negative A or C space. 212 - * - If it is not a TrueType font, it can be from another character set 213 - * than OEM_CHARSET. 214 - * - We do not look into the magic registry key mentioned above. 215 - */ 217 + /* 218 + * In ReactOS we relax some of the criteria: 219 + * - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts 220 + * that can be italic or have negative A or C space. 221 + * - If it is not a TrueType font, it can be from another character set 222 + * than OEM_CHARSET. When an Asian codepage is active however, we require 223 + * that this non-TrueType font has an Asian character set. 224 + */ 216 225 217 - /* Reject variable width fonts */ 218 - if (((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH) 219 - #if 0 /* Reject italic and TrueType fonts with negative A or C space */ 220 - || (lplf->lfItalic) 221 - || !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) 226 + /* Reject variable-width fonts ... */ 227 + if ( ( ((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH) 228 + #if 0 /* Reject italic and TrueType fonts with negative A or C space ... */ 229 + || (lplf->lfItalic) 230 + || !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) 222 231 #endif 223 - ) 232 + ) && 233 + /* ... if they are not in the list of additional TrueType fonts to include */ 234 + !IsAdditionalTTFont(FaceName) ) 224 235 { 225 - DPRINT1("Font '%S' rejected because it%s (lfPitchAndFamily = %d).\n", 226 - FaceName, !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" 227 - : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" 228 - : " is broken"), 236 + DPRINT1("Font '%S' rejected because it%s (lfPitchAndFamily = %d)\n", 237 + FaceName, 238 + !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" 239 + : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" 240 + : " is broken"), 229 241 lplf->lfPitchAndFamily); 230 242 return FALSE; 231 243 } ··· 238 250 return FALSE; 239 251 } 240 252 253 + /* Reject vertical fonts (tategaki) */ 254 + if (FaceName[0] == L'@') 255 + { 256 + DPRINT1("Font '%S' rejected because it's vertical\n", FaceName); 257 + return FALSE; 258 + } 259 + 241 260 /* Is the current code page Chinese, Japanese or Korean? */ 242 261 if (IsCJKCodePage(CodePage)) 243 262 { 244 - /* It's Asian */ 263 + /* It's CJK */ 264 + 245 265 if (FontType == TRUETYPE_FONTTYPE) 246 266 { 247 - if (lplf->lfCharSet != CodePageToCharSet(CodePage)) 267 + /* 268 + * Here we are inclusive and check for any CJK character set, 269 + * instead of looking just at the current one via CodePageToCharSet(). 270 + */ 271 + if (!IsCJKCharSet(lplf->lfCharSet) 272 + #if 1 // FIXME: Temporary HACK! 273 + && wcscmp(FaceName, L"Terminal") != 0 274 + #endif 275 + ) 248 276 { 249 - DPRINT1("TrueType font '%S' rejected because it's not user Asian charset (lfCharSet = %d)\n", 277 + DPRINT1("TrueType font '%S' rejected because it's not Asian charset (lfCharSet = %d)\n", 278 + FaceName, lplf->lfCharSet); 279 + return FALSE; 280 + } 281 + 282 + /* 283 + * If this is a cached TrueType font that is used only for certain 284 + * code pages, verify that the charset it claims is the correct one. 285 + * 286 + * Since there may be multiple entries for a cached TrueType font, 287 + * a general one (code page == 0) and one or more for explicit 288 + * code pages, we need to perform two search queries instead of 289 + * just one and retrieving the code page for this entry. 290 + */ 291 + if (IsAdditionalTTFont(FaceName) && !IsAdditionalTTFontCP(FaceName, 0) && 292 + !IsCJKCharSet(lplf->lfCharSet)) 293 + { 294 + DPRINT1("Cached TrueType font '%S' rejected because it claims a code page that is not Asian charset (lfCharSet = %d)\n", 250 295 FaceName, lplf->lfCharSet); 251 296 return FALSE; 252 297 } 253 298 } 254 299 else 255 300 { 301 + /* Reject non-TrueType fonts that do not have an Asian character set */ 302 + if (!IsCJKCharSet(lplf->lfCharSet) && (lplf->lfCharSet != OEM_CHARSET)) 303 + { 304 + DPRINT1("Non-TrueType font '%S' rejected because it's not Asian charset or OEM_CHARSET (lfCharSet = %d)\n", 305 + FaceName, lplf->lfCharSet); 306 + return FALSE; 307 + } 308 + 256 309 /* Reject non-TrueType fonts that are not Terminal */ 257 310 if (wcscmp(FaceName, L"Terminal") != 0) 258 311 { 259 - DPRINT1("Non-TrueType font '%S' rejected because it's not Terminal\n", FaceName); 312 + DPRINT1("Non-TrueType font '%S' rejected because it's not 'Terminal'\n", FaceName); 260 313 return FALSE; 261 314 } 262 315 } ··· 264 317 else 265 318 { 266 319 /* Not CJK */ 320 + 321 + /* Reject non-TrueType fonts that are not OEM or similar */ 267 322 if ((FontType != TRUETYPE_FONTTYPE) && 268 323 (lplf->lfCharSet != ANSI_CHARSET) && 269 324 (lplf->lfCharSet != DEFAULT_CHARSET) && ··· 273 328 FaceName, lplf->lfCharSet); 274 329 return FALSE; 275 330 } 276 - } 277 - 278 - /* Reject fonts that are vertical (tategaki) */ 279 - if (FaceName[0] == L'@') 280 - { 281 - DPRINT1("Font '%S' rejected because it's vertical\n", FaceName); 282 - return FALSE; 283 331 } 284 332 285 333 /* All good */ ··· 320 368 321 369 RtlZeroMemory(&lf, sizeof(lf)); 322 370 lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(CodePage); 323 - // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE; 371 + // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN; 324 372 StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), FaceName); 325 373 326 374 hDC = GetDC(NULL); ··· 328 376 ReleaseDC(NULL, hDC); 329 377 330 378 return Param.IsValidFont; 379 + } 380 + 381 + /* 382 + * To install additional TrueType fonts to be available for the console, 383 + * add entries of type REG_SZ named "0", "00" etc... in: 384 + * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont 385 + * The names of the fonts listed there should match those in: 386 + * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts 387 + * 388 + * This function initializes the cache of the fonts listed there. 389 + */ 390 + VOID 391 + InitTTFontCache(VOID) 392 + { 393 + BOOLEAN Success; 394 + HKEY hKeyTTFonts; // hKey; 395 + DWORD dwNumValues = 0; 396 + DWORD dwIndex; 397 + DWORD dwType; 398 + WCHAR szValueName[MAX_PATH]; 399 + DWORD dwValueName; 400 + WCHAR szValue[LF_FACESIZE] = L""; 401 + DWORD dwValue; 402 + PTT_FONT_ENTRY FontEntry; 403 + PWCHAR pszNext = NULL; 404 + UINT CodePage; 405 + 406 + if (!IsListEmpty(&TTFontCache)) 407 + return; 408 + // InitializeListHead(&TTFontCache); 409 + 410 + /* Open the key */ 411 + // "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont" 412 + Success = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, 413 + L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont", 414 + 0, 415 + KEY_READ, 416 + &hKeyTTFonts) == ERROR_SUCCESS); 417 + if (!Success) 418 + return; 419 + 420 + /* Enumerate each value */ 421 + if (RegQueryInfoKeyW(hKeyTTFonts, NULL, NULL, NULL, NULL, NULL, NULL, 422 + &dwNumValues, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) 423 + { 424 + DPRINT("ConCfgReadUserSettings: RegQueryInfoKeyW failed\n"); 425 + RegCloseKey(hKeyTTFonts); 426 + return; 427 + } 428 + 429 + for (dwIndex = 0; dwIndex < dwNumValues; dwIndex++) 430 + { 431 + dwValue = sizeof(szValue); 432 + dwValueName = ARRAYSIZE(szValueName); 433 + if (RegEnumValueW(hKeyTTFonts, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS) 434 + { 435 + DPRINT1("InitTTFontCache: RegEnumValueW failed, continuing...\n"); 436 + continue; 437 + } 438 + /* Only (multi-)string values are supported */ 439 + if ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ)) 440 + continue; 441 + 442 + /* The value name is a code page (in decimal), validate it */ 443 + CodePage = wcstoul(szValueName, &pszNext, 10); 444 + if (*pszNext) 445 + continue; // Non-numerical garbage followed... 446 + // IsValidCodePage(CodePage); 447 + 448 + FontEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*FontEntry)); 449 + if (!FontEntry) 450 + { 451 + DPRINT1("InitTTFontCache: Failed to allocate memory, continuing...\n"); 452 + continue; 453 + } 454 + 455 + FontEntry->CodePage = CodePage; 456 + 457 + pszNext = szValue; 458 + 459 + /* Check whether bold is disabled for this font */ 460 + if (*pszNext == L'*') 461 + { 462 + FontEntry->DisableBold = TRUE; 463 + ++pszNext; 464 + } 465 + else 466 + { 467 + FontEntry->DisableBold = FALSE; 468 + } 469 + 470 + /* Copy the font name */ 471 + StringCchCopyNW(FontEntry->FaceName, ARRAYSIZE(FontEntry->FaceName), 472 + pszNext, wcslen(pszNext)); 473 + 474 + if (dwType == REG_MULTI_SZ) 475 + { 476 + /* There may be an alternate face name as the second string */ 477 + pszNext += wcslen(pszNext) + 1; 478 + 479 + /* Check whether bold is disabled for this font */ 480 + if (*pszNext == L'*') 481 + { 482 + FontEntry->DisableBold = TRUE; 483 + ++pszNext; 484 + } 485 + // else, keep the original setting. 486 + 487 + /* Copy the alternate font name */ 488 + StringCchCopyNW(FontEntry->FaceNameAlt, ARRAYSIZE(FontEntry->FaceNameAlt), 489 + pszNext, wcslen(pszNext)); 490 + } 491 + 492 + InsertTailList(&TTFontCache, &FontEntry->Entry); 493 + } 494 + 495 + /* Close the key and quit */ 496 + RegCloseKey(hKeyTTFonts); 497 + } 498 + 499 + VOID 500 + ClearTTFontCache(VOID) 501 + { 502 + PLIST_ENTRY Entry; 503 + PTT_FONT_ENTRY FontEntry; 504 + 505 + while (!IsListEmpty(&TTFontCache)) 506 + { 507 + Entry = RemoveHeadList(&TTFontCache); 508 + FontEntry = CONTAINING_RECORD(Entry, TT_FONT_ENTRY, Entry); 509 + RtlFreeHeap(RtlGetProcessHeap(), 0, FontEntry); 510 + } 511 + InitializeListHead(&TTFontCache); 512 + } 513 + 514 + VOID 515 + RefreshTTFontCache(VOID) 516 + { 517 + ClearTTFontCache(); 518 + InitTTFontCache(); 519 + } 520 + 521 + PTT_FONT_ENTRY 522 + FindCachedTTFont( 523 + IN LPCWSTR FaceName, 524 + IN UINT CodePage) 525 + { 526 + PLIST_ENTRY Entry; 527 + PTT_FONT_ENTRY FontEntry; 528 + 529 + /* Search for the font in the cache */ 530 + for (Entry = TTFontCache.Flink; 531 + Entry != &TTFontCache; 532 + Entry = Entry->Flink) 533 + { 534 + FontEntry = CONTAINING_RECORD(Entry, TT_FONT_ENTRY, Entry); 535 + 536 + /* NOTE: The font face names are case-sensitive */ 537 + if ((wcscmp(FontEntry->FaceName , FaceName) == 0) || 538 + (wcscmp(FontEntry->FaceNameAlt, FaceName) == 0)) 539 + { 540 + /* Return a match if we don't look at the code pages, or when they match */ 541 + if ((CodePage == INVALID_CP) || (CodePage == FontEntry->CodePage)) 542 + { 543 + return FontEntry; 544 + } 545 + } 546 + } 547 + return NULL; 331 548 } 332 549 333 550 /* EOF */
+67 -4
win32ss/user/winsrv/concfg/font.h
··· 11 11 12 12 /* DEFINES ********************************************************************/ 13 13 14 - #define CP_SHIFTJIS 932 // Japanese Shift-JIS 15 - #define CP_HANGUL 949 // Korean Hangul 16 - #define CP_GB2312 936 // Chinese Simplified (GB2312) 17 - #define CP_BIG5 950 // Chinese Traditional (Big5) 14 + #define INVALID_CP ((UINT)-1) 15 + 16 + #define CP_SHIFTJIS 932 // Japanese Shift-JIS 17 + #define CP_HANGUL 949 // Korean Hangul/Wansung 18 + #define CP_JOHAB 1361 // Korean Johab 19 + #define CP_GB2312 936 // Chinese Simplified (GB2312) 20 + #define CP_BIG5 950 // Chinese Traditional (Big5) 18 21 19 22 /* IsFarEastCP(CodePage) */ 20 23 #define IsCJKCodePage(CodePage) \ 21 24 ((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \ 25 + /* (CodePage) == CP_JOHAB || */ \ 22 26 (CodePage) == CP_BIG5 || (CodePage) == CP_GB2312) 23 27 28 + #if !defined(_WINGDI_) || defined(NOGDI) 29 + #define SHIFTJIS_CHARSET 128 30 + #define HANGEUL_CHARSET 129 31 + #define HANGUL_CHARSET 129 // HANGEUL_CHARSET 32 + #if(WINVER >= 0x0400) 33 + #define JOHAB_CHARSET 130 34 + #endif /* WINVER */ 35 + #define GB2312_CHARSET 134 36 + #define CHINESEBIG5_CHARSET 136 37 + #endif /* !defined(_WINGDI_) || defined(NOGDI) */ 38 + 39 + /* IsAnyDBCSCharSet(CharSet) */ 40 + #define IsCJKCharSet(CharSet) \ 41 + ((CharSet) == SHIFTJIS_CHARSET || (CharSet) == HANGUL_CHARSET || \ 42 + /* (CharSet) == JOHAB_CHARSET || */ \ 43 + (CharSet) == GB2312_CHARSET || (CharSet) == CHINESEBIG5_CHARSET) 44 + 45 + #define IsBoldFont(Weight) \ 46 + ((Weight) >= FW_SEMIBOLD) /* Sometimes, just > FW_MEDIUM */ 47 + 48 + typedef struct _TT_FONT_ENTRY 49 + { 50 + LIST_ENTRY Entry; 51 + UINT CodePage; 52 + BOOL DisableBold; 53 + WCHAR FaceName[LF_FACESIZE]; 54 + WCHAR FaceNameAlt[LF_FACESIZE]; 55 + } TT_FONT_ENTRY, *PTT_FONT_ENTRY; 56 + 57 + 24 58 /* FUNCTIONS ******************************************************************/ 25 59 26 60 BYTE ··· 64 98 IsValidConsoleFont( 65 99 IN LPCWSTR FaceName, 66 100 IN UINT CodePage); 101 + 102 + /* 103 + * To install additional TrueType fonts to be available for the console, 104 + * add entries of type REG_SZ named "0", "00" etc... in: 105 + * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont 106 + * The names of the fonts listed there should match those in: 107 + * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts 108 + * 109 + * This function initializes the cache of the fonts listed there. 110 + */ 111 + VOID 112 + InitTTFontCache(VOID); 113 + 114 + VOID 115 + ClearTTFontCache(VOID); 116 + 117 + VOID 118 + RefreshTTFontCache(VOID); 119 + 120 + PTT_FONT_ENTRY 121 + FindCachedTTFont( 122 + IN LPCWSTR FaceName, 123 + IN UINT CodePage); 124 + 125 + #define IsAdditionalTTFont(FaceName) \ 126 + (FindCachedTTFont((FaceName), INVALID_CP) != NULL) 127 + 128 + #define IsAdditionalTTFontCP(FaceName, CodePage) \ 129 + (FindCachedTTFont((FaceName), (CodePage)) != NULL) 67 130 68 131 /* EOF */
+2 -1
win32ss/user/winsrv/concfg/precomp.h
··· 31 31 #include <ndk/obfuncs.h> 32 32 #include <ndk/rtlfuncs.h> 33 33 34 - #include <stdio.h> // for swprintf 34 + #include <stdio.h> // For swprintf() 35 + #include <stdlib.h> // For wcstoul() 35 36 #include <strsafe.h> 36 37 37 38 /* EOF */
+1 -1
win32ss/user/winsrv/consrv/frontends/gui/conwnd.c
··· 20 20 #define NDEBUG 21 21 #include <debug.h> 22 22 23 - #include "font.h" 23 + #include "concfg/font.h" 24 24 #include "guiterm.h" 25 25 #include "resource.h" 26 26
+3 -1
win32ss/user/winsrv/consrv/frontends/gui/guisettings.c
··· 14 14 #define NDEBUG 15 15 #include <debug.h> 16 16 17 + #include "concfg/font.h" 17 18 #include "guiterm.h" 18 19 #include "guisettings.h" 19 20 ··· 331 332 332 333 /* Set the terminal informations */ 333 334 334 - /* Change the font */ 335 + /* Refresh the additional TrueType fonts cache and change the font */ 336 + RefreshTTFontCache(); 335 337 InitFonts(GuiData, 336 338 pConInfo->FaceName, 337 339 pConInfo->FontFamily,
+7 -3
win32ss/user/winsrv/consrv/frontends/gui/guiterm.c
··· 16 16 #define NDEBUG 17 17 #include <debug.h> 18 18 19 + #include "concfg/font.h" 19 20 #include "guiterm.h" 20 21 #include "resource.h" 21 22 ··· 294 295 HANDLE hInputThread; 295 296 CLIENT_ID ClientId; 296 297 297 - /* 298 - * Initialize and register the console window class, if needed. 299 - */ 298 + /* Perform one-time initialization */ 300 299 if (!ConsInitialized) 301 300 { 301 + /* Initialize and register the console window class */ 302 302 if (!RegisterConWndClass(ConSrvDllInstance)) return FALSE; 303 + 304 + /* Initialize the font support -- additional TrueType fonts cache */ 305 + InitTTFontCache(); 306 + 303 307 ConsInitialized = TRUE; 304 308 } 305 309