https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2b526bceac3b6bad263b3…
commit 2b526bceac3b6bad263b308be779b7525d3cd8aa
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sat Aug 10 14:52:09 2019 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sat Aug 10 14:52:09 2019 +0900
[WIN32SS][NTGDI] Registry-based font management (#1816)
CORE-16269
- Add IntGdiAddFontResourceEx function that is extended from IntGdiAddFontResource, in
order to add dwFlags parameter.
- Add IntLoadFontsInRegistry function that will load the fonts from registry info.
- If loading from registry failed, IntLoadSystemFonts will be called.
- Use IntLoadFontsInRegistry rather than IntLoadSystemFonts in the OS startup.
- Add NameFromCharSet function.
- Append " (CharSetName)" to registry value name if not TrueType.
---
win32ss/gdi/ntgdi/font.h | 1 +
win32ss/gdi/ntgdi/freetype.c | 267 +++++++++++++++++++++++++++++++++++++++++--
win32ss/gdi/ntgdi/text.h | 6 +
3 files changed, 264 insertions(+), 10 deletions(-)
diff --git a/win32ss/gdi/ntgdi/font.h b/win32ss/gdi/ntgdi/font.h
index b5629c794fe..908a9f5b65f 100644
--- a/win32ss/gdi/ntgdi/font.h
+++ b/win32ss/gdi/ntgdi/font.h
@@ -62,6 +62,7 @@ typedef struct GDI_LOAD_FONT
DWORD Characteristics;
UNICODE_STRING RegValueName;
BOOL IsTrueType;
+ BYTE CharSet;
PFONT_ENTRY_MEM PrivateEntry;
} GDI_LOAD_FONT, *PGDI_LOAD_FONT;
diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c
index 2578bc04e27..b5ae335eabb 100644
--- a/win32ss/gdi/ntgdi/freetype.c
+++ b/win32ss/gdi/ntgdi/freetype.c
@@ -686,7 +686,14 @@ InitFontSupport(VOID)
return FALSE;
}
- IntLoadSystemFonts();
+ if (!IntLoadFontsInRegistry())
+ {
+ DPRINT1("Fonts registry is empty.\n");
+
+ /* Load font(s) with writing registry */
+ IntLoadSystemFonts();
+ }
+
IntLoadFontSubstList(&g_FontSubstListHead);
#if DBG
@@ -1020,7 +1027,7 @@ IntLoadSystemFonts(VOID)
TempString.MaximumLength = DirInfo->FileNameLength;
RtlCopyUnicodeString(&FileName, &Directory);
RtlAppendUnicodeStringToString(&FileName, &TempString);
- IntGdiAddFontResource(&FileName, 0);
+ IntGdiAddFontResourceEx(&FileName, 0, AFRX_WRITE_REGISTRY);
if (DirInfo->NextEntryOffset == 0)
break;
DirInfo = (PFILE_DIRECTORY_INFORMATION)((ULONG_PTR)DirInfo +
DirInfo->NextEntryOffset);
@@ -1316,6 +1323,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont)
if (!Error)
{
FontGDI->CharSet = WinFNT.charset;
+ pLoadFont->CharSet = WinFNT.charset;
}
IntUnLockFreeType();
}
@@ -1526,6 +1534,34 @@ Finish:
}
}
+static LPCWSTR FASTCALL
+NameFromCharSet(BYTE CharSet)
+{
+ switch (CharSet)
+ {
+ case ANSI_CHARSET: return L"ANSI";
+ case DEFAULT_CHARSET: return L"Default";
+ case SYMBOL_CHARSET: return L"Symbol";
+ case SHIFTJIS_CHARSET: return L"Shift_JIS";
+ case HANGUL_CHARSET: return L"Hangul";
+ case GB2312_CHARSET: return L"GB 2312";
+ case CHINESEBIG5_CHARSET: return L"Chinese Big5";
+ case OEM_CHARSET: return L"OEM";
+ case JOHAB_CHARSET: return L"Johab";
+ case HEBREW_CHARSET: return L"Hebrew";
+ case ARABIC_CHARSET: return L"Arabic";
+ case GREEK_CHARSET: return L"Greek";
+ case TURKISH_CHARSET: return L"Turkish";
+ case VIETNAMESE_CHARSET: return L"Vietnamese";
+ case THAI_CHARSET: return L"Thai";
+ case EASTEUROPE_CHARSET: return L"Eastern European";
+ case RUSSIAN_CHARSET: return L"Russian";
+ case MAC_CHARSET: return L"Mac";
+ case BALTIC_CHARSET: return L"Baltic";
+ default: return L"Unknown";
+ }
+}
+
/*
* IntGdiAddFontResource
*
@@ -1533,7 +1569,8 @@ Finish:
*/
INT FASTCALL
-IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
+IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics,
+ DWORD dwFlags)
{
NTSTATUS Status;
HANDLE FileHandle;
@@ -1588,6 +1625,7 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD
Characteristics)
LoadFont.Characteristics = Characteristics;
RtlInitUnicodeString(&LoadFont.RegValueName, NULL);
LoadFont.IsTrueType = FALSE;
+ LoadFont.CharSet = DEFAULT_CHARSET;
LoadFont.PrivateEntry = NULL;
FontCount = IntGdiLoadFontsFromMemory(&LoadFont);
@@ -1599,15 +1637,15 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD
Characteristics)
ObDereferenceObject(SectionObject);
/* Save the loaded font name into the registry */
- if (FontCount > 0)
+ if (FontCount > 0 && (dwFlags & AFRX_WRITE_REGISTRY))
{
+ UNICODE_STRING NewString;
+ SIZE_T Length;
+ PWCHAR pszBuffer;
+ LPCWSTR CharSetName;
if (LoadFont.IsTrueType)
{
/* Append " (TrueType)" */
- UNICODE_STRING NewString;
- SIZE_T Length;
- PWCHAR pszBuffer;
-
Length = LoadFont.RegValueName.Length + TrueTypePostfix.Length +
sizeof(UNICODE_NULL);
pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
if (pszBuffer)
@@ -1624,6 +1662,31 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD
Characteristics)
// FIXME!
}
}
+ else if (LoadFont.CharSet != DEFAULT_CHARSET)
+ {
+ /* Append " (CharSetName)" */
+ CharSetName = NameFromCharSet(LoadFont.CharSet);
+ Length = LoadFont.RegValueName.Length +
+ (wcslen(CharSetName) + 3) * sizeof(WCHAR) +
+ sizeof(UNICODE_NULL);
+
+ pszBuffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_USTR);
+ if (pszBuffer)
+ {
+ RtlInitEmptyUnicodeString(&NewString, pszBuffer, (USHORT)Length);
+ NewString.Buffer[0] = UNICODE_NULL;
+ RtlAppendUnicodeStringToString(&NewString,
&LoadFont.RegValueName);
+ RtlAppendUnicodeToString(&NewString, L" (");
+ RtlAppendUnicodeToString(&NewString, CharSetName);
+ RtlAppendUnicodeToString(&NewString, L")");
+ RtlFreeUnicodeString(&LoadFont.RegValueName);
+ LoadFont.RegValueName = NewString;
+ }
+ else
+ {
+ // FIXME!
+ }
+ }
InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
@@ -1632,10 +1695,23 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD
Characteristics)
if (NT_SUCCESS(Status))
{
SIZE_T DataSize;
- LPWSTR pFileName = wcsrchr(FileName->Buffer, L'\\');
+ LPWSTR pFileName;
+
+ if (dwFlags & AFRX_ALTERNATIVE_PATH)
+ {
+ pFileName = FileName->Buffer;
+ }
+ else
+ {
+ pFileName = wcsrchr(FileName->Buffer, L'\\');
+ }
+
if (pFileName)
{
- pFileName++;
+ if (!(dwFlags & AFRX_ALTERNATIVE_PATH))
+ {
+ pFileName++;
+ }
DataSize = (wcslen(pFileName) + 1) * sizeof(WCHAR);
ZwSetValueKey(KeyHandle, &LoadFont.RegValueName, 0, REG_SZ,
pFileName, DataSize);
@@ -1648,6 +1724,177 @@ IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD
Characteristics)
return FontCount;
}
+INT FASTCALL
+IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics)
+{
+ return IntGdiAddFontResourceEx(FileName, Characteristics, 0);
+}
+
+/* Borrowed from shlwapi!PathIsRelativeW */
+BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
+{
+ if (!lpszPath || !*lpszPath)
+ return TRUE;
+ if (*lpszPath == L'\\' || (*lpszPath && lpszPath[1] ==
L':'))
+ return FALSE;
+ return TRUE;
+}
+
+BOOL FASTCALL
+IntLoadFontsInRegistry(VOID)
+{
+ NTSTATUS Status;
+ HANDLE KeyHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ KEY_FULL_INFORMATION KeyFullInfo;
+ ULONG i, Length;
+ UNICODE_STRING FontTitleW, FileNameW;
+ SIZE_T InfoSize;
+ LPBYTE InfoBuffer;
+ PKEY_VALUE_FULL_INFORMATION pInfo;
+ LPWSTR pchPath;
+ BOOLEAN Success;
+ WCHAR szPath[MAX_PATH];
+ INT nFontCount = 0;
+ DWORD dwFlags;
+
+ /* open registry key */
+ InitializeObjectAttributes(&ObjectAttributes, &g_FontRegPath,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL, NULL);
+ Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwOpenKey failed: 0x%08X\n", Status);
+ return FALSE; /* failure */
+ }
+
+ /* query count of values */
+ Status = ZwQueryKey(KeyHandle, KeyFullInformation,
+ &KeyFullInfo, sizeof(KeyFullInfo), &Length);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwQueryKey failed: 0x%08X\n", Status);
+ ZwClose(KeyHandle);
+ return FALSE; /* failure */
+ }
+
+ /* allocate buffer */
+ InfoSize = (MAX_PATH + 256) * sizeof(WCHAR);
+ InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
+ if (!InfoBuffer)
+ {
+ DPRINT1("ExAllocatePoolWithTag failed\n");
+ ZwClose(KeyHandle);
+ return FALSE;
+ }
+
+ /* for each value */
+ for (i = 0; i < KeyFullInfo.Values; ++i)
+ {
+ /* get value name */
+ Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
+ InfoBuffer, InfoSize, &Length);
+ if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* too short buffer */
+ ExFreePoolWithTag(InfoBuffer, TAG_FONT);
+ InfoSize *= 2;
+ InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
+ if (!InfoBuffer)
+ {
+ DPRINT1("ExAllocatePoolWithTag failed\n");
+ break;
+ }
+ /* try again */
+ Status = ZwEnumerateValueKey(KeyHandle, i, KeyValueFullInformation,
+ InfoBuffer, InfoSize, &Length);
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwEnumerateValueKey failed: 0x%08X\n", Status);
+ break; /* failure */
+ }
+
+ /* create FontTitleW string */
+ pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
+ Length = pInfo->NameLength / sizeof(WCHAR);
+ pInfo->Name[Length] = UNICODE_NULL; /* truncate */
+ Success = RtlCreateUnicodeString(&FontTitleW, pInfo->Name);
+ if (!Success)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ DPRINT("RtlCreateUnicodeString failed\n");
+ break; /* failure */
+ }
+
+ /* query value */
+ Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
+ InfoBuffer, InfoSize, &Length);
+ if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* too short buffer */
+ ExFreePoolWithTag(InfoBuffer, TAG_FONT);
+ InfoSize *= 2;
+ InfoBuffer = ExAllocatePoolWithTag(PagedPool, InfoSize, TAG_FONT);
+ if (!InfoBuffer)
+ {
+ DPRINT1("ExAllocatePoolWithTag failed\n");
+ break;
+ }
+ /* try again */
+ Status = ZwQueryValueKey(KeyHandle, &FontTitleW, KeyValueFullInformation,
+ InfoBuffer, InfoSize, &Length);
+ }
+ pInfo = (PKEY_VALUE_FULL_INFORMATION)InfoBuffer;
+ if (!NT_SUCCESS(Status) || !pInfo->DataLength)
+ {
+ DPRINT("ZwQueryValueKey failed: 0x%08X\n", Status);
+ RtlFreeUnicodeString(&FontTitleW);
+ break; /* failure */
+ }
+
+ /* Build pchPath */
+ pchPath = (LPWSTR)((PUCHAR)pInfo + pInfo->DataOffset);
+ Length = pInfo->DataLength / sizeof(WCHAR);
+ pchPath[Length] = UNICODE_NULL; /* truncate */
+
+ /* Load font(s) without writing registry */
+ dwFlags = 0;
+ if (PathIsRelativeW(pchPath))
+ {
+ Status = RtlStringCbPrintfW(szPath, sizeof(szPath),
+ L"%s\\Fonts\\%s",
+ SharedUserData->NtSystemRoot, pchPath);
+ }
+ else
+ {
+ dwFlags |= AFRX_ALTERNATIVE_PATH;
+ Status = RtlStringCbCopyW(szPath, sizeof(szPath), pchPath);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ RtlCreateUnicodeString(&FileNameW, szPath);
+ nFontCount += IntGdiAddFontResourceEx(&FileNameW, 0, dwFlags);
+ RtlFreeUnicodeString(&FileNameW);
+ }
+
+ RtlFreeUnicodeString(&FontTitleW);
+ }
+
+ /* close now */
+ ZwClose(KeyHandle);
+
+ /* free memory block */
+ if (InfoBuffer)
+ {
+ ExFreePoolWithTag(InfoBuffer, TAG_FONT);
+ }
+
+ return (KeyFullInfo.Values != 0 && nFontCount != 0);
+}
+
HANDLE FASTCALL
IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded)
{
diff --git a/win32ss/gdi/ntgdi/text.h b/win32ss/gdi/ntgdi/text.h
index 830ceb11009..10a74c60032 100644
--- a/win32ss/gdi/ntgdi/text.h
+++ b/win32ss/gdi/ntgdi/text.h
@@ -100,6 +100,9 @@ TEXTOBJ_UnlockText(PLFONT plfnt)
LFONT_ShareUnlockFont(plfnt);
}
+/* dwFlags for IntGdiAddFontResourceEx */
+#define AFRX_WRITE_REGISTRY 0x1
+#define AFRX_ALTERNATIVE_PATH 0x2
PTEXTOBJ FASTCALL RealizeFontInit(HFONT);
NTSTATUS FASTCALL TextIntRealizeFont(HFONT,PTEXTOBJ);
@@ -111,8 +114,11 @@ BOOL FASTCALL IntIsFontRenderingEnabled(VOID);
VOID FASTCALL IntEnableFontRendering(BOOL Enable);
ULONG FASTCALL FontGetObject(PTEXTOBJ TextObj, ULONG Count, PVOID Buffer);
VOID FASTCALL IntLoadSystemFonts(VOID);
+BOOL FASTCALL IntLoadFontsInRegistry(VOID);
VOID FASTCALL IntGdiCleanupPrivateFontsForProcess(VOID);
INT FASTCALL IntGdiAddFontResource(PUNICODE_STRING FileName, DWORD Characteristics);
+INT FASTCALL IntGdiAddFontResourceEx(PUNICODE_STRING FileName, DWORD Characteristics,
+ DWORD dwFlags);
HANDLE FASTCALL IntGdiAddFontMemResource(PVOID Buffer, DWORD dwSize, PDWORD pNumAdded);
BOOL FASTCALL IntGdiRemoveFontMemResource(HANDLE hMMFont);
ULONG FASTCALL
ftGdiGetGlyphOutline(PDC,WCHAR,UINT,LPGLYPHMETRICS,ULONG,PVOID,LPMAT2,BOOL);