From 6ceb7d87f964fe8eb1017411e483e8941fce0de7 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 1 Aug 2017 11:25:35 +0100 Subject: [PATCH] Bug 835204 - Accept styled font-family names as used in the legacy GDI model, for compatibility with content that assumes GDI-style font naming. r=heycam --- gfx/thebes/gfxDWriteFontList.cpp | 24 +++++- gfx/thebes/gfxDWriteFontList.h | 6 +- gfx/thebes/gfxFT2FontList.cpp | 19 +++++ gfx/thebes/gfxFT2FontList.h | 4 + gfx/thebes/gfxFcPlatformFontList.cpp | 19 ++++- gfx/thebes/gfxFcPlatformFontList.h | 6 +- gfx/thebes/gfxFontEntry.cpp | 77 +++++++++++++++++++ gfx/thebes/gfxFontEntry.h | 20 ++++- gfx/thebes/gfxGDIFontList.cpp | 18 ++++- gfx/thebes/gfxGDIFontList.h | 8 +- gfx/thebes/gfxMacPlatformFontList.h | 6 +- gfx/thebes/gfxMacPlatformFontList.mm | 22 +++++- gfx/thebes/gfxPlatformFontList.cpp | 57 +++++++++++++- gfx/thebes/gfxPlatformFontList.h | 32 +++++++- gfx/thebes/gfxTextRun.cpp | 4 +- gfx/thebes/gfxUserFontSet.h | 9 ++- layout/reftests/bugs/481948-2-ref.html | 2 +- .../legacy-family-names-1-ref.html | 9 +++ .../font-matching/legacy-family-names-1.html | 9 +++ .../legacy-family-names-2-ref.html | 9 +++ .../font-matching/legacy-family-names-2.html | 9 +++ layout/reftests/font-matching/reftest.list | 6 ++ 22 files changed, 347 insertions(+), 28 deletions(-) create mode 100644 layout/reftests/font-matching/legacy-family-names-1-ref.html create mode 100644 layout/reftests/font-matching/legacy-family-names-1.html create mode 100644 layout/reftests/font-matching/legacy-family-names-2-ref.html create mode 100644 layout/reftests/font-matching/legacy-family-names-2.html diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index f468d2b948bd..f24c28bfca1b 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -282,7 +282,12 @@ gfxDWriteFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, void gfxDWriteFontFamily::LocalizedName(nsAString &aLocalizedName) { - aLocalizedName.AssignLiteral("Unknown Font"); + aLocalizedName = Name(); // just return canonical name in case of failure + + if (!mDWFamily) { + return; + } + HRESULT hr; nsAutoCString locale; // We use system locale here because it's what user expects to see. @@ -355,6 +360,13 @@ gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, //////////////////////////////////////////////////////////////////////////////// // gfxDWriteFontEntry +gfxFontEntry* +gfxDWriteFontEntry::Clone() const +{ + MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!"); + return new gfxDWriteFontEntry(Name(), mFont); +} + gfxDWriteFontEntry::~gfxDWriteFontEntry() { } @@ -1266,7 +1278,7 @@ gfxDWriteFontList::GetStandardFamilyName(const nsAString& aFontName, bool gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { @@ -1285,7 +1297,7 @@ gfxDWriteFontList::FindAndAddFamilies(const nsAString& aFamily, return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, - aDeferOtherFamilyNamesLoading, + aFlags, aStyle, aDevToCssSize); } @@ -1705,6 +1717,12 @@ gfxDWriteFontList::CreateFontInfoData() return fi.forget(); } +gfxFontFamily* +gfxDWriteFontList::CreateFontFamily(const nsAString& aName) const +{ + return new gfxDWriteFontFamily(aName, nullptr); +} + #ifdef MOZ_BUNDLED_FONTS diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index 33880c0c78be..dcf23e3a96dd 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -150,6 +150,8 @@ public: mIsCJK = UNINITIALIZED_VALUE; } + gfxFontEntry* Clone() const override; + virtual ~gfxDWriteFontEntry(); virtual bool IsSymbolFont(); @@ -359,6 +361,8 @@ public: // initialize font lists virtual nsresult InitFontListForPlatform() override; + gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; + virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName, uint16_t aWeight, int16_t aStretch, @@ -379,7 +383,7 @@ public: bool FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxFT2FontList.cpp b/gfx/thebes/gfxFT2FontList.cpp index 6e9627f21d20..e31b9970ccb4 100644 --- a/gfx/thebes/gfxFT2FontList.cpp +++ b/gfx/thebes/gfxFT2FontList.cpp @@ -228,6 +228,19 @@ FT2FontEntry::~FT2FontEntry() #endif } +gfxFontEntry* +FT2FontEntry::Clone() const +{ + MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!"); + FT2FontEntry* fe = new FT2FontEntry(Name()); + fe->mFilename = mFilename; + fe->mFTFontIndex = mFTFontIndex; + fe->mWeight = mWeight; + fe->mStretch = mStretch; + fe->mStyle = mStyle; + return fe; +} + gfxFont* FT2FontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) { @@ -1496,6 +1509,12 @@ gfxFT2FontList::GetFontFamilyList(nsTArray >& aFamilyArray } } +gfxFontFamily* +gfxFT2FontList::CreateFontFamily(const nsAString& aName) const +{ + return new FT2FontFamily(aName); +} + void gfxFT2FontList::WillShutdown() { diff --git a/gfx/thebes/gfxFT2FontList.h b/gfx/thebes/gfxFT2FontList.h index f8f5751fe350..39cf9173e75f 100644 --- a/gfx/thebes/gfxFT2FontList.h +++ b/gfx/thebes/gfxFT2FontList.h @@ -34,6 +34,8 @@ public: ~FT2FontEntry(); + gfxFontEntry* Clone() const override; + const nsString& GetName() const { return Name(); } @@ -135,6 +137,8 @@ public: virtual void GetFontFamilyList(nsTArray >& aFamilyArray) override; + gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; + void WillShutdown(); protected: diff --git a/gfx/thebes/gfxFcPlatformFontList.cpp b/gfx/thebes/gfxFcPlatformFontList.cpp index c92d745b2f44..4caae061b1a4 100644 --- a/gfx/thebes/gfxFcPlatformFontList.cpp +++ b/gfx/thebes/gfxFcPlatformFontList.cpp @@ -245,6 +245,13 @@ gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName, mStretch = MapFcWidth(width); } +gfxFontEntry* +gfxFontconfigFontEntry::Clone() const +{ + MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!"); + return new gfxFontconfigFontEntry(Name(), mFontPattern, mIgnoreFcCharmap); +} + gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName, uint16_t aWeight, int16_t aStretch, @@ -1516,7 +1523,7 @@ gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName, bool gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { @@ -1601,7 +1608,7 @@ gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, } gfxPlatformFontList::FindAndAddFamilies(subst, &cachedFamilies, - aDeferOtherFamilyNamesLoading); + aFlags); } // Cache the resulting list, so we don't have to do this again. @@ -1884,7 +1891,7 @@ gfxFcPlatformFontList::FindGenericFamilies(const nsAString& aGeneric, AutoTArray genericFamilies; if (gfxPlatformFontList::FindAndAddFamilies(mappedGenericName, &genericFamilies, - true)) { + FindFamiliesFlags(0))) { MOZ_ASSERT(genericFamilies.Length() == 1, "expected a single family"); if (!prefFonts->Contains(genericFamilies[0])) { @@ -1976,6 +1983,12 @@ gfxFcPlatformFontList::CheckFontUpdates(nsITimer *aTimer, void *aThis) } } +gfxFontFamily* +gfxFcPlatformFontList::CreateFontFamily(const nsAString& aName) const +{ + return new gfxFontconfigFontFamily(aName); +} + #ifdef MOZ_BUNDLED_FONTS void gfxFcPlatformFontList::ActivateBundledFonts() diff --git a/gfx/thebes/gfxFcPlatformFontList.h b/gfx/thebes/gfxFcPlatformFontList.h index 57c66dd03aeb..490922767f3c 100644 --- a/gfx/thebes/gfxFcPlatformFontList.h +++ b/gfx/thebes/gfxFcPlatformFontList.h @@ -95,6 +95,8 @@ public: int16_t aStretch, uint8_t aStyle); + gfxFontEntry* Clone() const override; + FcPattern* GetPattern() { return mFontPattern; } bool SupportsLangGroup(nsIAtom *aLangGroup) const override; @@ -260,7 +262,7 @@ public: bool FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; @@ -303,6 +305,8 @@ protected: virtual gfxFontFamily* GetDefaultFontForPlatform(const gfxFontStyle* aStyle) override; + gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; + #ifdef MOZ_BUNDLED_FONTS void ActivateBundledFonts(); nsCString mBundledFontsPath; diff --git a/gfx/thebes/gfxFontEntry.cpp b/gfx/thebes/gfxFontEntry.cpp index 53d492b86a68..b6ad830cdf61 100644 --- a/gfx/thebes/gfxFontEntry.cpp +++ b/gfx/thebes/gfxFontEntry.cpp @@ -1662,6 +1662,83 @@ gfxFontFamily::ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList) } } +static bool +LookForLegacyFamilyName(const nsAString& aCanonicalName, + const char* aNameData, + uint32_t aDataLength, + nsAString& aLegacyName /* outparam */) +{ + const gfxFontUtils::NameHeader* nameHeader = + reinterpret_cast(aNameData); + + uint32_t nameCount = nameHeader->count; + if (nameCount * sizeof(gfxFontUtils::NameRecord) > aDataLength) { + NS_WARNING("invalid font (name records)"); + return false; + } + + const gfxFontUtils::NameRecord* nameRecord = + reinterpret_cast + (aNameData + sizeof(gfxFontUtils::NameHeader)); + uint32_t stringsBase = uint32_t(nameHeader->stringOffset); + + for (uint32_t i = 0; i < nameCount; i++, nameRecord++) { + uint32_t nameLen = nameRecord->length; + uint32_t nameOff = nameRecord->offset; + + if (stringsBase + nameOff + nameLen > aDataLength) { + NS_WARNING("invalid font (name table strings)"); + return false; + } + + if (uint16_t(nameRecord->nameID) == gfxFontUtils::NAME_ID_FAMILY) { + bool ok = + gfxFontUtils::DecodeFontName(aNameData + stringsBase + nameOff, + nameLen, + uint32_t(nameRecord->platformID), + uint32_t(nameRecord->encodingID), + uint32_t(nameRecord->languageID), + aLegacyName); + // it's only a legacy name if it differs from the canonical name + if (ok && aLegacyName != aCanonicalName) { + return true; + } + } + } + return false; +} + +bool +gfxFontFamily::CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList) +{ + if (mCheckedForLegacyFamilyNames) { + // we already did this, so there's nothing more to add + return false; + } + mCheckedForLegacyFamilyNames = true; + bool added = false; + const uint32_t kNAME = TRUETYPE_TAG('n','a','m','e'); + for (auto& fe : mAvailableFonts) { + if (!fe) { + continue; + } + gfxFontEntry::AutoTable nameTable(fe, kNAME); + if (!nameTable) { + continue; + } + nsAutoString legacyName; + uint32_t dataLength; + const char* nameData = hb_blob_get_data(nameTable, &dataLength); + if (LookForLegacyFamilyName(Name(), nameData, dataLength, + legacyName)) { + if (aFontList->AddWithLegacyFamilyName(legacyName, fe)) { + added = true; + } + } + } + return added; +} + void gfxFontFamily::ReadFaceNames(gfxPlatformFontList *aPlatformFontList, bool aNeedFullnamePostscriptNames, diff --git a/gfx/thebes/gfxFontEntry.h b/gfx/thebes/gfxFontEntry.h index b91b87a5c061..6f2f47166dd7 100644 --- a/gfx/thebes/gfxFontEntry.h +++ b/gfx/thebes/gfxFontEntry.h @@ -108,6 +108,12 @@ public: explicit gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false); + // Create a new entry that refers to the same font as this, but without + // additional state that may have been set up (such as family name). + // (This is only to be used for system fonts in the platform font list, + // not user fonts.) + virtual gfxFontEntry* Clone() const = 0; + // unique name for the face, *not* the family; not necessarily the // "real" or user-friendly name, may be an internal identifier const nsString& Name() const { return mName; } @@ -606,14 +612,23 @@ public: mIsBadUnderlineFamily(false), mFamilyCharacterMapInitialized(false), mSkipDefaultFeatureSpaceCheck(false), - mCheckForFallbackFaces(false) + mCheckForFallbackFaces(false), + mCheckedForLegacyFamilyNames(false) { } const nsString& Name() { return mName; } virtual void LocalizedName(nsAString& aLocalizedName); virtual bool HasOtherFamilyNames(); - + + // See https://bugzilla.mozilla.org/show_bug.cgi?id=835204: + // check the font's 'name' table to see if it has a legacy family name + // that would have been used by GDI (e.g. to split extra-bold or light + // faces in a large family into separate "styled families" because of + // GDI's 4-faces-per-family limitation). If found, the styled family + // name will be added to the font list's "other family names" table. + bool CheckForLegacyFamilyNames(gfxPlatformFontList* aFontList); + nsTArray >& GetFontList() { return mAvailableFonts; } void AddFontEntry(RefPtr aFontEntry) { @@ -767,6 +782,7 @@ protected: bool mFamilyCharacterMapInitialized : 1; bool mSkipDefaultFeatureSpaceCheck : 1; bool mCheckForFallbackFaces : 1; // check other faces for character + bool mCheckedForLegacyFamilyNames : 1; enum { // for "simple" families, the faces are stored in mAvailableFonts diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 54676ec0e72a..3eda6f624da8 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -137,6 +137,14 @@ GDIFontEntry::GDIFontEntry(const nsAString& aFaceName, InitLogFont(aFaceName, aFontType); } +gfxFontEntry* +GDIFontEntry::Clone() const +{ + MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!"); + return new GDIFontEntry(Name(), mFontType, mStyle, mWeight, mStretch, + nullptr, mFamilyHasItalicFace); +} + nsresult GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData) { @@ -912,7 +920,7 @@ gfxGDIFontList::MakePlatformFont(const nsAString& aFontName, bool gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { @@ -931,7 +939,7 @@ gfxGDIFontList::FindAndAddFamilies(const nsAString& aFamily, return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, - aDeferOtherFamilyNamesLoading, + aFlags, aStyle, aDevToCssSize); } @@ -1170,6 +1178,12 @@ gfxGDIFontList::CreateFontInfoData() return fi.forget(); } +gfxFontFamily* +gfxGDIFontList::CreateFontFamily(const nsAString& aName) const +{ + return new GDIFontFamily(aName); +} + #ifdef MOZ_BUNDLED_FONTS void diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index 0cfda6319209..e9aa289a3f26 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -233,6 +233,8 @@ public: virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; + gfxFontEntry* Clone() const override; + // create a font entry for a font with a given name static GDIFontEntry* CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, @@ -287,7 +289,7 @@ protected: class GDIFontFamily : public gfxFontFamily { public: - explicit GDIFontFamily(nsAString &aName) : + explicit GDIFontFamily(const nsAString& aName) : gfxFontFamily(aName) {} virtual void FindStyleVariations(FontInfoData *aFontInfoData = nullptr); @@ -307,9 +309,11 @@ public: // initialize font lists virtual nsresult InitFontListForPlatform() override; + gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; + bool FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index 529cfccfb849..5e7ca67e0a23 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -43,6 +43,8 @@ public: ::CGFontRelease(mFontRef); } + gfxFontEntry* Clone() const override; + CGFontRef GetFontRef(); // override gfxFontEntry table access function to bypass table cache, @@ -88,6 +90,8 @@ public: return static_cast(sPlatformFontList); } + gfxFontFamily* CreateFontFamily(const nsAString& aName) const override; + static int32_t AppleWeightToCSSWeight(int32_t aAppleWeight); bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override; @@ -106,7 +110,7 @@ public: bool FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) override; diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index 58d9d4a0198e..978c4bb5cc77 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -348,6 +348,18 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, mIsLocalUserFont = aIsLocalUserFont; } +gfxFontEntry* +MacOSFontEntry::Clone() const +{ + MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!"); + MacOSFontEntry* fe = + new MacOSFontEntry(Name(), mWeight, mStandardFace, mSizeHint); + fe->mStyle = mStyle; + fe->mStretch = mStretch; + fe->mFixedPitch = mFixedPitch; + return fe; +} + CGFontRef MacOSFontEntry::GetFontRef() { @@ -1280,7 +1292,7 @@ static const char kSystemFont_system[] = "-apple-system"; bool gfxMacPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { @@ -1297,7 +1309,7 @@ gfxMacPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, return gfxPlatformFontList::FindAndAddFamilies(aFamily, aOutput, - aDeferOtherFamilyNamesLoading, + aFlags, aStyle, aDevToCssSize); } @@ -1516,6 +1528,12 @@ gfxMacPlatformFontList::CreateFontInfoData() return fi.forget(); } +gfxFontFamily* +gfxMacPlatformFontList::CreateFontFamily(const nsAString& aName) const +{ + return new gfxMacFontFamily(aName, 0.0); +} + void gfxMacPlatformFontList::ActivateFontsFromDir(nsIFile* aDir) { diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index 8d7cfc05d1f1..10f767d07541 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -248,6 +248,25 @@ gfxPlatformFontList::ApplyWhitelist() } } +bool +gfxPlatformFontList::AddWithLegacyFamilyName(const nsAString& aLegacyName, + gfxFontEntry* aFontEntry) +{ + bool added = false; + nsAutoString key; + ToLowerCase(aLegacyName, key); + gfxFontFamily* family = mOtherFamilyNames.GetWeak(key); + if (!family) { + family = CreateFontFamily(aLegacyName); + family->SetHasStyles(true); // we don't want the family to search for + // faces, we're adding them directly here + mOtherFamilyNames.Put(key, family); + added = true; + } + family->AddFontEntry(aFontEntry->Clone()); + return added; +} + nsresult gfxPlatformFontList::InitFontList() { @@ -685,7 +704,7 @@ gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily) bool gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle, gfxFloat aDevToCssSize) { @@ -708,7 +727,7 @@ gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, // although ASCII localized family names are possible they don't occur // in practice so avoid pulling in names at startup if (!familyEntry && !mOtherFamilyNamesInitialized && !IsASCII(aFamily)) { - InitOtherFamilyNames(aDeferOtherFamilyNamesLoading); + InitOtherFamilyNames(!(aFlags & FindFamiliesFlags::eForceOtherFamilyNamesLoading)); familyEntry = mOtherFamilyNames.GetWeak(key); if (!familyEntry && !mOtherFamilyNamesInitialized) { // localized family names load timed out, add name to list of @@ -721,6 +740,34 @@ gfxPlatformFontList::FindAndAddFamilies(const nsAString& aFamily, } familyEntry = CheckFamily(familyEntry); + + // If we failed to find the requested family, check for a space in the + // name; if found, and if the "base" name (up to the last space) exists + // as a family, then this might be a legacy GDI-style family name for + // an additional weight/width. Try searching the faces of the base family + // and create any corresponding legacy families. + if (!familyEntry && !(aFlags & FindFamiliesFlags::eNoSearchForLegacyFamilyNames)) { + // We don't have nsAString::RFindChar, so look for a space manually + const char16_t* data = aFamily.BeginReading(); + int32_t index = aFamily.Length(); + while (--index > 0) { + if (data[index] == ' ') { + break; + } + } + if (index > 0) { + gfxFontFamily* base = + FindFamily(Substring(aFamily, 0, index), + FindFamiliesFlags::eNoSearchForLegacyFamilyNames); + // If we found the "base" family name, and if it has members with + // legacy names, this will add corresponding font-family entries to + // the mOtherFamilyNames list; then retry the legacy-family search. + if (base && base->CheckForLegacyFamilyNames(this)) { + familyEntry = mOtherFamilyNames.GetWeak(key); + } + } + } + if (familyEntry) { aOutput->AppendElement(familyEntry); return true; @@ -882,7 +929,8 @@ gfxPlatformFontList::ResolveGenericFontNames( style.language = langGroup; style.systemFont = false; AutoTArray families; - FindAndAddFamilies(genericFamily, &families, true, &style); + FindAndAddFamilies(genericFamily, &families, FindFamiliesFlags(0), + &style); for (gfxFontFamily* f : families) { if (!aGenericFamilies->Contains(f)) { aGenericFamilies->AppendElement(f); @@ -1509,7 +1557,8 @@ gfxPlatformFontList::CleanupLoader() if (mOtherNamesMissed) { for (auto it = mOtherNamesMissed->Iter(); !it.Done(); it.Next()) { - if (FindFamily(it.Get()->GetKey(), false)) { + if (FindFamily(it.Get()->GetKey(), + FindFamiliesFlags::eForceOtherFamilyNamesLoading)) { forceReflow = true; ForceGlobalReflow(); break; diff --git a/gfx/thebes/gfxPlatformFontList.h b/gfx/thebes/gfxPlatformFontList.h index d2793cf68848..030cf384ab12 100644 --- a/gfx/thebes/gfxPlatformFontList.h +++ b/gfx/thebes/gfxPlatformFontList.h @@ -135,13 +135,30 @@ public: Script aRunScript, const gfxFontStyle* aStyle); + // Flags to control optional behaviors in FindAndAddFamilies. The sense + // of the bit flags have been chosen such that the default parameter of + // FindFamiliesFlags(0) in FindFamily will give the most commonly-desired + // behavior, and only a few callsites need to explicitly pass other values. + enum class FindFamiliesFlags { + // If set, "other" (e.g. localized) family names should be loaded + // immediately; if clear, InitOtherFamilyNames is allowed to defer + // loading to avoid blocking. + eForceOtherFamilyNamesLoading = 1 << 0, + + // If set, FindAndAddFamilies should not check for legacy "styled + // family" names to add to the font list. This is used to avoid + // a recursive search when using FindFamily to find a potential base + // family name for a styled variant. + eNoSearchForLegacyFamilyNames = 1 << 1 + }; + // Find family(ies) matching aFamily and append to the aOutput array // (there may be multiple results in the case of fontconfig aliases, etc). // Return true if any match was found and appended, false if none. virtual bool FindAndAddFamilies(const nsAString& aFamily, nsTArray* aOutput, - bool aDeferOtherFamilyNamesLoading, + FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0); @@ -266,6 +283,9 @@ public: gfxPlatformFontList::PlatformFontList()->UpdateFontList(); } + bool AddWithLegacyFamilyName(const nsAString& aLegacyName, + gfxFontEntry* aFontEntry); + protected: class InitOtherFamilyNamesRunnable : public mozilla::CancelableRunnable { @@ -360,14 +380,14 @@ protected: // by FindAndAddFamilies(). gfxFontFamily* FindFamily(const nsAString& aFamily, - bool aDeferOtherFamilyNamesLoading = true, + FindFamiliesFlags aFlags = FindFamiliesFlags(0), gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0) { AutoTArray families; return FindAndAddFamilies(aFamily, &families, - aDeferOtherFamilyNamesLoading, + aFlags, aStyle, aDevToCssSize) ? families[0] : nullptr; } @@ -477,6 +497,10 @@ protected: void ApplyWhitelist(); + // Create a new gfxFontFamily of the appropriate subclass for the platform, + // used when AddWithLegacyFamilyName needs to create a new family. + virtual gfxFontFamily* CreateFontFamily(const nsAString& aName) const = 0; + typedef nsRefPtrHashtable FontFamilyTable; typedef nsRefPtrHashtable FontEntryTable; @@ -565,4 +589,6 @@ protected: bool mFontFamilyWhitelistActive; }; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxPlatformFontList::FindFamiliesFlags) + #endif /* GFXPLATFORMFONTLIST_H_ */ diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 98ee81d04f8d..64917a018b2b 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1873,7 +1873,9 @@ gfxFontGroup::AddPlatformFont(const nsAString& aName, // Not known in the user font set ==> check system fonts gfxPlatformFontList::PlatformFontList() - ->FindAndAddFamilies(aName, &aFamilyList, true, &mStyle, mDevToCssSize); + ->FindAndAddFamilies(aName, &aFamilyList, + gfxPlatformFontList::FindFamiliesFlags(0), + &mStyle, mDevToCssSize); } void diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 0618797d4779..1c84ceb128d5 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -630,8 +630,8 @@ public: gfxCharacterMap* aUnicodeRanges, uint8_t aFontDisplay); - virtual gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle, - bool aNeedsBold); + gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle, + bool aNeedsBold) override; gfxFontEntry* GetPlatformFontEntry() const { return mPlatformFontEntry; } @@ -673,6 +673,11 @@ public: void GetFamilyNameAndURIForLogging(nsACString& aFamilyName, nsACString& aURI); + gfxFontEntry* Clone() const override { + MOZ_ASSERT_UNREACHABLE("cannot Clone user fonts"); + return nullptr; + } + protected: const uint8_t* SanitizeOpenTypeData(const uint8_t* aData, uint32_t aLength, diff --git a/layout/reftests/bugs/481948-2-ref.html b/layout/reftests/bugs/481948-2-ref.html index e8d6e89e5bf1..dac69d48acd8 100644 --- a/layout/reftests/bugs/481948-2-ref.html +++ b/layout/reftests/bugs/481948-2-ref.html @@ -3,7 +3,7 @@ + +Hello world + diff --git a/layout/reftests/font-matching/legacy-family-names-1.html b/layout/reftests/font-matching/legacy-family-names-1.html new file mode 100644 index 000000000000..7cec0ffd458f --- /dev/null +++ b/layout/reftests/font-matching/legacy-family-names-1.html @@ -0,0 +1,9 @@ + + + + + +Hello world + diff --git a/layout/reftests/font-matching/legacy-family-names-2-ref.html b/layout/reftests/font-matching/legacy-family-names-2-ref.html new file mode 100644 index 000000000000..2a9ba842463b --- /dev/null +++ b/layout/reftests/font-matching/legacy-family-names-2-ref.html @@ -0,0 +1,9 @@ + + + + + +Hello world + diff --git a/layout/reftests/font-matching/legacy-family-names-2.html b/layout/reftests/font-matching/legacy-family-names-2.html new file mode 100644 index 000000000000..112a5407421e --- /dev/null +++ b/layout/reftests/font-matching/legacy-family-names-2.html @@ -0,0 +1,9 @@ + + + + + +Hello world + diff --git a/layout/reftests/font-matching/reftest.list b/layout/reftests/font-matching/reftest.list index 37c646e8b5d5..aed58e9c448c 100644 --- a/layout/reftests/font-matching/reftest.list +++ b/layout/reftests/font-matching/reftest.list @@ -133,3 +133,9 @@ skip-if(!cocoaWidget) HTTP(..) != apple-symbols-1.html apple-symbols-1-notref.ht # random-if(!OSX) != system-generic-fallback-zh-tw.html system-generic-fallback-ja.html # random-if(!OSX) != system-generic-fallback-zh-cn.html system-generic-fallback-ja.html # random-if(!OSX) != system-generic-fallback-zh-tw.html system-generic-fallback-zh-cn.html + +# Tests for legacy font family name (GDI-model families) matching; +# these depend on specific fonts that are available as standard on macOS and Windows, +# and are not expected to pass on platforms that don't have those same fonts. +skip-if(!cocoaWidget) == legacy-family-names-1.html legacy-family-names-1-ref.html +skip-if(!winWidget) == legacy-family-names-2.html legacy-family-names-2-ref.html