https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5d3915d0fcc465f65a6146...
commit 5d3915d0fcc465f65a6146b3d6bd9c050638dc18 Author: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org AuthorDate: Sat Jan 29 20:04:16 2022 +0100 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org CommitDate: Tue Feb 8 15:59:07 2022 +0100
[CONCFG:FONT][CONSRV] Use a suitable font when changing console output CP; fail if none found. (#4337)
CORE-12451, CORE-17601, CORE-17803 Replaces PR #4281.
When changing the console output code page, check whether the current font can support it. If not, try to find a suitable font for the new code page. If none can be found:
- if we are creating a new console, forcefully switch to codepage 437 (OEM USA) and retry finding a font, falling back to "Terminal" if none could be found;
- if we were just changing the current CP, just fail and keep the old code page and font.
Rework the console font selection/creation functions for this new job (see CreateConsoleFontEx() and friends). Elements of implementation based from https://github.com/microsoft/terminal ; see code for more information.
Silence the noisy IsValidConsoleFont2() diagnostic messages.
Add Doxygen documentation.
[CONSOLE.CPL] Only add "Terminal" to the enumerated list of faces + add a TODO implementation comment. --- dll/cpl/console/font.c | 6 +- win32ss/user/winsrv/concfg/font.c | 703 +++++++++++++++++++-- win32ss/user/winsrv/concfg/font.h | 33 +- win32ss/user/winsrv/consrv/frontends/gui/conwnd.c | 113 +++- .../user/winsrv/consrv/frontends/gui/guisettings.c | 21 +- .../user/winsrv/consrv/frontends/gui/guisettings.h | 2 +- win32ss/user/winsrv/consrv/frontends/gui/guiterm.c | 27 +- win32ss/user/winsrv/consrv/frontends/gui/guiterm.h | 17 +- 8 files changed, 794 insertions(+), 128 deletions(-)
diff --git a/dll/cpl/console/font.c b/dll/cpl/console/font.c index 4cb5f4c61d3..888375924bb 100644 --- a/dll/cpl/console/font.c +++ b/dll/cpl/console/font.c @@ -429,9 +429,11 @@ FaceNameList_Initialize( DPRINT1("The ideal console fonts were not found; manually add default ones.\n");
AddFontToList(hWndList, L"Terminal", RASTER_FONTTYPE); +#if 0 + // TODO: insert only the *single* default TT font, that should + // be found in the TT font cache with the codepage number 0. AddFontToList(hWndList, L"Lucida Console", TRUETYPE_FONTTYPE); - if (CodePageToCharSet(CodePage) != DEFAULT_CHARSET) - AddFontToList(hWndList, L"Droid Sans Fallback", TRUETYPE_FONTTYPE); +#endif }
static VOID diff --git a/win32ss/user/winsrv/concfg/font.c b/win32ss/user/winsrv/concfg/font.c index 2889d9dd5ef..59b12e3ae90 100644 --- a/win32ss/user/winsrv/concfg/font.c +++ b/win32ss/user/winsrv/concfg/font.c @@ -1,10 +1,9 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS Console Server DLL - * FILE: win32ss/user/winsrv/concfg/font.c - * PURPOSE: Console Fonts Management - * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) - * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + * PROJECT: ReactOS Console Server DLL + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Console GDI Fonts Management. + * COPYRIGHT: Copyright 2017-2022 Hermès Bélusca-Maïto + * Copyright 2017 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */
/* INCLUDES *******************************************************************/ @@ -19,85 +18,594 @@ #define NDEBUG #include <debug.h>
+#define DBGFNT DPRINT +#define DBGFNT1 DPRINT1 +
/* GLOBALS ********************************************************************/
+#define TERMINAL_FACENAME L"Terminal" + // RTL_STATIC_LIST_HEAD(TTFontCache); LIST_ENTRY TTFontCache = {&TTFontCache, &TTFontCache};
+// NOTE: Used to tag code that makes sense only with a font cache. +// #define FONT_CACHE_PRESENT + + /* FUNCTIONS ******************************************************************/
-/* Retrieves the character set associated with a given code page */ +/** + * @brief + * Retrieves the character set associated with a given code page. + * + * @param[in] CodePage + * The code page to convert. + * + * @return + * The character set corresponding to the code page, or @b DEFAULT_CHARSET. + **/ BYTE CodePageToCharSet( _In_ UINT CodePage) { CHARSETINFO CharInfo; if (TranslateCharsetInfo(UlongToPtr(CodePage), &CharInfo, TCI_SRCCODEPAGE)) - return CharInfo.ciCharset; + return (BYTE)CharInfo.ciCharset; else return DEFAULT_CHARSET; }
-HFONT -CreateConsoleFontEx( - _In_ LONG Height, - _In_opt_ LONG Width, - _Inout_updates_z_(LF_FACESIZE) - PWSTR FaceName, - _In_ ULONG FontFamily, - _In_ ULONG FontWeight, - _In_ UINT CodePage) +/*****************************************************************************/ + +typedef struct _FIND_SUITABLE_FONT_PROC_PARAM +{ + /* Search criteria */ + _In_reads_or_z_(LF_FACESIZE) PCWSTR AltFaceName; + FONT_DATA SearchFont; + UINT CodePage; + BOOL StrictSearch; // TRUE to do strict search; FALSE for relaxed criteria. + + /* Candidate font data */ + BOOL FontFound; // TRUE/FALSE if we have/haven't found a suitable font. + FONT_DATA CandidateFont; + WCHAR CandidateFaceName[LF_FACESIZE]; +} FIND_SUITABLE_FONT_PROC_PARAM, *PFIND_SUITABLE_FONT_PROC_PARAM; + +#define TM_IS_TT_FONT(x) (((x) & TMPF_TRUETYPE) == TMPF_TRUETYPE) +#define SIZE_EQUAL(s1, s2) (((s1).X == (s2).X) && ((s1).Y == (s2).Y)) + +/** + * @brief EnumFontFamiliesEx() callback helper for FindSuitableFont(). + * + * @remark + * It implements a nearly-identical console-suitable font search + * algorithm based on the one from FindCreateFont() + * https://github.com/microsoft/terminal/blob/main/src/propsheet/fontdlg.cpp#L1... + * excepting that for now, it does not support an internal font cache. + **/ +static BOOL CALLBACK +FindSuitableFontProc( + _In_ PLOGFONTW lplf, + _In_ PNEWTEXTMETRICW lpntm, + _In_ DWORD FontType, + _In_ LPARAM lParam) +{ + PFIND_SUITABLE_FONT_PROC_PARAM Param = (PFIND_SUITABLE_FONT_PROC_PARAM)lParam; + PFONT_DATA SearchFont = &Param->SearchFont; + + if (!IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage)) + { + /* This font does not suit us; continue enumeration */ + return TRUE; + } + +#ifndef FONT_CACHE_PRESENT + /* + * Since we don't cache all the possible font sizes for TrueType fonts, + * we cannot check our requested size (and weight) against the enumerated + * one; therefore reset the enumerated values to the requested ones. + * On the contrary, Raster fonts get their specific font sizes (and weights) + * enumerated separately, so for them we can keep the enumerated values. + */ + if (FontType == TRUETYPE_FONTTYPE) + { + lplf->lfHeight = SearchFont->Size.Y; + lplf->lfWidth = 0; // SearchFont->Size.X; + lplf->lfWeight = FW_NORMAL; + } +#endif + + if (Param->StrictSearch) + { + /* + * Find whether this is an exact match. + */ + + /* If looking for a particular family, skip non-matches */ + if ((SearchFont->Family != 0) && + ((BYTE)SearchFont->Family != (lplf->lfPitchAndFamily & 0xF0))) + { + /* Continue enumeration */ + return TRUE; + } + + /* Skip non-matching sizes */ +#if 0 + if ((FontInfo[i].SizeWant.Y != Size.Y) && + !SIZE_EQUAL(FontInfo[i].Size, Size)) +#endif + if ((lplf->lfHeight != SearchFont->Size.Y) && + !(lplf->lfWidth == SearchFont->Size.X && + lplf->lfHeight == SearchFont->Size.Y)) + { + /* Continue enumeration */ + return TRUE; + } + + /* Skip non-matching weights */ + if ((SearchFont->Weight != 0) && + (SearchFont->Weight != lplf->lfWeight)) + { + /* Continue enumeration */ + return TRUE; + } + + /* NOTE: We are making the font enumeration at fixed CharSet, + * with the one specified in the parameter block. */ + ASSERT(lplf->lfCharSet == SearchFont->CharSet); + + if ((FontType != TRUETYPE_FONTTYPE) && // !TM_IS_TT_FONT(lpntm->tmPitchAndFamily) + (lplf->lfCharSet != SearchFont->CharSet) && + !(lplf->lfCharSet == OEM_CHARSET && IsCJKCodePage(Param->CodePage))) // g_fEastAsianSystem + { + /* Continue enumeration */ + return TRUE; + } + + /* + * Size (and maybe family) match. If we don't care about the name or + * if it matches, use this font. Otherwise, if name doesn't match and + * it is a raster font, consider it. + * + * NOTE: The font face names are case-sensitive. + */ + if (!SearchFont->FaceName || !*(SearchFont->FaceName) || + (wcscmp(lplf->lfFaceName, SearchFont->FaceName) == 0) || + (wcscmp(lplf->lfFaceName, Param->AltFaceName) == 0)) + { + // FontIndex = i; + + PFONT_DATA CandidateFont = &Param->CandidateFont; + + CandidateFont->FaceName = Param->CandidateFaceName; + StringCchCopyNW(Param->CandidateFaceName, + ARRAYSIZE(Param->CandidateFaceName), + lplf->lfFaceName, ARRAYSIZE(lplf->lfFaceName)); + + CandidateFont->Weight = lplf->lfWeight; + CandidateFont->Family = (lplf->lfPitchAndFamily & 0xF0); + + CandidateFont->Size.X = lplf->lfWidth; + CandidateFont->Size.Y = lplf->lfHeight; + + CandidateFont->CharSet = lplf->lfCharSet; + + /* The font is found, stop enumeration */ + Param->FontFound = TRUE; + return FALSE; + } + else if (FontType != TRUETYPE_FONTTYPE) // !TM_IS_TT_FONT(lpntm->tmPitchAndFamily) + { + // FontIndex = i; + + PFONT_DATA CandidateFont = &Param->CandidateFont; + + CandidateFont->FaceName = Param->CandidateFaceName; + StringCchCopyNW(Param->CandidateFaceName, + ARRAYSIZE(Param->CandidateFaceName), + lplf->lfFaceName, ARRAYSIZE(lplf->lfFaceName)); + + CandidateFont->Weight = lplf->lfWeight; + CandidateFont->Family = (lplf->lfPitchAndFamily & 0xF0); + + CandidateFont->Size.X = lplf->lfWidth; + CandidateFont->Size.Y = lplf->lfHeight; + + CandidateFont->CharSet = lplf->lfCharSet; + + /* A close Raster Font fit was found; only the name doesn't match. + * Continue enumeration to see whether we can find better. */ + Param->FontFound = TRUE; + } + } + else // !Param->StrictSearch + { + /* + * Failed to find exact match, even after enumeration, so now + * try to find a font of same family and same size or bigger. + */ + + if (IsCJKCodePage(Param->CodePage)) // g_fEastAsianSystem + { + if ((SearchFont->Family != 0) && + ((BYTE)SearchFont->Family != (lplf->lfPitchAndFamily & 0xF0))) + { + /* Continue enumeration */ + return TRUE; + } + + if ((FontType != TRUETYPE_FONTTYPE) && // !TM_IS_TT_FONT(lpntm->tmPitchAndFamily) + (lplf->lfCharSet != SearchFont->CharSet)) + { + /* Continue enumeration */ + return TRUE; + } + } + else + { + if (// (SearchFont->Family != 0) && + ((BYTE)SearchFont->Family != (lplf->lfPitchAndFamily & 0xF0))) + { + /* Continue enumeration */ + return TRUE; + } + } + + if ((lplf->lfHeight >= SearchFont->Size.Y) && + (lplf->lfWidth >= SearchFont->Size.X)) + { + /* Same family, size >= desired */ + // FontIndex = i; + + PFONT_DATA CandidateFont = &Param->CandidateFont; + + CandidateFont->FaceName = Param->CandidateFaceName; + StringCchCopyNW(Param->CandidateFaceName, + ARRAYSIZE(Param->CandidateFaceName), + lplf->lfFaceName, ARRAYSIZE(lplf->lfFaceName)); + + CandidateFont->Weight = lplf->lfWeight; + CandidateFont->Family = (lplf->lfPitchAndFamily & 0xF0); + + CandidateFont->Size.X = lplf->lfWidth; + CandidateFont->Size.Y = lplf->lfHeight; + + CandidateFont->CharSet = lplf->lfCharSet; + + /* The font is found, stop enumeration */ + Param->FontFound = TRUE; + return FALSE; + } + } + + /* Continue enumeration */ + return TRUE; +} + +/** + * @brief + * Finds a font suitable for the given code page, based on the current font + * and its characteristics provided in input. + * + * @param[in,out] FontData + * In input: The face name and characteristics of the font to search for, + * possibly getting a best match. + * In output: The face name and characteristics of the suitable font, + * in case of success. + * + * @param[in] CodePage + * The code page the font has to support. + * + * @return + * @b TRUE in case a suitable font has been found. Its name and characteristics + * are returned in @b FontData. @b FALSE if no suitable font has been found. + **/ +static BOOL +FindSuitableFont( + _Inout_ PFONT_DATA FontData, + _In_ UINT CodePage) { + FIND_SUITABLE_FONT_PROC_PARAM Param; + _Inout_updates_z_(LF_FACESIZE) PWSTR FaceName; + HDC hDC; LOGFONTW lf; + PTT_FONT_ENTRY FontEntry; + + /* Save the original FaceName pointer */ + FaceName = FontData->FaceName; + + /* Save our current search criteria */ + RtlZeroMemory(&Param, sizeof(Param)); + Param.SearchFont = *FontData; + + Param.SearchFont.CharSet = CodePageToCharSet(CodePage); + Param.CodePage = CodePage; + + /* Search for a TrueType alternative face name */ + FontEntry = FindCachedTTFont(FaceName, CodePage); + if (FontEntry) + { + /* NOTE: The font face names are case-sensitive */ + if (wcscmp(FontEntry->FaceName, FaceName) == 0) + Param.AltFaceName = FontEntry->FaceNameAlt; + else if (wcscmp(FontEntry->FaceNameAlt, FaceName) == 0) + Param.AltFaceName = FontEntry->FaceName; + } + else + { + Param.AltFaceName = FaceName; + } + + /* Initialize the search: start with a strict search, then a relaxed one */ + Param.FontFound = FALSE;
+ Param.StrictSearch = TRUE; +SearchAgain: + /* + * Enumerate all fonts with the given character set. + * We will match them with the search criteria. + */ RtlZeroMemory(&lf, sizeof(lf)); + lf.lfCharSet = Param.SearchFont.CharSet; + // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
- lf.lfHeight = Height; - lf.lfWidth = Width; + hDC = GetDC(NULL); + EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)FindSuitableFontProc, (LPARAM)&Param, 0); + ReleaseDC(NULL, hDC); + + /* If we failed to find any font, search again with relaxed criteria */ + if (Param.StrictSearch && !Param.FontFound) + { + Param.StrictSearch = FALSE; + goto SearchAgain; + } + + /* If no font was found again, return failure */ + if (!Param.FontFound) + return FALSE; + + /* Return the font details */ + *FontData = Param.CandidateFont; + FontData->FaceName = FaceName; // Restore the original FaceName pointer. + StringCchCopyNW(FaceName, LF_FACESIZE, + Param.CandidateFaceName, + ARRAYSIZE(Param.CandidateFaceName)); + + return TRUE; +} + +/** + * @brief + * Validates and creates a suitable console font based on the font + * characteristics given in input. + * + * @param[in] FontData + * The face name and characteristics of the font to create. + * + * @param[in] CodePage + * The code page the font has to support. + * + * @return + * A GDI handle to the created font, or @b NULL in case of failure. + **/ +static HFONT +CreateConsoleFontWorker( + _In_ PFONT_DATA FontData, + _In_ UINT CodePage) +{ + LOGFONTW lf; + + RtlZeroMemory(&lf, sizeof(lf)); + + lf.lfHeight = (LONG)(ULONG)FontData->Size.Y; + lf.lfWidth = (LONG)(ULONG)FontData->Size.X;
lf.lfEscapement = 0; lf.lfOrientation = 0; // TA_BASELINE; // TA_RTLREADING; when the console supports RTL? // lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = FALSE; - lf.lfWeight = FontWeight; + lf.lfWeight = FontData->Weight; lf.lfCharSet = CodePageToCharSet(CodePage); lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY;
/* Set the mandatory flags and remove those that we do not support */ - lf.lfPitchAndFamily = (BYTE)( (FIXED_PITCH | FF_MODERN | FontFamily) & + lf.lfPitchAndFamily = (BYTE)( (FIXED_PITCH | FF_MODERN | FontData->Family) & ~(VARIABLE_PITCH | FF_DECORATIVE | FF_ROMAN | FF_SCRIPT | FF_SWISS));
- if (!IsValidConsoleFont(FaceName, CodePage)) + if (!IsValidConsoleFont(FontData->FaceName, CodePage)) + return NULL; + + StringCchCopyNW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), + FontData->FaceName, LF_FACESIZE); + + return CreateFontIndirectW(&lf); +} + +/*****************************************************************************/ + +/** + * @brief + * Validates and creates a suitable console font based on the font + * characteristics given in input. + * + * @param[in] Height + * The font height in cell units (pixels). + * + * @param[in,opt] Width + * The font width in cell units (pixels). + * + * @param[in,out] FaceName + * A pointer to a maximally @b LF_FACESIZE-sized buffer. + * In input: The buffer contains the face name of the font to try to create. + * In output: The buffer receives the face name of the font that has been + * created, in case of success. It may, or may not be, identical to the face + * name provided in input, in case a substitute font has been chosen. + * + * @param[in] FontWeight + * The font weight. + * + * @param[in] FontFamily + * The font family. + * + * @param[in] CodePage + * The code page the font has to support. + * + * @param[in] UseDefaultFallback + * Whether (@b TRUE) or not (@b FALSE) to use a default fallback font in case + * neither the specified font nor any substitute font could be found and + * created for the specified code page. + * + * @param[out] FontData + * The face name and characteristics of the created font. + * + * @return + * A GDI handle to the created font, or @b NULL in case of failure. + * + * @remark + * Similar to FindCreateFont() + * https://github.com/microsoft/terminal/blob/main/src/propsheet/fontdlg.cpp#L1... + * but: + * - does not support an internal font cache for now; + * - returns a font handle (and not a font index to the cache). + **/ +HFONT +CreateConsoleFontEx( + _In_ LONG Height, + _In_opt_ LONG Width, + _Inout_updates_z_(LF_FACESIZE) + PWSTR FaceName, + _In_ ULONG FontWeight, + _In_ ULONG FontFamily, + _In_ UINT CodePage, + _In_ BOOL UseDefaultFallback, + _Out_ PFONT_DATA FontData) +{ + HFONT hFont; + + FontData->FaceName = FaceName; + FontData->Weight = FontWeight; + FontData->Family = FontFamily; + /* NOTE: FontSize is always in cell height/width units (pixels) */ + FontData->Size.X = Width; + FontData->Size.Y = Height; + FontData->CharSet = 0; // CodePageToCharSet(CodePage); + + hFont = CreateConsoleFontWorker(FontData, CodePage); + if (hFont) + return hFont; + + DBGFNT1("CreateConsoleFont('%S') failed - Try to find a suitable font...\n", + FaceName); + + /* + * We could not create a font with the default settings. + * Try to find a suitable font and retry. + */ + if (!FindSuitableFont(FontData, CodePage)) { - StringCchCopyW(FaceName, LF_FACESIZE, L"Terminal"); + /* We could not find any suitable font, fall back + * to some default one if required to do so. */ + DBGFNT1("FindSuitableFont could not find anything - %s\n", + UseDefaultFallback ? "Falling back to 'Terminal'" + : "Bailing out"); + + /* No fallback: no font! */ + if (!UseDefaultFallback) + return NULL; + + /* Use "Terminal" as the fallback */ + StringCchCopyW(FaceName, LF_FACESIZE, TERMINAL_FACENAME); +#if 0 + // FIXME: CJK font choose workaround: Don't choose Asian + // charset font if there is no preferred font for CJK. if (IsCJKCodePage(CodePage)) - { - lf.lfCharSet = ANSI_CHARSET; - } + FontData->CharSet = ANSI_CHARSET; +#endif + } + else + { + DBGFNT1("FindSuitableFont found: '%S', size (%d x %d)\n", + FaceName, FontData->Size.X, FontData->Size.Y); }
- StringCchCopyNW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), - FaceName, LF_FACESIZE); + /* Retry creating the font */ + hFont = CreateConsoleFontWorker(FontData, CodePage); + if (!hFont) + DBGFNT1("CreateConsoleFont('%S') failed\n", FaceName);
- return CreateFontIndirectW(&lf); + return hFont; }
+/** + * @brief + * A wrapper for CreateConsoleFontEx(). + * + * @param[in] Height + * The font height in cell units (pixels). + * + * @param[in,opt] Width + * The font width in cell units (pixels). + * + * @param[in,out] ConsoleInfo + * A pointer to console settings information, containing in particular + * (in input) the face name and characteristics of the font to create + * with the current console code page. + * In output, the font information gets updated. + * Note that a default fallback font is always being used in case neither + * the specified font nor any substitute font could be found and created + * for the specified code page. + * + * @return + * A GDI handle to the created font, or @b NULL in case of failure. + * + * @see CreateConsoleFontEx(), CreateConsoleFont() + **/ HFONT CreateConsoleFont2( _In_ LONG Height, _In_opt_ LONG Width, _Inout_ PCONSOLE_STATE_INFO ConsoleInfo) { - return CreateConsoleFontEx(Height, - Width, - ConsoleInfo->FaceName, - ConsoleInfo->FontFamily, - ConsoleInfo->FontWeight, - ConsoleInfo->CodePage); + FONT_DATA FontData; + HFONT hFont; + + hFont = CreateConsoleFontEx(Height, + Width, + ConsoleInfo->FaceName, + ConsoleInfo->FontWeight, + ConsoleInfo->FontFamily, + ConsoleInfo->CodePage, + TRUE, // UseDefaultFallback + &FontData); + if (hFont) + { + ConsoleInfo->FontWeight = FontData.Weight; + ConsoleInfo->FontFamily = FontData.Family; + } + + return hFont; }
+/** + * @brief + * A wrapper for CreateConsoleFontEx(). + * + * @param[in,out] ConsoleInfo + * A pointer to console settings information, containing in particular + * (in input) the face name and characteristics of the font to create + * with the current console code page. + * In output, the font information gets updated. + * Note that a default fallback font is always being used in case neither + * the specified font nor any substitute font could be found and created + * for the specified code page. + * + * @return + * A GDI handle to the created font, or @b NULL in case of failure. + * + * @see CreateConsoleFontEx(), CreateConsoleFont2() + **/ HFONT CreateConsoleFont( _Inout_ PCONSOLE_STATE_INFO ConsoleInfo) @@ -108,14 +616,30 @@ CreateConsoleFont( * Height = FontSize.Y = HIWORD(FontSize); */ /* NOTE: FontSize is always in cell height/width units (pixels) */ - return CreateConsoleFontEx((LONG)(ULONG)ConsoleInfo->FontSize.Y, - (LONG)(ULONG)ConsoleInfo->FontSize.X, - ConsoleInfo->FaceName, - ConsoleInfo->FontFamily, - ConsoleInfo->FontWeight, - ConsoleInfo->CodePage); + return CreateConsoleFont2((LONG)(ULONG)ConsoleInfo->FontSize.Y, + (LONG)(ULONG)ConsoleInfo->FontSize.X, + ConsoleInfo); }
+/** + * @brief + * Retrieves the cell size for a console font. + * + * @param[in,opt] hDC + * An optional GDI device context handle. + * + * @param[in] hFont + * The GDI handle to the font. + * + * @param[out] Height + * In case of success, receives the cell height size (in pixels). + * + * @param[out] Width + * In case of success, receives the cell height size (in pixels). + * + * @return + * @b TRUE if success, @b FALSE in case of failure. + **/ _Success_(return) BOOL GetFontCellSize( @@ -138,7 +662,7 @@ GetFontCellSize( hOldFont = SelectObject(hDC, hFont); if (hOldFont == NULL) { - DPRINT1("GetFontCellSize: SelectObject failed\n"); + DBGFNT1("GetFontCellSize: SelectObject failed\n"); goto Quit; }
@@ -152,7 +676,7 @@ GetFontCellSize( */ if (!GetTextMetricsW(hDC, &tm)) { - DPRINT1("GetFontCellSize: GetTextMetrics failed\n"); + DBGFNT1("GetFontCellSize: GetTextMetrics failed\n"); goto Cleanup; }
@@ -186,6 +710,31 @@ Quit: return Success; }
+/** + * @brief + * Validates whether a given font can be supported in the console, + * under the specified code page. + * + * @param[in] lplf + * @param[in] lpntm + * @param[in] FontType + * The GDI font characteristics of the font to validate. + * + * @param[in] CodePage + * The code page the font has to support. + * + * @return + * @b TRUE if the font is valid and supported in the console, + * @b FALSE if not. + * + * @remark + * Equivalent of the font validation tests in FontEnumForV2Console() + * (or the more restrictive ones in FontEnum()) + * https://github.com/microsoft/terminal/blob/main/src/propsheet/misc.cpp#L465 + * https://github.com/microsoft/terminal/blob/main/src/propsheet/misc.cpp#L607 + * + * @see IsValidConsoleFont() + **/ BOOL IsValidConsoleFont2( _In_ PLOGFONTW lplf, @@ -212,7 +761,7 @@ IsValidConsoleFont2( * - If it is an Asian TrueType font, it must also be an Asian character set. * * See also Raymond Chen's blog: https://devblogs.microsoft.com/oldnewthing/?p=26843 - * and MIT-licensed Microsoft Terminal source code: https://github.com/microsoft/Terminal/blob/master/src/propsheet/misc.cpp + * and MIT-licensed Microsoft Terminal source code: https://github.com/microsoft/terminal/blob/main/src/propsheet/misc.cpp * for other details. * * To install additional TrueType fonts to be available for the console, @@ -241,27 +790,27 @@ IsValidConsoleFont2( /* ... if they are not in the list of additional TrueType fonts to include */ !IsAdditionalTTFont(FaceName) ) { - DPRINT1("Font '%S' rejected because it%s (lfPitchAndFamily = %d)\n", - FaceName, - !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" - : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" - : " is broken"), - lplf->lfPitchAndFamily); + DBGFNT("Font '%S' rejected because it%s (lfPitchAndFamily = %d)\n", + FaceName, + !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH" + : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space" + : " is broken"), + lplf->lfPitchAndFamily); return FALSE; }
/* Reject TrueType fonts that are not FF_MODERN */ if ((FontType == TRUETYPE_FONTTYPE) && ((lplf->lfPitchAndFamily & 0xF0) != FF_MODERN)) { - DPRINT1("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n", - FaceName, lplf->lfPitchAndFamily); + DBGFNT("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n", + FaceName, lplf->lfPitchAndFamily); return FALSE; }
/* Reject vertical fonts (tategaki) */ if (FaceName[0] == L'@') { - DPRINT1("Font '%S' rejected because it's vertical\n", FaceName); + DBGFNT("Font '%S' rejected because it's vertical\n", FaceName); return FALSE; }
@@ -276,14 +825,10 @@ IsValidConsoleFont2( * Here we are inclusive and check for any CJK character set, * instead of looking just at the current one via CodePageToCharSet(). */ - if (!IsCJKCharSet(lplf->lfCharSet) -#if 1 // FIXME: Temporary HACK! - && wcscmp(FaceName, L"Terminal") != 0 -#endif - ) + if (!IsCJKCharSet(lplf->lfCharSet)) { - DPRINT1("TrueType font '%S' rejected because it's not Asian charset (lfCharSet = %d)\n", - FaceName, lplf->lfCharSet); + DBGFNT("TrueType font '%S' rejected because it's not Asian charset (lfCharSet = %d)\n", + FaceName, lplf->lfCharSet); return FALSE; }
@@ -299,8 +844,8 @@ IsValidConsoleFont2( if (IsAdditionalTTFont(FaceName) && !IsAdditionalTTFontCP(FaceName, 0) && !IsCJKCharSet(lplf->lfCharSet)) { - DPRINT1("Cached TrueType font '%S' rejected because it claims a code page that is not Asian charset (lfCharSet = %d)\n", - FaceName, lplf->lfCharSet); + DBGFNT("Cached TrueType font '%S' rejected because it claims a code page that is not Asian charset (lfCharSet = %d)\n", + FaceName, lplf->lfCharSet); return FALSE; } } @@ -309,15 +854,15 @@ IsValidConsoleFont2( /* Reject non-TrueType fonts that do not have an Asian character set */ if (!IsCJKCharSet(lplf->lfCharSet) && (lplf->lfCharSet != OEM_CHARSET)) { - DPRINT1("Non-TrueType font '%S' rejected because it's not Asian charset or OEM_CHARSET (lfCharSet = %d)\n", - FaceName, lplf->lfCharSet); + DBGFNT("Non-TrueType font '%S' rejected because it's not Asian charset or OEM_CHARSET (lfCharSet = %d)\n", + FaceName, lplf->lfCharSet); return FALSE; }
/* Reject non-TrueType fonts that are not Terminal */ - if (wcscmp(FaceName, L"Terminal") != 0) + if (wcscmp(FaceName, TERMINAL_FACENAME) != 0) { - DPRINT1("Non-TrueType font '%S' rejected because it's not 'Terminal'\n", FaceName); + DBGFNT("Non-TrueType font '%S' rejected because it's not 'Terminal'\n", FaceName); return FALSE; } } @@ -332,8 +877,8 @@ IsValidConsoleFont2( (lplf->lfCharSet != DEFAULT_CHARSET) && (lplf->lfCharSet != OEM_CHARSET)) { - DPRINT1("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n", - FaceName, lplf->lfCharSet); + DBGFNT("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n", + FaceName, lplf->lfCharSet); return FALSE; } } @@ -348,6 +893,9 @@ typedef struct _IS_VALID_CONSOLE_FONT_PARAM UINT CodePage; } IS_VALID_CONSOLE_FONT_PARAM, *PIS_VALID_CONSOLE_FONT_PARAM;
+/** + * @brief EnumFontFamiliesEx() callback helper for IsValidConsoleFont(). + **/ static BOOL CALLBACK IsValidConsoleFontProc( _In_ PLOGFONTW lplf, @@ -362,6 +910,23 @@ IsValidConsoleFontProc( return FALSE; }
+/** + * @brief + * Validates whether a given font can be supported in the console, + * under the specified code page. + * + * @param[in] FaceName + * The face name of the font to validate. + * + * @param[in] CodePage + * The code page the font has to support. + * + * @return + * @b TRUE if the font is valid and supported in the console, + * @b FALSE if not. + * + * @see IsValidConsoleFont2() + **/ BOOL IsValidConsoleFont( // _In_reads_or_z_(LF_FACESIZE) @@ -460,7 +1025,7 @@ InitTTFontCache(VOID) FontEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*FontEntry)); if (!FontEntry) { - DPRINT1("InitTTFontCache: Failed to allocate memory, continuing...\n"); + DBGFNT1("InitTTFontCache: Failed to allocate memory, continuing...\n"); continue; }
diff --git a/win32ss/user/winsrv/concfg/font.h b/win32ss/user/winsrv/concfg/font.h index 870b3805a63..6faa59dad33 100644 --- a/win32ss/user/winsrv/concfg/font.h +++ b/win32ss/user/winsrv/concfg/font.h @@ -1,10 +1,9 @@ /* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS Console Server DLL - * FILE: win32ss/user/winsrv/concfg/font.h - * PURPOSE: Console Fonts Management - * PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr) - * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + * PROJECT: ReactOS Console Server DLL + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Console GDI Fonts Management. + * COPYRIGHT: Copyright 2017-2022 Hermès Bélusca-Maïto + * Copyright 2017 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */
#pragma once @@ -13,6 +12,12 @@
#define INVALID_CP ((UINT)-1)
+#ifndef CP_UTF8 +#define CP_UTF8 65001 +#endif + +#define CP_USA 437 // United States (OEM) + #define CP_SHIFTJIS 932 // Japanese Shift-JIS #define CP_HANGUL 949 // Korean Hangul/Wansung #define CP_JOHAB 1361 // Korean Johab @@ -70,15 +75,27 @@ BYTE CodePageToCharSet( _In_ UINT CodePage);
+// FIXME: Will be redefined once we support a font cache. +typedef struct _FONT_DATA +{ + _Inout_updates_z_(LF_FACESIZE) PWSTR FaceName; + ULONG Weight; + ULONG Family; + COORD Size; + BYTE CharSet; +} FONT_DATA, *PFONT_DATA; + HFONT CreateConsoleFontEx( _In_ LONG Height, _In_opt_ LONG Width, _Inout_updates_z_(LF_FACESIZE) PWSTR FaceName, - _In_ ULONG FontFamily, _In_ ULONG FontWeight, - _In_ UINT CodePage); + _In_ ULONG FontFamily, + _In_ UINT CodePage, + _In_ BOOL UseDefaultFallback, + _Out_ PFONT_DATA FontData);
HFONT CreateConsoleFont2( diff --git a/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c b/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c index a1d180d5f93..8b6f67c7e9d 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c +++ b/win32ss/user/winsrv/consrv/frontends/gui/conwnd.c @@ -3,7 +3,7 @@ * PROJECT: ReactOS Console Server DLL * FILE: win32ss/user/winsrv/consrv/frontends/gui/conwnd.c * PURPOSE: GUI Console Window Class - * PROGRAMMERS: G� van Geldorp + * PROGRAMMERS: Gé van Geldorp * Johannes Anderwald * Jeffrey Morlan * Hermes Belusca-Maito (hermes.belusca@sfr.fr) @@ -518,31 +518,54 @@ CreateDerivedFont(HFONT OrgFont, }
BOOL -InitFonts(PGUI_CONSOLE_DATA GuiData, - LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements. - ULONG FontFamily, - COORD FontSize, - ULONG FontWeight) +InitFonts( + _Inout_ PGUI_CONSOLE_DATA GuiData, + _In_reads_or_z_(LF_FACESIZE) + PCWSTR FaceName, + _In_ ULONG FontWeight, + _In_ ULONG FontFamily, + _In_ COORD FontSize, + _In_opt_ UINT CodePage, + _In_ BOOL UseDefaultFallback) { HDC hDC; HFONT hFont; + FONT_DATA FontData; + UINT OldCharWidth = GuiData->CharWidth; + UINT OldCharHeight = GuiData->CharHeight; + COORD OldFontSize = GuiData->GuiInfo.FontSize; + WCHAR NewFaceName[LF_FACESIZE]; + + /* Default to current code page if none has been provided */ + if (!CodePage) + CodePage = GuiData->Console->OutputCodePage;
/* - * Initialize a new NORMAL font and get its character cell size. + * Initialize a new NORMAL font. */ + + /* Copy the requested face name into the local buffer. + * It will be modified in output by CreateConsoleFontEx() + * to hold a possible fallback font face name. */ + StringCchCopyNW(NewFaceName, ARRAYSIZE(NewFaceName), + FaceName, LF_FACESIZE); + /* NOTE: FontSize is always in cell height/width units (pixels) */ hFont = CreateConsoleFontEx((LONG)(ULONG)FontSize.Y, (LONG)(ULONG)FontSize.X, - FaceName, - FontFamily, + NewFaceName, FontWeight, - GuiData->Console->OutputCodePage); - if (hFont == NULL) + FontFamily, + CodePage, + UseDefaultFallback, + &FontData); + if (!hFont) { - DPRINT1("InitFonts: CreateConsoleFontEx failed\n"); + DPRINT1("InitFonts: CreateConsoleFontEx('%S') failed\n", NewFaceName); return FALSE; }
+ /* Retrieve its character cell size */ hDC = GetDC(GuiData->hWindow); if (!GetFontCellSize(hDC, hFont, &GuiData->CharHeight, &GuiData->CharWidth)) { @@ -561,35 +584,43 @@ InitFonts(PGUI_CONSOLE_DATA GuiData, GuiData->Font[FONT_NORMAL] = hFont;
/* - * Now build the other fonts (bold, underlined, mixed). + * Now build the optional fonts (bold, underlined, mixed). + * Do not error in case they fail to be created. */ GuiData->Font[FONT_BOLD] = CreateDerivedFont(GuiData->Font[FONT_NORMAL], - FontWeight < FW_BOLD ? FW_BOLD : FontWeight, + max(FW_BOLD, FontData.Weight), FALSE, FALSE); GuiData->Font[FONT_UNDERLINE] = CreateDerivedFont(GuiData->Font[FONT_NORMAL], - FontWeight, + FontData.Weight, TRUE, FALSE); GuiData->Font[FONT_BOLD | FONT_UNDERLINE] = CreateDerivedFont(GuiData->Font[FONT_NORMAL], - FontWeight < FW_BOLD ? FW_BOLD : FontWeight, + max(FW_BOLD, FontData.Weight), TRUE, FALSE);
/* - * Save the settings. + * Save the new font characteristics. */ - if (FaceName != GuiData->GuiInfo.FaceName) + StringCchCopyNW(GuiData->GuiInfo.FaceName, + ARRAYSIZE(GuiData->GuiInfo.FaceName), + NewFaceName, ARRAYSIZE(NewFaceName)); + GuiData->GuiInfo.FontWeight = FontData.Weight; + GuiData->GuiInfo.FontFamily = FontData.Family; + GuiData->GuiInfo.FontSize = FontData.Size; + + /* Resize the terminal, in case the new font has a different size */ + if ((OldCharWidth != GuiData->CharWidth) || + (OldCharHeight != GuiData->CharHeight) || + (OldFontSize.X != FontData.Size.X || + OldFontSize.Y != FontData.Size.Y)) { - StringCchCopyNW(GuiData->GuiInfo.FaceName, ARRAYSIZE(GuiData->GuiInfo.FaceName), - FaceName, LF_FACESIZE); + TermResizeTerminal(GuiData->Console); } - GuiData->GuiInfo.FontFamily = FontFamily; - GuiData->GuiInfo.FontSize = FontSize; - GuiData->GuiInfo.FontWeight = FontWeight;
return TRUE; } @@ -615,14 +646,40 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create) /* Initialize the fonts */ if (!InitFonts(GuiData, GuiData->GuiInfo.FaceName, + GuiData->GuiInfo.FontWeight, GuiData->GuiInfo.FontFamily, GuiData->GuiInfo.FontSize, - GuiData->GuiInfo.FontWeight)) + 0, FALSE)) { - DPRINT1("GuiConsoleNcCreate: InitFonts failed\n"); - GuiData->hWindow = NULL; - NtSetEvent(GuiData->hGuiInitEvent, NULL); - return FALSE; + /* Reset only the output code page if we don't have a suitable + * font for it, possibly falling back to "United States (OEM)". */ + UINT AltCodePage = GetOEMCP(); + + if (AltCodePage == Console->OutputCodePage) + AltCodePage = CP_USA; + + DPRINT1("Could not initialize font '%S' for code page %d - Resetting CP to %d\n", + GuiData->GuiInfo.FaceName, Console->OutputCodePage, AltCodePage); + + CON_SET_OUTPUT_CP(Console, AltCodePage); + + /* We will use a fallback font if we cannot find + * anything for this replacement code page. */ + if (!InitFonts(GuiData, + GuiData->GuiInfo.FaceName, + GuiData->GuiInfo.FontWeight, + GuiData->GuiInfo.FontFamily, + GuiData->GuiInfo.FontSize, + 0, TRUE)) + { + DPRINT1("Failed to initialize font '%S' for code page %d\n", + GuiData->GuiInfo.FaceName, Console->OutputCodePage); + + DPRINT1("GuiConsoleNcCreate: InitFonts failed\n"); + GuiData->hWindow = NULL; + NtSetEvent(GuiData->hGuiInitEvent, NULL); + return FALSE; + } }
/* Initialize the terminal framebuffer */ diff --git a/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c b/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c index 1ee89ed8a47..38dec0bbd75 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c +++ b/win32ss/user/winsrv/consrv/frontends/gui/guisettings.c @@ -163,9 +163,9 @@ GuiConsoleShowConsoleProperties(PGUI_CONSOLE_DATA GuiData, /* GUI Information */ StringCchCopyNW(pSharedInfo->FaceName, ARRAYSIZE(pSharedInfo->FaceName), GuiData->GuiInfo.FaceName, ARRAYSIZE(GuiData->GuiInfo.FaceName)); + pSharedInfo->FontWeight = GuiData->GuiInfo.FontWeight; pSharedInfo->FontFamily = GuiData->GuiInfo.FontFamily; pSharedInfo->FontSize = GuiData->GuiInfo.FontSize; - pSharedInfo->FontWeight = GuiData->GuiInfo.FontWeight; pSharedInfo->FullScreen = GuiData->GuiInfo.FullScreen; pSharedInfo->AutoPosition = GuiData->GuiInfo.AutoPosition; pSharedInfo->WindowPosition = GuiData->GuiInfo.WindowOrigin; @@ -312,28 +312,29 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
// TODO: Check that GuiData->hWindow == pConInfo->hWnd
- /* Retrieve terminal informations */ - /* Console information */
/* * Apply the settings */
- /* Set the console informations */ + /* Refresh the additional TrueType fonts cache now, + * as ConSrvApplyUserSettings() could change the output + * code page and trigger a font change in the terminal. */ + RefreshTTFontCache(); + + /* Apply the generic console settings */ ConSrvApplyUserSettings(Console, pConInfo);
- /* Set the terminal informations */ + /* Set the terminal settings */
- /* Refresh the additional TrueType fonts cache and change the font */ - RefreshTTFontCache(); + /* Now, attempt to change the font to what the user specified */ InitFonts(GuiData, pConInfo->FaceName, + pConInfo->FontWeight, pConInfo->FontFamily, pConInfo->FontSize, - pConInfo->FontWeight); - // HACK, needed because changing font may change the size of the window - /**/TermResizeTerminal(Console);/**/ + 0, FALSE);
/* Move the window to the user's values */ GuiData->GuiInfo.AutoPosition = !!pConInfo->AutoPosition; diff --git a/win32ss/user/winsrv/consrv/frontends/gui/guisettings.h b/win32ss/user/winsrv/consrv/frontends/gui/guisettings.h index e67c537ee8f..71e968a57a6 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/guisettings.h +++ b/win32ss/user/winsrv/consrv/frontends/gui/guisettings.h @@ -16,9 +16,9 @@ typedef struct _GUI_CONSOLE_INFO { WCHAR FaceName[LF_FACESIZE]; + ULONG FontWeight; ULONG FontFamily; COORD FontSize; - ULONG FontWeight;
BOOL FullScreen; /* Whether the console is displayed in full-screen or windowed mode */ // ULONG HardwareState; /* _GDI_MANAGED, _DIRECT */ diff --git a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c index 778b11073c1..0594ff4a0c8 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c +++ b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.c @@ -3,7 +3,7 @@ * PROJECT: ReactOS Console Server DLL * FILE: win32ss/user/winsrv/consrv/frontends/gui/guiterm.c * PURPOSE: GUI Terminal Front-End - * PROGRAMMERS: G� van Geldorp + * PROGRAMMERS: Gé van Geldorp * Johannes Anderwald * Jeffrey Morlan * Hermes Belusca-Maito (hermes.belusca@sfr.fr) @@ -1038,9 +1038,28 @@ static BOOL NTAPI GuiSetCodePage(IN OUT PFRONTEND This, UINT CodePage) { - // TODO: Find a suitable console font for the given code page, - // and set it if found; otherwise fail the call, or fall back - // to some default font... + PGUI_CONSOLE_DATA GuiData = This->Context; + + /* + * Attempt to reinitialize the current font for the new code page, + * trying to keep the current font with the same characteristics. + * If the current font does not support the new code page, switch + * to a different font supporting the code page but having similar + * characteristics. + * If no font can be found for this code page, stay using the + * original font and refuse changing the code page. + */ + if (!InitFonts(GuiData, + GuiData->GuiInfo.FaceName, + GuiData->GuiInfo.FontWeight, + GuiData->GuiInfo.FontFamily, + GuiData->GuiInfo.FontSize, + CodePage, FALSE)) + { + DPRINT1("Failed to initialize font '%S' for code page %d - Refuse CP change\n", + GuiData->GuiInfo.FaceName, CodePage); + return FALSE; + }
return TRUE; } diff --git a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h index 4ed6c1e8c19..e83f2a0cf96 100644 --- a/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h +++ b/win32ss/user/winsrv/consrv/frontends/gui/guiterm.h @@ -3,7 +3,7 @@ * PROJECT: ReactOS Console Server DLL * FILE: win32ss/user/winsrv/consrv/frontends/gui/guiterm.h * PURPOSE: GUI Terminal Front-End - * PROGRAMMERS: G� van Geldorp + * PROGRAMMERS: Gé van Geldorp * Johannes Anderwald * Jeffrey Morlan * Hermes Belusca-Maito (hermes.belusca@sfr.fr) @@ -65,11 +65,16 @@ GuiConsoleMoveWindow(PGUI_CONSOLE_DATA GuiData); /* conwnd.c */
BOOL -InitFonts(PGUI_CONSOLE_DATA GuiData, - LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements. - ULONG FontFamily, - COORD FontSize, - ULONG FontWeight); +InitFonts( + _Inout_ PGUI_CONSOLE_DATA GuiData, + _In_reads_or_z_(LF_FACESIZE) + PCWSTR FaceName, + _In_ ULONG FontWeight, + _In_ ULONG FontFamily, + _In_ COORD FontSize, + _In_opt_ UINT CodePage, + _In_ BOOL UseDefaultFallback); + VOID DeleteFonts(PGUI_CONSOLE_DATA GuiData);