Bug 1245811 - Make gfxPlatformFontList::FindFamily return a list of families, fixing fontconfig prioritization. r?karlt
MozReview-Commit-ID: B8ZhoAMvjgc
--- a/gfx/thebes/gfxFcPlatformFontList.cpp
+++ b/gfx/thebes/gfxFcPlatformFontList.cpp
@@ -1179,19 +1179,20 @@ gfxFcPlatformFontList::MakePlatformFont(
NS_Free((void*)aFontData);
return nullptr;
}
return new gfxFontconfigFontEntry(aFontName, aWeight, aStretch,
aStyle, aFontData, face);
}
-gfxFontFamily*
-gfxFcPlatformFontList::FindFamily(const nsAString& aFamily, gfxFontStyle* aStyle,
- gfxFloat aDevToCssSize)
+void
+gfxFcPlatformFontList::FindFamily(const nsAString& aFamily,
+ nsTArray<gfxFontFamily*>& aOutput,
+ gfxFontStyle* aStyle, gfxFloat aDevToCssSize)
{
nsAutoString familyName(aFamily);
ToLowerCase(familyName);
nsIAtom* language = (aStyle ? aStyle->language.get() : nullptr);
// deprecated generic names are explicitly converted to standard generics
bool isDeprecatedGeneric = false;
if (familyName.EqualsLiteral("sans") ||
@@ -1203,19 +1204,19 @@ gfxFcPlatformFontList::FindFamily(const
isDeprecatedGeneric = true;
}
// fontconfig generics? use fontconfig to determine the family for lang
if (isDeprecatedGeneric ||
mozilla::FontFamilyName::Convert(familyName).IsGeneric()) {
PrefFontList* prefFonts = FindGenericFamilies(familyName, language);
if (prefFonts && !prefFonts->IsEmpty()) {
- return (*prefFonts)[0];
+ aOutput.AppendElement((*prefFonts)[0]);
}
- return nullptr;
+ return;
}
// fontconfig allows conditional substitutions in such a way that it's
// difficult to distinguish an explicit substitution from other suggested
// choices. To sniff out explicit substitutions, compare the substitutions
// for "font, -moz-sentinel" to "-moz-sentinel" to sniff out the
// substitutions
//
@@ -1225,57 +1226,54 @@ gfxFcPlatformFontList::FindFamily(const
// Helvetica, serif ==> Helvetica, TeX Gyre Heros, Nimbus Sans L, DejaVu Serif
//
// In this case fontconfig is including Tex Gyre Heros and
// Nimbus Sans L as alternatives for Helvetica.
// Because the FcConfigSubstitute call is quite expensive, we cache the
// actual font family found via this process. So check the cache first:
NS_ConvertUTF16toUTF8 familyToFind(familyName);
- gfxFontFamily* cached = mFcSubstituteCache.GetWeak(familyToFind);
- if (cached) {
- return cached;
+
+ // Create a new cache entry for the given family, or fetch cached font families.
+ auto families = mFcSubstituteCache.LookupOrAdd(familyToFind);
+ if (families->Length() > 0) {
+ aOutput.AppendElements(*families);
+ return;
}
const FcChar8* kSentinelName = ToFcChar8Ptr("-moz-sentinel");
FcChar8* sentinelFirstFamily = nullptr;
nsAutoRef<FcPattern> sentinelSubst(FcPatternCreate());
FcPatternAddString(sentinelSubst, FC_FAMILY, kSentinelName);
FcConfigSubstitute(nullptr, sentinelSubst, FcMatchPattern);
FcPatternGetString(sentinelSubst, FC_FAMILY, 0, &sentinelFirstFamily);
// substitutions for font, -moz-sentinel pattern
nsAutoRef<FcPattern> fontWithSentinel(FcPatternCreate());
FcPatternAddString(fontWithSentinel, FC_FAMILY,
ToFcChar8Ptr(familyToFind.get()));
FcPatternAddString(fontWithSentinel, FC_FAMILY, kSentinelName);
FcConfigSubstitute(nullptr, fontWithSentinel, FcMatchPattern);
- // iterate through substitutions until hitting the sentinel
+ // Add all font family matches until reaching the sentinel.
FcChar8* substName = nullptr;
for (int i = 0;
FcPatternGetString(fontWithSentinel, FC_FAMILY,
i, &substName) == FcResultMatch;
i++)
{
NS_ConvertUTF8toUTF16 subst(ToCharPtr(substName));
if (sentinelFirstFamily &&
FcStrCmp(substName, sentinelFirstFamily) == 0) {
break;
}
- gfxFontFamily* foundFamily = gfxPlatformFontList::FindFamily(subst);
- if (foundFamily) {
- // We've figured out what family the given name maps to, after any
- // fontconfig subsitutions. Cache it to speed up future lookups.
- mFcSubstituteCache.Put(familyToFind, foundFamily);
- return foundFamily;
- }
+ gfxPlatformFontList::FindFamily(subst, *families);
}
- return nullptr;
+ aOutput.AppendElements(*families);
}
bool
gfxFcPlatformFontList::GetStandardFamilyName(const nsAString& aFontName,
nsAString& aFamilyName)
{
aFamilyName.Truncate();
@@ -1542,20 +1540,20 @@ gfxFcPlatformFontList::FindGenericFamili
if (FcPatternGetBool(font, FC_SCALABLE, 0, &scalable) != FcResultMatch ||
!scalable) {
continue;
}
FcPatternGetString(font, FC_FAMILY, 0, &mappedGeneric);
if (mappedGeneric) {
NS_ConvertUTF8toUTF16 mappedGenericName(ToCharPtr(mappedGeneric));
- gfxFontFamily* genericFamily =
- gfxPlatformFontList::FindFamily(mappedGenericName);
- if (genericFamily && !prefFonts->Contains(genericFamily)) {
- prefFonts->AppendElement(genericFamily);
+ nsTArray<gfxFontFamily*> genericFamilies;
+ gfxPlatformFontList::FindFamily(mappedGenericName, genericFamilies);
+ if (genericFamilies.Length() > 0) {
+ prefFonts->AppendElements(genericFamilies);
bool foundLang = !fcLang.IsEmpty() &&
PatternHasLang(font, ToFcChar8Ptr(fcLang.get()));
foundFontWithLang = foundFontWithLang || foundLang;
// check to see if the list is full
if (prefFonts->Length() >= limit) {
break;
}
}
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -6,16 +6,17 @@
#ifndef GFXFCPLATFORMFONTLIST_H_
#define GFXFCPLATFORMFONTLIST_H_
#include "gfxFont.h"
#include "gfxFontEntry.h"
#include "gfxFT2FontBase.h"
#include "gfxPlatformFontList.h"
#include "mozilla/mozalloc.h"
+#include "nsClassHashtable.h"
#include <fontconfig/fontconfig.h>
#include "ft2build.h"
#include FT_FREETYPE_H
#include FT_TRUETYPE_TABLES_H
#include <cairo.h>
#include <cairo-ft.h>
@@ -219,19 +220,20 @@ public:
gfxFontEntry*
MakePlatformFont(const nsAString& aFontName, uint16_t aWeight,
int16_t aStretch,
uint8_t aStyle,
const uint8_t* aFontData,
uint32_t aLength) override;
- gfxFontFamily* FindFamily(const nsAString& aFamily,
- gfxFontStyle* aStyle = nullptr,
- gfxFloat aDevToCssSize = 1.0) override;
+ void FindFamily(const nsAString& aFamily,
+ nsTArray<gfxFontFamily*>& aOutput,
+ gfxFontStyle* aStyle = nullptr,
+ gfxFloat aDevToCssSize = 1.0) override;
bool GetStandardFamilyName(const nsAString& aFontName,
nsAString& aFamilyName) override;
FcConfig* GetLastConfig() const { return mLastConfig; }
// override to use fontconfig lookup for generics
void AddGenericFonts(mozilla::FontFamilyType aGenericType,
@@ -276,17 +278,17 @@ protected:
FcPattern*> mLocalNames;
// caching generic/lang ==> font family list
nsBaseHashtable<nsCStringHashKey,
nsAutoPtr<PrefFontList>,
PrefFontList*> mGenericMappings;
// caching family lookups as found by FindFamily after resolving substitutions
- nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> mFcSubstituteCache;
+ nsClassHashtable<nsCStringHashKey, nsTArray<gfxFontFamily*>> mFcSubstituteCache;
nsCOMPtr<nsITimer> mCheckFontUpdatesTimer;
nsCountedRef<FcConfig> mLastConfig;
// By default, font prefs under Linux are set to simply lookup
// via fontconfig the appropriate font for serif/sans-serif/monospace.
// Rather than check each time a font pref is used, check them all at startup
// and set a boolean to flag the case that non-default user font prefs exist
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -635,67 +635,69 @@ gfxPlatformFontList::CheckFamily(gfxFont
GenerateFontListKey(aFamily->Name(), key);
mFontFamilies.Remove(key);
return nullptr;
}
return aFamily;
}
-gfxFontFamily*
-gfxPlatformFontList::FindFamily(const nsAString& aFamily, gfxFontStyle* aStyle,
+void
+gfxPlatformFontList::FindFamily(const nsAString& aFamily,
+ nsTArray<gfxFontFamily*>& aOutput,
+ gfxFontStyle* aStyle,
gfxFloat aDevToCssSize)
{
nsAutoString key;
gfxFontFamily *familyEntry;
GenerateFontListKey(aFamily, key);
NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
// lookup in canonical (i.e. English) family name list
if ((familyEntry = mFontFamilies.GetWeak(key))) {
- return CheckFamily(familyEntry);
+ aOutput.AppendElement(CheckFamily(familyEntry));
+ return;
}
// lookup in other family names list (mostly localized names)
if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
- return CheckFamily(familyEntry);
+ aOutput.AppendElement(CheckFamily(familyEntry));
+ return;
}
// name not found and other family names not yet fully initialized so
// initialize the rest of the list and try again. this is done lazily
// since reading name table entries is expensive.
// although ASCII localized family names are possible they don't occur
// in practice so avoid pulling in names at startup
if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
InitOtherFamilyNames();
if ((familyEntry = mOtherFamilyNames.GetWeak(key)) != nullptr) {
- return CheckFamily(familyEntry);
+ aOutput.AppendElement(CheckFamily(familyEntry));
} else if (!mOtherFamilyNamesInitialized) {
// localized family names load timed out, add name to list of
// names to check after localized names are loaded
if (!mOtherNamesMissed) {
mOtherNamesMissed = new nsTHashtable<nsStringHashKey>(2);
}
mOtherNamesMissed->PutEntry(key);
}
}
-
- return nullptr;
}
gfxFontEntry*
gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
{
- gfxFontFamily *familyEntry = FindFamily(aFamily);
+ gfxFontFamily* family = FindFamilyByCanonicalName(aFamily);
aNeedsBold = false;
- if (familyEntry)
- return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
+ if (family)
+ return family->FindFontForStyle(*aStyle, aNeedsBold);
return nullptr;
}
void
gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
{
nsAutoString key;
@@ -733,21 +735,22 @@ gfxPlatformFontList::AddPostscriptName(g
NS_ConvertUTF16toUTF8(aPostscriptName).get()));
}
}
bool
gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
{
aFamilyName.Truncate();
- gfxFontFamily *ff = FindFamily(aFontName);
- if (!ff) {
+
+ gfxFontFamily* family = FindFamilyByCanonicalName(aFontName);
+ if (!family)
return false;
- }
- aFamilyName.Assign(ff->Name());
+
+ aFamilyName.Assign(family->Name());
return true;
}
gfxCharacterMap*
gfxPlatformFontList::FindCharMap(gfxCharacterMap *aCmap)
{
aCmap->CalcHash();
gfxCharacterMap *cmap = AddCmap(aCmap);
@@ -814,29 +817,22 @@ gfxPlatformFontList::ResolveGenericFontN
nsIAtom* langGroup = GetLangGroupForPrefLang(aPrefLang);
NS_ASSERTION(langGroup, "null lang group for pref lang");
// lookup and add platform fonts uniquely
for (const nsString& genericFamily : genericFamilies) {
gfxFontStyle style;
style.language = langGroup;
style.systemFont = false;
- RefPtr<gfxFontFamily> family =
- FindFamily(genericFamily, &style);
- if (family) {
- bool notFound = true;
- for (const gfxFontFamily* f : *aGenericFamilies) {
- if (f == family) {
- notFound = false;
- break;
- }
- }
- if (notFound) {
- aGenericFamilies->AppendElement(family);
- }
+ nsTArray<gfxFontFamily*> families;
+ FindFamily(genericFamily, families, &style);
+ for (gfxFontFamily* f : families) {
+ if (!aGenericFamilies->Contains(f)) {
+ aGenericFamilies->AppendElement(f);
+ }
}
}
#if 0 // dump out generic mappings
printf("%s ===> ", prefFontName.get());
for (uint32_t k = 0; k < aGenericFamilies->Length(); k++) {
if (k > 0) printf(", ");
printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]->Name()).get());
@@ -1436,17 +1432,17 @@ gfxPlatformFontList::CleanupLoader()
break;
}
}
mFaceNamesMissed = nullptr;
}
if (mOtherNamesMissed) {
for (auto it = mOtherNamesMissed->Iter(); !it.Done(); it.Next()) {
- if (FindFamily(it.Get()->GetKey())) {
+ if (FindFamilyByCanonicalName(it.Get()->GetKey())) {
forceReflow = true;
ForceGlobalReflow();
break;
}
}
mOtherNamesMissed = nullptr;
}
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -124,19 +124,19 @@ public:
virtual void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray);
gfxFontEntry*
SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
int32_t aRunScript,
const gfxFontStyle* aStyle);
- virtual gfxFontFamily*
- FindFamily(const nsAString& aFamily, gfxFontStyle* aStyle = nullptr,
- gfxFloat aDevToCssSize = 1.0);
+ virtual void
+ FindFamily(const nsAString& aFamily, nsTArray<gfxFontFamily*>& aOutput,
+ gfxFontStyle* aStyle = nullptr, gfxFloat aDevToCssSize = 1.0);
gfxFontEntry* FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold);
// name lookup table methods
void AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName);
void AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname);
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -1654,26 +1654,23 @@ gfxFontGroup::AddPlatformFont(const nsAS
// First, look up in the user font set...
// If the fontSet matches the family, we must not look for a platform
// font of the same name, even if we fail to actually get a fontEntry
// here; we'll fall back to the next name in the CSS font-family list.
if (mUserFontSet) {
// Add userfonts to the fontlist whether already loaded
// or not. Loading is initiated during font matching.
family = mUserFontSet->LookupFamily(aName);
+ aFamilyList.AppendElement(family);
}
// Not known in the user font set ==> check system fonts
gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList();
if (!family) {
- family = fontList->FindFamily(aName, &mStyle, mDevToCssSize);
- }
-
- if (family) {
- aFamilyList.AppendElement(family);
+ fontList->FindFamily(aName, aFamilyList, &mStyle, mDevToCssSize);
}
}
void
gfxFontGroup::AddFamilyToFontList(gfxFontFamily* aFamily)
{
NS_ASSERTION(aFamily, "trying to add a null font family to fontlist");
AutoTArray<gfxFontEntry*,4> fontEntryList;