mirror of
https://github.com/reactos/reactos.git
synced 2025-01-07 14:51:00 +00:00
333 lines
9.9 KiB
C
333 lines
9.9 KiB
C
/*
|
|
* 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)
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include <winuser.h>
|
|
|
|
#include "settings.h"
|
|
#include "font.h"
|
|
// #include "concfg.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
/* Retrieves the character set associated with a given code page */
|
|
BYTE
|
|
CodePageToCharSet(
|
|
IN UINT CodePage)
|
|
{
|
|
CHARSETINFO CharInfo;
|
|
if (TranslateCharsetInfo((LPDWORD)CodePage, &CharInfo, TCI_SRCCODEPAGE))
|
|
return CharInfo.ciCharset;
|
|
else
|
|
return DEFAULT_CHARSET;
|
|
}
|
|
|
|
HFONT
|
|
CreateConsoleFontEx(
|
|
IN LONG Height,
|
|
IN LONG Width OPTIONAL,
|
|
IN OUT LPWSTR FaceName, // Points to a WCHAR array of LF_FACESIZE elements
|
|
IN ULONG FontFamily,
|
|
IN ULONG FontWeight,
|
|
IN UINT CodePage)
|
|
{
|
|
LOGFONTW lf;
|
|
|
|
RtlZeroMemory(&lf, sizeof(lf));
|
|
|
|
lf.lfHeight = Height;
|
|
lf.lfWidth = Width;
|
|
|
|
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.lfCharSet = CodePageToCharSet(CodePage);
|
|
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
lf.lfQuality = DEFAULT_QUALITY;
|
|
lf.lfPitchAndFamily = (BYTE)(FIXED_PITCH | FontFamily);
|
|
|
|
if (!IsValidConsoleFont(FaceName, CodePage))
|
|
StringCchCopyW(FaceName, LF_FACESIZE, L"Terminal");
|
|
|
|
StringCchCopyNW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName),
|
|
FaceName, LF_FACESIZE);
|
|
|
|
return CreateFontIndirectW(&lf);
|
|
}
|
|
|
|
HFONT
|
|
CreateConsoleFont2(
|
|
IN LONG Height,
|
|
IN LONG Width OPTIONAL,
|
|
IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
|
|
{
|
|
return CreateConsoleFontEx(Height,
|
|
Width,
|
|
ConsoleInfo->FaceName,
|
|
ConsoleInfo->FontFamily,
|
|
ConsoleInfo->FontWeight,
|
|
ConsoleInfo->CodePage);
|
|
}
|
|
|
|
HFONT
|
|
CreateConsoleFont(
|
|
IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
|
|
{
|
|
/*
|
|
* Format:
|
|
* Width = FontSize.X = LOWORD(FontSize);
|
|
* 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);
|
|
}
|
|
|
|
BOOL
|
|
GetFontCellSize(
|
|
IN HDC hDC OPTIONAL,
|
|
IN HFONT hFont,
|
|
OUT PUINT Height,
|
|
OUT PUINT Width)
|
|
{
|
|
BOOL Success = FALSE;
|
|
HDC hOrgDC = hDC;
|
|
HFONT hOldFont;
|
|
// LONG LogSize, PointSize;
|
|
LONG CharWidth, CharHeight;
|
|
TEXTMETRICW tm;
|
|
// SIZE CharSize;
|
|
|
|
if (!hDC)
|
|
hDC = GetDC(NULL);
|
|
|
|
hOldFont = SelectObject(hDC, hFont);
|
|
if (hOldFont == NULL)
|
|
{
|
|
DPRINT1("GetFontCellSize: SelectObject failed\n");
|
|
goto Quit;
|
|
}
|
|
|
|
/*
|
|
* See also: Display_SetTypeFace in applications/fontview/display.c
|
|
*/
|
|
|
|
/*
|
|
* Note that the method with GetObjectW just returns
|
|
* the original parameters with which the font was created.
|
|
*/
|
|
if (!GetTextMetricsW(hDC, &tm))
|
|
{
|
|
DPRINT1("GetFontCellSize: GetTextMetrics failed\n");
|
|
goto Cleanup;
|
|
}
|
|
|
|
CharHeight = tm.tmHeight + tm.tmExternalLeading;
|
|
|
|
#if 0
|
|
/* Measure real char width more precisely if possible */
|
|
if (GetTextExtentPoint32W(hDC, L"R", 1, &CharSize))
|
|
CharWidth = CharSize.cx;
|
|
#else
|
|
CharWidth = tm.tmAveCharWidth; // tm.tmMaxCharWidth;
|
|
#endif
|
|
|
|
#if 0
|
|
/*** Logical to Point size ***/
|
|
LogSize = tm.tmHeight - tm.tmInternalLeading;
|
|
PointSize = MulDiv(LogSize, 72, GetDeviceCaps(hDC, LOGPIXELSY));
|
|
/*****************************/
|
|
#endif
|
|
|
|
*Height = (UINT)CharHeight;
|
|
*Width = (UINT)CharWidth;
|
|
Success = TRUE;
|
|
|
|
Cleanup:
|
|
SelectObject(hDC, hOldFont);
|
|
Quit:
|
|
if (!hOrgDC)
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
return Success;
|
|
}
|
|
|
|
BOOL
|
|
IsValidConsoleFont2(
|
|
IN PLOGFONTW lplf,
|
|
IN PNEWTEXTMETRICW lpntm,
|
|
IN DWORD FontType,
|
|
IN UINT CodePage)
|
|
{
|
|
LPCWSTR FaceName = lplf->lfFaceName;
|
|
|
|
/* Record the font's attributes (Fixedwidth and Truetype) */
|
|
// BOOL fFixed = ((lplf->lfPitchAndFamily & 0x03) == FIXED_PITCH);
|
|
// BOOL fTrueType = (lplf->lfOutPrecision == OUT_STROKE_PRECIS);
|
|
|
|
/*
|
|
* According to: http://support.microsoft.com/kb/247815
|
|
* the criteria for console-eligible fonts are:
|
|
* - The font must be a fixed-pitch font.
|
|
* - The font cannot be an italic font.
|
|
* - The font cannot have a negative A or C space.
|
|
* - If it is a TrueType font, it must be FF_MODERN.
|
|
* - If it is not a TrueType font, it must be OEM_CHARSET.
|
|
*
|
|
* Non documented: vertical fonts are forbidden (their name start with a '@').
|
|
*
|
|
* Additional criteria for Asian installations:
|
|
* - If it is not a TrueType font, the face name must be "Terminal".
|
|
* - If it is an Asian TrueType font, it must also be an Asian character set.
|
|
*
|
|
* To install additional TrueType fonts to be available for the console,
|
|
* add entries of type REG_SZ named "0", "00" etc... in:
|
|
* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont
|
|
* The names of the fonts listed there should match those in:
|
|
* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts
|
|
*/
|
|
|
|
/*
|
|
* In ReactOS we relax some of the criteria:
|
|
* - We allow fixed-pitch FF_MODERN (Monospace) TrueType fonts
|
|
* that can be italic or have negative A or C space.
|
|
* - If it is not a TrueType font, it can be from another character set
|
|
* than OEM_CHARSET.
|
|
* - We do not look into the magic registry key mentioned above.
|
|
*/
|
|
|
|
/* Reject variable width fonts */
|
|
if (((lplf->lfPitchAndFamily & 0x03) != FIXED_PITCH)
|
|
#if 0 /* Reject italic and TrueType fonts with negative A or C space */
|
|
|| (lplf->lfItalic)
|
|
|| !(lpntm->ntmFlags & NTM_NONNEGATIVE_AC)
|
|
#endif
|
|
)
|
|
{
|
|
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);
|
|
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);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Is the current code page Chinese, Japanese or Korean? */
|
|
if (IsCJKCodePage(CodePage))
|
|
{
|
|
/* It's Asian */
|
|
if (FontType == TRUETYPE_FONTTYPE)
|
|
{
|
|
if (lplf->lfCharSet != CodePageToCharSet(CodePage))
|
|
{
|
|
DPRINT1("TrueType font '%S' rejected because it's not user Asian charset (lfCharSet = %d)\n",
|
|
FaceName, lplf->lfCharSet);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Reject non-TrueType fonts that are not Terminal */
|
|
if (wcscmp(FaceName, L"Terminal") != 0)
|
|
{
|
|
DPRINT1("Non-TrueType font '%S' rejected because it's not Terminal\n", FaceName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Not CJK */
|
|
if ((FontType != TRUETYPE_FONTTYPE) &&
|
|
(lplf->lfCharSet != ANSI_CHARSET) &&
|
|
(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);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Reject fonts that are vertical (tategaki) */
|
|
if (FaceName[0] == L'@')
|
|
{
|
|
DPRINT1("Font '%S' rejected because it's vertical\n", FaceName);
|
|
return FALSE;
|
|
}
|
|
|
|
/* All good */
|
|
return TRUE;
|
|
}
|
|
|
|
typedef struct _IS_VALID_CONSOLE_FONT_PARAM
|
|
{
|
|
BOOL IsValidFont;
|
|
UINT CodePage;
|
|
} IS_VALID_CONSOLE_FONT_PARAM, *PIS_VALID_CONSOLE_FONT_PARAM;
|
|
|
|
static BOOL CALLBACK
|
|
IsValidConsoleFontProc(
|
|
IN PLOGFONTW lplf,
|
|
IN PNEWTEXTMETRICW lpntm,
|
|
IN DWORD FontType,
|
|
IN LPARAM lParam)
|
|
{
|
|
PIS_VALID_CONSOLE_FONT_PARAM Param = (PIS_VALID_CONSOLE_FONT_PARAM)lParam;
|
|
Param->IsValidFont = IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage);
|
|
|
|
/* Stop the enumeration now */
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
IsValidConsoleFont(
|
|
IN LPCWSTR FaceName,
|
|
IN UINT CodePage)
|
|
{
|
|
IS_VALID_CONSOLE_FONT_PARAM Param;
|
|
HDC hDC;
|
|
LOGFONTW lf;
|
|
|
|
Param.IsValidFont = FALSE;
|
|
Param.CodePage = CodePage;
|
|
|
|
RtlZeroMemory(&lf, sizeof(lf));
|
|
lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(CodePage);
|
|
// lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
|
|
StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), FaceName);
|
|
|
|
hDC = GetDC(NULL);
|
|
EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)IsValidConsoleFontProc, (LPARAM)&Param, 0);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
return Param.IsValidFont;
|
|
}
|
|
|
|
/* EOF */
|