[CONSOLE][CONCFG][CONSRV] Provide support for specified additional TrueType fonts...
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 19 May 2019 20:55:14 +0000 (22:55 +0200)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 19 May 2019 21:10:41 +0000 (23:10 +0200)
CORE-12451 CORE-13182 CORE-13196

- CONSOLE: Initialize the additional TrueType fonts cache.
  * Fix the font preview when a TrueType font has been selected.
  * Refresh the available fonts and the font preview when the selected
    code page is changed (Work In Progress), or when the OS pool of
    font resources has changed (WM_FONTCHANGE message).

- CONCFG: Implement support for the additional TrueType fonts cache:
  the contents of the cache is enumerated under the registry key
    HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont

  * Add helper functions and macros.
  * In CreateConsoleFontEx(), set the mandatory font pitch&family flags
    and remove those that we do not support.
  * In IsValidConsoleFont2(), update the validity checks and the
    documentation links.

- CONSRV: Load/refresh the additional TrueType fonts cache when needed.

dll/cpl/console/console.c
dll/cpl/console/console.h
dll/cpl/console/font.c
dll/cpl/console/layout.c
dll/cpl/console/options.c
win32ss/user/winsrv/concfg/font.c
win32ss/user/winsrv/concfg/font.h
win32ss/user/winsrv/concfg/precomp.h
win32ss/user/winsrv/consrv/frontends/gui/conwnd.c
win32ss/user/winsrv/consrv/frontends/gui/guisettings.c
win32ss/user/winsrv/consrv/frontends/gui/guiterm.c

index 89e9ac5..09c204c 100644 (file)
@@ -227,11 +227,9 @@ InitApplet(HANDLE hSectionOrWnd)
         InitDefaultConsoleInfo(ConInfo);
     }
 
-    /* Initialize the font support */
-    FontPreview.hFont = CreateConsoleFont(ConInfo);
-    if (FontPreview.hFont == NULL)
-        DPRINT1("InitApplet: CreateConsoleFont() failed\n");
-    GetFontCellSize(NULL, FontPreview.hFont, &FontPreview.CharHeight, &FontPreview.CharWidth);
+    /* Initialize the font support -- additional TrueType fonts cache and current preview font */
+    InitTTFontCache();
+    RefreshFontPreview(&FontPreview, ConInfo);
 
     /* Initialize the property sheet structure */
     ZeroMemory(&psh, sizeof(psh));
@@ -274,8 +272,8 @@ InitApplet(HANDLE hSectionOrWnd)
     UnRegisterWinPrevClass(hApplet);
 
     /* Clear the font support */
-    if (FontPreview.hFont) DeleteObject(FontPreview.hFont);
-    FontPreview.hFont = NULL;
+    ResetFontPreview(&FontPreview);
+    ClearTTFontCache();
 
     /* Save the console settings */
     if (SetConsoleInfo)
index 0f7b592..fbd7a81 100644 (file)
@@ -49,6 +49,23 @@ extern FONT_PREVIEW FontPreview;
 
 VOID ApplyConsoleInfo(HWND hwndDlg);
 
