[0.4.9][WIN32SS] Fix regression CORE-15558 Font enumeration

Fixes CORE-15558 "AbiWord font listbox should display a specific font only once, but displays each of them many times instead"
which regressed by SVN r75491 == 0.4.7-dev-32-g d10c0ec112

by porting back the commits:
0.4.12-dev-320-g 6e4e5a004c
and
0.4.13-dev-107-g ae8417fd90 to prevent introducing another regression CORE_15785 with the initial fix.
and some more addendums to prevent introducing regression CORE_15755

I verified afterwards that all 3 issues: CORE-15558, CORE_15785 and CORE_15755 are in fixed state.

Actually I don't really like the resulting code due to the qsort() that it introduces into
win32ss/gdi/gdi32/objects/font.c
We did not need that at all before 0.4.7-dev-32-g d10c0ec112
In case that qsort() would ever reveal any new trouble like reduced performance or stack overflow,
we should structurally revert all that context to 0.4.7-dev-31 instead.
IntEnumFontFamilies() is called immediately upon process initialization for many applications and the qsorted-list is *huge*,
so this indeed could be relevant for performance.
This commit is contained in:
Joachim Henze 2020-12-31 22:10:01 +01:00
parent cbd0b79f8a
commit 9be0765be1
4 changed files with 307 additions and 234 deletions

View file

@ -58,5 +58,6 @@
#include <ntgdibad.h> #include <ntgdibad.h>
#include <undocgdi.h> #include <undocgdi.h>
#include <ntintsafe.h>
#endif /* _GDI32_PCH_ */ #endif /* _GDI32_PCH_ */

View file

