diff options
Diffstat (limited to 'gfx/thebes/SharedFontList.h')
-rw-r--r-- | gfx/thebes/SharedFontList.h | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/gfx/thebes/SharedFontList.h b/gfx/thebes/SharedFontList.h new file mode 100644 index 0000000000..6ef2a7744c --- /dev/null +++ b/gfx/thebes/SharedFontList.h @@ -0,0 +1,393 @@ +/* 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 SharedFontList_h +#define SharedFontList_h + +#include "gfxFontEntry.h" +#include <atomic> + +class gfxCharacterMap; +struct gfxFontStyle; +struct GlobalFontMatch; + +namespace mozilla { +namespace fontlist { + +class FontList; // See the separate SharedFontList-impl.h header + +/** + * A Pointer in the shared font list contains a packed index/offset pair, + * with a 12-bit index into the array of shared-memory blocks, and a 20-bit + * offset into the block. + * The maximum size of each block is therefore 2^20 bytes (1 MB) if sub-parts + * of the block are to be allocated; however, a larger block (up to 2^32 bytes) + * can be created and used as a single allocation if necessary. + */ +struct Pointer { + private: + friend class FontList; + static const uint32_t kIndexBits = 12u; + static const uint32_t kBlockShift = 20u; + static_assert(kIndexBits + kBlockShift == 32u, "bad Pointer bit count"); + + static const uint32_t kNullValue = 0xffffffffu; + static const uint32_t kOffsetMask = (1u << kBlockShift) - 1; + + public: + static Pointer Null() { return Pointer(); } + + Pointer() : mBlockAndOffset(kNullValue) {} + + Pointer(uint32_t aBlock, uint32_t aOffset) + : mBlockAndOffset((aBlock << kBlockShift) | aOffset) { + MOZ_ASSERT(aBlock < (1u << kIndexBits) && aOffset < (1u << kBlockShift)); + } + + Pointer(const Pointer& aOther) { + mBlockAndOffset.store(aOther.mBlockAndOffset); + } + + Pointer(Pointer&& aOther) { mBlockAndOffset.store(aOther.mBlockAndOffset); } + + /** + * Check if a Pointer has the null value. + * + * NOTE! + * In a child process, it is possible that conversion to a "real" pointer + * using ToPtr() will fail even when IsNull() is false, so calling code + * that may run in child processes must be prepared to handle this. + */ + bool IsNull() const { return mBlockAndOffset == kNullValue; } + + uint32_t Block() const { return mBlockAndOffset >> kBlockShift; } + + uint32_t Offset() const { return mBlockAndOffset & kOffsetMask; } + + /** + * Convert a fontlist::Pointer to a standard C++ pointer. This requires the + * FontList, which will know where the shared memory block is mapped in + * the current process's address space. + * + * NOTE! + * In child processes this may fail and return nullptr, even if IsNull() is + * false, in cases where the font list is in the process of being rebuilt. + */ + void* ToPtr(FontList* aFontList) const; + + Pointer& operator=(const Pointer& aOther) { + mBlockAndOffset.store(aOther.mBlockAndOffset); + return *this; + } + + Pointer& operator=(Pointer&& aOther) { + mBlockAndOffset.store(aOther.mBlockAndOffset); + return *this; + } + + // We store the block index and the offset within the block as a single + // atomic 32-bit value so we can safely modify a Pointer without other + // processes seeing a broken (partially-updated) value. + std::atomic<uint32_t> mBlockAndOffset; +}; + +/** + * Family and face names are stored as String records, which hold a length + * (in utf-8 code units) and a Pointer to the string's UTF-8 characters. + */ +struct String { + String() : mPointer(Pointer::Null()), mLength(0) {} + + String(FontList* aList, const nsACString& aString) + : mPointer(Pointer::Null()) { + Assign(aString, aList); + } + + const nsCString AsString(FontList* aList) const { + MOZ_ASSERT(!mPointer.IsNull()); + // It's tempting to use AssignLiteral here so that we get an nsCString that + // simply wraps the character data in the shmem block without needing to + // allocate or copy. But that's unsafe because in the event of font-list + // reinitalization, that shared memory will be unmapped; then any copy of + // the nsCString that may still be around will crash if accessed. + return nsCString(static_cast<const char*>(mPointer.ToPtr(aList)), mLength); + } + + void Assign(const nsACString& aString, FontList* aList); + + const char* BeginReading(FontList* aList) const { + MOZ_ASSERT(!mPointer.IsNull()); + auto str = static_cast<const char*>(mPointer.ToPtr(aList)); + return str ? str : ""; + } + + uint32_t Length() const { return mLength; } + + /** + * Return whether the String has been set to a value. + * + * NOTE! + * In a child process, accessing the value could fail even if IsNull() + * returned false. In this case, the nsCString constructor used by AsString() + * will be passed a null pointer, and return an empty string despite the + * non-zero Length() recorded here. + */ + bool IsNull() const { return mPointer.IsNull(); } + + private: + Pointer mPointer; + uint32_t mLength; +}; + +/** + * A Face record represents an individual font resource; it has the style + * properties needed for font matching, as well as a pointer to a character + * map that records the supported character set. This may be Null if we have + * not yet loaded the data. + * The mDescriptor and mIndex fields provide the information needed to + * instantiate a (platform-specific) font reference that can be used with + * platform font APIs; their content depends on the requirements of the + * platform APIs (e.g. font PostScript name, file pathname, serialized + * fontconfig pattern, etc). + */ +struct Face { + // Data required to initialize a Face + struct InitData { + nsCString mDescriptor; // descriptor that can be used to instantiate a + // platform font reference + uint16_t mIndex; // an index used with descriptor (on some platforms) + bool mFixedPitch; // is the face fixed-pitch (monospaced)? + mozilla::WeightRange mWeight; // CSS font-weight value + mozilla::StretchRange mStretch; // CSS font-stretch value + mozilla::SlantStyleRange mStyle; // CSS font-style value + RefPtr<gfxCharacterMap> mCharMap; // character map, or null if not loaded + }; + + // Note that mCharacterMap is not set from the InitData by this constructor; + // the caller must use SetCharacterMap to handle that separately if required. + Face(FontList* aList, const InitData& aData) + : mDescriptor(aList, aData.mDescriptor), + mIndex(aData.mIndex), + mFixedPitch(aData.mFixedPitch), + mWeight(aData.mWeight), + mStretch(aData.mStretch), + mStyle(aData.mStyle), + mCharacterMap(Pointer::Null()) {} + + bool HasValidDescriptor() const { + return !mDescriptor.IsNull() && mIndex != uint16_t(-1); + } + + void SetCharacterMap(FontList* aList, gfxCharacterMap* aCharMap); + + String mDescriptor; + uint16_t mIndex; + bool mFixedPitch; + mozilla::WeightRange mWeight; + mozilla::StretchRange mStretch; + mozilla::SlantStyleRange mStyle; + Pointer mCharacterMap; +}; + +/** + * A Family record represents an available (installed) font family; it has + * a name (for display purposes) and a key (lowercased, for case-insensitive + * lookups), as well as a pointer to an array of Faces. Depending on the + * platform, the array of faces may be lazily initialized the first time we + * want to use the family. + */ +struct Family { + static constexpr uint32_t kNoIndex = uint32_t(-1); + + // Data required to initialize a Family + struct InitData { + InitData(const nsACString& aKey, // lookup key (lowercased) + const nsACString& aName, // display name + uint32_t aIndex = kNoIndex, // [win] system collection index + FontVisibility aVisibility = FontVisibility::Unknown, + bool aBundled = false, // [win] font was bundled with the app + // rather than system-installed + bool aBadUnderline = false, // underline-position in font is bad + bool aForceClassic = false, // [win] use "GDI classic" rendering + bool aAltLocale = false // font is alternate localized family + ) + : mKey(aKey), + mName(aName), + mIndex(aIndex), + mVisibility(aVisibility), + mBundled(aBundled), + mBadUnderline(aBadUnderline), + mForceClassic(aForceClassic), + mAltLocale(aAltLocale) {} + bool operator<(const InitData& aRHS) const { return mKey < aRHS.mKey; } + bool operator==(const InitData& aRHS) const { + return mKey == aRHS.mKey && mName == aRHS.mName && + mVisibility == aRHS.mVisibility && mBundled == aRHS.mBundled && + mBadUnderline == aRHS.mBadUnderline; + } + const nsCString mKey; + const nsCString mName; + uint32_t mIndex; + FontVisibility mVisibility; + bool mBundled; + bool mBadUnderline; + bool mForceClassic; + bool mAltLocale; + }; + + /** + * Font families are considered "simple" if they contain only 4 faces with + * style attributes corresponding to Regular, Bold, Italic, and BoldItalic + * respectively, or a subset of these (e.g. only Regular and Bold). In this + * case, the faces are stored at predefined positions in the mFaces array, + * and a simplified (faster) style-matching algorithm can be used. + */ + enum { + // Indexes into mFaces for families where mIsSimple is true + kRegularFaceIndex = 0, + kBoldFaceIndex = 1, + kItalicFaceIndex = 2, + kBoldItalicFaceIndex = 3, + // mask values for selecting face with bold and/or italic attributes + kBoldMask = 0x01, + kItalicMask = 0x02 + }; + + Family(FontList* aList, const InitData& aData); + + void AddFaces(FontList* aList, const nsTArray<Face::InitData>& aFaces); + + void SetFacePtrs(FontList* aList, nsTArray<Pointer>& aFaces); + + const String& Key() const { return mKey; } + + const String& DisplayName() const { return mName; } + + uint32_t Index() const { return mIndex; } + bool IsBundled() const { return mIsBundled; } + + uint32_t NumFaces() const { + MOZ_ASSERT(IsInitialized()); + return mFaceCount; + } + + Pointer* Faces(FontList* aList) const { + MOZ_ASSERT(IsInitialized()); + return static_cast<Pointer*>(mFaces.ToPtr(aList)); + } + + FontVisibility Visibility() const { return mVisibility; } + bool IsHidden() const { return Visibility() == FontVisibility::Hidden; } + + bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; } + bool IsForceClassic() const { return mIsForceClassic; } + bool IsSimple() const { return mIsSimple; } + bool IsAltLocaleFamily() const { return mIsAltLocale; } + + // IsInitialized indicates whether the family has been populated with faces, + // and is therefore ready to use. + // It is possible that character maps have not yet been loaded. + bool IsInitialized() const { return !mFaces.IsNull(); } + + // IsFullyInitialized indicates that not only faces but also character maps + // have been set up, so the family can be searched without the possibility + // that IPC messaging will be triggered. + bool IsFullyInitialized() const { + return IsInitialized() && !mCharacterMap.IsNull(); + } + + void FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle, + nsTArray<Face*>& aFaceList, + bool aIgnoreSizeTolerance = false) const; + + Face* FindFaceForStyle(FontList* aList, const gfxFontStyle& aStyle, + bool aIgnoreSizeTolerance = false) const; + + void SearchAllFontsForChar(FontList* aList, GlobalFontMatch* aMatchData); + + void SetupFamilyCharMap(FontList* aList); + + private: + std::atomic<uint32_t> mFaceCount; + String mKey; + String mName; + Pointer mCharacterMap; // If non-null, union of character coverage of all + // faces in the family + Pointer mFaces; // Pointer to array of |mFaceCount| face pointers + uint32_t mIndex; // [win] Top bit set indicates app-bundled font family + FontVisibility mVisibility; + bool mIsSimple; // family allows simplified style matching: mFaces contains + // exactly 4 entries [Regular, Bold, Italic, BoldItalic]. + bool mIsBundled : 1; + bool mIsBadUnderlineFamily : 1; + bool mIsForceClassic : 1; + bool mIsAltLocale : 1; +}; + +/** + * For platforms where we build an index of local font face names (PS-name + * and fullname of the font) to support @font-face{src:local(...)}, we map + * each face name to an index into the family list, and an index into the + * family's list of faces. + */ +struct LocalFaceRec { + /** + * The InitData struct needs to record the family name rather than index, + * as we may be collecting these records at the same time as building the + * family list, so we don't yet know the final family index. + * Likewise, in some cases we don't know the final face index because the + * faces may be re-sorted to fit into predefined positions in a "simple" + * family (if we're reading names before the family has been fully set up). + * In that case, we'll store uint32_t(-1) as mFaceIndex, and record the + * string descriptor instead. + * When actually recorded in the FontList's mLocalFaces array, the family + * will be stored as a simple index into the mFamilies array, and the face + * as an index into the family's mFaces. + */ + struct InitData { + nsCString mFamilyName; + nsCString mFaceDescriptor; + uint32_t mFaceIndex = uint32_t(-1); + InitData(const nsACString& aFamily, const nsACString& aFace) + : mFamilyName(aFamily), mFaceDescriptor(aFace) {} + InitData(const nsACString& aFamily, uint32_t aFaceIndex) + : mFamilyName(aFamily), mFaceIndex(aFaceIndex) {} + InitData() = default; + }; + String mKey; + uint32_t mFamilyIndex; // Index into the font list's Families array + uint32_t mFaceIndex; // Index into the family's Faces array +}; + +} // namespace fontlist +} // namespace mozilla + +#include "ipc/IPCMessageUtils.h" + +namespace IPC { + +template <> +struct ParamTraits<mozilla::fontlist::Pointer> { + typedef mozilla::fontlist::Pointer paramType; + static void Write(Message* aMsg, const paramType& aParam) { + uint32_t v = aParam.mBlockAndOffset; + WriteParam(aMsg, v); + } + static bool Read(const Message* aMsg, PickleIterator* aIter, + paramType* aResult) { + uint32_t v; + if (ReadParam(aMsg, aIter, &v)) { + aResult->mBlockAndOffset.store(v); + return true; + } + return false; + } +}; + +} // namespace IPC + +#undef ERROR // This is defined via Windows.h, but conflicts with some bindings + // code when this gets included in the same compilation unit. + +#endif /* SharedFontList_h */ |