mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
[0.4.11][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-gd10c0ec112
by porting back the commits: 0.4.12-dev-320-g6e4e5a004c
and 0.4.13-dev-107-gae8417fd90
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-gd10c0ec112
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:
parent
982cda94c0
commit
deae917e9b
4 changed files with 289 additions and 230 deletions
|
@ -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_ */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2202,73 +2202,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;
|
|
||||||
|
|
||||||
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, &g_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)
|
||||||
|
@ -2695,76 +2628,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)
|
||||||
{
|
{
|
||||||
|
@ -2775,36 +2651,41 @@ 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)
|
{
|
||||||
|
/* 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
|
if (NominalName)
|
||||||
{
|
{
|
||||||
if (Count < MaxCount)
|
/* 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));
|
RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
|
||||||
}
|
}
|
||||||
Count++;
|
Count++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
*pCount = Count;
|
*pCount = Count;
|
||||||
|
|
||||||
|
@ -2812,17 +2693,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 = &g_FontSubstListHead;
|
PLIST_ENTRY pEntry, pHead = &g_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)
|
||||||
{
|
{
|
||||||
|
@ -2831,25 +2711,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 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
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, &g_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;
|
||||||
|
@ -5479,41 +5377,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, &g_FontListHead) )
|
InfoCount, &g_FontListHead))
|
||||||
{
|
{
|
||||||
IntUnLockGlobalFonts();
|
IntUnLockGlobalFonts();
|
||||||
ExFreePoolWithTag(Info, GDITAG_TEXT);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
IntUnLockGlobalFonts();
|
IntUnLockGlobalFonts();
|
||||||
|
@ -5521,27 +5400,105 @@ 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)
|
||||||
{
|
{
|
||||||
Status = MmCopyToCaller(UnsafeInfo, Info,
|
NTSTATUS Status;
|
||||||
(Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
|
LOGFONTW LogFont;
|
||||||
|
PFONTFAMILYINFO Info;
|
||||||
|
LONG GotCount, AvailCount, SafeInfoCount;
|
||||||
|
ULONG DataSize;
|
||||||
|
|
||||||
|
if (UnsafeLogFont == NULL || UnsafeInfo == NULL || UnsafeInfoCount == NULL)
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
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))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
ExFreePoolWithTag(Info, GDITAG_TEXT);
|
ExFreePoolWithTag(Info, GDITAG_TEXT);
|
||||||
|
@ -5552,7 +5509,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
|
||||||
|
|
||||||
ExFreePoolWithTag(Info, GDITAG_TEXT);
|
ExFreePoolWithTag(Info, GDITAG_TEXT);
|
||||||
|
|
||||||
return Count;
|
return GotCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue