ReactOS 0.4.15-dev-7924-g5949c20
font.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Console Server DLL
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Console GDI Fonts Management.
5 * COPYRIGHT: Copyright 2017-2022 Hermès Bélusca-Maïto
6 * Copyright 2017 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "precomp.h"
12#include <winuser.h>
13
14#include "settings.h"
15#include "font.h"
16// #include "concfg.h"
17
18#define NDEBUG
19#include <debug.h>
20
21#define DBGFNT DPRINT
22#define DBGFNT1 DPRINT1
23
24
25/* GLOBALS ********************************************************************/
26
27#define TERMINAL_FACENAME L"Terminal"
28#define DEFAULT_NON_DBCS_FONTFACE L"Lucida Console" // L"Consolas"
29#define DEFAULT_TT_FONT_FACENAME L"__DefaultTTFont__"
30
31/* TrueType font list cache */
33
34// NOTE: Used to tag code that makes sense only with a font cache.
35// #define FONT_CACHE_PRESENT
36
37
38/* FUNCTIONS ******************************************************************/
39
50BYTE
52 _In_ UINT CodePage)
53{
54 CHARSETINFO CharInfo;
55 if (TranslateCharsetInfo(UlongToPtr(CodePage), &CharInfo, TCI_SRCCODEPAGE))
56 return (BYTE)CharInfo.ciCharset;
57 else
58 return DEFAULT_CHARSET;
59}
60
61/*****************************************************************************/
62
64{
65 /* Search criteria */
67 FONT_DATA SearchFont;
68 UINT CodePage;
69 BOOL StrictSearch; // TRUE to do strict search; FALSE for relaxed criteria.
70
71 /* Candidate font data */
72 BOOL FontFound; // TRUE/FALSE if we have/haven't found a suitable font.
73 FONT_DATA CandidateFont;
74 WCHAR CandidateFaceName[LF_FACESIZE];
76
77#define TM_IS_TT_FONT(x) (((x) & TMPF_TRUETYPE) == TMPF_TRUETYPE)
78#define SIZE_EQUAL(s1, s2) (((s1).X == (s2).X) && ((s1).Y == (s2).Y))
79
89static BOOL CALLBACK
91 _In_ PLOGFONTW lplf,
93 _In_ DWORD FontType,
95{
97 PFONT_DATA SearchFont = &Param->SearchFont;
98
99 if (!IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage))
100 {
101 /* This font does not suit us; continue enumeration */
102 return TRUE;
103 }
104
105#ifndef FONT_CACHE_PRESENT
106 /*
107 * Since we don't cache all the possible font sizes for TrueType fonts,
108 * we cannot check our requested size (and weight) against the enumerated
109 * one; therefore reset the enumerated values to the requested ones.
110 * On the contrary, Raster fonts get their specific font sizes (and weights)
111 * enumerated separately, so for them we can keep the enumerated values.
112 */
113 if (FontType == TRUETYPE_FONTTYPE)
114 {
115 lplf->lfHeight = SearchFont->Size.Y;
116 lplf->lfWidth = 0; // SearchFont->Size.X;
117 lplf->lfWeight = FW_NORMAL;
118 }
119#endif
120
121 if (Param->StrictSearch)
122 {
123 /*
124 * Find whether this is an exact match.
125 */
126
127 /* If looking for a particular family, skip non-matches */
128 if ((SearchFont->Family != 0) &&
129 ((BYTE)SearchFont->Family != (lplf->lfPitchAndFamily & 0xF0)))
130 {
131 /* Continue enumeration */
132 return TRUE;
133 }
134
135 /* Skip non-matching sizes */
136#if 0
137 if ((FontInfo[i].SizeWant.Y != Size.Y) &&
138 !SIZE_EQUAL(FontInfo[i].Size, Size))
139#endif
140 if ((lplf->lfHeight != SearchFont->Size.Y) &&
141 !(lplf->lfWidth == SearchFont->Size.X &&
142 lplf->lfHeight == SearchFont->Size.Y))
143 {
144 /* Continue enumeration */
145 return TRUE;
146 }
147
148 /* Skip non-matching weights */
149 if ((SearchFont->Weight != 0) &&
150 (SearchFont->Weight != lplf->lfWeight))
151 {
152 /* Continue enumeration */
153 return TRUE;
154 }
155
156 /* NOTE: We are making the font enumeration at fixed CharSet,
157 * with the one specified in the parameter block. */
158 ASSERT(lplf->lfCharSet == SearchFont->CharSet);
159
160 if ((FontType != TRUETYPE_FONTTYPE) && // !TM_IS_TT_FONT(lpntm->tmPitchAndFamily)
161 (lplf->lfCharSet != SearchFont->CharSet) &&
162 !(lplf->lfCharSet == OEM_CHARSET && IsCJKCodePage(Param->CodePage))) // g_fEastAsianSystem
163 {
164 /* Continue enumeration */
165 return TRUE;
166 }
167
168 /*
169 * Size (and maybe family) match. If we don't care about the name or
170 * if it matches, use this font. Otherwise, if name doesn't match and
171 * it is a raster font, consider it.
172 *
173 * NOTE: The font face names are case-sensitive.
174 */
175 if (!SearchFont->FaceName || !*(SearchFont->FaceName) ||
176 (wcscmp(lplf->lfFaceName, SearchFont->FaceName) == 0) ||
177 (wcscmp(lplf->lfFaceName, Param->AltFaceName) == 0))
178 {
179 // FontIndex = i;
180
181 PFONT_DATA CandidateFont = &Param->CandidateFont;
182
183 CandidateFont->FaceName = Param->CandidateFaceName;
184 StringCchCopyNW(Param->CandidateFaceName,
185 ARRAYSIZE(Param->CandidateFaceName),
186 lplf->lfFaceName, ARRAYSIZE(lplf->lfFaceName));
187
188 CandidateFont->Weight = lplf->lfWeight;
189 CandidateFont->Family = (lplf->lfPitchAndFamily & 0xF0);
190
191 CandidateFont->Size.X = lplf->lfWidth;
192 CandidateFont->Size.Y = lplf->lfHeight;
193
194 CandidateFont->CharSet = lplf->lfCharSet;
195
196 /* The font is found, stop enumeration */
197 Param->FontFound = TRUE;
198 return FALSE;
199 }
200 else if (FontType != TRUETYPE_FONTTYPE) // !TM_IS_TT_FONT(lpntm->tmPitchAndFamily)
201 {
202 // FontIndex = i;
203
204 PFONT_DATA CandidateFont = &Param->CandidateFont;
205
206 CandidateFont->FaceName = Param->CandidateFaceName;
207 StringCchCopyNW(Param->CandidateFaceName,
208 ARRAYSIZE(Param->CandidateFaceName),
209 lplf->lfFaceName, ARRAYSIZE(lplf->lfFaceName));
210
211 CandidateFont->Weight = lplf->lfWeight;
212 CandidateFont->Family = (lplf->lfPitchAndFamily & 0xF0);
213
214 CandidateFont->Size.X = lplf->lfWidth;
215 CandidateFont->Size.Y = lplf->lfHeight;
216
217 CandidateFont->CharSet = lplf->lfCharSet;
218
219 /* A close Raster Font fit was found; only the name doesn't match.
220 * Continue enumeration to see whether we can find better. */
221 Param->FontFound = TRUE;
222 }
223 }
224 else // !Param->StrictSearch
225 {
226 /*
227 * Failed to find exact match, even after enumeration, so now
228 * try to find a font of same family and same size or bigger.
229 */
230
231 if (IsCJKCodePage(Param->CodePage)) // g_fEastAsianSystem
232 {
233 if ((SearchFont->Family != 0) &&
234 ((BYTE)SearchFont->Family != (lplf->lfPitchAndFamily & 0xF0)))
235 {
236 /* Continue enumeration */
237 return TRUE;
238 }
239
240 if ((FontType != TRUETYPE_FONTTYPE) && // !TM_IS_TT_FONT(lpntm->tmPitchAndFamily)
241 (lplf->lfCharSet != SearchFont->CharSet))
242 {
243 /* Continue enumeration */
244 return TRUE;
245 }
246 }
247 else
248 {
249 if (// (SearchFont->Family != 0) &&
250 ((BYTE)SearchFont->Family != (lplf->lfPitchAndFamily & 0xF0)))
251 {
252 /* Continue enumeration */
253 return TRUE;
254 }
255 }
256
257 if ((lplf->lfHeight >= SearchFont->Size.Y) &&
258 (lplf->lfWidth >= SearchFont->Size.X))
259 {
260 /* Same family, size >= desired */
261 // FontIndex = i;
262
263 PFONT_DATA CandidateFont = &Param->CandidateFont;
264
265 CandidateFont->FaceName = Param->CandidateFaceName;
266 StringCchCopyNW(Param->CandidateFaceName,
267 ARRAYSIZE(Param->CandidateFaceName),
268 lplf->lfFaceName, ARRAYSIZE(lplf->lfFaceName));
269
270 CandidateFont->Weight = lplf->lfWeight;
271 CandidateFont->Family = (lplf->lfPitchAndFamily & 0xF0);
272
273 CandidateFont->Size.X = lplf->lfWidth;
274 CandidateFont->Size.Y = lplf->lfHeight;
275
276 CandidateFont->CharSet = lplf->lfCharSet;
277
278 /* The font is found, stop enumeration */
279 Param->FontFound = TRUE;
280 return FALSE;
281 }
282 }
283
284 /* Continue enumeration */
285 return TRUE;
286}
287
306static BOOL
308 _Inout_ PFONT_DATA FontData,
309 _In_ UINT CodePage)
310{
313 HDC hDC;
314 LOGFONTW lf;
315 PTT_FONT_ENTRY FontEntry;
316
317 /* Save the original FaceName pointer */
318 FaceName = FontData->FaceName;
319
320 /* Save our current search criteria */
321 RtlZeroMemory(&Param, sizeof(Param));
322 Param.SearchFont = *FontData;
323
324 Param.SearchFont.CharSet = CodePageToCharSet(CodePage);
325 Param.CodePage = CodePage;
326
327 if (/* !FaceName || */ !*FaceName)
328 {
329 /* Find and use a default Raster font */
330
331 /* Use "Terminal" as the fallback */
333#if 0
334 // FIXME: CJK font choose workaround: Don't choose Asian
335 // charset font if there is no preferred font for CJK.
336 if (IsCJKCodePage(CodePage))
337 FontData->CharSet = ANSI_CHARSET;
338#endif
339 FontData->Family &= ~TMPF_TRUETYPE;
340 }
341 else if (wcscmp(FaceName, DEFAULT_TT_FONT_FACENAME) == 0)
342 {
343 /* Find and use a default TrueType font */
344 FontEntry = FindCachedTTFont(NULL, CodePage);
345 if (FontEntry)
346 {
347 StringCchCopyW(FaceName, LF_FACESIZE, FontEntry->FaceName);
348 }
349 else
350 {
352 }
353 FontData->Family |= TMPF_TRUETYPE;
354 }
355
356 /* Search for a TrueType alternative face name */
357 FontEntry = FindCachedTTFont(FaceName, CodePage);
358 if (FontEntry)
359 {
360 /* NOTE: The font face names are case-sensitive */
361 if (wcscmp(FontEntry->FaceName, FaceName) == 0)
362 Param.AltFaceName = FontEntry->FaceNameAlt;
363 else if (wcscmp(FontEntry->FaceNameAlt, FaceName) == 0)
364 Param.AltFaceName = FontEntry->FaceName;
365 }
366 else
367 {
368 Param.AltFaceName = FaceName;
369 }
370
371 /* Initialize the search: start with a strict search, then a relaxed one */
372 Param.FontFound = FALSE;
373
374 Param.StrictSearch = TRUE;
375SearchAgain:
376 /*
377 * Enumerate all fonts with the given character set.
378 * We will match them with the search criteria.
379 */
380 RtlZeroMemory(&lf, sizeof(lf));
381 lf.lfCharSet = Param.SearchFont.CharSet;
382 // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
383
384 hDC = GetDC(NULL);
387
388 /* If we failed to find any font, search again with relaxed criteria */
389 if (Param.StrictSearch && !Param.FontFound)
390 {
391 Param.StrictSearch = FALSE;
392 goto SearchAgain;
393 }
394
395 /* If no font was found again, return failure */
396 if (!Param.FontFound)
397 return FALSE;
398
399 /* Return the font details */
400 *FontData = Param.CandidateFont;
401 FontData->FaceName = FaceName; // Restore the original FaceName pointer.
403 Param.CandidateFaceName,
404 ARRAYSIZE(Param.CandidateFaceName));
405
406 return TRUE;
407}
408
423static HFONT
425 _In_ PFONT_DATA FontData,
426 _In_ UINT CodePage)
427{
428 LOGFONTW lf;
429
430 RtlZeroMemory(&lf, sizeof(lf));
431
432 lf.lfHeight = (LONG)(ULONG)FontData->Size.Y;
433 lf.lfWidth = (LONG)(ULONG)FontData->Size.X;
434
435 lf.lfEscapement = 0;
436 lf.lfOrientation = 0; // TA_BASELINE; // TA_RTLREADING; when the console supports RTL?
437 // lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = FALSE;
438 lf.lfWeight = FontData->Weight;
439 lf.lfCharSet = CodePageToCharSet(CodePage);
443
444 /* Set the mandatory flags and remove those that we do not support */
445 lf.lfPitchAndFamily = (BYTE)( (FIXED_PITCH | FF_MODERN | FontData->Family) &
447
448 if (!IsValidConsoleFont(FontData->FaceName, CodePage))
449 return NULL;
450
452 FontData->FaceName, LF_FACESIZE);
453
454 return CreateFontIndirectW(&lf);
455}
456
457/*****************************************************************************/
458
504HFONT
509 PWSTR FaceName,
510 _In_ ULONG FontWeight,
512 _In_ UINT CodePage,
513 _In_ BOOL UseDefaultFallback,
514 _Out_ PFONT_DATA FontData)
515{
516 HFONT hFont;
517
518 FontData->FaceName = FaceName;
519 FontData->Weight = FontWeight;
520 FontData->Family = FontFamily;
521 /* NOTE: FontSize is always in cell height/width units (pixels) */
522 FontData->Size.X = Width;
523 FontData->Size.Y = Height;
524 FontData->CharSet = 0; // CodePageToCharSet(CodePage);
525
526 if (/* !FaceName || */ !*FaceName || wcscmp(FaceName, DEFAULT_TT_FONT_FACENAME) == 0)
527 {
528 /* We do not have an actual font face name yet and should find one.
529 * Call FindSuitableFont() to determine the default font to use. */
530 }
531 else
532 {
533 hFont = CreateConsoleFontWorker(FontData, CodePage);
534 if (hFont)
535 return hFont;
536
537 DBGFNT1("CreateConsoleFont('%S') failed - Try to find a suitable font...\n",
538 FaceName);
539 }
540
541 /*
542 * We could not create a font with the default settings.
543 * Try to find a suitable font and retry.
544 */
545 if (!FindSuitableFont(FontData, CodePage))
546 {
547 /* We could not find any suitable font, fall back
548 * to some default one if required to do so. */
549 DBGFNT1("FindSuitableFont could not find anything - %s\n",
550 UseDefaultFallback ? "Falling back to 'Terminal'"
551 : "Bailing out");
552
553 /* No fallback: no font! */
554 if (!UseDefaultFallback)
555 return NULL;
556
557 //
558 // FIXME: See also !*FaceName case in FindSuitableFont().
559 //
560 /* Use "Terminal" as the fallback */
562#if 0
563 // FIXME: CJK font choose workaround: Don't choose Asian
564 // charset font if there is no preferred font for CJK.
565 if (IsCJKCodePage(CodePage))
566 FontData->CharSet = ANSI_CHARSET;
567#endif
568 FontData->Family &= ~TMPF_TRUETYPE;
569 }
570 else
571 {
572 DBGFNT1("FindSuitableFont found: '%S', size (%d x %d)\n",
573 FaceName, FontData->Size.X, FontData->Size.Y);
574 }
575
576 /* Retry creating the font */
577 hFont = CreateConsoleFontWorker(FontData, CodePage);
578 if (!hFont)
579 DBGFNT1("CreateConsoleFont('%S') failed\n", FaceName);
580
581 return hFont;
582}
583
608HFONT
613{
614 FONT_DATA FontData;
615 HFONT hFont;
616
618 Width,
619 ConsoleInfo->FaceName,
620 ConsoleInfo->FontWeight,
621 ConsoleInfo->FontFamily,
622 ConsoleInfo->CodePage,
623 TRUE, // UseDefaultFallback
624 &FontData);
625 if (hFont)
626 {
627 ConsoleInfo->FontWeight = FontData.Weight;
628 ConsoleInfo->FontFamily = FontData.Family;
629 }
630
631 return hFont;
632}
633
652HFONT
655{
656 /*
657 * Format:
658 * Width = FontSize.X = LOWORD(FontSize);
659 * Height = FontSize.Y = HIWORD(FontSize);
660 */
661 /* NOTE: FontSize is always in cell height/width units (pixels) */
662 return CreateConsoleFont2((LONG)(ULONG)ConsoleInfo->FontSize.Y,
663 (LONG)(ULONG)ConsoleInfo->FontSize.X,
665}
666
687BOOL
688GetFontCellSize(
693{
695 HDC hOrgDC = hDC;
696 HFONT hOldFont;
697 // LONG LogSize, PointSize;
700 // SIZE CharSize;
701
702 if (!hDC)
703 hDC = GetDC(NULL);
704
705 hOldFont = SelectObject(hDC, hFont);
706 if (hOldFont == NULL)
707 {
708 DBGFNT1("GetFontCellSize: SelectObject failed\n");
709 goto Quit;
710 }
711
712/*
713 * See also: Display_SetTypeFace in applications/fontview/display.c
714 */
715
716 /*
717 * Note that the method with GetObjectW just returns
718 * the original parameters with which the font was created.
719 */
720 if (!GetTextMetricsW(hDC, &tm))
721 {
722 DBGFNT1("GetFontCellSize: GetTextMetrics failed\n");
723 goto Cleanup;
724 }
725
726 CharHeight = tm.tmHeight + tm.tmExternalLeading;
727
728#if 0
729 /* Measure real char width more precisely if possible */
730 if (GetTextExtentPoint32W(hDC, L"R", 1, &CharSize))
731 CharWidth = CharSize.cx;
732#else
733 CharWidth = tm.tmAveCharWidth; // tm.tmMaxCharWidth;
734#endif
735
736#if 0
737 /*** Logical to Point size ***/
738 LogSize = tm.tmHeight - tm.tmInternalLeading;
739 PointSize = MulDiv(LogSize, 72, GetDeviceCaps(hDC, LOGPIXELSY));
740 /*****************************/
741#endif
742
744 *Width = (UINT)CharWidth;
745 Success = TRUE;
746
747Cleanup:
748 SelectObject(hDC, hOldFont);
749Quit:
750 if (!hOrgDC)
752
753 return Success;
754}
755
781BOOL
783 _In_ PLOGFONTW lplf,
784 _In_ PNEWTEXTMETRICW lpntm,
785 _In_ DWORD FontType,
786 _In_ UINT CodePage)
787{
788 LPCWSTR FaceName = lplf->lfFaceName;
789
790 /*
791 * According to: https://web.archive.org/web/20140901124501/http://support.microsoft.com/kb/247815
792 * "Necessary criteria for fonts to be available in a command window",
793 * the criteria for console-eligible fonts are as follows:
794 * - The font must be a fixed-pitch font.
795 * - The font cannot be an italic font.
796 * - The font cannot have a negative A or C space.
797 * - If it is a TrueType font, it must be FF_MODERN.
798 * - If it is not a TrueType font, it must be OEM_CHARSET.
799 *
800 * Non documented: vertical fonts are forbidden (their name start with a '@').
801 *
802 * Additional criteria for Asian installations:
803 * - If it is not a TrueType font, the face name must be "Terminal".
804 * - If it is an Asian TrueType font, it must also be an Asian character set.
805 *
806 * See also Raymond Chen's blog: https://devblogs.microsoft.com/oldnewthing/?p=26843
807 * and MIT-licensed Microsoft Terminal source code: https://github.com/microsoft/terminal/blob/main/src/propsheet/misc.cpp
808 * for other details.
809 *
810 * To install additional TrueType fonts to be available for the console,
811 * add entries of type REG_SZ named "0", "00" etc... in:
812 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont
813 * The names of the fonts listed there should match those in:
814 * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts
815 */
816
817 /*
818 * In ReactOS we relax some of the criteria:
819 * - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts
820 * that can be italic or have negative A or C space.
821 * - If it is not a TrueType font, it can be from another character set
822 * than OEM_CHARSET. When an Asian codepage is active however, we require
823 * that this non-TrueType font has an Asian character set.
824 */
825
826 /* Reject variable-width fonts ... */
827 if ( ( ((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH)
828#if 0 /* Reject italic and TrueType fonts with negative A or C space ... */
829 || (lplf->lfItalic)
830 || !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC)
831#endif
832 ) &&
833 /* ... if they are not in the list of additional TrueType fonts to include */
834 !IsAdditionalTTFont(FaceName) )
835 {
836 DBGFNT("Font '%S' rejected because it%s (lfPitchAndFamily = %d)\n",
837 FaceName,
838 !(lplf->lfPitchAndFamily & FIXED_PITCH) ? "'s not FIXED_PITCH"
839 : (!(lpntm->ntmFlags & NTM_NONNEGATIVE_AC) ? " has negative A or C space"
840 : " is broken"),
841 lplf->lfPitchAndFamily);
842 return FALSE;
843 }
844
845 /* Reject TrueType fonts that are not FF_MODERN */
846 if ((FontType == TRUETYPE_FONTTYPE) && ((lplf->lfPitchAndFamily & 0xF0) != FF_MODERN))
847 {
848 DBGFNT("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n",
849 FaceName, lplf->lfPitchAndFamily);
850 return FALSE;
851 }
852
853 /* Reject vertical fonts (tategaki) */
854 if (FaceName[0] == L'@')
855 {
856 DBGFNT("Font '%S' rejected because it's vertical\n", FaceName);
857 return FALSE;
858 }
859
860 /* Is the current code page Chinese, Japanese or Korean? */
861 if (IsCJKCodePage(CodePage))
862 {
863 /* It's CJK */
864
865 if (FontType == TRUETYPE_FONTTYPE)
866 {
867 /*
868 * Here we are inclusive and check for any CJK character set,
869 * instead of looking just at the current one via CodePageToCharSet().
870 */
871 if (!IsCJKCharSet(lplf->lfCharSet))
872 {
873 DBGFNT("TrueType font '%S' rejected because it's not Asian charset (lfCharSet = %d)\n",
874 FaceName, lplf->lfCharSet);
875 return FALSE;
876 }
877
878 /*
879 * If this is a cached TrueType font that is used only for certain
880 * code pages, verify that the charset it claims is the correct one.
881 *
882 * Since there may be multiple entries for a cached TrueType font,
883 * a general one (code page == 0) and one or more for explicit
884 * code pages, we need to perform two search queries instead of
885 * just one and retrieving the code page for this entry.
886 */
887 if (IsAdditionalTTFont(FaceName) && !IsAdditionalTTFontCP(FaceName, 0) &&
888 !IsCJKCharSet(lplf->lfCharSet))
889 {
890 DBGFNT("Cached TrueType font '%S' rejected because it claims a code page that is not Asian charset (lfCharSet = %d)\n",
891 FaceName, lplf->lfCharSet);
892 return FALSE;
893 }
894 }
895 else
896 {
897 /* Reject non-TrueType fonts that do not have an Asian character set */
898 if (!IsCJKCharSet(lplf->lfCharSet) && (lplf->lfCharSet != OEM_CHARSET))
899 {
900 DBGFNT("Non-TrueType font '%S' rejected because it's not Asian charset or OEM_CHARSET (lfCharSet = %d)\n",
901 FaceName, lplf->lfCharSet);
902 return FALSE;
903 }
904
905 /* Reject non-TrueType fonts that are not Terminal */
906 if (wcscmp(FaceName, TERMINAL_FACENAME) != 0)
907 {
908 DBGFNT("Non-TrueType font '%S' rejected because it's not 'Terminal'\n", FaceName);
909 return FALSE;
910 }
911 }
912 }
913 else
914 {
915 /* Not CJK */
916
917 /* Reject non-TrueType fonts that are not OEM or similar */
918 if ((FontType != TRUETYPE_FONTTYPE) &&
919 (lplf->lfCharSet != ANSI_CHARSET) &&
920 (lplf->lfCharSet != DEFAULT_CHARSET) &&
921 (lplf->lfCharSet != OEM_CHARSET))
922 {
923 DBGFNT("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n",
924 FaceName, lplf->lfCharSet);
925 return FALSE;
926 }
927 }
928
929 /* All good */
930 return TRUE;
931}
932
934{
938
942static BOOL CALLBACK
944 _In_ PLOGFONTW lplf,
945 _In_ PNEWTEXTMETRICW lpntm,
946 _In_ DWORD FontType,
948{
950 Param->IsValidFont = IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage);
951
952 /* Stop the enumeration now */
953 return FALSE;
954}
955
973BOOL
975 // _In_reads_or_z_(LF_FACESIZE)
976 _In_ PCWSTR FaceName,
977 _In_ UINT CodePage)
978{
980 HDC hDC;
981 LOGFONTW lf;
982
983 Param.IsValidFont = FALSE;
984 Param.CodePage = CodePage;
985
986 RtlZeroMemory(&lf, sizeof(lf));
987 lf.lfCharSet = CodePageToCharSet(CodePage);
988 // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
990
991 hDC = GetDC(NULL);
994
995 return Param.IsValidFont;
996}
997
998
1012VOID
1014{
1015 LRESULT lResult;
1016 HKEY hKey;
1017 DWORD dwIndex, dwType;
1018 WCHAR szValueName[MAX_PATH];
1019 DWORD cchValueName;
1020 WCHAR szValue[LF_FACESIZE] = L"";
1021 DWORD cbValue;
1022 UINT CodePage;
1023 PTT_FONT_ENTRY FontEntry;
1024 PWCHAR pszNext;
1025
1026 if (TTFontCache.Next != NULL)
1027 return;
1028 // TTFontCache.Next = NULL;
1029
1030 /* Open the Console\TrueTypeFont key */
1031 // "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont"
1033 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont",
1034 0,
1036 &hKey) != ERROR_SUCCESS)
1037 {
1038 return;
1039 }
1040
1041 /* Enumerate all the available TrueType console fonts */
1042 for (dwIndex = 0, cchValueName = ARRAYSIZE(szValueName),
1043 cbValue = sizeof(szValue);
1044 (lResult = RegEnumValueW(hKey, dwIndex,
1045 szValueName, &cchValueName,
1046 NULL, &dwType,
1047 (PBYTE)szValue, &cbValue)) != ERROR_NO_MORE_ITEMS;
1048 ++dwIndex, cchValueName = ARRAYSIZE(szValueName),
1049 cbValue = sizeof(szValue))
1050 {
1051 /* Ignore if we failed for another reason, e.g. because
1052 * the value name is too long (and thus, invalid). */
1053 if (lResult != ERROR_SUCCESS)
1054 continue;
1055
1056 /* Validate the value name (exclude the unnamed value) */
1057 if (!cchValueName || (*szValueName == UNICODE_NULL))
1058 continue;
1059 /* Too large value names have already been handled with ERROR_MORE_DATA */
1060 ASSERT((cchValueName < ARRAYSIZE(szValueName)) &&
1061 (szValueName[cchValueName] == UNICODE_NULL));
1062
1063 /* Only (multi-)string values are supported */
1064 if ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))
1065 continue;
1066
1067 /* The value name is a code page (in decimal), validate it */
1068 CodePage = wcstoul(szValueName, &pszNext, 10);
1069 if (*pszNext)
1070 continue; // Non-numerical garbage followed...
1071 // IsValidCodePage(CodePage);
1072
1073 FontEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*FontEntry));
1074 if (!FontEntry)
1075 {
1076 DBGFNT1("InitTTFontCache: Failed to allocate memory, continuing...\n");
1077 continue;
1078 }
1079
1080 FontEntry->CodePage = CodePage;
1081
1082 pszNext = szValue;
1083
1084 /* Check whether bold is disabled for this font */
1085 if (*pszNext == BOLD_MARK)
1086 {
1087 FontEntry->DisableBold = TRUE;
1088 ++pszNext;
1089 }
1090 else
1091 {
1092 FontEntry->DisableBold = FALSE;
1093 }
1094
1095 /* Copy the font name */
1096 StringCchCopyNW(FontEntry->FaceName, ARRAYSIZE(FontEntry->FaceName),
1097 pszNext, wcslen(pszNext));
1098
1099 if (dwType == REG_MULTI_SZ)
1100 {
1101 /* There may be an alternate face name as the second string */
1102 pszNext += wcslen(pszNext) + 1;
1103
1104 /* Check whether bold is disabled for this font */
1105 if (*pszNext == BOLD_MARK)
1106 {
1107 FontEntry->DisableBold = TRUE;
1108 ++pszNext;
1109 }
1110 // else, keep the original setting.
1111
1112 /* Copy the alternate font name */
1113 StringCchCopyNW(FontEntry->FaceNameAlt, ARRAYSIZE(FontEntry->FaceNameAlt),
1114 pszNext, wcslen(pszNext));
1115 }
1116
1117 PushEntryList(&TTFontCache, &FontEntry->Entry);
1118 }
1119
1120 /* Close the key and quit */
1122}
1123
1130VOID
1132{
1134 PTT_FONT_ENTRY FontEntry;
1135
1136 while (TTFontCache.Next != NULL)
1137 {
1140 RtlFreeHeap(RtlGetProcessHeap(), 0, FontEntry);
1141 }
1143}
1144
1152VOID
1154{
1157}
1158
1185 PCWSTR FaceName,
1186 _In_ UINT CodePage)
1187{
1189 PTT_FONT_ENTRY FontEntry;
1190
1191 if (FaceName)
1192 {
1193 /* Search for the named font */
1194 for (Entry = TTFontCache.Next;
1195 Entry != NULL;
1196 Entry = Entry->Next)
1197 {
1199
1200 /* NOTE: The font face names are case-sensitive */
1201 if ((wcscmp(FontEntry->FaceName , FaceName) == 0) ||
1202 (wcscmp(FontEntry->FaceNameAlt, FaceName) == 0))
1203 {
1204 /* Return the font if we don't search by code page, or when they match */
1205 if ((CodePage == INVALID_CP) || (CodePage == FontEntry->CodePage))
1206 {
1207 return FontEntry;
1208 }
1209 }
1210 }
1211 }
1212 else if (CodePage != INVALID_CP)
1213 {
1214 /* Search for a font with the specified code page */
1215 for (Entry = TTFontCache.Next;
1216 Entry != NULL;
1217 Entry = Entry->Next)
1218 {
1220
1221 /* Return the font if the code pages match */
1222 if (CodePage == FontEntry->CodePage)
1223 return FontEntry;
1224 }
1225 }
1226
1227 return NULL;
1228}
1229
1230/* EOF */
static HDC hDC
Definition: 3dtext.c:33
HFONT hFont
Definition: main.c:53
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
#define RegCloseKey(hKey)
Definition: registry.h:49
static int CharWidth
Definition: carets.c:7
static int CharHeight
Definition: carets.c:8
#define IsCJKCharSet(CharSet)
Definition: cjkcode.h:44
#define IsCJKCodePage(CodePage)
Definition: cjkcode.h:27
LPARAM lParam
Definition: combotst.c:139
#define ERROR_SUCCESS
Definition: deptool.c:10
#define LF_FACESIZE
Definition: dimm.idl:39
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
LONG WINAPI RegEnumValueW(_In_ HKEY hKey, _In_ DWORD index, _Out_ LPWSTR value, _Inout_ PDWORD val_count, _Reserved_ PDWORD reserved, _Out_opt_ PDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ PDWORD count)
Definition: reg.c:2830
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:105
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
static const WCHAR Cleanup[]
Definition: register.c:80
#define UlongToPtr(u)
Definition: config.h:106
@ Success
Definition: eventcreate.c:712
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FxAutoRegKey hKey
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_Check_return_ unsigned long __cdecl wcstoul(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define REG_SZ
Definition: layer.c:22
#define ASSERT(a)
Definition: mode.c:44
static HDC
Definition: imagelist.c:92
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
#define _In_reads_or_z_(size)
Definition: ms_sal.h:325
#define _Success_(expr)
Definition: ms_sal.h:259
#define _Inout_
Definition: ms_sal.h:378
#define _In_reads_or_z_opt_(size)
Definition: ms_sal.h:326
#define _Inout_updates_z_(size)
Definition: ms_sal.h:389
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
INT WINAPI MulDiv(INT nNumber, INT nNumerator, INT nDenominator)
Definition: muldiv.c:25
unsigned int * PUINT
Definition: ndis.h:50
unsigned int UINT
Definition: ndis.h:50
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define REG_MULTI_SZ
Definition: nt_native.h:1501
#define UNICODE_NULL
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
long LONG
Definition: pedump.c:60
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define INVALID_CP
Definition: stream.h:53
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
STRSAFEAPI StringCchCopyNW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc, size_t cchToCopy)
Definition: strsafe.h:236
base of all file and directory entries
Definition: entries.h:83
BYTE lfOutPrecision
Definition: dimm.idl:68
LONG lfHeight
Definition: dimm.idl:59
LONG lfWeight
Definition: dimm.idl:63
WCHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:72
LONG lfOrientation
Definition: dimm.idl:62
LONG lfWidth
Definition: dimm.idl:60
BYTE lfClipPrecision
Definition: dimm.idl:69
LONG lfEscapement
Definition: dimm.idl:61
BYTE lfCharSet
Definition: dimm.idl:67
BYTE lfQuality
Definition: dimm.idl:70
BYTE lfPitchAndFamily
Definition: dimm.idl:71
ULONG Y
Definition: bl.h:1340
ULONG X
Definition: bl.h:1339
BYTE CharSet
Definition: font.h:58
COORD Size
Definition: font.h:57
ULONG Family
Definition: font.h:56
ULONG Weight
Definition: font.h:55
Definition: ntbasedef.h:628
struct _SINGLE_LIST_ENTRY * Next
Definition: ntbasedef.h:629
Definition: font.h:36
WCHAR FaceName[LF_FACESIZE]
Definition: font.h:40
BOOL DisableBold
Definition: font.h:39
UINT CodePage
Definition: font.h:38
SINGLE_LIST_ENTRY Entry
Definition: font.h:37
WCHAR FaceNameAlt[LF_FACESIZE]
Definition: font.h:41
UINT ciCharset
Definition: wingdi.h:1546
Definition: time.h:68
static CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
Definition: video.c:47
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define IsAdditionalTTFontCP(FaceName, CodePage)
Definition: font.h:134
_In_ HFONT _Out_ PUINT _Out_ PUINT Width
Definition: font.h:89
_In_ HFONT _Out_ PUINT Height
Definition: font.h:88
#define IsAdditionalTTFont(FaceName)
Verifies whether the given font is an additional console TrueType font. Wrapper macros around FindCac...
Definition: font.h:131
#define BOLD_MARK
Definition: font.h:33
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
PTT_FONT_ENTRY FindCachedTTFont(_In_reads_or_z_opt_(LF_FACESIZE) PCWSTR FaceName, _In_ UINT CodePage)
Searches for a font in the console TrueType font cache, with the specified code page.
Definition: font.c:1183
#define SIZE_EQUAL(s1, s2)
Definition: font.c:78
HFONT CreateConsoleFont(_Inout_ PCONSOLE_STATE_INFO ConsoleInfo)
A wrapper for CreateConsoleFontEx().
Definition: font.c:653
VOID InitTTFontCache(VOID)
Initializes the console TrueType font cache.
Definition: font.c:1013
BOOL IsValidConsoleFont2(_In_ PLOGFONTW lplf, _In_ PNEWTEXTMETRICW lpntm, _In_ DWORD FontType, _In_ UINT CodePage)
Validates whether a given font can be supported in the console, under the specified code page.
Definition: font.c:782
static BOOL CALLBACK IsValidConsoleFontProc(_In_ PLOGFONTW lplf, _In_ PNEWTEXTMETRICW lpntm, _In_ DWORD FontType, _In_ LPARAM lParam)
EnumFontFamiliesEx() callback helper for IsValidConsoleFont().
Definition: font.c:943
struct _FIND_SUITABLE_FONT_PROC_PARAM FIND_SUITABLE_FONT_PROC_PARAM
#define DBGFNT
Definition: font.c:21
#define TERMINAL_FACENAME
Definition: font.c:27
SINGLE_LIST_ENTRY TTFontCache
Definition: font.c:32
struct _IS_VALID_CONSOLE_FONT_PARAM IS_VALID_CONSOLE_FONT_PARAM
struct _FIND_SUITABLE_FONT_PROC_PARAM * PFIND_SUITABLE_FONT_PROC_PARAM
#define DEFAULT_NON_DBCS_FONTFACE
Definition: font.c:28
#define DBGFNT1
Definition: font.c:22
static HFONT CreateConsoleFontWorker(_In_ PFONT_DATA FontData, _In_ UINT CodePage)
Validates and creates a suitable console font based on the font characteristics given in input.
Definition: font.c:424
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)
Validates and creates a suitable console font based on the font characteristics given in input.
Definition: font.c:505
BOOL IsValidConsoleFont(_In_ PCWSTR FaceName, _In_ UINT CodePage)
Validates whether a given font can be supported in the console, under the specified code page.
Definition: font.c:974
HFONT CreateConsoleFont2(_In_ LONG Height, _In_opt_ LONG Width, _Inout_ PCONSOLE_STATE_INFO ConsoleInfo)
A wrapper for CreateConsoleFontEx().
Definition: font.c:609
#define DEFAULT_TT_FONT_FACENAME
Definition: font.c:29
static BOOL FindSuitableFont(_Inout_ PFONT_DATA FontData, _In_ UINT CodePage)
Finds a font suitable for the given code page, based on the current font and its characteristics prov...
Definition: font.c:307
BYTE CodePageToCharSet(_In_ UINT CodePage)
Retrieves the character set associated with a given code page.
Definition: font.c:51
VOID ClearTTFontCache(VOID)
Clears the console TrueType font cache.
Definition: font.c:1131
struct _IS_VALID_CONSOLE_FONT_PARAM * PIS_VALID_CONSOLE_FONT_PARAM
VOID RefreshTTFontCache(VOID)
Refreshes the console TrueType font cache, by clearing and re-initializing it.
Definition: font.c:1153
static BOOL CALLBACK FindSuitableFontProc(_In_ PLOGFONTW lplf, _In_ PNEWTEXTMETRICW lpntm, _In_ DWORD FontType, _In_ LPARAM lParam)
EnumFontFamiliesEx() callback helper for FindSuitableFont().
Definition: font.c:90
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
#define FIXED_PITCH
Definition: wingdi.h:444
#define VARIABLE_PITCH
Definition: wingdi.h:445
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
#define FF_MODERN
Definition: wingdi.h:449
#define FF_DECORATIVE
Definition: wingdi.h:447
int WINAPI GetDeviceCaps(_In_opt_ HDC, _In_ int)
#define FF_SCRIPT
Definition: wingdi.h:451
#define FF_ROMAN
Definition: wingdi.h:450
int WINAPI EnumFontFamiliesExW(_In_ HDC, _In_ PLOGFONTW, _In_ FONTENUMPROCW, _In_ LPARAM, _In_ DWORD)
#define DEFAULT_QUALITY
Definition: wingdi.h:436
#define TRUETYPE_FONTTYPE
Definition: wingdi.h:1109
#define LOGPIXELSY
Definition: wingdi.h:719
FARPROC FONTENUMPROCW
Definition: wingdi.h:2897
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1539
#define DEFAULT_CHARSET
Definition: wingdi.h:384
#define TMPF_TRUETYPE
Definition: wingdi.h:1313
#define OUT_DEFAULT_PRECIS
Definition: wingdi.h:415
#define ANSI_CHARSET
Definition: wingdi.h:383
#define CLIP_DEFAULT_PRECIS
Definition: wingdi.h:426
#define OEM_CHARSET
Definition: wingdi.h:400
#define FW_NORMAL
Definition: wingdi.h:373
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)
BOOL WINAPI TranslateCharsetInfo(_Inout_ PDWORD, _Out_ LPCHARSETINFO, _In_ DWORD)
#define FF_SWISS
Definition: wingdi.h:452
BOOL WINAPI GetTextExtentPoint32W(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define NTM_NONNEGATIVE_AC
Definition: wingdi.h:25
#define TCI_SRCCODEPAGE
Definition: wingdi.h:962
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
HDC WINAPI GetDC(_In_opt_ HWND)
FORCEINLINE VOID PushEntryList(_Inout_ PSINGLE_LIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PSINGLE_LIST_ENTRY Entry)
Definition: rtlfuncs.h:253
FORCEINLINE PSINGLE_LIST_ENTRY PopEntryList(_Inout_ PSINGLE_LIST_ENTRY ListHead)
Definition: rtlfuncs.h:240
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
unsigned char BYTE
Definition: xxhash.c:193