mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			402 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			402 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* 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.
 | 
						|
   *
 | 
						|
   * aSize is the expected size of the pointed-to object, for bounds checking.
 | 
						|
   *
 | 
						|
   * 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, size_t aSize) const;
 | 
						|
 | 
						|
  template <typename T>
 | 
						|
  T* ToPtr(FontList* aFontList) const {
 | 
						|
    return static_cast<T*>(ToPtr(aFontList, sizeof(T)));
 | 
						|
  }
 | 
						|
 | 
						|
  template <typename T>
 | 
						|
  T* ToArray(FontList* aFontList, size_t aCount) const {
 | 
						|
    return static_cast<T*>(ToPtr(aFontList, sizeof(T) * aCount));
 | 
						|
  }
 | 
						|
 | 
						|
  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(mPointer.ToArray<const char>(aList, mLength), mLength);
 | 
						|
  }
 | 
						|
 | 
						|
  void Assign(const nsACString& aString, FontList* aList);
 | 
						|
 | 
						|
  const char* BeginReading(FontList* aList) const {
 | 
						|
    MOZ_ASSERT(!mPointer.IsNull());
 | 
						|
    auto* str = mPointer.ToArray<const char>(aList, mLength);
 | 
						|
    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)
 | 
						|
#ifdef MOZ_WIDGET_GTK
 | 
						|
    uint16_t mSize;  // pixel size if bitmap; zero indicates scalable
 | 
						|
#endif
 | 
						|
    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),
 | 
						|
#ifdef MOZ_WIDGET_GTK
 | 
						|
        mSize(aData.mSize),
 | 
						|
#endif
 | 
						|
        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,
 | 
						|
                       const Family* aFamily);
 | 
						|
 | 
						|
  String mDescriptor;
 | 
						|
  uint16_t mIndex;
 | 
						|
#ifdef MOZ_WIDGET_GTK
 | 
						|
  uint16_t mSize;
 | 
						|
#endif
 | 
						|
  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;
 | 
						|
    }
 | 
						|
    nsCString mKey;
 | 
						|
    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 mFaces.ToArray<Pointer>(aList, mFaceCount);
 | 
						|
  }
 | 
						|
 | 
						|
  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);
 | 
						|
 | 
						|
  // Return the index of this family in the font-list's Families() or
 | 
						|
  // AliasFamilies() list, and which of those it belongs to.
 | 
						|
  // Returns Nothing if the family cannot be found.
 | 
						|
  mozilla::Maybe<std::pair<uint32_t, bool>> FindIndex(FontList* aList) const;
 | 
						|
 | 
						|
 private:
 | 
						|
  // Returns true if there are specifically-sized bitmap faces in the list,
 | 
						|
  // so size selection still needs to be done. (Currently only on Linux.)
 | 
						|
  bool FindAllFacesForStyleInternal(FontList* aList, const gfxFontStyle& aStyle,
 | 
						|
                                    nsTArray<Face*>& aFaceList) const;
 | 
						|
 | 
						|
  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
 | 
						|
 | 
						|
#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 */
 |