@ -204,61 +204,162 @@ NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
tma->ntmFontSig = tmw->ntmFontSig; tma->ntmFontSig = tmw->ntmFontSig;
} }
// IntFontFamilyCompareEx's flags
#define IFFCX_CHARSET 1
#define IFFCX_STYLE 2
FORCEINLINE int FASTCALL
IntFontFamilyCompareEx(const FONTFAMILYINFO *ffi1,
const FONTFAMILYINFO *ffi2, DWORD dwCompareFlags)
{
const LOGFONTW *plf1 = &ffi1->EnumLogFontEx.elfLogFont;
const LOGFONTW *plf2 = &ffi2->EnumLogFontEx.elfLogFont;
ULONG WeightDiff1, WeightDiff2;
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);
WeightDiff2 = labs(plf2->lfWeight - FW_NORMAL);
if (WeightDiff1 < WeightDiff2)
return -1;
if (WeightDiff1 > WeightDiff2)
return 1;
if (plf1->lfItalic < plf2->lfItalic)
return -1;
if (plf1->lfItalic > plf2->lfItalic)
return 1;
}
return 0;
}
static int __cdecl
IntFontFamilyCompare(const void *ffi1, const void *ffi2)
{
return IntFontFamilyCompareEx(ffi1, ffi2, IFFCX_STYLE | IFFCX_CHARSET);
}
// IntEnumFontFamilies' flags:
#define IEFF_UNICODE 1
#define IEFF_EXTENDED 2
int FASTCALL
IntFontFamilyListUnique(FONTFAMILYINFO *InfoList, INT nCount,
const LOGFONTW *plf, DWORD dwFlags)
{
FONTFAMILYINFO *first, *last, *result;
DWORD dwCompareFlags = 0;
if (plf->lfFaceName[0])
dwCompareFlags |= IFFCX_STYLE;
if ((dwFlags & IEFF_EXTENDED) && plf->lfCharSet == DEFAULT_CHARSET)
dwCompareFlags |= IFFCX_CHARSET;
first = InfoList;
last = &InfoList[nCount];
/* std::unique(first, last, IntFontFamilyCompareEx); */
if (first == last)
return 0;
result = first;
while (++first != last)
{
if (IntFontFamilyCompareEx(result, first, dwCompareFlags) != 0)
{
*(++result) = *first;
}
}
nCount = (int)(++result - InfoList);
return nCount;
}
static int FASTCALL static int FASTCALL
IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam, IntEnumFontFamilies(HDC Dc, const LOGFONTW *LogFont, PVOID EnumProc, LPARAM lParam,
BOOL Unicode) DWORD dwFlags)
{ {
int FontFamilyCount; int FontFamilyCount;
int FontFamilySize;
PFONTFAMILYINFO Info; PFONTFAMILYINFO Info;
int Ret = 1; int Ret = 1;
int i; int i;
ENUMLOGFONTEXA EnumLogFontExA; ENUMLOGFONTEXA EnumLogFontExA;
NEWTEXTMETRICEXA NewTextMetricExA; NEWTEXTMETRICEXA NewTextMetricExA;
LOGFONTW lfW; LOGFONTW lfW;
LONG InfoCount;
ULONG DataSize;
NTSTATUS Status;
Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize = INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO);
INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO)); Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
if (NULL == Info) if (Info == NULL)
{ {
return 1; return 1;
} }
/* Initialize the LOGFONT structure */
ZeroMemory(&lfW, sizeof(lfW));
if (!LogFont) if (!LogFont)
{ {
lfW.lfCharSet = DEFAULT_CHARSET; lfW.lfCharSet = DEFAULT_CHARSET;
lfW.lfPitchAndFamily = 0; }
lfW.lfFaceName[0] = 0; else
LogFont = &lfW; {
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) if (FontFamilyCount < 0)
{ {
RtlFreeHeap(GetProcessHeap(), 0, Info); RtlFreeHeap(GetProcessHeap(), 0, Info);
return 1; 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); RtlFreeHeap(GetProcessHeap(), 0, Info);
Info = RtlAllocateHeap(GetProcessHeap(), 0,
FontFamilyCount * sizeof(FONTFAMILYINFO)); Status = RtlULongMult(InfoCount, sizeof(FONTFAMILYINFO), &DataSize);
if (NULL == Info) if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
{
DPRINT1("Overflowed.\n");
return 1;
}
Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
if (Info == NULL)
{ {
return 1; return 1;
} }
FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize); FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount);
if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount) if (FontFamilyCount < 0 || FontFamilyCount < InfoCount)
{ {
RtlFreeHeap(GetProcessHeap(), 0, Info); RtlFreeHeap(GetProcessHeap(), 0, Info);
return 1; return 1;
} }
} }
/* Sort and remove redundant information */
qsort(Info, FontFamilyCount, sizeof(*Info), IntFontFamilyCompare);
FontFamilyCount = IntFontFamilyListUnique(Info, FontFamilyCount, &lfW, dwFlags);
/* call the callback */
for (i = 0; i < FontFamilyCount; i++) for (i = 0; i < FontFamilyCount; i++)
{ {
if (Unicode) if (dwFlags & IEFF_UNICODE)
{ {
Ret = ((FONTENUMPROCW) EnumProc)( Ret = ((FONTENUMPROCW) EnumProc)(
(VOID*)&Info[i].EnumLogFontEx, (VOID*)&Info[i].EnumLogFontEx,
@ -299,7 +400,8 @@ int WINAPI
EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc, EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
LPARAM lParam, DWORD dwFlags) LPARAM lParam, DWORD dwFlags)
{ {
return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE); return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam,
IEFF_UNICODE | IEFF_EXTENDED);
} }
@ -320,7 +422,7 @@ EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE); lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
} }
return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE); return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, IEFF_UNICODE);
} }
@ -341,7 +443,7 @@ EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamE
else pLogFontW = NULL; else pLogFontW = NULL;
/* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */ /* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, FALSE); return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, IEFF_EXTENDED);
} }
@ -362,7 +464,7 @@ EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE); MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
} }
return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, FALSE); return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, 0);
} }

View file

@ -577,6 +577,21 @@ SubstituteFontByList(PLIST_ENTRY pHead,
return FALSE; return FALSE;
} }
static VOID
IntUnicodeStringToBuffer(LPWSTR pszBuffer, USHORT cbBuffer, const UNICODE_STRING *pString)
{
USHORT cbLength = pString->Length;
if (cbBuffer < sizeof(UNICODE_NULL))
return;
if (cbLength > cbBuffer - sizeof(UNICODE_NULL))
cbLength = cbBuffer - sizeof(UNICODE_NULL);
RtlCopyMemory(pszBuffer, pString->Buffer, cbLength);
pszBuffer[cbLength / sizeof(WCHAR)] = UNICODE_NULL;
}
static BOOL static BOOL
SubstituteFontRecurse(LOGFONTW* pLogFont) SubstituteFontRecurse(LOGFONTW* pLogFont)
{ {
@ -599,7 +614,7 @@ SubstituteFontRecurse(LOGFONTW* pLogFont)
if (!Found) if (!Found)
break; break;
RtlStringCchCopyW(pLogFont->lfFaceName, LF_FACESIZE, OutputNameW.Buffer); IntUnicodeStringToBuffer(pLogFont->lfFaceName, sizeof(pLogFont->lfFaceName), &OutputNameW);
if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET || if (CharSetMap[FONTSUBST_FROM] == DEFAULT_CHARSET ||
CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet) CharSetMap[FONTSUBST_FROM] == pLogFont->lfCharSet)
@ -870,6 +885,7 @@ IntGdiLoadFontsFromMemory(PGDI_LOAD_FONT pLoadFont,
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0; /* failure */ return 0; /* failure */
} }
RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length); RtlCopyMemory(FontGDI->Filename, pFileName->Buffer, pFileName->Length);
FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL; FontGDI->Filename[pFileName->Length / sizeof(WCHAR)] = UNICODE_NULL;
} }
@ -1966,75 +1982,6 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
return Cache->OutlineRequiredSize; return Cache->OutlineRequiredSize;
} }
static PFONTGDI FASTCALL
FindFaceNameInList(PUNICODE_STRING FaceName, PLIST_ENTRY Head)
{
PLIST_ENTRY Entry;
PFONT_ENTRY CurrentEntry;
ANSI_STRING EntryFaceNameA;
UNICODE_STRING EntryFaceNameW;
FONTGDI *FontGDI;
NTSTATUS status;
Entry = Head->Flink;
while (Entry != Head)
{
CurrentEntry = CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
FontGDI = CurrentEntry->Font;
ASSERT(FontGDI);
RtlInitAnsiString(&EntryFaceNameA, FontGDI->SharedFace->Face->family_name);
status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
if (!NT_SUCCESS(status))
{
break;
}
if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
{
EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
}
if (RtlEqualUnicodeString(FaceName, &EntryFaceNameW, TRUE))
{
RtlFreeUnicodeString(&EntryFaceNameW);
return FontGDI;
}
RtlFreeUnicodeString(&EntryFaceNameW);
Entry = Entry->Flink;
}
return NULL;
}
static PFONTGDI FASTCALL
FindFaceNameInLists(PUNICODE_STRING FaceName)
{
PPROCESSINFO Win32Process;
PFONTGDI Font;
/* Search the process local list.
We do not have to search the 'Mem' list, since those fonts are linked in the PrivateFontListHead */
Win32Process = PsGetCurrentProcessWin32Process();
IntLockProcessPrivateFonts(Win32Process);
Font = FindFaceNameInList(FaceName, &Win32Process->PrivateFontListHead);
IntUnLockProcessPrivateFonts(Win32Process);
if (NULL != Font)
{
return Font;
}
/* Search the global list */
IntLockGlobalFonts;
Font = FindFaceNameInList(FaceName, &FontListHead);
IntUnLockGlobalFonts;
return Font;
}
/* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */ /* See https://msdn.microsoft.com/en-us/library/bb165625(v=vs.90).aspx */
static BYTE static BYTE
CharSetFromLangID(LANGID LangID) CharSetFromLangID(LANGID LangID)
@ -2459,76 +2406,19 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
Info->NewTextMetricEx.ntmFontSig = fs; Info->NewTextMetricEx.ntmFontSig = fs;
} }
static int FASTCALL
FindFaceNameInInfo(PUNICODE_STRING FaceName, PFONTFAMILYINFO Info, DWORD InfoEntries)
{
DWORD i;
UNICODE_STRING InfoFaceName;
for (i = 0; i < InfoEntries; i++)
{
RtlInitUnicodeString(&InfoFaceName, Info[i].EnumLogFontEx.elfLogFont.lfFaceName);
if (RtlEqualUnicodeString(&InfoFaceName, FaceName, TRUE))
{
return i;
}
}
return -1;
}
static BOOLEAN FASTCALL static BOOLEAN FASTCALL
FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName, GetFontFamilyInfoForList(const LOGFONTW *LogFont,
PFONTFAMILYINFO Info, DWORD InfoEntries)
{
UNICODE_STRING LogFontFaceName;
RtlInitUnicodeString(&LogFontFaceName, LogFont->lfFaceName);
if (0 != LogFontFaceName.Length &&
!RtlEqualUnicodeString(&LogFontFaceName, FaceName, TRUE))
{
return FALSE;
}
return FindFaceNameInInfo(FaceName, Info, InfoEntries) < 0;
}
static BOOL FASTCALL
FontFamilyFound(PFONTFAMILYINFO InfoEntry,
PFONTFAMILYINFO Info, DWORD InfoCount)
{
LPLOGFONTW plf1 = &InfoEntry->EnumLogFontEx.elfLogFont;
LPWSTR pFullName1 = InfoEntry->EnumLogFontEx.elfFullName;
LPWSTR pFullName2;
DWORD i;
for (i = 0; i < InfoCount; ++i)
{
LPLOGFONTW plf2 = &Info[i].EnumLogFontEx.elfLogFont;
if (plf1->lfCharSet != plf2->lfCharSet)
continue;
pFullName2 = Info[i].EnumLogFontEx.elfFullName;
if (_wcsicmp(pFullName1, pFullName2) != 0)
continue;
return TRUE;
}
return FALSE;
}
static BOOLEAN FASTCALL
GetFontFamilyInfoForList(LPLOGFONTW LogFont,
PFONTFAMILYINFO Info, PFONTFAMILYINFO Info,
DWORD *pCount, LPCWSTR NominalName,
DWORD MaxCount, LONG *pCount,
LONG MaxCount,
PLIST_ENTRY Head) PLIST_ENTRY Head)
{ {
PLIST_ENTRY Entry; PLIST_ENTRY Entry;
PFONT_ENTRY CurrentEntry; PFONT_ENTRY CurrentEntry;
FONTGDI *FontGDI; FONTGDI *FontGDI;
FONTFAMILYINFO InfoEntry; FONTFAMILYINFO InfoEntry;
DWORD Count = *pCount; LONG Count = *pCount;
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
{ {
@ -2539,35 +2429,40 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont,
if (LogFont->lfCharSet != DEFAULT_CHARSET && if (LogFont->lfCharSet != DEFAULT_CHARSET &&
LogFont->lfCharSet != FontGDI->CharSet) LogFont->lfCharSet != FontGDI->CharSet)
{ {
continue; continue; /* charset mismatch */
}
if (LogFont->lfFaceName[0] == UNICODE_NULL)
{
if (Count < MaxCount)
{
FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
}
Count++;
continue;
} }
/* get one info entry */
FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI); FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
if (_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0 && if (LogFont->lfFaceName[0] != UNICODE_NULL)
_wcsnicmp(LogFont->lfFaceName, InfoEntry.EnumLogFontEx.elfFullName, RTL_NUMBER_OF(LogFont->lfFaceName)-1) != 0)
{ {
continue; /* check name */
if (_wcsnicmp(LogFont->lfFaceName,
InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0 &&
_wcsnicmp(LogFont->lfFaceName,
InfoEntry.EnumLogFontEx.elfFullName,
RTL_NUMBER_OF(LogFont->lfFaceName) - 1) != 0)
{
continue;
}
} }
if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount))) if (NominalName)
{ {
if (Count < MaxCount) /* store the nominal name */
{ RtlStringCbCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry)); sizeof(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
} NominalName);
Count++;
} }
/* store one entry to Info */
if (0 <= Count && Count < MaxCount)
{
RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
}
Count++;
} }
*pCount = Count; *pCount = Count;
@ -2576,17 +2471,16 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont,
} }
static BOOLEAN FASTCALL static BOOLEAN FASTCALL
GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont, GetFontFamilyInfoForSubstitutes(const LOGFONTW *LogFont,
PFONTFAMILYINFO Info, PFONTFAMILYINFO Info,
DWORD *pCount, LONG *pCount,
DWORD MaxCount) LONG MaxCount)
{ {
PLIST_ENTRY pEntry, pHead = &FontSubstListHead; PLIST_ENTRY pEntry, pHead = &FontSubstListHead;
PFONTSUBST_ENTRY pCurrentEntry; PFONTSUBST_ENTRY pCurrentEntry;
PUNICODE_STRING pFromW; PUNICODE_STRING pFromW, pToW;
FONTGDI *FontGDI;
LOGFONTW lf = *LogFont; LOGFONTW lf = *LogFont;
UNICODE_STRING NameW; PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink) for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
{ {
@ -2595,25 +2489,43 @@ GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM]; pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
if (LogFont->lfFaceName[0] != UNICODE_NULL) if (LogFont->lfFaceName[0] != UNICODE_NULL)
{ {
if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount))) /* check name */
if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
continue; /* mismatch */ continue; /* mismatch */
} }
RtlStringCchCopyW(lf.lfFaceName, LF_FACESIZE, pFromW->Buffer); pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
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); SubstituteFontRecurse(&lf);
if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
continue;
RtlInitUnicodeString(&NameW, lf.lfFaceName); /* search in global fonts */
FontGDI = FindFaceNameInLists(&NameW); IntLockGlobalFonts;
if (FontGDI == NULL) GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &FontListHead);
{ IntUnLockGlobalFonts;
continue; /* no real font */
}
if (*pCount < MaxCount) /* search in private fonts */
IntLockProcessPrivateFonts(Win32Process);
GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
&Win32Process->PrivateFontListHead);
IntUnLockProcessPrivateFonts(Win32Process);
if (LogFont->lfFaceName[0])
{ {
FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI); /* it's already matched to the exact name and charset if the name
was specified at here, then so don't scan more for another name */
break;
} }
(*pCount)++;
} }
return TRUE; return TRUE;
@ -5004,41 +4916,22 @@ ftGdiGetKerningPairs( PFONTGDI Font,
// Functions needing sorting. // Functions needing sorting.
// //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
int APIENTRY
NtGdiGetFontFamilyInfo(HDC Dc, LONG FASTCALL
LPLOGFONTW UnsafeLogFont, IntGetFontFamilyInfo(HDC Dc,
PFONTFAMILYINFO UnsafeInfo, const LOGFONTW *SafeLogFont,
DWORD Size) PFONTFAMILYINFO SafeInfo,
LONG InfoCount)
{ {
NTSTATUS Status; LONG AvailCount = 0;
LOGFONTW LogFont;
PFONTFAMILYINFO Info;
DWORD Count;
PPROCESSINFO Win32Process; 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 */ /* Enumerate font families in the global list */
IntLockGlobalFonts; IntLockGlobalFonts;
Count = 0; if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount,
if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) ) InfoCount, &FontListHead))
{ {
IntUnLockGlobalFonts; IntUnLockGlobalFonts;
ExFreePoolWithTag(Info, GDITAG_TEXT);
return -1; return -1;
} }
IntUnLockGlobalFonts; IntUnLockGlobalFonts;
@ -5046,28 +4939,106 @@ NtGdiGetFontFamilyInfo(HDC Dc,
/* Enumerate font families in the process local list */ /* Enumerate font families in the process local list */
Win32Process = PsGetCurrentProcessWin32Process(); Win32Process = PsGetCurrentProcessWin32Process();
IntLockProcessPrivateFonts(Win32Process); IntLockProcessPrivateFonts(Win32Process);
if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, if (!GetFontFamilyInfoForList(SafeLogFont, SafeInfo, NULL, &AvailCount, InfoCount,
&Win32Process->PrivateFontListHead)) &Win32Process->PrivateFontListHead))
{ {
IntUnLockProcessPrivateFonts(Win32Process); IntUnLockProcessPrivateFonts(Win32Process);
ExFreePoolWithTag(Info, GDITAG_TEXT);
return -1; return -1;
} }
IntUnLockProcessPrivateFonts(Win32Process); IntUnLockProcessPrivateFonts(Win32Process);
/* Enumerate font families in the registry */ /* 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 -1;
} }
/* Return data to caller */ return AvailCount;
if (0 != Count) }
LONG NTAPI
NtGdiGetFontFamilyInfo(HDC Dc,
const LOGFONTW *UnsafeLogFont,
PFONTFAMILYINFO UnsafeInfo,
LPLONG UnsafeInfoCount)
{
NTSTATUS Status;
LOGFONTW LogFont;
PFONTFAMILYINFO Info;
LONG GotCount, AvailCount, SafeInfoCount;
ULONG DataSize;
if (UnsafeLogFont == NULL || UnsafeInfo == NULL || UnsafeInfoCount == NULL)
{ {
Status = MmCopyToCaller(UnsafeInfo, Info, EngSetLastError(ERROR_INVALID_PARAMETER);
(Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO)); return -1;
if (! NT_SUCCESS(Status)) }
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 */
Status = RtlULongMult(SafeInfoCount, sizeof(FONTFAMILYINFO), &DataSize);
if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
{
DPRINT1("Overflowed.\n");
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)
{
Status = RtlULongMult(GotCount, sizeof(FONTFAMILYINFO), &DataSize);
if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
{
DPRINT1("Overflowed.\n");
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); ExFreePoolWithTag(Info, GDITAG_TEXT);
EngSetLastError(ERROR_INVALID_PARAMETER); EngSetLastError(ERROR_INVALID_PARAMETER);
@ -5077,7 +5048,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
ExFreePoolWithTag(Info, GDITAG_TEXT); ExFreePoolWithTag(Info, GDITAG_TEXT);
return Count; return GotCount;
} }
FORCEINLINE FORCEINLINE

View file

@ -50,14 +50,13 @@ typedef struct tagFONTFAMILYINFO
} FONTFAMILYINFO, *PFONTFAMILYINFO; } FONTFAMILYINFO, *PFONTFAMILYINFO;
/* Should be using NtGdiEnumFontChunk */ /* Should be using NtGdiEnumFontChunk */
INT LONG
NTAPI NTAPI
NtGdiGetFontFamilyInfo( NtGdiGetFontFamilyInfo(
HDC Dc, HDC Dc,
LPLOGFONTW LogFont, const LOGFONTW *LogFont,
PFONTFAMILYINFO Info, PFONTFAMILYINFO Info,
DWORD Size LPLONG UnsafeInfoCount);
);
/* Use NtGdiGetDCPoint with GdiGetViewPortExt */ /* Use NtGdiGetDCPoint with GdiGetViewPortExt */
BOOL APIENTRY NtGdiGetViewportExtEx(HDC hDC, LPSIZE viewportExt); BOOL APIENTRY NtGdiGetViewportExtEx(HDC hDC, LPSIZE viewportExt);