[FONT][GDI32] Fix font enumeration functions (#1221)

Fix EnumFonts, EnumFontFamilies and EnumFontFamiliesEx functions.
The charsets of the font substitutes are also enumerated.
Delete meaningless codes. CORE-15558
This commit is contained in:
Katayama Hirofumi MZ 2019-01-06 10:43:34 +09:00 committed by GitHub
parent cdaff94c3d
commit 6e4e5a004c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 136 additions and 158 deletions

View file

@ -204,9 +204,88 @@ NewTextMetricExW2A(NEWTEXTMETRICEXA *tma, NEWTEXTMETRICEXW *tmw)
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_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;
}
if (dwCompareFlags & IFFCX_CHARSET)
{
if (plf1->lfCharSet < plf2->lfCharSet)
return -1;
if (plf1->lfCharSet > plf2->lfCharSet)
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;
// std::unique(first, last, IntFontFamilyCompareEx);
if (nCount == 0)
return 0;
result = first = InfoList;
last = &InfoList[nCount];
while (++first != last)
{
if (IntFontFamilyCompareEx(result, first, dwCompareFlags) != 0 &&
++result != first)
{
*result = *first;
}
}
nCount = (int)(++result - InfoList);
return nCount;
}
static int FASTCALL
IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
BOOL Unicode)
DWORD dwFlags)
{
int FontFamilyCount;
int FontFamilySize;
@ -256,9 +335,15 @@ IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
}
}
DPRINT("qsort\n");
qsort(Info, FontFamilyCount, sizeof(*Info), IntFontFamilyCompare);
DPRINT("qsort done\n");
FontFamilyCount = IntFontFamilyListUnique(Info, FontFamilyCount, LogFont, dwFlags);
DPRINT("unique done\n");
for (i = 0; i < FontFamilyCount; i++)
{
if (Unicode)
if (dwFlags & IEFF_UNICODE)
{
Ret = ((FONTENUMPROCW) EnumProc)(
(VOID*)&Info[i].EnumLogFontEx,
@ -299,7 +384,8 @@ int WINAPI
EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
LPARAM lParam, DWORD dwFlags)
{
return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE);
return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam,
IEFF_UNICODE | IEFF_EXTENDED);
}
@ -320,7 +406,7 @@ EnumFontFamiliesW(HDC hdc, LPCWSTR lpszFamily, FONTENUMPROCW lpEnumFontFamProc,
lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
}
return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE);
return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, IEFF_UNICODE);
}
@ -341,7 +427,7 @@ EnumFontFamiliesExA (HDC hdc, LPLOGFONTA lpLogfont, FONTENUMPROCA lpEnumFontFamE
else pLogFontW = NULL;
/* 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 +448,7 @@ EnumFontFamiliesA(HDC hdc, LPCSTR lpszFamily, FONTENUMPROCA lpEnumFontFamProc,
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

@ -2251,73 +2251,6 @@ IntGetOutlineTextMetrics(PFONTGDI FontGDI,
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 */
static BYTE
CharSetFromLangID(LANGID LangID)
@ -2744,67 +2677,10 @@ FontFamilyFillInfo(PFONTFAMILYINFO Info, LPCWSTR FaceName,
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
FontFamilyInclude(LPLOGFONTW LogFont, PUNICODE_STRING FaceName,
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,
LPCWSTR NominalName,
DWORD *pCount,
DWORD MaxCount,
PLIST_ENTRY Head)
@ -2831,28 +2707,38 @@ GetFontFamilyInfoForList(LPLOGFONTW LogFont,
{
if (Count < MaxCount)
{
FontFamilyFillInfo(&Info[Count], NULL, NULL, FontGDI);
FontFamilyFillInfo(&Info[Count], NominalName, NULL, FontGDI);
}
Count++;
continue;
}
FontFamilyFillInfo(&InfoEntry, NULL, NULL, FontGDI);
FontFamilyFillInfo(&InfoEntry, NominalName, NULL, FontGDI);
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)
if (NominalName)
{
continue;
RtlStringCchCopyW(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName,
RTL_NUMBER_OF(InfoEntry.EnumLogFontEx.elfLogFont.lfFaceName),
NominalName);
}
if (!FontFamilyFound(&InfoEntry, Info, min(Count, MaxCount)))
else
{
if (Count < MaxCount)
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)
{
RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
continue;
}
Count++;
}
if (Count < MaxCount)
{
RtlCopyMemory(&Info[Count], &InfoEntry, sizeof(InfoEntry));
}
Count++;
}
*pCount = Count;
@ -2868,10 +2754,9 @@ GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
{
PLIST_ENTRY pEntry, pHead = &g_FontSubstListHead;
PFONTSUBST_ENTRY pCurrentEntry;
PUNICODE_STRING pFromW;
FONTGDI *FontGDI;
PUNICODE_STRING pFromW, pToW;
LOGFONTW lf = *LogFont;
UNICODE_STRING NameW;
PPROCESSINFO Win32Process = PsGetCurrentProcessWin32Process();
for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink)
{
@ -2880,25 +2765,32 @@ GetFontFamilyInfoForSubstitutes(LPLOGFONTW LogFont,
pFromW = &pCurrentEntry->FontNames[FONTSUBST_FROM];
if (LogFont->lfFaceName[0] != UNICODE_NULL)
{
if (!FontFamilyInclude(LogFont, pFromW, Info, min(*pCount, MaxCount)))
if (_wcsicmp(LogFont->lfFaceName, pFromW->Buffer) != 0)
continue; /* mismatch */
}
pToW = &pCurrentEntry->FontNames[FONTSUBST_TO];
if (RtlEqualUnicodeString(pFromW, pToW, TRUE) &&
pCurrentEntry->CharSets[FONTSUBST_FROM] ==
pCurrentEntry->CharSets[FONTSUBST_TO])
{
continue;
}
IntUnicodeStringToBuffer(lf.lfFaceName, sizeof(lf.lfFaceName), pFromW);
SubstituteFontRecurse(&lf);
if (LogFont->lfCharSet != DEFAULT_CHARSET && LogFont->lfCharSet != lf.lfCharSet)
continue;
RtlInitUnicodeString(&NameW, lf.lfFaceName);
FontGDI = FindFaceNameInLists(&NameW);
if (FontGDI == NULL)
{
continue; /* no real font */
}
IntLockGlobalFonts();
GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount, &g_FontListHead);
IntUnLockGlobalFonts();
if (*pCount < MaxCount)
{
FontFamilyFillInfo(&Info[*pCount], pFromW->Buffer, NULL, FontGDI);
}
(*pCount)++;
IntLockProcessPrivateFonts(Win32Process);
GetFontFamilyInfoForList(&lf, Info, pFromW->Buffer, pCount, MaxCount,
&Win32Process->PrivateFontListHead);
IntUnLockProcessPrivateFonts(Win32Process);
break;
}
return TRUE;
@ -5541,7 +5433,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
/* Enumerate font families in the global list */
IntLockGlobalFonts();
Count = 0;
if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &g_FontListHead) )
if (! GetFontFamilyInfoForList(&LogFont, Info, NULL, &Count, Size, &g_FontListHead) )
{
IntUnLockGlobalFonts();
ExFreePoolWithTag(Info, GDITAG_TEXT);
@ -5552,7 +5444,7 @@ NtGdiGetFontFamilyInfo(HDC Dc,
/* Enumerate font families in the process local list */
Win32Process = PsGetCurrentProcessWin32Process();
IntLockProcessPrivateFonts(Win32Process);
if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
if (! GetFontFamilyInfoForList(&LogFont, Info, NULL, &Count, Size,
&Win32Process->PrivateFontListHead))
{
IntUnLockProcessPrivateFonts(Win32Process);