tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SharedFontList.h (15015B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifndef SharedFontList_h
      6 #define SharedFontList_h
      7 
      8 #include "gfxFontEntry.h"
      9 #include <atomic>
     10 
     11 class gfxCharacterMap;
     12 struct gfxFontStyle;
     13 struct GlobalFontMatch;
     14 
     15 namespace mozilla {
     16 namespace fontlist {
     17 
     18 class FontList;  // See the separate SharedFontList-impl.h header
     19 
     20 /**
     21 * A Pointer in the shared font list contains a packed index/offset pair,
     22 * with a 12-bit index into the array of shared-memory blocks, and a 20-bit
     23 * offset into the block.
     24 * The maximum size of each block is therefore 2^20 bytes (1 MB) if sub-parts
     25 * of the block are to be allocated; however, a larger block (up to 2^32 bytes)
     26 * can be created and used as a single allocation if necessary.
     27 */
     28 struct Pointer {
     29 private:
     30  friend class FontList;
     31  static const uint32_t kIndexBits = 12u;
     32  static const uint32_t kBlockShift = 20u;
     33  static_assert(kIndexBits + kBlockShift == 32u, "bad Pointer bit count");
     34 
     35  static const uint32_t kNullValue = 0xffffffffu;
     36  static const uint32_t kOffsetMask = (1u << kBlockShift) - 1;
     37 
     38 public:
     39  static Pointer Null() { return Pointer(); }
     40 
     41  Pointer() : mBlockAndOffset(kNullValue) {}
     42 
     43  Pointer(uint32_t aBlock, uint32_t aOffset)
     44      : mBlockAndOffset((aBlock << kBlockShift) | aOffset) {
     45    MOZ_ASSERT(aBlock < (1u << kIndexBits) && aOffset < (1u << kBlockShift));
     46  }
     47 
     48  Pointer(const Pointer& aOther) {
     49    mBlockAndOffset.store(aOther.mBlockAndOffset);
     50  }
     51 
     52  Pointer(Pointer&& aOther) { mBlockAndOffset.store(aOther.mBlockAndOffset); }
     53 
     54  /**
     55   * Check if a Pointer has the null value.
     56   *
     57   * NOTE!
     58   * In a child process, it is possible that conversion to a "real" pointer
     59   * using ToPtr() will fail even when IsNull() is false, so calling code
     60   * that may run in child processes must be prepared to handle this.
     61   */
     62  bool IsNull() const { return mBlockAndOffset == kNullValue; }
     63 
     64  uint32_t Block() const { return mBlockAndOffset >> kBlockShift; }
     65 
     66  uint32_t Offset() const { return mBlockAndOffset & kOffsetMask; }
     67 
     68  /**
     69   * Convert a fontlist::Pointer to a standard C++ pointer. This requires the
     70   * FontList, which will know where the shared memory block is mapped in
     71   * the current process's address space.
     72   *
     73   * aSize is the expected size of the pointed-to object, for bounds checking.
     74   *
     75   * NOTE!
     76   * In child processes this may fail and return nullptr, even if IsNull() is
     77   * false, in cases where the font list is in the process of being rebuilt.
     78   */
     79  void* ToPtr(FontList* aFontList, size_t aSize) const;
     80 
     81  template <typename T>
     82  T* ToPtr(FontList* aFontList) const {
     83    return static_cast<T*>(ToPtr(aFontList, sizeof(T)));
     84  }
     85 
     86  template <typename T>
     87  T* ToArray(FontList* aFontList, size_t aCount) const {
     88    return static_cast<T*>(ToPtr(aFontList, sizeof(T) * aCount));
     89  }
     90 
     91  Pointer& operator=(const Pointer& aOther) {
     92    mBlockAndOffset.store(aOther.mBlockAndOffset);
     93    return *this;
     94  }
     95 
     96  Pointer& operator=(Pointer&& aOther) {
     97    mBlockAndOffset.store(aOther.mBlockAndOffset);
     98    return *this;
     99  }
    100 
    101  // We store the block index and the offset within the block as a single
    102  // atomic 32-bit value so we can safely modify a Pointer without other
    103  // processes seeing a broken (partially-updated) value.
    104  std::atomic<uint32_t> mBlockAndOffset;
    105 };
    106 
    107 /**
    108 * Family and face names are stored as String records, which hold a length
    109 * (in utf-8 code units) and a Pointer to the string's UTF-8 characters.
    110 */
    111 struct String {
    112  String() : mPointer(Pointer::Null()), mLength(0) {}
    113 
    114  String(FontList* aList, const nsACString& aString)
    115      : mPointer(Pointer::Null()) {
    116    Assign(aString, aList);
    117  }
    118 
    119  const nsCString AsString(FontList* aList) const {
    120    MOZ_ASSERT(!mPointer.IsNull());
    121    // It's tempting to use AssignLiteral here so that we get an nsCString that
    122    // simply wraps the character data in the shmem block without needing to
    123    // allocate or copy. But that's unsafe because in the event of font-list
    124    // reinitalization, that shared memory will be unmapped; then any copy of
    125    // the nsCString that may still be around will crash if accessed.
    126    return nsCString(mPointer.ToArray<const char>(aList, mLength), mLength);
    127  }
    128 
    129  void Assign(const nsACString& aString, FontList* aList);
    130 
    131  const char* BeginReading(FontList* aList) const {
    132    MOZ_ASSERT(!mPointer.IsNull());
    133    auto* str = mPointer.ToArray<const char>(aList, mLength);
    134    return str ? str : "";
    135  }
    136 
    137  uint32_t Length() const { return mLength; }
    138 
    139  /**
    140   * Return whether the String has been set to a value.
    141   *
    142   * NOTE!
    143   * In a child process, accessing the value could fail even if IsNull()
    144   * returned false. In this case, the nsCString constructor used by AsString()
    145   * will be passed a null pointer, and return an empty string despite the
    146   * non-zero Length() recorded here.
    147   */
    148  bool IsNull() const { return mPointer.IsNull(); }
    149 
    150 private:
    151  Pointer mPointer;
    152  uint32_t mLength;
    153 };
    154 
    155 /**
    156 * A Face record represents an individual font resource; it has the style
    157 * properties needed for font matching, as well as a pointer to a character
    158 * map that records the supported character set. This may be Null if we have
    159 * not yet loaded the data.
    160 * The mDescriptor and mIndex fields provide the information needed to
    161 * instantiate a (platform-specific) font reference that can be used with
    162 * platform font APIs; their content depends on the requirements of the
    163 * platform APIs (e.g. font PostScript name, file pathname, serialized
    164 * fontconfig pattern, etc).
    165 */
    166 struct Face {
    167  // Data required to initialize a Face
    168  struct InitData {
    169    nsCString mDescriptor;  // descriptor that can be used to instantiate a
    170                            // platform font reference
    171    uint16_t mIndex;        // an index used with descriptor (on some platforms)
    172 #ifdef MOZ_WIDGET_GTK
    173    uint16_t mSize;  // pixel size if bitmap; zero indicates scalable
    174 #endif
    175    bool mFixedPitch;                  // is the face fixed-pitch (monospaced)?
    176    mozilla::WeightRange mWeight;      // CSS font-weight value
    177    mozilla::StretchRange mStretch;    // CSS font-stretch value
    178    mozilla::SlantStyleRange mStyle;   // CSS font-style value
    179    RefPtr<gfxCharacterMap> mCharMap;  // character map, or null if not loaded
    180  };
    181 
    182  // Note that mCharacterMap is not set from the InitData by this constructor;
    183  // the caller must use SetCharacterMap to handle that separately if required.
    184  Face(FontList* aList, const InitData& aData)
    185      : mDescriptor(aList, aData.mDescriptor),
    186        mIndex(aData.mIndex),
    187 #ifdef MOZ_WIDGET_GTK
    188        mSize(aData.mSize),
    189 #endif
    190        mFixedPitch(aData.mFixedPitch),
    191        mWeight(aData.mWeight),
    192        mStretch(aData.mStretch),
    193        mStyle(aData.mStyle),
    194        mCharacterMap(Pointer::Null()) {
    195  }
    196 
    197  bool HasValidDescriptor() const {
    198    return !mDescriptor.IsNull() && mIndex != uint16_t(-1);
    199  }
    200 
    201  void SetCharacterMap(FontList* aList, gfxCharacterMap* aCharMap,
    202                       const Family* aFamily);
    203 
    204  String mDescriptor;
    205  uint16_t mIndex;
    206 #ifdef MOZ_WIDGET_GTK
    207  uint16_t mSize;
    208 #endif
    209  bool mFixedPitch;
    210  mozilla::WeightRange mWeight;
    211  mozilla::StretchRange mStretch;
    212  mozilla::SlantStyleRange mStyle;
    213  Pointer mCharacterMap;
    214 };
    215 
    216 /**
    217 * A Family record represents an available (installed) font family; it has
    218 * a name (for display purposes) and a key (lowercased, for case-insensitive
    219 * lookups), as well as a pointer to an array of Faces. Depending on the
    220 * platform, the array of faces may be lazily initialized the first time we
    221 * want to use the family.
    222 */
    223 struct Family {
    224  static constexpr uint32_t kNoIndex = uint32_t(-1);
    225 
    226  // Data required to initialize a Family
    227  struct InitData {
    228    InitData(const nsACString& aKey,      // lookup key (lowercased)
    229             const nsACString& aName,     // display name
    230             uint32_t aIndex = kNoIndex,  // [win] system collection index
    231             FontVisibility aVisibility = FontVisibility::Unknown,
    232             bool aBundled = false,       // [win] font was bundled with the app
    233                                          // rather than system-installed
    234             bool aBadUnderline = false,  // underline-position in font is bad
    235             bool aForceClassic = false,  // [win] use "GDI classic" rendering
    236             bool aAltLocale = false      // font is alternate localized family
    237             )
    238        : mKey(aKey),
    239          mName(aName),
    240          mIndex(aIndex),
    241          mVisibility(aVisibility),
    242          mBundled(aBundled),
    243          mBadUnderline(aBadUnderline),
    244          mForceClassic(aForceClassic),
    245          mAltLocale(aAltLocale) {}
    246    bool operator<(const InitData& aRHS) const { return mKey < aRHS.mKey; }
    247    bool operator==(const InitData& aRHS) const {
    248      return mKey == aRHS.mKey && mName == aRHS.mName &&
    249             mVisibility == aRHS.mVisibility && mBundled == aRHS.mBundled &&
    250             mBadUnderline == aRHS.mBadUnderline;
    251    }
    252    nsCString mKey;
    253    nsCString mName;
    254    uint32_t mIndex;
    255    FontVisibility mVisibility;
    256    bool mBundled;
    257    bool mBadUnderline;
    258    bool mForceClassic;
    259    bool mAltLocale;
    260  };
    261 
    262  /**
    263   * Font families are considered "simple" if they contain only 4 faces with
    264   * style attributes corresponding to Regular, Bold, Italic, and BoldItalic
    265   * respectively, or a subset of these (e.g. only Regular and Bold). In this
    266   * case, the faces are stored at predefined positions in the mFaces array,
    267   * and a simplified (faster) style-matching algorithm can be used.
    268   */
    269  enum {
    270    // Indexes into mFaces for families where mIsSimple is true
    271    kRegularFaceIndex = 0,
    272    kBoldFaceIndex = 1,
    273    kItalicFaceIndex = 2,
    274    kBoldItalicFaceIndex = 3,
    275    // mask values for selecting face with bold and/or italic attributes
    276    kBoldMask = 0x01,
    277    kItalicMask = 0x02
    278  };
    279 
    280  Family(FontList* aList, const InitData& aData);
    281 
    282  void AddFaces(FontList* aList, const nsTArray<Face::InitData>& aFaces);
    283 
    284  void SetFacePtrs(FontList* aList, nsTArray<Pointer>& aFaces);
    285 
    286  const String& Key() const { return mKey; }
    287 
    288  const String& DisplayName() const { return mName; }
    289 
    290  uint32_t Index() const { return mIndex; }
    291  bool IsBundled() const { return mIsBundled; }
    292 
    293  uint32_t NumFaces() const {
    294    MOZ_ASSERT(IsInitialized());
    295    return mFaceCount;
    296  }
    297 
    298  Pointer* Faces(FontList* aList) const {
    299    MOZ_ASSERT(IsInitialized());
    300    return mFaces.ToArray<Pointer>(aList, mFaceCount);
    301  }
    302 
    303  FontVisibility Visibility() const { return mVisibility; }
    304  bool IsHidden() const { return Visibility() == FontVisibility::Hidden; }
    305 
    306  bool IsBadUnderlineFamily() const { return mIsBadUnderlineFamily; }
    307  bool IsForceClassic() const { return mIsForceClassic; }
    308  bool IsSimple() const { return mIsSimple; }
    309  bool IsAltLocaleFamily() const { return mIsAltLocale; }
    310 
    311  // IsInitialized indicates whether the family has been populated with faces,
    312  // and is therefore ready to use.
    313  // It is possible that character maps have not yet been loaded.
    314  bool IsInitialized() const { return !mFaces.IsNull(); }
    315 
    316  // IsFullyInitialized indicates that not only faces but also character maps
    317  // have been set up, so the family can be searched without the possibility
    318  // that IPC messaging will be triggered.
    319  bool IsFullyInitialized() const {
    320    return IsInitialized() && !mCharacterMap.IsNull();
    321  }
    322 
    323  void FindAllFacesForStyle(FontList* aList, const gfxFontStyle& aStyle,
    324                            nsTArray<Face*>& aFaceList,
    325                            bool aIgnoreSizeTolerance = false) const;
    326 
    327  Face* FindFaceForStyle(FontList* aList, const gfxFontStyle& aStyle,
    328                         bool aIgnoreSizeTolerance = false) const;
    329 
    330  void SearchAllFontsForChar(FontList* aList, GlobalFontMatch* aMatchData);
    331 
    332  void SetupFamilyCharMap(FontList* aList);
    333 
    334  // Return the index of this family in the font-list's Families() or
    335  // AliasFamilies() list, and which of those it belongs to.
    336  // Returns Nothing if the family cannot be found.
    337  mozilla::Maybe<std::pair<uint32_t, bool>> FindIndex(FontList* aList) const;
    338 
    339 private:
    340  // Returns true if there are specifically-sized bitmap faces in the list,
    341  // so size selection still needs to be done. (Currently only on Linux.)
    342  bool FindAllFacesForStyleInternal(FontList* aList, const gfxFontStyle& aStyle,
    343                                    nsTArray<Face*>& aFaceList) const;
    344 
    345  std::atomic<uint32_t> mFaceCount;
    346  String mKey;
    347  String mName;
    348  Pointer mCharacterMap;  // If non-null, union of character coverage of all
    349                          // faces in the family
    350  Pointer mFaces;         // Pointer to array of |mFaceCount| face pointers
    351  uint32_t mIndex;        // [win] Top bit set indicates app-bundled font family
    352  FontVisibility mVisibility;
    353  bool mIsSimple;  // family allows simplified style matching: mFaces contains
    354                   // exactly 4 entries [Regular, Bold, Italic, BoldItalic].
    355  bool mIsBundled : 1;
    356  bool mIsBadUnderlineFamily : 1;
    357  bool mIsForceClassic : 1;
    358  bool mIsAltLocale : 1;
    359 };
    360 
    361 /**
    362 * For platforms where we build an index of local font face names (PS-name
    363 * and fullname of the font) to support @font-face{src:local(...)}, we map
    364 * each face name to an index into the family list, and an index into the
    365 * family's list of faces.
    366 */
    367 struct LocalFaceRec {
    368  /**
    369   * The InitData struct needs to record the family name rather than index,
    370   * as we may be collecting these records at the same time as building the
    371   * family list, so we don't yet know the final family index.
    372   * Likewise, in some cases we don't know the final face index because the
    373   * faces may be re-sorted to fit into predefined positions in a "simple"
    374   * family (if we're reading names before the family has been fully set up).
    375   * In that case, we'll store uint32_t(-1) as mFaceIndex, and record the
    376   * string descriptor instead.
    377   * When actually recorded in the FontList's mLocalFaces array, the family
    378   * will be stored as a simple index into the mFamilies array, and the face
    379   * as an index into the family's mFaces.
    380   */
    381  struct InitData {
    382    nsCString mFamilyName;
    383    nsCString mFaceDescriptor;
    384    uint32_t mFaceIndex = uint32_t(-1);
    385    InitData(const nsACString& aFamily, const nsACString& aFace)
    386        : mFamilyName(aFamily), mFaceDescriptor(aFace) {}
    387    InitData(const nsACString& aFamily, uint32_t aFaceIndex)
    388        : mFamilyName(aFamily), mFaceIndex(aFaceIndex) {}
    389    InitData() = default;
    390  };
    391  String mKey;
    392  uint32_t mFamilyIndex;  // Index into the font list's Families array
    393  uint32_t mFaceIndex;    // Index into the family's Faces array
    394 };
    395 
    396 }  // namespace fontlist
    397 }  // namespace mozilla
    398 
    399 #undef ERROR  // This is defined via Windows.h, but conflicts with some bindings
    400              // code when this gets included in the same compilation unit.
    401 
    402 #endif /* SharedFontList_h */