From 811faed421a798659af3cb3f09369af84fc4edf0 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Thu, 11 Apr 2019 11:46:52 +0900 Subject: [PATCH] [GDI32][NTGDI][SETUP] Fix font enumeration part 2 (#1492) Eliminate some bugs about font enumeration. CORE-15755 - Add "Microsoft Sans Serif" font substitution. - Fix and improve the treatment of the nominal font names. - Split IntGetFontFamilyInfo function from NtGdiGetFontFamilyInfo. - Add DoFontSystemUnittest function for font system unittest to GDI32. - Call DoFontSystemUnittest function at CreateFontIndirectW first call. --- base/setup/lib/muifonts.h | 10 ++ boot/bootdata/livecd.inf | 1 + win32ss/gdi/gdi32/objects/font.c | 140 +++++++++++++++++++---- win32ss/gdi/ntgdi/freetype.c | 190 ++++++++++++++++++++----------- win32ss/include/ntgdibad.h | 7 +- 5 files changed, 252 insertions(+), 96 deletions(-) diff --git a/base/setup/lib/muifonts.h b/base/setup/lib/muifonts.h index 72292afc466..826d512bdc1 100644 --- a/base/setup/lib/muifonts.h +++ b/base/setup/lib/muifonts.h @@ -11,6 +11,7 @@ MUI_SUBFONT LatinFonts[] = { L"Helv", L"Tahoma" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"Tahoma" }, { L"MS Sans Serif", L"Tahoma" }, { L"MS Shell Dlg", L"Tahoma" }, { L"MS Shell Dlg 2", L"Tahoma" }, @@ -37,6 +38,7 @@ MUI_SUBFONT CyrillicFonts[] = { L"Helv", L"Tahoma" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"Tahoma" }, { L"MS Sans Serif", L"Tahoma" }, { L"MS Shell Dlg", L"Tahoma" }, { L"MS Shell Dlg 2", L"Tahoma" }, @@ -63,6 +65,7 @@ MUI_SUBFONT GreekFonts[] = { L"Helv", L"DejaVu Sans" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"DejaVu Sans" }, { L"MS Sans Serif", L"DejaVu Sans" }, { L"MS Shell Dlg", L"DejaVu Sans" }, { L"MS Shell Dlg 2", L"DejaVu Sans" }, @@ -89,6 +92,7 @@ MUI_SUBFONT HebrewFonts[] = { L"Helv", L"Tahoma" }, { L"Helvetica", L"Tahoma" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"Tahoma" }, { L"MS Sans Serif", L"Tahoma" }, { L"MS Shell Dlg", L"Tahoma" }, { L"MS Shell Dlg 2", L"Tahoma" }, @@ -121,6 +125,7 @@ MUI_SUBFONT ChineseSimplifiedFonts[] = { L"Helv", L"Droid Sans Fallback" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"Droid Sans Fallback" }, { L"MS Sans Serif", L"Droid Sans Fallback" }, { L"MS Shell Dlg", L"Droid Sans Fallback" }, { L"MS Shell Dlg 2", L"Droid Sans Fallback" }, @@ -163,6 +168,7 @@ MUI_SUBFONT ChineseTraditionalFonts[] = { L"Helv", L"Droid Sans Fallback" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"Droid Sans Fallback" }, { L"MS Sans Serif", L"Droid Sans Fallback" }, { L"MS Shell Dlg", L"Droid Sans Fallback" }, { L"MS Shell Dlg 2", L"Droid Sans Fallback" }, @@ -206,6 +212,7 @@ MUI_SUBFONT JapaneseFonts[] = { L"Helv", L"Droid Sans Fallback" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"Droid Sans Fallback" }, { L"MS Sans Serif", L"Droid Sans Fallback" }, { L"MS Shell Dlg", L"Droid Sans Fallback" }, { L"MS Shell Dlg 2", L"Droid Sans Fallback" }, @@ -250,6 +257,7 @@ MUI_SUBFONT KoreanFonts[] = { L"Helv", L"Droid Sans Fallback" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"Droid Sans Fallback" }, { L"MS Sans Serif", L"Droid Sans Fallback" }, { L"MS Shell Dlg", L"Droid Sans Fallback" }, { L"MS Shell Dlg 2", L"Droid Sans Fallback" }, @@ -293,6 +301,7 @@ MUI_SUBFONT UnicodeFonts[] = { L"Helv", L"DejaVu Sans" }, { L"Helvetica", L"DejaVu Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"DejaVu Sans" }, { L"MS Sans Serif", L"DejaVu Sans" }, { L"MS Shell Dlg", L"DejaVu Sans" }, { L"MS Shell Dlg 2", L"DejaVu Sans" }, @@ -320,6 +329,7 @@ MUI_SUBFONT HindiFonts[] = { L"Helv", L"Tahoma" }, { L"Helvetica", L"Liberation Sans" }, { L"Lucida Console", L"DejaVu Sans Mono" }, + { L"Microsoft Sans Serif", L"FreeSans" }, { L"MS Sans Serif", L"FreeSans" }, { L"MS Shell Dlg", L"FreeSans" }, { L"MS Shell Dlg 2", L"FreeSans" }, diff --git a/boot/bootdata/livecd.inf b/boot/bootdata/livecd.inf index fda2356a978..dd44f0ed533 100644 --- a/boot/bootdata/livecd.inf +++ b/boot/bootdata/livecd.inf @@ -50,6 +50,7 @@ HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Fixedsys",0 HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Helv",0x00000000,"Tahoma" HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Helvetica",0x00000000,"Liberation Sans" HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Lucida Console",0x00000000,"DejaVu Sans Mono" +HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Microsoft Sans Serif",0x00000000,"Tahoma" HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS Sans Serif",0x00000000,"Tahoma" HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS Shell Dlg",0x00000000,"Tahoma" HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS Shell Dlg 2",0x00000000,"Tahoma" diff --git a/win32ss/gdi/gdi32/objects/font.c b/win32ss/gdi/gdi32/objects/font.c index 2f187b0edbc..e20c0702fb9 100644 --- a/win32ss/gdi/gdi32/objects/font.c +++ b/win32ss/gdi/gdi32/objects/font.c @@ -218,6 +218,13 @@ IntFontFamilyCompareEx(const FONTFAMILYINFO *ffi1, int cmp = _wcsicmp(plf1->lfFaceName, plf2->lfFaceName); if (cmp) return cmp; + if (dwCompareFlags & IFFCX_CHARSET) + { + if (plf1->lfCharSet < plf2->lfCharSet) + return -1; + if (plf1->lfCharSet > plf2->lfCharSet) + return 1; + } if (dwCompareFlags & IFFCX_STYLE) { WeightDiff1 = labs(plf1->lfWeight - FW_NORMAL); @@ -231,13 +238,6 @@ IntFontFamilyCompareEx(const FONTFAMILYINFO *ffi1, if (plf1->lfItalic > plf2->lfItalic) return 1; } - if (dwCompareFlags & IFFCX_CHARSET) - { - if (plf1->lfCharSet < plf2->lfCharSet) - return -1; - if (plf1->lfCharSet > plf2->lfCharSet) - return 1; - } return 0; } @@ -267,7 +267,7 @@ IntFontFamilyListUnique(FONTFAMILYINFO *InfoList, INT nCount, first = InfoList; last = &InfoList[nCount]; - // std::unique(first, last, IntFontFamilyCompareEx); + /* std::unique(first, last, IntFontFamilyCompareEx); */ if (first == last) return 0; @@ -285,60 +285,70 @@ IntFontFamilyListUnique(FONTFAMILYINFO *InfoList, INT nCount, } static int FASTCALL -IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam, +IntEnumFontFamilies(HDC Dc, const LOGFONTW *LogFont, PVOID EnumProc, LPARAM lParam, DWORD dwFlags) { int FontFamilyCount; - int FontFamilySize; PFONTFAMILYINFO Info; int Ret = 1; int i; ENUMLOGFONTEXA EnumLogFontExA; NEWTEXTMETRICEXA NewTextMetricExA; LOGFONTW lfW; + LONG DataSize, InfoCount; - Info = RtlAllocateHeap(GetProcessHeap(), 0, - INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO)); - if (NULL == Info) + DataSize = INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO); + Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize); + if (Info == NULL) { return 1; } + /* Initialize the LOGFONT structure */ + ZeroMemory(&lfW, sizeof(lfW)); if (!LogFont) { lfW.lfCharSet = DEFAULT_CHARSET; - lfW.lfPitchAndFamily = 0; - lfW.lfFaceName[0] = 0; - LogFont = &lfW; + } + else + { + lfW.lfCharSet = LogFont->lfCharSet; + lfW.lfPitchAndFamily = LogFont->lfPitchAndFamily; + StringCbCopyW(lfW.lfFaceName, sizeof(lfW.lfFaceName), LogFont->lfFaceName); } - FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT); + /* Retrieve the font information */ + InfoCount = INITIAL_FAMILY_COUNT; + FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount); if (FontFamilyCount < 0) { RtlFreeHeap(GetProcessHeap(), 0, Info); return 1; } - if (INITIAL_FAMILY_COUNT < FontFamilyCount) + + /* Resize the buffer if the buffer is too small */ + if (INITIAL_FAMILY_COUNT < InfoCount) { - FontFamilySize = FontFamilyCount; RtlFreeHeap(GetProcessHeap(), 0, Info); - Info = RtlAllocateHeap(GetProcessHeap(), 0, - FontFamilyCount * sizeof(FONTFAMILYINFO)); - if (NULL == Info) + DataSize = InfoCount * sizeof(FONTFAMILYINFO); + Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize); + if (Info == NULL) { return 1; } - FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize); - if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount) + FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount); + if (FontFamilyCount < 0 || FontFamilyCount < InfoCount) { RtlFreeHeap(GetProcessHeap(), 0, Info); return 1; } } + /* Sort and remove redundant information */ qsort(Info, FontFamilyCount, sizeof(*Info), IntFontFamilyCompare); - FontFamilyCount = IntFontFamilyListUnique(Info, FontFamilyCount, LogFont, dwFlags); + FontFamilyCount = IntFontFamilyListUnique(Info, FontFamilyCount, &lfW, dwFlags); + /* call the callback */ for (i = 0; i < FontFamilyCount; i++) { if (dwFlags & IEFF_UNICODE) @@ -1693,6 +1703,78 @@ CreateFontIndirectA( } +#if DBG +VOID DumpFamilyInfo(const FONTFAMILYINFO *Info, LONG Count) +{ + LONG i; + const LOGFONTW *plf; + + DPRINT1("---\n"); + DPRINT1("Count: %d\n", Count); + for (i = 0; i < Count; ++i) + { + plf = &Info[i].EnumLogFontEx.elfLogFont; + DPRINT1("%d: '%S',%u,'%S', %ld:%ld, %ld, %d, %d\n", i, + plf->lfFaceName, plf->lfCharSet, Info[i].EnumLogFontEx.elfFullName, + plf->lfHeight, plf->lfWidth, plf->lfWeight, plf->lfItalic, plf->lfPitchAndFamily); + } +} + +VOID DoFontSystemUnittest(VOID) +{ + LOGFONTW LogFont; + FONTFAMILYINFO Info[4]; + UNICODE_STRING Str1, Str2; + LONG ret, InfoCount; + + //DumpFontInfo(TRUE); + + /* L"" DEFAULT_CHARSET */ + RtlZeroMemory(&LogFont, sizeof(LogFont)); + LogFont.lfCharSet = DEFAULT_CHARSET; + InfoCount = RTL_NUMBER_OF(Info); + ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount); + DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount); + DumpFamilyInfo(Info, ret); + ASSERT(ret == RTL_NUMBER_OF(Info)); + ASSERT(InfoCount > 32); + + /* L"Microsoft Sans Serif" ANSI_CHARSET */ + RtlZeroMemory(&LogFont, sizeof(LogFont)); + LogFont.lfCharSet = ANSI_CHARSET; + StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Microsoft Sans Serif"); + InfoCount = RTL_NUMBER_OF(Info); + ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount); + DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount); + DumpFamilyInfo(Info, ret); + ASSERT(ret != -1); + ASSERT(InfoCount > 0); + ASSERT(InfoCount < 16); + + RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfLogFont.lfFaceName); + RtlInitUnicodeString(&Str2, L"Microsoft Sans Serif"); + ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE); + ASSERT(ret == 0); + + RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfFullName); + RtlInitUnicodeString(&Str2, L"Tahoma"); + ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE); + ASSERT(ret == 0); + + /* L"Non-Existent" DEFAULT_CHARSET */ + RtlZeroMemory(&LogFont, sizeof(LogFont)); + LogFont.lfCharSet = ANSI_CHARSET; + StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Non-Existent"); + InfoCount = RTL_NUMBER_OF(Info); + ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount); + DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount); + DumpFamilyInfo(Info, ret); + ASSERT(ret == 0); + ASSERT(InfoCount == 0); +} +#endif + +/* EOF */ /* * @implemented */ @@ -1702,6 +1784,14 @@ CreateFontIndirectW( CONST LOGFONTW *lplf ) { +#if DBG + static BOOL bDidTest = FALSE; + if (!bDidTest) + { + DoFontSystemUnittest(); + bDidTest = TRUE; + } +#endif if (lplf) { ENUMLOGFONTEXDVW Logfont; diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index a5f93e92c8f..298c1fa12ca 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -2675,18 +2675,18 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName, } static BOOLEAN FASTCALL -GetFontFamilyInfoForList(LPLOGFONTW LogFont, +GetFontFamilyInfoForList(const LOGFONTW *LogFont, PFONTFAMILYINFO Info, LPCWSTR NominalName, - DWORD *pCount, - DWORD MaxCount, + LONG *pCount, + LONG MaxCount, PLIST_ENTRY Head) { PLIST_ENTRY Entry; PFONT_ENTRY CurrentEntry; FONTGDI *FontGDI; FONTFAMILYINFO InfoEntry; - DWORD Count = *pCount; + LONG Count = *pCount; for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { @@ -2697,29 +2697,15 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont, if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != FontGDI->CharSet) { - continue; + continue; /* charset mismatch */ } - if (LogFont->lfFaceName[0] == UNICODE_NULL) - { - if (Count < MaxCount) - { - FontFamilyFillInfo(&Info[Count], NominalName, NULL, FontGDI); - } - Count++; - continue; - } + /* get one info entry */ + FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI); - FontFamilyFillInfo(&InfoEntry, NominalName, NULL, FontGDI); - - if (NominalName) - { - RtlStringCchCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, - RTL_NUMBER_OF(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName), - NominalName); - } - else + if (LogFont->lfFaceName[0] != UNICODE_NULL) { + /* check name */ if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 && @@ -2731,7 +2717,16 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont, } } - if (Count < MaxCount) + if (NominalName) + { + /* store the nominal name */ + RtlStringCbCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, + sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName), + NominalName); + } + + /* store one entry to Info */ + if (0 <= Count && Count < MaxCount) { RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry)); } @@ -2744,10 +2739,10 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont, } static BOOLEAN FASTCALL -GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, +GetFontFamilyInfoForSubstitutes(const LOGFONTW *LogFont, PFONTFAMILYINFO Info, - DWORD *pCount, - DWORD MaxCount) + LONG *pCount, + LONG MaxCount) { PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead; PFONTSUBST_ENTRY pCurrentEntry; @@ -2762,6 +2757,7 @@ GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM]; if (LogFont->lfFaceName[0] != UNICODE_NULL) { + /* check name */ if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0) continue; /* mismatch */ } @@ -2771,18 +2767,22 @@ GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, pCurrentEntry->CharSets[FONTSUBST_FROM] == pCurrentEntry->CharSets[FONTSUBST_TO]) { + /* identical mapping */ continue; } + /* substitute and get the real name */ IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW); SubstituteFontRecurse(&lf); if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet) continue; + /* search in global fonts */ IntLockGlobalFonts(); GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead); IntUnLockGlobalFonts(); + /* search in private fonts */ IntLockProcessPrivateFonts(Win32Process); GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &Win32Process->PrivateFontListHead); @@ -5407,41 +5407,22 @@ ftGdiGetKerningPairs( PFONTGDI Font, // Functions needing sorting. // /////////////////////////////////////////////////////////////////////////// -int APIENTRY -NtGdiGetFontFamilyInfo(HDC Dc, - LPLOGFONTW UnsafeLogFont, - PFONTFAMILYINFO UnsafeInfo, - DWORD Size) + +LONG FASTCALL +IntGetFontFamilyInfo(HDC Dc, + const LOGFONTW *SafeLogFont, + PFONTFAMILYINFO SafeInfo, + LONG InfoCount) { - NTSTATUS Status; - LOGFONTW LogFont; - PFONTFAMILYINFO Info; - DWORD Count; + LONG AvailCount = 0; PPROCESSINFO Win32Process; - /* Make a safe copy */ - Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW)); - if (! NT_SUCCESS(Status)) - { - EngSetLastError(ERROR_INVALID_PARAMETER); - return -1; - } - - /* Allocate space for a safe copy */ - Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), GDITAG_TEXT); - if (NULL == Info) - { - EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); - return -1; - } - /* Enumerate font families in the global list */ IntLockGlobalFonts(); - Count = 0; - if (! GetFontFamilyInfoForList(&LogFont, Info, NULL, &Count, Size, &g_FontListHead) ) + if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount, + InfoCount, &g_FontListHead)) { IntUnLockGlobalFonts(); - ExFreePoolWithTag(Info, GDITAG_TEXT); return -1; } IntUnLockGlobalFonts(); @@ -5449,28 +5430,103 @@ NtGdiGetFontFamilyInfo(HDC Dc, /* Enumerate font families in the process local list */ Win32Process = PsGetCurrentProcessWin32Process(); IntLockProcessPrivateFonts(Win32Process); - if (! GetFontFamilyInfoForList(&LogFont, Info, NULL, &Count, Size, - &Win32Process->PrivateFontListHead)) + if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount, InfoCount, + &Win32Process->PrivateFontListHead)) { IntUnLockProcessPrivateFonts(Win32Process); - ExFreePoolWithTag(Info, GDITAG_TEXT); return -1; } IntUnLockProcessPrivateFonts(Win32Process); /* Enumerate font families in the registry */ - if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size)) + if (!GetFontFamilyInfoForSubstitutes(SafeLogFont, SafeInfo, &AvailCount, InfoCount)) { - ExFreePoolWithTag(Info, GDITAG_TEXT); return -1; } - /* Return data to caller */ - if (0 != Count) + return AvailCount; +} + +LONG NTAPI +NtGdiGetFontFamilyInfo(HDC Dc, + const LOGFONTW *UnsafeLogFont, + PFONTFAMILYINFO UnsafeInfo, + LPLONG UnsafeInfoCount) +{ + NTSTATUS Status; + LOGFONTW LogFont; + PFONTFAMILYINFO Info; + LONG GotCount, AvailCount, DataSize, SafeInfoCount; + + if (UnsafeLogFont == NULL || UnsafeInfo == NULL || UnsafeInfoCount == NULL) { - Status = MmCopyToCaller(UnsafeInfo, Info, - (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO)); - if (! NT_SUCCESS(Status)) + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + + Status = MmCopyFromCaller(&SafeInfoCount, UnsafeInfoCount, sizeof(SafeInfoCount)); + if (!NT_SUCCESS(Status)) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + GotCount = 0; + Status = MmCopyToCaller(UnsafeInfoCount, &GotCount, sizeof(*UnsafeInfoCount)); + if (!NT_SUCCESS(Status)) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW)); + if (!NT_SUCCESS(Status)) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + if (SafeInfoCount <= 0) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + + /* Allocate space for a safe copy */ + DataSize = SafeInfoCount * sizeof(FONTFAMILYINFO); + if (DataSize <= 0) + { + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + Info = ExAllocatePoolWithTag(PagedPool, DataSize, GDITAG_TEXT); + if (Info == NULL) + { + EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); + return -1; + } + + /* Retrieve the information */ + AvailCount = IntGetFontFamilyInfo(Dc, &LogFont, Info, SafeInfoCount); + GotCount = min(AvailCount, SafeInfoCount); + SafeInfoCount = AvailCount; + + /* Return data to caller */ + if (GotCount > 0) + { + DataSize = GotCount * sizeof(FONTFAMILYINFO); + if (DataSize <= 0) + { + ExFreePoolWithTag(Info, GDITAG_TEXT); + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + Status = MmCopyToCaller(UnsafeInfo, Info, DataSize); + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(Info, GDITAG_TEXT); + EngSetLastError(ERROR_INVALID_PARAMETER); + return -1; + } + Status = MmCopyToCaller(UnsafeInfoCount, &SafeInfoCount, sizeof(*UnsafeInfoCount)); + if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(Info, GDITAG_TEXT); EngSetLastError(ERROR_INVALID_PARAMETER); @@ -5480,7 +5536,7 @@ NtGdiGetFontFamilyInfo(HDC Dc, ExFreePoolWithTag(Info, GDITAG_TEXT); - return Count; + return GotCount; } FORCEINLINE @@ -6618,7 +6674,7 @@ NtGdiGetCharABCWidthsW( if(Safepwch) ExFreePoolWithTag(Safepwch , GDITAG_TEXT); - if (! NT_SUCCESS(Status)) + if (!NT_SUCCESS(Status)) { SetLastNtError(Status); return FALSE; diff --git a/win32ss/include/ntgdibad.h b/win32ss/include/ntgdibad.h index ba8588f2f96..58d644e68e9 100644 --- a/win32ss/include/ntgdibad.h +++ b/win32ss/include/ntgdibad.h @@ -50,14 +50,13 @@ typedef struct tagFONTFAMILYINFO } FONTFAMILYINFO, *PFONTFAMILYINFO; /* Should be using NtGdiEnumFontChunk */ -INT +LONG NTAPI NtGdiGetFontFamilyInfo( HDC Dc, - LPLOGFONTW LogFont, + const LOGFONTW *LogFont, PFONTFAMILYINFO Info, - DWORD Size -); + LPLONG UnsafeInfoCount); /* Use NtGdiGetDCPoint with GdiGetViewPortExt */ BOOL APIENTRY NtGdiGetViewportExtEx(HDC hDC, LPSIZE viewportExt);