From 5a21337fae48514111d9437f6c71e54524cf58a0 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Thu, 7 Nov 2024 22:54:04 +0000 Subject: [PATCH] Bug 1928458 - Make local font name lookup prefer face [postscript/full] names that are more similar to their family name, in case of duplicates.. r=dshin Differential Revision: https://phabricator.services.mozilla.com/D228340 --- gfx/thebes/gfxDWriteFontList.cpp | 8 +++--- gfx/thebes/gfxFT2FontList.cpp | 32 ++++++++++++---------- gfx/thebes/gfxFT2FontList.h | 3 +- gfx/thebes/gfxFcPlatformFontList.cpp | 23 ++++++++-------- gfx/thebes/gfxPlatformFontList.cpp | 41 ++++++++++++++++++++++++++++ gfx/thebes/gfxPlatformFontList.h | 8 ++++++ 6 files changed, 85 insertions(+), 30 deletions(-) diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index 38ee6678e5f9..6d046d02c369 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -1539,16 +1539,16 @@ void gfxDWriteFontList::ReadFaceNamesForFamily( if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName( data, size, gfxFontUtils::NAME_ID_POSTSCRIPT, psname))) { ToLowerCase(psname); - mLocalNameTable.InsertOrUpdate( - psname, fontlist::LocalFaceRec::InitData(key, i)); + MaybeAddToLocalNameTable(psname, + fontlist::LocalFaceRec::InitData(key, i)); } } if (NS_SUCCEEDED(gfxFontUtils::ReadCanonicalName( data, size, gfxFontUtils::NAME_ID_FULL, fullname))) { ToLowerCase(fullname); if (fullname != psname) { - mLocalNameTable.InsertOrUpdate( - fullname, fontlist::LocalFaceRec::InitData(key, i)); + MaybeAddToLocalNameTable(fullname, + fontlist::LocalFaceRec::InitData(key, i)); } } diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 9c9811213ea8..5c94e81d9be8 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -702,13 +702,13 @@ void gfxFT2FontList::CollectInitData(const FontListEntry& aFLE, nsAutoCString psname(aPSName), fullname(aFullName); if (!psname.IsEmpty()) { ToLowerCase(psname); - mLocalNameTable.InsertOrUpdate( + MaybeAddToLocalNameTable( psname, fontlist::LocalFaceRec::InitData(key, aFLE.filepath())); } if (!fullname.IsEmpty()) { ToLowerCase(fullname); if (fullname != psname) { - mLocalNameTable.InsertOrUpdate( + MaybeAddToLocalNameTable( fullname, fontlist::LocalFaceRec::InitData(key, aFLE.filepath())); } } @@ -1207,15 +1207,18 @@ void gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName, uint32_t(s.st_mtime) == timestamp && s.st_size == filesize) { CollectFunc unshared = [](const FontListEntry& aFLE, const nsCString& aPSName, - const nsCString& aFullName, StandardFile aStdFile) { - auto* pfl = PlatformFontList(); - pfl->mLock.AssertCurrentThreadIn(); - pfl->AppendFaceFromFontListEntry(aFLE, aStdFile); - }; + const nsCString& aFullName, StandardFile aStdFile) + MOZ_REQUIRES(PlatformFontList()->mLock) { + auto* pfl = PlatformFontList(); + pfl->mLock.AssertCurrentThreadIn(); + pfl->AppendFaceFromFontListEntry(aFLE, aStdFile); + }; CollectFunc shared = [](const FontListEntry& aFLE, const nsCString& aPSName, - const nsCString& aFullName, StandardFile aStdFile) { - PlatformFontList()->CollectInitData(aFLE, aPSName, aFullName, aStdFile); - }; + const nsCString& aFullName, StandardFile aStdFile) + MOZ_REQUIRES(PlatformFontList()->mLock) { + PlatformFontList()->CollectInitData( + aFLE, aPSName, aFullName, aStdFile); + }; if (AppendFacesFromCachedFaceList(SharedFontList() ? shared : unshared, aFileName, cachedFaceList, aStdFile)) { LOG(("using cached font info for %s", aFileName.get())); @@ -1495,10 +1498,11 @@ void gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive, }; CollectFunc shared = [](const FontListEntry& aFLE, const nsCString& aPSName, - const nsCString& aFullName, - StandardFile aStdFile) { - PlatformFontList()->CollectInitData(aFLE, aPSName, aFullName, aStdFile); - }; + const nsCString& aFullName, StandardFile aStdFile) + MOZ_REQUIRES(PlatformFontList()->mLock) { + PlatformFontList()->CollectInitData( + aFLE, aPSName, aFullName, aStdFile); + }; if (AppendFacesFromCachedFaceList(SharedFontList() ? shared : unshared, aEntryName, faceList, kStandard)) { return; diff --git a/gfx/thebes/gfxFT2FontList.h b/gfx/thebes/gfxFT2FontList.h index 0e92d31944cc..446aeaf0cd22 100644 --- a/gfx/thebes/gfxFT2FontList.h +++ b/gfx/thebes/gfxFT2FontList.h @@ -208,7 +208,8 @@ class gfxFT2FontList final : public gfxPlatformFontList { void InitSharedFontListForPlatform() MOZ_REQUIRES(mLock) override; void CollectInitData(const FontListEntry& aFLE, const nsCString& aPSName, - const nsCString& aFullName, StandardFile aStdFile); + const nsCString& aFullName, StandardFile aStdFile) + MOZ_REQUIRES(mLock); nsTArray> GetFilteredPlatformFontLists() override; diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index 6839d40ed986..7a976e2e9479 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -1860,26 +1860,25 @@ void gfxFcPlatformFontList::InitSharedFontListForPlatform() { // map the psname, fullname ==> font family for local font lookups nsAutoCString psname, fullname; GetFaceNames(aPattern, aFamilyName, psname, fullname); + MOZ_PUSH_IGNORE_THREAD_SAFETY if (!psname.IsEmpty()) { ToLowerCase(psname); - mLocalNameTable.InsertOrUpdate( + MaybeAddToLocalNameTable( psname, fontlist::LocalFaceRec::InitData(keyName, descriptor)); } if (!fullname.IsEmpty()) { ToLowerCase(fullname); if (fullname != psname) { - mLocalNameTable.WithEntryHandle(fullname, [&](auto&& entry) { - if (entry && !singleName) { - // We only override an existing entry if this is the only way to - // name this family. This prevents dubious aliases from clobbering - // the local name table. - return; - } - entry.InsertOrUpdate( - fontlist::LocalFaceRec::InitData(keyName, descriptor)); - }); + // We only consider overriding an existing entry if this is the only + // way to name this family. This prevents dubious aliases from + // clobbering the local name table. + if (singleName || !mLocalNameTable.Contains(fullname)) { + MaybeAddToLocalNameTable( + fullname, fontlist::LocalFaceRec::InitData(keyName, descriptor)); + } } } + MOZ_POP_THREAD_SAFETY return visibility == FontVisibility::Base; }; @@ -1938,6 +1937,7 @@ void gfxFcPlatformFontList::InitSharedFontListForPlatform() { // This substantially reduces the pressure on shared memory (bug 1664151) // due to the large font descriptors (serialized patterns). FcChar8* fontFormat; + MOZ_PUSH_IGNORE_THREAD_SAFETY if (FcPatternGetString(clone, FC_FONTFORMAT, 0, &fontFormat) == FcResultMatch && (!FcStrCmp(fontFormat, (const FcChar8*)"TrueType") || @@ -1951,6 +1951,7 @@ void gfxFcPlatformFontList::InitSharedFontListForPlatform() { ++count; } } + MOZ_POP_THREAD_SAFETY FcPatternDestroy(clone); } diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index e6a24356e290..d9d201477c45 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -941,6 +941,47 @@ gfxFontEntry* gfxPlatformFontList::LookupInSharedFaceNameList( return fe; } +void gfxPlatformFontList::MaybeAddToLocalNameTable( + const nsACString& aName, const fontlist::LocalFaceRec::InitData& aData) { + // Compute a measure of the similarity between aName (which will be a PSName + // or FullName) and aReference (a font family name). + auto nameSimilarity = [](const nsACString& aName, + const nsACString& aReference) -> uint32_t { + uint32_t nameIdx = 0, refIdx = 0, matchCount = 0; + while (nameIdx < aName.Length() && refIdx < aReference.Length()) { + // Ignore non-alphanumerics in the ASCII range, so that a PSname like + // "TimesNewRomanPSMT" is a good match for family "Times New Roman". + while (nameIdx < aName.Length() && IsAscii(aName[nameIdx]) && + !IsAsciiAlphanumeric(aName[nameIdx])) { + ++nameIdx; + } + while (refIdx < aReference.Length() && IsAscii(aReference[refIdx]) && + !IsAsciiAlphanumeric(aReference[refIdx])) { + ++refIdx; + } + if (nameIdx == aName.Length() || refIdx == aReference.Length() || + aName[nameIdx] != aReference[refIdx]) { + break; + } + ++nameIdx; + ++refIdx; + ++matchCount; + } + return matchCount; + }; + + mLocalNameTable.WithEntryHandle(aName, [&](auto entry) -> void { + if (entry) { + if (nameSimilarity(aName, aData.mFamilyName) > + nameSimilarity(aName, entry.Data().mFamilyName)) { + entry.Update(aData); + } + } else { + entry.OrInsert(aData); + } + }); +} + void gfxPlatformFontList::LoadBadUnderlineList() { gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", mBadUnderlineFamilyNames); diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index 2bc262844bd4..7c1c9546db6e 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -871,6 +871,14 @@ class gfxPlatformFontList : public gfxFontInfoLoader { SlantStyleRange aStyleForEntry) MOZ_REQUIRES(mLock); + // Add an entry for aName to the local names table, but only if it is not + // already present, or aName and aData.mFamilyName look like a better match + // than the existing entry. + void MaybeAddToLocalNameTable( + const nsACString& aName, + const mozilla::fontlist::LocalFaceRec::InitData& aData) + MOZ_REQUIRES(mLock); + // load the bad underline blocklist from pref. void LoadBadUnderlineList();