diff --git a/win32ss/gdi/gdi32/objects/font.c b/win32ss/gdi/gdi32/objects/font.c index 38758fa7902..566d703ccb5 100644 --- a/win32ss/gdi/gdi32/objects/font.c +++ b/win32ss/gdi/gdi32/objects/font.c @@ -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); } diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c index 744db67cb10..7d253211870 100644 --- a/win32ss/gdi/ntgdi/freetype.c +++ b/win32ss/gdi/ntgdi/freetype.c @@ -2202,73 +2202,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) @@ -2695,67 +2628,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) @@ -2782,28 +2658,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; @@ -2819,10 +2705,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) { @@ -2831,25 +2716,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; @@ -5502,7 +5394,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); @@ -5513,7 +5405,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);