Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFXPLATFORMFONTLIST_H_
#define GFXPLATFORMFONTLIST_H_
#include "nsClassHashtable.h"
#include "nsTHashMap.h"
#include "nsTHashSet.h"
#include "nsRefPtrHashtable.h"
#include "nsTHashtable.h"
#include "gfxFontUtils.h"
#include "gfxFontInfoLoader.h"
#include "gfxFont.h"
#include "gfxFontConstants.h"
#include "gfxPlatform.h"
#include "SharedFontList.h"
#include "nsIMemoryReporter.h"
#include "mozilla/Attributes.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/FontPropertyTypes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/RangedArray.h"
#include "mozilla/RecursiveMutex.h"
#include "nsLanguageAtomService.h"
#include "base/shared_memory.h"
namespace mozilla {
namespace fontlist {
struct AliasData;
}
} // namespace mozilla
class CharMapHashKey : public PLDHashEntryHdr {
public:
typedef gfxCharacterMap* KeyType;
typedef const gfxCharacterMap* KeyTypePointer;
explicit CharMapHashKey(const gfxCharacterMap* aCharMap)
: mCharMap(const_cast<gfxCharacterMap*>(aCharMap)) {
MOZ_COUNT_CTOR(CharMapHashKey);
}
CharMapHashKey(const CharMapHashKey& toCopy) : mCharMap(toCopy.mCharMap) {
MOZ_COUNT_CTOR(CharMapHashKey);
}
MOZ_COUNTED_DTOR(CharMapHashKey)
gfxCharacterMap* GetKey() const { return mCharMap.get(); }
bool KeyEquals(const gfxCharacterMap* aCharMap) const {
MOZ_ASSERT(!aCharMap->mBuildOnTheFly && !mCharMap->mBuildOnTheFly,
"custom cmap used in shared cmap hashtable");
// cmaps built on the fly never match
if (aCharMap->mHash != mCharMap->mHash) {
return false;
}
return mCharMap->Equals(aCharMap);
}
static const gfxCharacterMap* KeyToPointer(gfxCharacterMap* aCharMap) {
return aCharMap;
}
static PLDHashNumber HashKey(const gfxCharacterMap* aCharMap) {
return aCharMap->mHash;
}
enum { ALLOW_MEMMOVE = true };
protected:
friend class gfxPlatformFontList;
// gfxCharacterMap::Release() will notify us when the refcount of a
// charmap drops to 1; at that point, we'll lock the cache, check if
// the charmap is owned by the cache and this is still the only ref,
// and if so, delete it.
RefPtr<gfxCharacterMap> mCharMap;
};
/**
* A helper class used to create a SharedBitSet instance in a FontList's shared
* memory, while ensuring that we avoid bloating memory by avoiding creating
* duplicate instances.
*/
class ShmemCharMapHashEntry final : public PLDHashEntryHdr {
public:
typedef const gfxSparseBitSet* KeyType;
typedef const gfxSparseBitSet* KeyTypePointer;
/**
* Creation from a gfxSparseBitSet creates not only the ShmemCharMapHashEntry
* itself, but also a SharedBitSet in shared memory.
* Only the parent process creates and manages these entries.
*/
explicit ShmemCharMapHashEntry(const gfxSparseBitSet* aCharMap);
ShmemCharMapHashEntry(ShmemCharMapHashEntry&&) = default;
ShmemCharMapHashEntry& operator=(ShmemCharMapHashEntry&&) = default;
/**
* Return a shared-memory Pointer that refers to the wrapped SharedBitSet.
* This can be passed to content processes to give them access to the same
* SharedBitSet as the parent stored.
*/
mozilla::fontlist::Pointer GetCharMap() const { return mCharMap; }
bool KeyEquals(KeyType aCharMap) const {
// mHash is a 32-bit Adler checksum of the bitset; if it doesn't match we
// can immediately reject it as non-matching, but if it is equal we still
// need to do a full equality check below.
if (mHash != aCharMap->GetChecksum()) {
return false;
}
return mCharMap.ToPtr<const SharedBitSet>(mList)->Equals(aCharMap);
}
static KeyTypePointer KeyToPointer(KeyType aCharMap) { return aCharMap; }
static PLDHashNumber HashKey(KeyType aCharMap) {
return aCharMap->GetChecksum();
}
enum { ALLOW_MEMMOVE = false }; // because of the Pointer member
private:
// charMaps are stored in the shared memory that FontList objects point to,
// and are never deleted until the FontList (all referencing font lists,
// actually) have gone away.
mozilla::fontlist::FontList* mList;
mozilla::fontlist::Pointer mCharMap;
uint32_t mHash;
};
// gfxPlatformFontList is an abstract class for the global font list on the
// system; concrete subclasses for each platform implement the actual interface
// to the system fonts. This class exists because we cannot rely on the platform
// font-finding APIs to behave in sensible/similar ways, particularly with rich,
// complex OpenType families, so we do our own font family/style management here
// instead.
// Much of this is based on the old gfxQuartzFontCache, but adapted for use on
// all platforms.
struct FontListSizes {
uint32_t mFontListSize; // size of the font list and dependent objects
// (font family and face names, etc), but NOT
// including the font table cache and the cmaps
uint32_t
mFontTableCacheSize; // memory used for the gfxFontEntry table caches
uint32_t mCharMapsSize; // memory used for cmap coverage info
uint32_t mLoaderSize; // memory used for (platform-specific) loader
uint32_t mSharedSize; // shared-memory use (reported by parent only)
};
class gfxUserFontSet;
class gfxPlatformFontList : public gfxFontInfoLoader {
friend class InitOtherFamilyNamesRunnable;
public:
typedef mozilla::StretchRange StretchRange;
typedef mozilla::SlantStyleRange SlantStyleRange;
typedef mozilla::WeightRange WeightRange;
typedef mozilla::intl::Script Script;
using AutoLock = mozilla::RecursiveMutexAutoLock;
using AutoUnlock = mozilla::RecursiveMutexAutoUnlock;
// Class used to hold cached copies of the font-name prefs, so that they can
// be accessed from non-main-thread callers who are not allowed to touch the
// Preferences service.
class FontPrefs final {
public:
using HashMap = nsTHashMap<nsCStringHashKey, nsCString>;
FontPrefs();
~FontPrefs() = default;
FontPrefs(const FontPrefs& aOther) = delete;
FontPrefs& operator=(const FontPrefs& aOther) = delete;
// Lookup the font.name.<foo> or font.name-list.<foo> pref for a given
// generic+langgroup pair.
bool LookupName(const nsACString& aPref, nsACString& aValue) const;
bool LookupNameList(const nsACString& aPref, nsACString& aValue) const;
// Does the font.name-list.emoji pref have a user-set value?
bool EmojiHasUserValue() const { return mEmojiHasUserValue; }
// Expose iterators over all the defined prefs of each type.
HashMap::ConstIterator NameIter() const { return mFontName.ConstIter(); }
HashMap::ConstIterator NameListIter() const {
return mFontNameList.ConstIter();
}
private:
static constexpr char kNamePrefix[] = "font.name.";
static constexpr char kNameListPrefix[] = "font.name-list.";
void Init();
HashMap mFontName;
HashMap mFontNameList;
bool mEmojiHasUserValue = false;
};
// For font family lists loaded from user preferences (prefs such as
// font.name-list.<generic>.<langGroup>) that map CSS generics to
// platform-specific font families.
typedef nsTArray<FontFamily> PrefFontList;
// Return the global font-list singleton, or NULL if aMustInitialize is false
// and it has not yet been fully initialized.
static gfxPlatformFontList* PlatformFontList(bool aMustInitialize = true) {
if (!aMustInitialize &&
!(sPlatformFontList && sPlatformFontList->IsInitialized())) {
return nullptr;
}
// If there is a font-list initialization thread, we need to let it run
// to completion before the font list can be used for anything else.
if (sInitFontListThread) {
// If we're currently on the initialization thread, just continue;
// otherwise wait for it to finish.
if (IsInitFontListThread()) {
return sPlatformFontList;
}
PR_JoinThread(sInitFontListThread);
sInitFontListThread = nullptr;
// If font-list initialization failed, the thread will have cleared
// the static sPlatformFontList pointer; we cannot proceed without any
// usable fonts.
if (!sPlatformFontList) {
MOZ_CRASH("Could not initialize gfxPlatformFontList");
}
}
if (!sPlatformFontList->IsInitialized()) {
if (!sPlatformFontList->InitFontList()) {
MOZ_CRASH("Could not initialize gfxPlatformFontList");
}
}
return sPlatformFontList;
}
void GetMissingFonts(nsCString& aMissingFonts);
static bool Initialize(gfxPlatformFontList* aList);
static void Shutdown() {
// Ensure any font-list initialization thread is finished before we delete
// the platform fontlist singleton, which that thread may try to use.
if (sInitFontListThread && !IsInitFontListThread()) {
PR_JoinThread(sInitFontListThread);
sInitFontListThread = nullptr;
}
delete sPlatformFontList;
sPlatformFontList = nullptr;
}
bool IsInitialized() const { return mFontlistInitCount; }
virtual ~gfxPlatformFontList();
// Initialize font lists; return true on success, false if something fails.
bool InitFontList();
void FontListChanged();
/**
* Gathers (from a platform's underlying font system) the information needed
* to initialize a fontlist::Family with its Face members.
*/
virtual void GetFacesInitDataForFamily(
const mozilla::fontlist::Family* aFamily,
nsTArray<mozilla::fontlist::Face::InitData>& aFaces,
bool aLoadCmaps) const {}
virtual void GetFontList(nsAtom* aLangGroup, const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts);
// Pass false to notify content that the shared font list has been modified
// but not completely invalidated.
void UpdateFontList(bool aFullRebuild = true);
void ClearLangGroupPrefFonts() {
AutoLock lock(mLock);
ClearLangGroupPrefFontsLocked();
}
virtual void ClearLangGroupPrefFontsLocked() MOZ_REQUIRES(mLock);
void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily>>& aFamilyArray);
already_AddRefed<gfxFont> SystemFindFontForChar(
nsPresContext* aPresContext, uint32_t aCh, uint32_t aNextCh,
Script aRunScript, eFontPresentation aPresentation,
const gfxFontStyle* aStyle, FontVisibility* aVisibility);
// 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,
// If set, FindAndAddFamilies will not add a missing entry to
// mOtherNamesMissed
eNoAddToNamesMissedWhenSearching = 1 << 2,
// If set, the family name was quoted and so must not be treated as a CSS
// generic.
eQuotedFamilyName = 1 << 3,
// If set, "hidden" font families (like ".SF NS Text" on macOS) are
// searched in addition to standard user-visible families.
eSearchHiddenFamilies = 1 << 4,
};
// 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.
bool FindAndAddFamilies(
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0);
virtual bool FindAndAddFamiliesLocked(
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGeneric,
const nsACString& aFamily, nsTArray<FamilyAndGeneric>* aOutput,
FindFamiliesFlags aFlags, gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr, gfxFloat aDevToCssSize = 1.0)
MOZ_REQUIRES(mLock);
gfxFontEntry* FindFontForFamily(nsPresContext* aPresContext,
const nsACString& aFamily,
const gfxFontStyle* aStyle);
mozilla::fontlist::FontList* SharedFontList() const {
return mSharedFontList.get();
}
// Create a handle for a single shmem block (identified by index) ready to
// be shared to the given processId.
void ShareFontListShmBlockToProcess(uint32_t aGeneration, uint32_t aIndex,
base::ProcessId aPid,
base::SharedMemoryHandle* aOut);
// Populate the array aBlocks with the complete list of shmem handles ready
// to be shared to the given processId.
void ShareFontListToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
base::ProcessId aPid);
void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
base::SharedMemoryHandle aHandle);
base::SharedMemoryHandle ShareShmBlockToProcess(uint32_t aIndex,
base::ProcessId aPid);
void SetCharacterMap(uint32_t aGeneration, uint32_t aFamilyIndex, bool aAlias,
uint32_t aFaceIndex, const gfxSparseBitSet& aMap);
void SetupFamilyCharMap(uint32_t aGeneration, uint32_t aIndex, bool aAlias);
// Start the async cmap loading process, if not already under way, from the
// given family index. (For use in any process that needs font lookups.)
void StartCmapLoadingFromFamily(uint32_t aStartIndex);
// [Parent] Handle request from content process to start cmap loading.
void StartCmapLoading(uint32_t aGeneration, uint32_t aStartIndex);
void CancelLoadCmapsTask() {
if (mLoadCmapsRunnable) {
mLoadCmapsRunnable->Cancel();
mLoadCmapsRunnable = nullptr;
}
}
// Populate aFamily with face records, and if aLoadCmaps is true, also load
// their character maps (rather than leaving this to be done lazily).
// Note that even when aFamily->IsInitialized() is true, it can make sense
// to call InitializeFamily again if passing aLoadCmaps=true, in order to
// ensure cmaps are loaded.
[[nodiscard]] bool InitializeFamily(mozilla::fontlist::Family* aFamily,
bool aLoadCmaps = false);
void InitializeFamily(uint32_t aGeneration, uint32_t aFamilyIndex,
bool aLoadCmaps);
// name lookup table methods
void AddOtherFamilyNames(gfxFontFamily* aFamilyEntry,
const nsTArray<nsCString>& aOtherFamilyNames);
void AddFullname(gfxFontEntry* aFontEntry, const nsCString& aFullname) {
AutoLock lock(mLock);
AddFullnameLocked(aFontEntry, aFullname);
}
void AddFullnameLocked(gfxFontEntry* aFontEntry, const nsCString& aFullname)
MOZ_REQUIRES(mLock);
void AddPostscriptName(gfxFontEntry* aFontEntry,
const nsCString& aPostscriptName) {
AutoLock lock(mLock);
AddPostscriptNameLocked(aFontEntry, aPostscriptName);
}
void AddPostscriptNameLocked(gfxFontEntry* aFontEntry,
const nsCString& aPostscriptName)
MOZ_REQUIRES(mLock);
bool NeedFullnamePostscriptNames() { return mExtraNames != nullptr; }
/**
* Read PSName and FullName of the given face, for src:local lookup,
* returning true if actually implemented and succeeded.
*/
virtual bool ReadFaceNames(const mozilla::fontlist::Family* aFamily,
const mozilla::fontlist::Face* aFace,
nsCString& aPSName, nsCString& aFullName) {
return false;
}
// initialize localized family names
bool InitOtherFamilyNames(bool aDeferOtherFamilyNamesLoading);
bool InitOtherFamilyNames(uint32_t aGeneration, bool aDefer);
// pure virtual functions, to be provided by concrete subclasses
// get the system default font family
FontFamily GetDefaultFont(nsPresContext* aPresContext,
const gfxFontStyle* aStyle);
FontFamily GetDefaultFontLocked(nsPresContext* aPresContext,
const gfxFontStyle* aStyle)
MOZ_REQUIRES(mLock);
// get the "ultimate" default font, for use if the font list is otherwise
// unusable (e.g. in the middle of being updated)
gfxFontEntry* GetDefaultFontEntry() {
AutoLock lock(mLock);
return mDefaultFontEntry.get();
}
/**
* Look up a font by name on the host platform.
*
* Note that the style attributes (weight, stretch, style) are NOT used in
* selecting the platform font, which is looked up by name only; these are
* values to be recorded in the new font entry.
*/
virtual gfxFontEntry* LookupLocalFont(nsPresContext* aPresContext,
const nsACString& aFontName,
WeightRange aWeightForEntry,
StretchRange aStretchForEntry,
SlantStyleRange aStyleForEntry) = 0;
/**
* Create a new platform font from downloaded data (@font-face).
*
* Note that the style attributes (weight, stretch, style) are NOT related
* (necessarily) to any values within the font resource itself; these are
* values to be recorded in the new font entry and used for face selection,
* in place of whatever inherent style attributes the resource may have.
*
* This method takes ownership of the data block passed in as aFontData,
* and must ensure it is free()'d when no longer required.
*/
virtual gfxFontEntry* MakePlatformFont(const nsACString& aFontName,
WeightRange aWeightForEntry,
StretchRange aStretchForEntry,
SlantStyleRange aStyleForEntry,
const uint8_t* aFontData,
uint32_t aLength) = 0;
// get the standard family name on the platform for a given font name
// (platforms may override, eg Mac)
virtual bool GetStandardFamilyName(const nsCString& aFontName,
nsACString& aFamilyName);
// Get the localized family name for a given font family.
bool GetLocalizedFamilyName(const FontFamily& aFamily,
nsACString& aFamilyName);
// get the default font name which is available on the system from
// font.name-list.*. if there are no available fonts in the pref,
// returns an empty FamilyAndGeneric record.
FamilyAndGeneric GetDefaultFontFamily(const nsACString& aLangGroup,
const nsACString& aGenericFamily);
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const;
mozilla::fontlist::Pointer GetShmemCharMap(const gfxSparseBitSet* aCmap) {
AutoLock lock(mLock);
return GetShmemCharMapLocked(aCmap);
}
mozilla::fontlist::Pointer GetShmemCharMapLocked(const gfxSparseBitSet* aCmap)
MOZ_REQUIRES(mLock);
// Search for existing cmap that matches the input; return the input if no
// match is found.
already_AddRefed<gfxCharacterMap> FindCharMap(gfxCharacterMap* aCmap);
// Remove the cmap from the shared cmap set if it holds the only remaining
// reference to the object.
void MaybeRemoveCmap(gfxCharacterMap* aCharMap);
// Keep track of userfont sets to notify when global fontlist changes occur.
void AddUserFontSet(gfxUserFontSet* aUserFontSet) {
AutoLock lock(mLock);
mUserFontSetList.Insert(aUserFontSet);
}
void RemoveUserFontSet(gfxUserFontSet* aUserFontSet) {
AutoLock lock(mLock);
mUserFontSetList.Remove(aUserFontSet);
}
static const gfxFontEntry::ScriptRange sComplexScriptRanges[];
void GetFontlistInitInfo(uint32_t& aNumInits, uint32_t& aLoaderState) {
aNumInits = mFontlistInitCount;
aLoaderState = (uint32_t)mState;
}
virtual void AddGenericFonts(nsPresContext* aPresContext,
mozilla::StyleGenericFontFamily aGenericType,
nsAtom* aLanguage,
nsTArray<FamilyAndGeneric>& aFamilyList);
/**
* Given a Face from the shared font list, return a gfxFontEntry usable
* by the current process. This returns a cached entry if available,
* otherwise it calls the (platform-specific) CreateFontEntry method to
* make one, and adds it to the cache.
*/
gfxFontEntry* GetOrCreateFontEntry(mozilla::fontlist::Face* aFace,
const mozilla::fontlist::Family* aFamily) {
AutoLock lock(mLock);
return GetOrCreateFontEntryLocked(aFace, aFamily);
}
gfxFontEntry* GetOrCreateFontEntryLocked(
mozilla::fontlist::Face* aFace, const mozilla::fontlist::Family* aFamily)
MOZ_REQUIRES(mLock);
const FontPrefs* GetFontPrefs() const MOZ_REQUIRES(mLock) {
return mFontPrefs.get();
}
bool EmojiPrefHasUserValue() const {
AutoLock lock(mLock);
return mFontPrefs->EmojiHasUserValue();
}
PrefFontList* GetPrefFontsLangGroup(
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGenericType,
eFontPrefLang aPrefLang) {
AutoLock lock(mLock);
return GetPrefFontsLangGroupLocked(aPresContext, aGenericType, aPrefLang);
}
PrefFontList* GetPrefFontsLangGroupLocked(
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGenericType,
eFontPrefLang aPrefLang) MOZ_REQUIRES(mLock);
// in some situations, need to make decisions about ambiguous characters, may
// need to look at multiple pref langs
void GetLangPrefs(eFontPrefLang aPrefLangs[], uint32_t& aLen,
eFontPrefLang aCharLang, eFontPrefLang aPageLang);
// convert a lang group to enum constant (i.e. "zh-TW" ==>
// eFontPrefLang_ChineseTW)
static eFontPrefLang GetFontPrefLangFor(const char* aLang);
// convert a lang group atom to enum constant
static eFontPrefLang GetFontPrefLangFor(nsAtom* aLang);
// convert an enum constant to a lang group atom
static nsAtom* GetLangGroupForPrefLang(eFontPrefLang aLang);
// convert a enum constant to lang group string (i.e. eFontPrefLang_ChineseTW
// ==> "zh-TW")
static const char* GetPrefLangName(eFontPrefLang aLang);
// map a char code to a font language for Preferences
static eFontPrefLang GetFontPrefLangFor(uint32_t aCh);
// returns true if a pref lang is CJK
static bool IsLangCJK(eFontPrefLang aLang);
// helper method to add a pref lang to an array, if not already in array
static void AppendPrefLang(eFontPrefLang aPrefLangs[], uint32_t& aLen,
eFontPrefLang aAddLang);
// default serif/sans-serif choice based on font.default.xxx prefs
mozilla::StyleGenericFontFamily GetDefaultGeneric(eFontPrefLang aLang);
// Returns true if the font family whitelist is not empty. In this case we
// ignore the "CSS visibility level"; only the given fonts are present in
// the browser's font list.
bool IsFontFamilyWhitelistActive() const {
return mFontFamilyWhitelistActive;
};
static void FontWhitelistPrefChanged(const char* aPref, void* aClosure);
bool AddWithLegacyFamilyName(const nsACString& aLegacyName,
gfxFontEntry* aFontEntry,
FontVisibility aVisibility);
static const char* GetGenericName(
mozilla::StyleGenericFontFamily aGenericType);
bool SkipFontFallbackForChar(FontVisibility aVisibility, uint32_t aCh) const {
AutoLock lock(mLock);
return mCodepointsWithNoFonts[aVisibility].test(aCh);
}
// Return whether the given font-family record should be visible to CSS,
// in a context with the given FontVisibility setting.
bool IsVisibleToCSS(const gfxFontFamily& aFamily,
FontVisibility aVisibility) const;
bool IsVisibleToCSS(const mozilla::fontlist::Family& aFamily,
FontVisibility aVisibility) const;
// (Re-)initialize the set of codepoints that we know cannot be rendered.
void InitializeCodepointsWithNoFonts() MOZ_REQUIRES(mLock);
// If using the shared font list, returns a generation count that is
// incremented if/when the platform list is reinitialized (e.g. because
// fonts are installed/removed while the browser is running), such that
// existing references to shared font family or face objects and character
// maps will no longer be valid.
// (The legacy (non-shared) list just returns 0 here.)
uint32_t GetGeneration() const;
// Sometimes we need to know if we're on the InitFontList startup thread.
static bool IsInitFontListThread() {
return PR_GetCurrentThread() == sInitFontListThread;
}
bool IsKnownIconFontFamily(const nsAtom* aFamilyName) const;
void LoadIconFontOverrideList();
void Lock() MOZ_CAPABILITY_ACQUIRE(mLock) { mLock.Lock(); }
void Unlock() MOZ_CAPABILITY_RELEASE(mLock) { mLock.Unlock(); }
// This is only public because some external callers want to be able to
// assert about the locked status.
mutable mozilla::RecursiveMutex mLock;
protected:
virtual nsTArray<std::pair<const char**, uint32_t>>
GetFilteredPlatformFontLists() = 0;
friend class mozilla::fontlist::FontList;
friend class InitOtherFamilyNamesForStylo;
template <size_t N>
static bool FamilyInList(const nsACString& aName, const char* (&aList)[N]) {
return FamilyInList(aName, aList, N);
}
static bool FamilyInList(const nsACString& aName, const char* aList[],
size_t aCount);
// Check list is correctly sorted (in debug build only; no-op on release).
template <size_t N>
static void CheckFamilyList(const char* (&aList)[N]) {
CheckFamilyList(aList, N);
}
static void CheckFamilyList(const char* aList[], size_t aCount);
class InitOtherFamilyNamesRunnable : public mozilla::CancelableRunnable {
public:
InitOtherFamilyNamesRunnable()
: CancelableRunnable(
"gfxPlatformFontList::InitOtherFamilyNamesRunnable"),
mIsCanceled(false) {}
NS_IMETHOD Run() override {
if (mIsCanceled) {
return NS_OK;
}
gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList();
if (!fontList) {
return NS_OK;
}
fontList->InitOtherFamilyNamesInternal(true);
return NS_OK;
}
nsresult Cancel() override {
mIsCanceled = true;
return NS_OK;
}
private:
bool mIsCanceled;
};
class MemoryReporter final : public nsIMemoryReporter {
~MemoryReporter() = default;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIMEMORYREPORTER
};
class PrefName final : public nsAutoCString {
void Init(const nsACString& aGeneric, const nsACString& aLangGroup) {
Assign(aGeneric);
if (!aLangGroup.IsEmpty()) {
Append('.');
Append(aLangGroup);
}
}
public:
PrefName(const nsACString& aGeneric, const nsACString& aLangGroup) {
Init(aGeneric, aLangGroup);
}
PrefName(const char* aGeneric, const char* aLangGroup) {
Init(nsDependentCString(aGeneric), nsDependentCString(aLangGroup));
}
PrefName(const char* aGeneric, nsAtom* aLangGroup) {
if (aLangGroup) {
Init(nsDependentCString(aGeneric), nsAtomCString(aLangGroup));
} else {
Init(nsDependentCString(aGeneric), nsAutoCString());
}
}
};
explicit gfxPlatformFontList(bool aNeedFullnamePostscriptNames = true);
static gfxPlatformFontList* sPlatformFontList;
/**
* Convenience method to return the first matching family (if any) as found
* by FindAndAddFamilies(). The family will be initialized (synchronously)
* if this has not already been done, so the returned pointer, if non-null,
* is ready for use.
*/
mozilla::fontlist::Family* FindSharedFamily(
nsPresContext* aPresContext, const nsACString& aFamily,
FindFamiliesFlags aFlags = FindFamiliesFlags(0),
gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) MOZ_REQUIRES(mLock);
gfxFontFamily* FindUnsharedFamily(
nsPresContext* aPresContext, const nsACString& aFamily,
FindFamiliesFlags aFlags = FindFamiliesFlags(0),
gfxFontStyle* aStyle = nullptr, nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) MOZ_REQUIRES(mLock) {
if (SharedFontList()) {
return nullptr;
}
AutoTArray<FamilyAndGeneric, 1> families;
if (FindAndAddFamiliesLocked(
aPresContext, mozilla::StyleGenericFontFamily::None, aFamily,
&families, aFlags, aStyle, aLanguage, aDevToCssSize)) {
return families[0].mFamily.mUnshared;
}
return nullptr;
}
FontFamily FindFamily(nsPresContext* aPresContext, const nsACString& aFamily,
FindFamiliesFlags aFlags = FindFamiliesFlags(0),
gfxFontStyle* aStyle = nullptr,
nsAtom* aLanguage = nullptr,
gfxFloat aDevToCssSize = 1.0) MOZ_REQUIRES(mLock) {
if (SharedFontList()) {
return FontFamily(FindSharedFamily(aPresContext, aFamily, aFlags, aStyle,
aLanguage, aDevToCssSize));
}
return FontFamily(FindUnsharedFamily(aPresContext, aFamily, aFlags, aStyle,
aLanguage, aDevToCssSize));
}
// Lookup family name in global family list without substitutions or
// localized family name lookup. Used for common font fallback families.
gfxFontFamily* FindFamilyByCanonicalName(const nsACString& aFamily)
MOZ_REQUIRES(mLock) {
nsAutoCString key;
gfxFontFamily* familyEntry;
GenerateFontListKey(aFamily, key);
if ((familyEntry = mFontFamilies.GetWeak(key))) {
return CheckFamily(familyEntry);
}
return nullptr;
}
// returns default font for a given character, null otherwise
already_AddRefed<gfxFont> CommonFontFallback(nsPresContext* aPresContext,
uint32_t aCh, uint32_t aNextCh,
Script aRunScript,
eFontPresentation aPresentation,
const gfxFontStyle* aMatchStyle,
FontFamily& aMatchedFamily)
MOZ_REQUIRES(mLock);
// Search fonts system-wide for a given character, null if not found.
already_AddRefed<gfxFont> GlobalFontFallback(
nsPresContext* aPresContext, uint32_t aCh, uint32_t aNextCh,
Script aRunScript, eFontPresentation aPresentation,
const gfxFontStyle* aMatchStyle, uint32_t& aCmapCount,
FontFamily& aMatchedFamily) MOZ_REQUIRES(mLock);
// Platform-specific implementation of global font fallback, if any;
// this may return nullptr in which case the default cmap-based fallback
// will be performed.
virtual gfxFontEntry* PlatformGlobalFontFallback(
nsPresContext* aPresContext, const uint32_t aCh, Script aRunScript,
const gfxFontStyle* aMatchStyle, FontFamily& aMatchedFamily) {
return nullptr;
}
// whether system-based font fallback is used or not
// if system fallback is used, no need to load all cmaps
virtual bool UsesSystemFallback() { return false; }
void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t& aLen,
eFontPrefLang aCharLang, eFontPrefLang aPageLang)
MOZ_REQUIRES(mLock);
// verifies that a family contains a non-zero font count
gfxFontFamily* CheckFamily(gfxFontFamily* aFamily) MOZ_REQUIRES(mLock);
// initialize localized family names
void InitOtherFamilyNamesInternal(bool aDeferOtherFamilyNamesLoading);
void CancelInitOtherFamilyNamesTask();
void AddToMissedNames(const nsCString& aKey) MOZ_REQUIRES(mLock);
// search through font families, looking for a given name, initializing
// facename lists along the way. first checks all families with names
// close to face name, then searchs all families if not found.
gfxFontEntry* SearchFamiliesForFaceName(const nsACString& aFaceName)
MOZ_REQUIRES(mLock);
// helper method for finding fullname/postscript names in facename lists
gfxFontEntry* FindFaceName(const nsACString& aFaceName) MOZ_REQUIRES(mLock);
// look up a font by name, for cases where platform font list
// maintains explicit mappings of fullname/psname ==> font
virtual gfxFontEntry* LookupInFaceNameLists(const nsACString& aFaceName)
MOZ_REQUIRES(mLock);
gfxFontEntry* LookupInSharedFaceNameList(nsPresContext* aPresContext,
const nsACString& aFaceName,
WeightRange aWeightForEntry,
StretchRange aStretchForEntry,
SlantStyleRange aStyleForEntry)
MOZ_REQUIRES(mLock);
// load the bad underline blocklist from pref.
void LoadBadUnderlineList();
// This version of the function will not modify aKeyName
void GenerateFontListKey(const nsACString& aKeyName, nsACString& aResult);
// This version of the function WILL modify aKeyName
void GenerateFontListKey(nsACString& aKeyName);
virtual void GetFontFamilyNames(nsTArray<nsCString>& aFontFamilyNames)
MOZ_REQUIRES(mLock);
// helper function to map lang to lang group
nsAtom* GetLangGroup(nsAtom* aLanguage);
// gfxFontInfoLoader overrides, used to load in font cmaps
void InitLoader() MOZ_REQUIRES(mLock) override;
bool LoadFontInfo() override;
void CleanupLoader() override;
void ForceGlobalReflowLocked(
gfxPlatform::NeedsReframe aNeedsReframe,
gfxPlatform::BroadcastToChildren aBroadcastToChildren =
gfxPlatform::BroadcastToChildren::Yes) MOZ_REQUIRES(mLock);
// read the loader initialization prefs, and start it
void GetPrefsAndStartLoader();
// If aForgetLocalFaces is true, all gfxFontEntries for src:local fonts must
// be discarded (not potentially reused to satisfy the rebuilt rules),
// because they may no longer be valid.
void RebuildLocalFonts(bool aForgetLocalFaces = false) MOZ_REQUIRES(mLock);
void ResolveGenericFontNames(nsPresContext* aPresContext,
mozilla::StyleGenericFontFamily aGenericType,
eFontPrefLang aPrefLang,
PrefFontList* aGenericFamilies)
MOZ_REQUIRES(mLock);
void ResolveEmojiFontNames(nsPresContext* aPresContext,
PrefFontList* aGenericFamilies)
MOZ_REQUIRES(mLock);
void GetFontFamiliesFromGenericFamilies(
nsPresContext* aPresContext, mozilla::StyleGenericFontFamily aGenericType,
nsTArray<nsCString>& aGenericNameFamilies, nsAtom* aLangGroup,
PrefFontList* aFontFamilies) MOZ_REQUIRES(mLock);
virtual nsresult InitFontListForPlatform() MOZ_REQUIRES(mLock) = 0;
virtual void InitSharedFontListForPlatform() MOZ_REQUIRES(mLock) {}
virtual gfxFontEntry* CreateFontEntry(
mozilla::fontlist::Face* aFace,
const mozilla::fontlist::Family* aFamily) {
return nullptr;
}
/**
* Methods to apply the font.system.whitelist anti-fingerprinting pref,
* by filtering the list of installed fonts so that only whitelisted families
* are exposed.
* There are separate implementations of this for the per-process font list
* and for the shared-memory font list.
*/
void ApplyWhitelist() MOZ_REQUIRES(mLock);
void ApplyWhitelist(nsTArray<mozilla::fontlist::Family::InitData>& aFamilies);
// Create a new gfxFontFamily of the appropriate subclass for the platform,
// used when AddWithLegacyFamilyName needs to create a new family.
virtual gfxFontFamily* CreateFontFamily(const nsACString& aName,
FontVisibility aVisibility) const = 0;
/**
* For the post-startup font info loader task.
* Perform platform-specific work to read alternate names (if any) for a
* font family, recording them in mAliasTable. Once alternate names have been
* loaded for all families, the accumulated records are stored in the shared
* font list's mAliases list.
* Some platforms (currently Linux/fontconfig) may load alternate names as
* part of initially populating the font list with family records, in which
* case this method is unused.
*/
virtual void ReadFaceNamesForFamily(mozilla::fontlist::Family* aFamily,
bool aNeedFullnamePostscriptNames)
MOZ_REQUIRES(mLock) {}
typedef nsRefPtrHashtable<nsCStringHashKey, gfxFontFamily> FontFamilyTable;
typedef nsRefPtrHashtable<nsCStringHashKey, gfxFontEntry> FontEntryTable;
// used by memory reporter to accumulate sizes of family names in the table
static size_t SizeOfFontFamilyTableExcludingThis(
const FontFamilyTable& aTable, mozilla::MallocSizeOf aMallocSizeOf);
static size_t SizeOfFontEntryTableExcludingThis(
const FontEntryTable& aTable, mozilla::MallocSizeOf aMallocSizeOf);
// Platform-specific helper for GetDefaultFont(...).
virtual FontFamily GetDefaultFontForPlatform(nsPresContext* aPresContext,
const gfxFontStyle* aStyle,
nsAtom* aLanguage = nullptr)
MOZ_REQUIRES(mLock) = 0;
// canonical family name ==> family entry (unique, one name per family entry)
FontFamilyTable mFontFamilies MOZ_GUARDED_BY(mLock);
// other family name ==> family entry (not unique, can have multiple names per
// family entry, only names *other* than the canonical names are stored here)
FontFamilyTable mOtherFamilyNames MOZ_GUARDED_BY(mLock);
// flag set after InitOtherFamilyNames is called upon first name lookup miss
mozilla::Atomic<bool> mOtherFamilyNamesInitialized;
// The pending InitOtherFamilyNames() task.
RefPtr<mozilla::CancelableRunnable> mPendingOtherFamilyNameTask;
// flag set after fullname and Postcript name lists are populated
mozilla::Atomic<bool> mFaceNameListsInitialized;
struct ExtraNames {
ExtraNames() = default;
// fullname ==> font entry (unique, one name per font entry)
FontEntryTable mFullnames{64};
// Postscript name ==> font entry (unique, one name per font entry)
FontEntryTable mPostscriptNames{64};
};
// The lock is needed to guard access to the actual name tables, but does not
// need to be held to just test whether mExtraNames is non-null as it is set
// during initialization before other threads have a chance to see it.
mozilla::UniquePtr<ExtraNames> mExtraNames MOZ_PT_GUARDED_BY(mLock);
// face names missed when face name loading takes a long time
mozilla::UniquePtr<nsTHashSet<nsCString>> mFaceNamesMissed
MOZ_GUARDED_BY(mLock);
// localized family names missed when face name loading takes a long time
mozilla::UniquePtr<nsTHashSet<nsCString>> mOtherNamesMissed
MOZ_GUARDED_BY(mLock);
typedef mozilla::RangedArray<mozilla::UniquePtr<PrefFontList>,
size_t(mozilla::StyleGenericFontFamily::None),
size_t(
mozilla::StyleGenericFontFamily::MozEmoji)>
PrefFontsForLangGroup;
mozilla::RangedArray<PrefFontsForLangGroup, eFontPrefLang_First,
eFontPrefLang_Count>
mLangGroupPrefFonts MOZ_GUARDED_BY(mLock);
mozilla::UniquePtr<PrefFontList> mEmojiPrefFont MOZ_GUARDED_BY(mLock);
// When system-wide font lookup fails for a character, cache it to skip future
// searches. This is an array of bitsets, one for each FontVisibility level.
mozilla::EnumeratedArray<FontVisibility, gfxSparseBitSet,
size_t(FontVisibility::Count)>
mCodepointsWithNoFonts MOZ_GUARDED_BY(mLock);
// the family to use for U+FFFD fallback, to avoid expensive search every time
// on pages with lots of problems
mozilla::EnumeratedArray<FontVisibility, FontFamily,
size_t(FontVisibility::Count)>
mReplacementCharFallbackFamily MOZ_GUARDED_BY(mLock);
// Sorted array of lowercased family names; use ContainsSorted to test
nsTArray<nsCString> mBadUnderlineFamilyNames;
// character map data shared across families
// contains weak ptrs to cmaps shared by font entry objects
nsTHashtable<CharMapHashKey> mSharedCmaps MOZ_GUARDED_BY(mLock);
nsTHashtable<ShmemCharMapHashEntry> mShmemCharMaps MOZ_GUARDED_BY(mLock);
// data used as part of the font cmap loading process
nsTArray<RefPtr<gfxFontFamily>> mFontFamiliesToLoad MOZ_GUARDED_BY(mLock);
uint32_t mStartIndex MOZ_GUARDED_BY(mLock) = 0;
uint32_t mNumFamilies MOZ_GUARDED_BY(mLock) = 0;
// xxx - info for diagnosing no default font aborts
// see bugs 636957, 1070983, 1189129
uint32_t mFontlistInitCount = 0; // num times InitFontList called
nsTHashSet<gfxUserFontSet*> mUserFontSetList MOZ_GUARDED_BY(mLock);
nsLanguageAtomService* mLangService = nullptr;
nsTArray<uint32_t> mCJKPrefLangs MOZ_GUARDED_BY(mLock);
nsTArray<mozilla::StyleGenericFontFamily> mDefaultGenericsLangGroup
MOZ_GUARDED_BY(mLock);
nsTArray<nsCString> mEnabledFontsList;
nsTHashSet<nsCString> mIconFontsSet;
mozilla::UniquePtr<mozilla::fontlist::FontList> mSharedFontList;
nsClassHashtable<nsCStringHashKey, mozilla::fontlist::AliasData> mAliasTable;
nsTHashMap<nsCStringHashKey, mozilla::fontlist::LocalFaceRec::InitData>
mLocalNameTable;
nsRefPtrHashtable<nsPtrHashKey<const mozilla::fontlist::Face>, gfxFontEntry>
mFontEntries MOZ_GUARDED_BY(mLock);
mozilla::UniquePtr<FontPrefs> mFontPrefs;
RefPtr<gfxFontEntry> mDefaultFontEntry MOZ_GUARDED_BY(mLock);
RefPtr<mozilla::CancelableRunnable> mLoadCmapsRunnable;
uint32_t mStartedLoadingCmapsFrom MOZ_GUARDED_BY(mLock) = 0xffffffffu;
bool mFontFamilyWhitelistActive = false;
static PRThread* sInitFontListThread;
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxPlatformFontList::FindFamiliesFlags)
#endif /* GFXPLATFORMFONTLIST_H_ */