xref: /reactos/win32ss/user/winsrv/concfg/font.c (revision f4d29a74)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/concfg/font.c
5  * PURPOSE:         Console Fonts Management
6  * PROGRAMMERS:     Hermes Belusca-Maito (hermes.belusca@sfr.fr)
7  *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include "precomp.h"
13 #include <winuser.h>
14 
15 #include "settings.h"
16 #include "font.h"
17 // #include "concfg.h"
18 
19 #define NDEBUG
20 #include <debug.h>
21 
22 
23 /* FUNCTIONS ******************************************************************/
24 
25 /* Retrieves the character set associated with a given code page */
26 BYTE
27 CodePageToCharSet(
28     IN UINT CodePage)
29 {
30     CHARSETINFO CharInfo;
31     if (TranslateCharsetInfo(UlongToPtr(CodePage), &CharInfo, TCI_SRCCODEPAGE))
32         return CharInfo.ciCharset;
33     else
34         return DEFAULT_CHARSET;
35 }
36 
37 HFONT
38 CreateConsoleFontEx(
39     IN LONG Height,
40     IN LONG Width OPTIONAL,
41     IN OUT LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements
42     IN ULONG FontFamily,
43     IN ULONG FontWeight,
44     IN UINT  CodePage)
45 {
46     LOGFONTW lf;
47 
48     RtlZeroMemory(&lf, sizeof(lf));
49 
50     lf.lfHeight = Height;
51     lf.lfWidth  = Width;
52 
53     lf.lfEscapement  = 0;
54     lf.lfOrientation = 0; // TA_BASELINE; // TA_RTLREADING; when the console supports RTL?
55     // lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = FALSE;
56     lf.lfWeight  = FontWeight;
57     lf.lfCharSet = CodePageToCharSet(CodePage);
58     lf.lfOutPrecision  = OUT_DEFAULT_PRECIS;
59     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
60     lf.lfQuality = DEFAULT_QUALITY;
61     lf.lfPitchAndFamily = (BYTE)(FIXED_PITCH | FontFamily);
62 
63     if (!IsValidConsoleFont(FaceName, CodePage))
64         StringCchCopyW(FaceName, LF_FACESIZE, L"Terminal");
65 
66     StringCchCopyNW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName),
67                     FaceName, LF_FACESIZE);
68 
69     return CreateFontIndirectW(&lf);
70 }
71 
72 HFONT
73 CreateConsoleFont2(
74     IN LONG Height,
75     IN LONG Width OPTIONAL,
76     IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
77 {
78     return CreateConsoleFontEx(Height,
79                                Width,
80                                ConsoleInfo->FaceName,
81                                ConsoleInfo->FontFamily,
82                                ConsoleInfo->FontWeight,
83                                ConsoleInfo->CodePage);
84 }
85 
86 HFONT
87 CreateConsoleFont(
88     IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
89 {
90     /*
91      * Format:
92      * Width  = FontSize.X = LOWORD(FontSize);
93      * Height = FontSize.Y = HIWORD(FontSize);
94      */
95     /* NOTE: FontSize is always in cell height/width units (pixels) */
96     return CreateConsoleFontEx((LONG)(ULONG)ConsoleInfo->FontSize.Y,
97                                (LONG)(ULONG)ConsoleInfo->FontSize.X,
98                                ConsoleInfo->FaceName,
99                                ConsoleInfo->FontFamily,
100                                ConsoleInfo->FontWeight,
101                                ConsoleInfo->CodePage);
102 }
103 
104 BOOL
105 GetFontCellSize(
106     IN HDC hDC OPTIONAL,
107     IN HFONT hFont,
108     OUT PUINT Height,
109     OUT PUINT Width)
110 {
111     BOOL Success = FALSE;
112     HDC hOrgDC = hDC;
113     HFONT hOldFont;
114     // LONG LogSize, PointSize;
115     LONG CharWidth, CharHeight;
116     TEXTMETRICW tm;
117     // SIZE CharSize;
118 
119     if (!hDC)
120         hDC = GetDC(NULL);
121 
122     hOldFont = SelectObject(hDC, hFont);
123     if (hOldFont == NULL)
124     {
125         DPRINT1("GetFontCellSize: SelectObject failed\n");
126         goto Quit;
127     }
128 
129 /*
130  * See also: Display_SetTypeFace in applications/fontview/display.c
131  */
132 
133     /*
134      * Note that the method with GetObjectW just returns
135      * the original parameters with which the font was created.
136      */
137     if (!GetTextMetricsW(hDC, &tm))
138     {
139         DPRINT1("GetFontCellSize: GetTextMetrics failed\n");
140         goto Cleanup;
141     }
142 
143     CharHeight = tm.tmHeight + tm.tmExternalLeading;
144 
145 #if 0
146     /* Measure real char width more precisely if possible */
147     if (GetTextExtentPoint32W(hDC, L"R", 1, &CharSize))
148         CharWidth = CharSize.cx;
149 #else
150     CharWidth = tm.tmAveCharWidth; // tm.tmMaxCharWidth;
151 #endif
152 
153 #if 0
154     /*** Logical to Point size ***/
155     LogSize   = tm.tmHeight - tm.tmInternalLeading;
156     PointSize = MulDiv(LogSize, 72, GetDeviceCaps(hDC, LOGPIXELSY));
157     /*****************************/
158 #endif
159 
160     *Height = (UINT)CharHeight;
161     *Width  = (UINT)CharWidth;
162     Success = TRUE;
163 
164 Cleanup:
165     SelectObject(hDC, hOldFont);
166 Quit:
167     if (!hOrgDC)
168         ReleaseDC(NULL, hDC);
169 
170     return Success;
171 }
172 
173 BOOL
174 IsValidConsoleFont2(
175     IN PLOGFONTW lplf,
176     IN PNEWTEXTMETRICW lpntm,
177     IN DWORD FontType,
178     IN UINT CodePage)
179 {
180     LPCWSTR FaceName = lplf->lfFaceName;
181 
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     /*
187      * According to: http://support.microsoft.com/kb/247815
188      * the criteria for console-eligible fonts are:
189      * - The font must be a fixed-pitch font.
190      * - The font cannot be an italic font.
191      * - The font cannot have a negative A or C space.
192      * - If it is a TrueType font, it must be FF_MODERN.
193      * - If it is not a TrueType font, it must be OEM_CHARSET.
194      *
195      * Non documented: vertical fonts are forbidden (their name start with a '@').
196      *
197      * Additional criteria for Asian installations:
198      * - If it is not a TrueType font, the face name must be "Terminal".
199      * - If it is an Asian TrueType font, it must also be an Asian character set.
200      *
201      * To install additional TrueType fonts to be available for the console,
202      * add entries of type REG_SZ named "0", "00" etc... in:
203      * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont
204      * The names of the fonts listed there should match those in:
205      * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts
206      */
207 
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       */
216 
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)
222 #endif
223         )
224     {
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"),
229                 lplf->lfPitchAndFamily);
230         return FALSE;
231     }
232 
233     /* Reject TrueType fonts that are not FF_MODERN */
234     if ((FontType == TRUETYPE_FONTTYPE) && ((lplf->lfPitchAndFamily & 0xF0) != FF_MODERN))
235     {
236         DPRINT1("TrueType font '%S' rejected because it's not FF_MODERN (lfPitchAndFamily = %d)\n",
237                 FaceName, lplf->lfPitchAndFamily);
238         return FALSE;
239     }
240 
241     /* Is the current code page Chinese, Japanese or Korean? */
242     if (IsCJKCodePage(CodePage))
243     {
244         /* It's Asian */
245         if (FontType == TRUETYPE_FONTTYPE)
246         {
247             if (lplf->lfCharSet != CodePageToCharSet(CodePage))
248             {
249                 DPRINT1("TrueType font '%S' rejected because it's not user Asian charset (lfCharSet = %d)\n",
250                         FaceName, lplf->lfCharSet);
251                 return FALSE;
252             }
253         }
254         else
255         {
256             /* Reject non-TrueType fonts that are not Terminal */
257             if (wcscmp(FaceName, L"Terminal") != 0)
258             {
259                 DPRINT1("Non-TrueType font '%S' rejected because it's not Terminal\n", FaceName);
260                 return FALSE;
261             }
262         }
263     }
264     else
265     {
266         /* Not CJK */
267         if ((FontType != TRUETYPE_FONTTYPE) &&
268             (lplf->lfCharSet != ANSI_CHARSET) &&
269             (lplf->lfCharSet != DEFAULT_CHARSET) &&
270             (lplf->lfCharSet != OEM_CHARSET))
271         {
272             DPRINT1("Non-TrueType font '%S' rejected because it's not ANSI_CHARSET or DEFAULT_CHARSET or OEM_CHARSET (lfCharSet = %d)\n",
273                     FaceName, lplf->lfCharSet);
274             return FALSE;
275         }
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     }
284 
285     /* All good */
286     return TRUE;
287 }
288 
289 typedef struct _IS_VALID_CONSOLE_FONT_PARAM
290 {
291     BOOL IsValidFont;
292     UINT CodePage;
293 } IS_VALID_CONSOLE_FONT_PARAM, *PIS_VALID_CONSOLE_FONT_PARAM;
294 
295 static BOOL CALLBACK
296 IsValidConsoleFontProc(
297     IN PLOGFONTW lplf,
298     IN PNEWTEXTMETRICW lpntm,
299     IN DWORD  FontType,
300     IN LPARAM lParam)
301 {
302     PIS_VALID_CONSOLE_FONT_PARAM Param = (PIS_VALID_CONSOLE_FONT_PARAM)lParam;
303     Param->IsValidFont = IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage);
304 
305     /* Stop the enumeration now */
306     return FALSE;
307 }
308 
309 BOOL
310 IsValidConsoleFont(
311     IN LPCWSTR FaceName,
312     IN UINT CodePage)
313 {
314     IS_VALID_CONSOLE_FONT_PARAM Param;
315     HDC hDC;
316     LOGFONTW lf;
317 
318     Param.IsValidFont = FALSE;
319     Param.CodePage = CodePage;
320 
321     RtlZeroMemory(&lf, sizeof(lf));
322     lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(CodePage);
323     // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
324     StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), FaceName);
325 
326     hDC = GetDC(NULL);
327     EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)IsValidConsoleFontProc, (LPARAM)&Param, 0);
328     ReleaseDC(NULL, hDC);
329 
330     return Param.IsValidFont;
331 }
332 
333 /* EOF */
334