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