+
+VOID
+RefreshFontPreview(
+    IN FONT_PREVIEW* Preview,
+    IN PCONSOLE_STATE_INFO pConInfo);
+
+VOID
+UpdateFontPreview(
+    IN FONT_PREVIEW* Preview,
+    IN HFONT hFont,
+    IN UINT  CharWidth,
+    IN UINT  CharHeight);
+
+#define ResetFontPreview(Preview)   \
+    UpdateFontPreview((Preview), NULL, 0, 0)
+
+
 /* Preview Windows */
 BOOL
 RegisterWinPrevClass(
index 66c9cc6..522a6fb 100644 (file)
@@ -45,6 +45,31 @@ static INT   CurrentSelFont  = LB_ERR;
 static DWORD CurrentFontType = (DWORD)-1;   // Invalid font type
 
 
+VOID
+RefreshFontPreview(
+    IN FONT_PREVIEW* Preview,
+    IN PCONSOLE_STATE_INFO pConInfo)
+{
+    if (Preview->hFont) DeleteObject(Preview->hFont);
+    Preview->hFont = CreateConsoleFont(pConInfo);
+    if (Preview->hFont == NULL)
+        DPRINT1("RefreshFontPreview: CreateConsoleFont() failed\n");
+    GetFontCellSize(NULL, Preview->hFont, &Preview->CharHeight, &Preview->CharWidth);
+}
+
+VOID
+UpdateFontPreview(
+    IN FONT_PREVIEW* Preview,
+    IN HFONT hFont,
+    IN UINT  CharWidth,
+    IN UINT  CharHeight)
+{
+    if (Preview->hFont) DeleteObject(Preview->hFont);
+    Preview->hFont = hFont;
+    Preview->CharWidth  = CharWidth;
+    Preview->CharHeight = CharHeight;
+}
+
 // PLIST_GETCOUNT
 static INT
 RasterSizeList_GetCount(
@@ -284,13 +309,6 @@ EnumFaceNamesProc(
 {
     PFACE_NAMES_PROC_PARAM Param = (PFACE_NAMES_PROC_PARAM)lParam;
 
-    /*
-     * 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
-     */
     if (IsValidConsoleFont2(lplf, lpntm, FontType, Param->CodePage))
     {
         /* Add the font to the list */
@@ -374,7 +392,7 @@ FaceNameList_Initialize(
 
     ZeroMemory(&lf, sizeof(lf));
     lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(CodePage);
-    // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
+    // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
 
     hDC = GetDC(NULL);
     EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFaceNamesProc, (LPARAM)&Param, 0);
@@ -397,9 +415,14 @@ FaceNameList_Initialize(
 }
 
 static VOID
-FaceNameList_SelectFaceName(
+FaceNameList_SelectFont(
+    IN HWND hDlg,
     IN HWND hWndList,
-    IN LPCWSTR FaceName)
+    IN PFONTSIZE_LIST_CTL SizeList,
+    IN LPCWSTR FaceName,
+    IN ULONG FontFamily,
+    IN ULONG FontWeight,
+    IN COORD FontSize)
 {
     INT iItem;
 
@@ -410,6 +433,21 @@ FaceNameList_SelectFaceName(
         iItem = 0;
     SendMessageW(hWndList, LB_SETCURSEL, (WPARAM)iItem, 0);
 
+    if (FontWeight >= FW_BOLD)
+        CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_CHECKED);
+    else
+        CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_UNCHECKED);
+
+    /* Select the current font size */
+    /*
+     * Format:
+     * Width  = FontSize.X = LOWORD(FontSize);
+     * Height = FontSize.Y = HIWORD(FontSize);
+     */
+    SizeList->CurrentRasterSize = MAKELONG(FontSize.X, FontSize.Y);
+    SizeList->CurrentTTSize = FontSize.Y;
+    // FontSizeList_SelectFontSize(SizeList, SizeList->CurrentRasterSize);
+
     // return iItem;
 }
 
@@ -486,7 +524,6 @@ FontTypeChange(
 {
     HWND hListBox = GetDlgItem(hDlg, IDC_LBOX_FONTTYPE);
     INT Length, nSel;
-    LOGFONTW lf;
     LPWSTR FaceName;
     DWORD FontType;
     LPCWSTR FontGrpBoxLabelTpl = NULL;
@@ -518,12 +555,7 @@ FontTypeChange(
     FaceName[Length] = L'\0';
 
     StringCchCopyW(pConInfo->FaceName, ARRAYSIZE(pConInfo->FaceName), FaceName);
-    DPRINT1("pConInfo->FaceName = '%S'\n", pConInfo->FaceName);
-
-    ZeroMemory(&lf, sizeof(lf));
-    lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(pConInfo->CodePage);
-    // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
-    StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), FaceName);
+    DPRINT("pConInfo->FaceName = '%S'\n", pConInfo->FaceName);
 
     /*
      * Retrieve the read-only font group box label string template,
@@ -560,6 +592,7 @@ FontTypeChange(
         if ((CurrentFontType != FontType) ||
             (FontType == RASTER_FONTTYPE && CurrentSelFont != nSel))
         {
+            LOGFONTW lf;
             HDC hDC;
 
             if (SizeList->UseRasterOrTTList)
@@ -567,6 +600,11 @@ FontTypeChange(
             else
                 SendMessageW(SizeList->hWndTTSizeList, CB_RESETCONTENT, 0, 0);
 
+            ZeroMemory(&lf, sizeof(lf));
+            lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(pConInfo->CodePage);
+            // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
+            StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), pConInfo->FaceName);
+
             hDC = GetDC(NULL);
             EnumFontFamiliesExW(hDC, &lf, (FONTENUMPROCW)EnumFontSizesProc, (LPARAM)SizeList, 0);
             ReleaseDC(NULL, hDC);
@@ -597,7 +635,9 @@ FontSizeChange(
     IN PFONTSIZE_LIST_CTL SizeList,
     IN OUT PCONSOLE_STATE_INFO pConInfo)
 {
-    LONG FontSize, CharWidth, CharHeight;
+    LONG FontSize;
+    UINT CharWidth, CharHeight;
+    HFONT hFont;
     WCHAR szFontSize[100];
 
     /*
@@ -610,35 +650,44 @@ FontSizeChange(
     if (FontSize == 0)
         return FALSE; // We have got an invalid font size...
 
-    CharHeight = (SizeList->UseRasterOrTTList ? (LONG)HIWORD(FontSize) : FontSize);
-    CharWidth  = (SizeList->UseRasterOrTTList ? (LONG)LOWORD(FontSize) : 0);
+    /*
+     * For TrueType fonts we set the requested width to zero
+     * so as to obtain a default aspect-ratio width.
+     */
+    CharHeight = (UINT)(SizeList->UseRasterOrTTList ? HIWORD(FontSize) : FontSize);
+    CharWidth  = (UINT)(SizeList->UseRasterOrTTList ? LOWORD(FontSize) : 0);
 
-    if (FontPreview.hFont) DeleteObject(FontPreview.hFont);
-    FontPreview.hFont = CreateConsoleFont2(CharHeight, CharWidth, pConInfo);
-    if (FontPreview.hFont == NULL)
+    hFont = CreateConsoleFont2((LONG)CharHeight, (LONG)CharWidth, pConInfo);
+    if (hFont == NULL)
         DPRINT1("FontSizeChange: CreateConsoleFont2() failed\n");
 
     /* Retrieve the real character size in pixels */
-    GetFontCellSize(NULL, FontPreview.hFont, &FontPreview.CharHeight, &FontPreview.CharWidth);
+    GetFontCellSize(NULL, hFont, &CharHeight, &CharWidth);
+
+    /*
+     * Update the font preview as well, and store the font handle. It will be
+     * freed at later update or when the font preview is refreshed or reset.
+     * For TrueType fonts, the preview will show the actual character width.
+     */
+    UpdateFontPreview(&FontPreview, hFont, CharWidth, CharHeight);
 
     /*
      * Format:
      * Width  = FontSize.X = LOWORD(FontSize);
      * Height = FontSize.Y = HIWORD(FontSize);
      */
-    pConInfo->FontSize.X = (SHORT)(SizeList->UseRasterOrTTList ? FontPreview.CharWidth : 0);
-    pConInfo->FontSize.Y = (SHORT)FontPreview.CharHeight;
+    pConInfo->FontSize.X = (SHORT)(SizeList->UseRasterOrTTList ? CharWidth : 0);
+    pConInfo->FontSize.Y = (SHORT)CharHeight;
 
-    DPRINT1("pConInfo->FontSize = (%d x %d) ; (CharWidth x CharHeight) = (%d x %d)\n",
-            pConInfo->FontSize.X, pConInfo->FontSize.Y,
-            FontPreview.CharWidth, FontPreview.CharHeight);
+    DPRINT("pConInfo->FontSize = (%d x %d) ; (CharWidth x CharHeight) = (%d x %d)\n",
+           pConInfo->FontSize.X, pConInfo->FontSize.Y, CharWidth, CharHeight);
 
     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_FONT_WINDOW_PREVIEW), NULL, TRUE);
     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_SELECT_FONT_PREVIEW), NULL, TRUE);
 
-    StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", FontPreview.CharWidth);
+    StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", CharWidth);
     SetDlgItemText(hDlg, IDC_FONT_SIZE_X, szFontSize);
-    StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", FontPreview.CharHeight);
+    StringCchPrintfW(szFontSize, ARRAYSIZE(szFontSize), L"%d", CharHeight);
     SetDlgItemText(hDlg, IDC_FONT_SIZE_Y, szFontSize);
 
     return TRUE;
@@ -689,22 +738,12 @@ FontProc(HWND hDlg,
 
             /* Select the current font */
             DPRINT1("ConInfo->FaceName = '%S'\n", ConInfo->FaceName);
-            FaceNameList_SelectFaceName(hFontList, ConInfo->FaceName);
-
-            if (ConInfo->FontWeight >= FW_BOLD)
-                CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_CHECKED);
-            else
-                CheckDlgButton(hDlg, IDC_CHECK_BOLD_FONTS, BST_UNCHECKED);
-
-            /* Select the current font size */
-            /*
-             * Format:
-             * Width  = FontSize.X = LOWORD(FontSize);
-             * Height = FontSize.Y = HIWORD(FontSize);
-             */
-            SizeList->CurrentRasterSize = MAKELONG(ConInfo->FontSize.X, ConInfo->FontSize.Y);
-            SizeList->CurrentTTSize = ConInfo->FontSize.Y;
-            // FontSizeList_SelectFontSize(SizeList, SizeList->CurrentRasterSize);
+            FaceNameList_SelectFont(hDlg, hFontList,
+                                    SizeList,
+                                    ConInfo->FaceName,
+                                    ConInfo->FontFamily,
+                                    ConInfo->FontWeight,
+                                    ConInfo->FontSize);
 
             /* Refresh everything */
             FontTypeChange(hDlg, SizeList, ConInfo);
@@ -737,6 +776,42 @@ FontProc(HWND hDlg,
             break;
         }
 
+#if 0
+        case PSM_QUERYSIBLINGS:
+        {
+            /*
+             * If this is a notification from the "Options" dialog because we
+             * changed the code page, treat it using the WM_FONTCHANGE case,
+             * otherwise ignore it.
+             */
+            if (wParam != IDL_CODEPAGE)
+                return FALSE;
+
+            /* Fall through */
+        }
+#endif
+
+        case WM_FONTCHANGE:
+        {
+            /* The pool of font resources has changed, re-enumerate the fonts */
+            HWND hFontList = GetDlgItem(hDlg, IDC_LBOX_FONTTYPE);
+
+            /* Initialize the font list */
+            FaceNameList_Initialize(hFontList, ConInfo->CodePage);
+
+            /* Select the current font */
+            FaceNameList_SelectFont(hDlg, hFontList,
+                                    SizeList,
+                                    ConInfo->FaceName,
+                                    ConInfo->FontFamily,
+                                    ConInfo->FontWeight,
+                                    ConInfo->FontSize);
+
+            /* Refresh everything */
+            FontTypeChange(hDlg, SizeList, ConInfo);
+            break;
+        }
+
         case WM_NOTIFY:
         {
             switch (((LPNMHDR)lParam)->code)
index f8d9986..a94bcb5 100644 (file)
@@ -203,6 +203,9 @@ WinPrev_OnDraw(
      * Compute the console window layout
      */
 
+    if (FontPreview.hFont == NULL)
+        RefreshFontPreview(&FontPreview, pConInfo);
+
     /* We start with the console client area, rescaled for the preview */
     SetRect(&rcWin, 0, 0,
             pConInfo->WindowSize.X * FontPreview.CharWidth,
@@ -489,6 +492,9 @@ PaintText(
     hBrush = CreateSolidBrush(nbkColor);
     if (!hBrush) return;
 
+    if (FontPreview.hFont == NULL)
+        RefreshFontPreview(&FontPreview, pConInfo);
+
     hOldFont = SelectObject(drawItem->hDC, FontPreview.hFont);
     //if (hOldFont == NULL)
     //{
index 689553d..e35a247 100644 (file)
@@ -72,7 +72,8 @@ AddCodePage(
 
 static VOID
 BuildCodePageList(
-    IN HWND hDlg)
+    IN HWND hDlg,
+    IN UINT CurrentCodePage)
 {
     LIST_CTL ListCtl;
     HKEY hKey;
@@ -126,7 +127,7 @@ BuildCodePageList(
     AddCodePage(&ListCtl, CP_UTF8);
 
     /* Find and select the current code page in the sorted list */
-    if (BisectListSortedByValue(&ListCtl, ConInfo->CodePage, &CodePage, FALSE) == CB_ERR ||
+    if (BisectListSortedByValue(&ListCtl, CurrentCodePage, &CodePage, FALSE) == CB_ERR ||
         CodePage == CB_ERR)
     {
         /* Not found, select the first element */
@@ -212,7 +213,7 @@ OptionsProc(HWND hDlg,
     {
         case WM_INITDIALOG:
         {
-            BuildCodePageList(hDlg);
+            BuildCodePageList(hDlg, ConInfo->CodePage);
             UpdateDialogElements(hDlg, ConInfo);
             return TRUE;
         }
@@ -332,6 +333,7 @@ OptionsProc(HWND hDlg,
                 }
             }
             else
+            // (HIWORD(wParam) == CBN_KILLFOCUS)
             if ((HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_SELENDOK) &&
                 (LOWORD(wParam) == IDL_CODEPAGE))
             {
@@ -347,11 +349,15 @@ OptionsProc(HWND hDlg,
                 if (CodePage == CB_ERR)
                     break;
 
-                ConInfo->CodePage = CodePage;
-
-                /* Change the property sheet state only if the user validated */
-                if (HIWORD(wParam) == CBN_SELENDOK)
+                /* If the user validated a different code page... */
+                if ((HIWORD(wParam) == CBN_SELENDOK) && (CodePage != ConInfo->CodePage))
+                {
+                    /* ... update the code page, notify the siblings and change the property sheet state */
+                    ConInfo->CodePage = CodePage;
+                    // PropSheet_QuerySiblings(GetParent(hDlg), IDL_CODEPAGE, 0);
+                    ResetFontPreview(&FontPreview);
                     PropSheet_Changed(GetParent(hDlg), hDlg);
+                }
             }
 
             break;
index fdc4e15..6aa75b0 100644 (file)
 #include <debug.h>
 
 
+/* GLOBALS ********************************************************************/
+
+// RTL_STATIC_LIST_HEAD(TTFontCache);
+LIST_ENTRY TTFontCache = {&TTFontCache, &TTFontCache};
+
 /* FUNCTIONS ******************************************************************/
 
 /* Retrieves the character set associated with a given code page */
@@ -58,7 +63,10 @@ CreateConsoleFontEx(
     lf.lfOutPrecision  = OUT_DEFAULT_PRECIS;
     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
     lf.lfQuality = DEFAULT_QUALITY;
-    lf.lfPitchAndFamily = (BYTE)(FIXED_PITCH | FontFamily);
+
+    /* Set the mandatory flags and remove those that we do not support */
+    lf.lfPitchAndFamily = (BYTE)( (FIXED_PITCH | FF_MODERN | FontFamily) &
+                                 ~(VARIABLE_PITCH | FF_DECORATIVE | FF_ROMAN | FF_SCRIPT | FF_SWISS));
 
     if (!IsValidConsoleFont(FaceName, CodePage))
         StringCchCopyW(FaceName, LF_FACESIZE, L"Terminal");
@@ -179,13 +187,10 @@ IsValidConsoleFont2(
 {
     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:
+     * According to: https://web.archive.org/web/20140901124501/http://support.microsoft.com/kb/247815
+     * "Necessary criteria for fonts to be available in a command window",
+     * the criteria for console-eligible fonts are as follows:
      * - 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.
@@ -198,6 +203,10 @@ IsValidConsoleFont2(
      * - 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.
      *
+     * 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
+     * for other details.
+     *
      * 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
@@ -205,27 +214,30 @@ IsValidConsoleFont2(
      * 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)
+    /*
+     * 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. When an Asian codepage is active however, we require
+     *   that this non-TrueType font has an Asian character set.
+     */
+
+    /* 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
-        )
+         ) &&
+        /* ... 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"),
+        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;
     }
@@ -238,25 +250,66 @@ IsValidConsoleFont2(
         return FALSE;
     }
 
+    /* Reject vertical fonts (tategaki) */
+    if (FaceName[0] == L'@')
+    {
+        DPRINT1("Font '%S' rejected because it's vertical\n", FaceName);
+        return FALSE;
+    }
+
     /* Is the current code page Chinese, Japanese or Korean? */
     if (IsCJKCodePage(CodePage))
     {
-        /* It's Asian */
+        /* It's CJK */
+
         if (FontType == TRUETYPE_FONTTYPE)
         {
-            if (lplf->lfCharSet != CodePageToCharSet(CodePage))
+            /*
+             * 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
+               )
             {
-                DPRINT1("TrueType font '%S' rejected because it's not user Asian charset (lfCharSet = %d)\n",
+                DPRINT1("TrueType font '%S' rejected because it's not Asian charset (lfCharSet = %d)\n",
+                        FaceName, lplf->lfCharSet);
+                return FALSE;
+            }
+
+            /*
+             * If this is a cached TrueType font that is used only for certain
+             * code pages, verify that the charset it claims is the correct one.
+             *
+             * Since there may be multiple entries for a cached TrueType font,
+             * a general one (code page == 0) and one or more for explicit
+             * code pages, we need to perform two search queries instead of
+             * just one and retrieving the code page for this entry.
+             */
+            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);
                 return FALSE;
             }
         }
         else
         {
+            /* 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);
+                return FALSE;
+            }
+
             /* 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);
+                DPRINT1("Non-TrueType font '%S' rejected because it's not 'Terminal'\n", FaceName);
                 return FALSE;
             }
         }
@@ -264,6 +317,8 @@ IsValidConsoleFont2(
     else
     {
         /* Not CJK */
+
+        /* Reject non-TrueType fonts that are not OEM or similar */
         if ((FontType != TRUETYPE_FONTTYPE) &&
             (lplf->lfCharSet != ANSI_CHARSET) &&
             (lplf->lfCharSet != DEFAULT_CHARSET) &&
@@ -275,13 +330,6 @@ IsValidConsoleFont2(
         }
     }
 
-    /* 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;
 }
@@ -320,7 +368,7 @@ IsValidConsoleFont(
 
     RtlZeroMemory(&lf, sizeof(lf));
     lf.lfCharSet = DEFAULT_CHARSET; // CodePageToCharSet(CodePage);
-    // lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
+    // lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
     StringCchCopyW(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), FaceName);
 
     hDC = GetDC(NULL);
@@ -330,4 +378,173 @@ IsValidConsoleFont(
     return Param.IsValidFont;
 }
 
+/*
+ * 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
+ *
+ * This function initializes the cache of the fonts listed there.
+ */
+VOID
+InitTTFontCache(VOID)
+{
+    BOOLEAN Success;
+    HKEY  hKeyTTFonts; // hKey;
+    DWORD dwNumValues = 0;
+    DWORD dwIndex;
+    DWORD dwType;
+    WCHAR szValueName[MAX_PATH];
+    DWORD dwValueName;
+    WCHAR szValue[LF_FACESIZE] = L"";
+    DWORD dwValue;
+    PTT_FONT_ENTRY FontEntry;
+    PWCHAR pszNext = NULL;
+    UINT CodePage;
+
+    if (!IsListEmpty(&TTFontCache))
+        return;
+    // InitializeListHead(&TTFontCache);
+
+    /* Open the key */
+    // "\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont"
+    Success = (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                             L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Console\\TrueTypeFont",
+                             0,
+                             KEY_READ,
+                             &hKeyTTFonts) == ERROR_SUCCESS);
+    if (!Success)
+        return;
+
+    /* Enumerate each value */
+    if (RegQueryInfoKeyW(hKeyTTFonts, NULL, NULL, NULL, NULL, NULL, NULL,
+                         &dwNumValues, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+    {
+        DPRINT("ConCfgReadUserSettings: RegQueryInfoKeyW failed\n");
+        RegCloseKey(hKeyTTFonts);
+        return;
+    }
+
+    for (dwIndex = 0; dwIndex < dwNumValues; dwIndex++)
+    {
+        dwValue = sizeof(szValue);
+        dwValueName = ARRAYSIZE(szValueName);
+        if (RegEnumValueW(hKeyTTFonts, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
+        {
+            DPRINT1("InitTTFontCache: RegEnumValueW failed, continuing...\n");
+            continue;
+        }
+        /* Only (multi-)string values are supported */
+        if ((dwType != REG_SZ) && (dwType != REG_MULTI_SZ))
+            continue;
+
+        /* The value name is a code page (in decimal), validate it */
+        CodePage = wcstoul(szValueName, &pszNext, 10);
+        if (*pszNext)
+            continue; // Non-numerical garbage followed...
+        // IsValidCodePage(CodePage);
+
+        FontEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*FontEntry));
+        if (!FontEntry)
+        {
+            DPRINT1("InitTTFontCache: Failed to allocate memory, continuing...\n");
+            continue;
+        }
+
+        FontEntry->CodePage = CodePage;
+
+        pszNext = szValue;
+
+        /* Check whether bold is disabled for this font */
+        if (*pszNext == L'*')
+        {
+            FontEntry->DisableBold = TRUE;
+            ++pszNext;
+        }
+        else
+        {
+            FontEntry->DisableBold = FALSE;
+        }
+
+        /* Copy the font name */
+        StringCchCopyNW(FontEntry->FaceName, ARRAYSIZE(FontEntry->FaceName),
+                        pszNext, wcslen(pszNext));
+
+        if (dwType == REG_MULTI_SZ)
+        {
+            /* There may be an alternate face name as the second string */
+            pszNext += wcslen(pszNext) + 1;
+
+            /* Check whether bold is disabled for this font */
+            if (*pszNext == L'*')
+            {
+                FontEntry->DisableBold = TRUE;
+                ++pszNext;
+            }
+            // else, keep the original setting.
+
+            /* Copy the alternate font name */
+            StringCchCopyNW(FontEntry->FaceNameAlt, ARRAYSIZE(FontEntry->FaceNameAlt),
+                            pszNext, wcslen(pszNext));
+        }
+
+        InsertTailList(&TTFontCache, &FontEntry->Entry);
+    }
+
+    /* Close the key and quit */
+    RegCloseKey(hKeyTTFonts);
+}
+
+VOID
+ClearTTFontCache(VOID)
+{
+    PLIST_ENTRY Entry;
+    PTT_FONT_ENTRY FontEntry;
+
+    while (!IsListEmpty(&TTFontCache))
+    {
+        Entry = RemoveHeadList(&TTFontCache);
+        FontEntry = CONTAINING_RECORD(Entry, TT_FONT_ENTRY, Entry);
+        RtlFreeHeap(RtlGetProcessHeap(), 0, FontEntry);
+    }
+    InitializeListHead(&TTFontCache);
+}
+
+VOID
+RefreshTTFontCache(VOID)
+{
+    ClearTTFontCache();
+    InitTTFontCache();
+}
+
+PTT_FONT_ENTRY
+FindCachedTTFont(
+    IN LPCWSTR FaceName,
+    IN UINT CodePage)
+{
+    PLIST_ENTRY Entry;
+    PTT_FONT_ENTRY FontEntry;
+
+    /* Search for the font in the cache */
+    for (Entry = TTFontCache.Flink;
+         Entry != &TTFontCache;
+         Entry = Entry->Flink)
+    {
+        FontEntry = CONTAINING_RECORD(Entry, TT_FONT_ENTRY, Entry);
+
+        /* NOTE: The font face names are case-sensitive */
+        if ((wcscmp(FontEntry->FaceName   , FaceName) == 0) ||
+            (wcscmp(FontEntry->FaceNameAlt, FaceName) == 0))
+        {
+            /* Return a match if we don't look at the code pages, or when they match */
+            if ((CodePage == INVALID_CP) || (CodePage == FontEntry->CodePage))
+            {
+                return FontEntry;
+            }
+        }
+    }
+    return NULL;
+}
+
 /* EOF */
index 09b076a..ee1aa92 100644 (file)
 
 /* DEFINES ********************************************************************/
 
-#define CP_SHIFTJIS 932 // Japanese Shift-JIS
-#define CP_HANGUL   949 // Korean Hangul
-#define CP_GB2312   936 // Chinese Simplified (GB2312)
-#define CP_BIG5     950 // Chinese Traditional (Big5)
+#define INVALID_CP  ((UINT)-1)
+
+#define CP_SHIFTJIS 932  // Japanese Shift-JIS
+#define CP_HANGUL   949  // Korean Hangul/Wansung
+#define CP_JOHAB    1361 // Korean Johab
+#define CP_GB2312   936  // Chinese Simplified (GB2312)
+#define CP_BIG5     950  // Chinese Traditional (Big5)
 
 /* IsFarEastCP(CodePage) */
 #define IsCJKCodePage(CodePage) \
     ((CodePage) == CP_SHIFTJIS || (CodePage) == CP_HANGUL || \
+  /* (CodePage) == CP_JOHAB || */ \
      (CodePage) == CP_BIG5     || (CodePage) == CP_GB2312)
 
+#if !defined(_WINGDI_) || defined(NOGDI)
+#define SHIFTJIS_CHARSET    128
+#define HANGEUL_CHARSET     129
+#define HANGUL_CHARSET      129 // HANGEUL_CHARSET
+#if(WINVER >= 0x0400)
+#define JOHAB_CHARSET       130
+#endif /* WINVER */
+#define GB2312_CHARSET      134
+#define CHINESEBIG5_CHARSET 136
+#endif /* !defined(_WINGDI_) || defined(NOGDI) */
+
+/* IsAnyDBCSCharSet(CharSet) */
+#define IsCJKCharSet(CharSet)   \
+    ((CharSet) == SHIFTJIS_CHARSET || (CharSet) == HANGUL_CHARSET || \
+  /* (CharSet) == JOHAB_CHARSET || */ \
+     (CharSet) == GB2312_CHARSET   || (CharSet) == CHINESEBIG5_CHARSET)
+
+#define IsBoldFont(Weight)  \
+    ((Weight) >= FW_SEMIBOLD) /* Sometimes, just > FW_MEDIUM */
+
+typedef struct _TT_FONT_ENTRY
+{
+    LIST_ENTRY Entry;
+    UINT CodePage;
+    BOOL DisableBold;
+    WCHAR FaceName[LF_FACESIZE];
+    WCHAR FaceNameAlt[LF_FACESIZE];
+} TT_FONT_ENTRY, *PTT_FONT_ENTRY;
+
+
 /* FUNCTIONS ******************************************************************/
 
 BYTE
@@ -65,4 +99,33 @@ IsValidConsoleFont(
     IN LPCWSTR FaceName,
     IN UINT CodePage);
 
+/*
+ * 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
+ *
+ * This function initializes the cache of the fonts listed there.
+ */
+VOID
+InitTTFontCache(VOID);
+
+VOID
+ClearTTFontCache(VOID);
+
+VOID
+RefreshTTFontCache(VOID);
+
+PTT_FONT_ENTRY
+FindCachedTTFont(
+    IN LPCWSTR FaceName,
+    IN UINT CodePage);
+
+#define IsAdditionalTTFont(FaceName) \
+    (FindCachedTTFont((FaceName), INVALID_CP) != NULL)
+
+#define IsAdditionalTTFontCP(FaceName, CodePage) \
+    (FindCachedTTFont((FaceName), (CodePage)) != NULL)
+
 /* EOF */
index cfa0519..5f6ca4a 100644 (file)
@@ -31,7 +31,8 @@
 #include <ndk/obfuncs.h>
 #include <ndk/rtlfuncs.h>
 
-#include <stdio.h> // for swprintf
+#include <stdio.h>  // For swprintf()
+#include <stdlib.h> // For wcstoul()
 #include <strsafe.h>
 
 /* EOF */
index 13f5da9..6e3603f 100644 (file)
@@ -20,7 +20,7 @@
 #define NDEBUG
 #include <debug.h>
 
-#include "font.h"
+#include "concfg/font.h"
 #include "guiterm.h"
 #include "resource.h"
 
index e317334..1ccee59 100644 (file)
@@ -14,6 +14,7 @@
 #define NDEBUG
 #include <debug.h>
 
+#include "concfg/font.h"
 #include "guiterm.h"
 #include "guisettings.h"
 
@@ -331,7 +332,8 @@ GuiApplyUserSettings(PGUI_CONSOLE_DATA GuiData,
 
         /* Set the terminal informations */
 
-        /* Change the font */
+        /* Refresh the additional TrueType fonts cache and change the font */
+        RefreshTTFontCache();
         InitFonts(GuiData,
                   pConInfo->FaceName,
                   pConInfo->FontFamily,
index c811c4c..afca593 100644 (file)
@@ -16,6 +16,7 @@
 #define NDEBUG
 #include <debug.h>
 
+#include "concfg/font.h"
 #include "guiterm.h"
 #include "resource.h"
 
@@ -294,12 +295,15 @@ GuiInit(IN PCONSOLE_INIT_INFO ConsoleInitInfo,
     HANDLE hInputThread;
     CLIENT_ID ClientId;
 
-    /*
-     * Initialize and register the console window class, if needed.
-     */
+    /* Perform one-time initialization */
     if (!ConsInitialized)
     {
+        /* Initialize and register the console window class */
         if (!RegisterConWndClass(ConSrvDllInstance)) return FALSE;
+
+        /* Initialize the font support -- additional TrueType fonts cache */
+        InitTTFontCache();
+
         ConsInitialized = TRUE;
     }