tor-browser

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

SharedFontList-impl.h (15560B)


      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_impl_h
      6 #define SharedFontList_impl_h
      7 
      8 #include "SharedFontList.h"
      9 
     10 #include "base/process.h"
     11 #include "gfxFontUtils.h"
     12 #include "nsClassHashtable.h"
     13 #include "nsTHashMap.h"
     14 #include "nsXULAppAPI.h"
     15 #include "mozilla/UniquePtr.h"
     16 #include "mozilla/ipc/SharedMemoryMapping.h"
     17 
     18 // This is split out from SharedFontList.h because that header is included
     19 // quite widely (via gfxPlatformFontList.h, gfxTextRun.h, etc). This header,
     20 // which defines the actual shared-memory FontList class, is included only by
     21 // the .cpp files that implement or directly interface with the font list, to
     22 // avoid polluting other headers.
     23 
     24 namespace mozilla {
     25 namespace fontlist {
     26 
     27 /**
     28 * Data used to initialize a font family alias (a "virtual" family that refers
     29 * to some or all of the faces of another family, used when alternate family
     30 * names are found in the font resource for localization or for styled
     31 * subfamilies). AliasData records are collected incrementally while scanning
     32 * the fonts, and then used to set up the Aliases list in the shared font list.
     33 */
     34 struct AliasData {
     35  nsTArray<Pointer> mFaces;
     36  nsCString mBaseFamily;
     37  uint32_t mIndex = 0;
     38  FontVisibility mVisibility = FontVisibility::Unknown;
     39  bool mBundled = false;
     40  bool mBadUnderline = false;
     41  bool mForceClassic = false;
     42 
     43  void InitFromFamily(const Family* aFamily, const nsCString& aBaseFamily) {
     44    mBaseFamily = aBaseFamily;
     45    mIndex = aFamily->Index();
     46    mVisibility = aFamily->Visibility();
     47    mBundled = aFamily->IsBundled();
     48    mBadUnderline = aFamily->IsBadUnderlineFamily();
     49    mForceClassic = aFamily->IsForceClassic();
     50  }
     51 };
     52 
     53 /**
     54 * The Shared Font List is a collection of data that lives in shared memory
     55 * so that all processes can use it, rather than maintaining their own copies,
     56 * and provides the metadata needed for CSS font-matching (a list of all the
     57 * available font families and their faces, style properties, etc, as well as
     58 * character coverage).
     59 *
     60 * An important assumption is that all processes see the same collection of
     61 * installed fonts; therefore it is valid for them all to share the same set
     62 * of font metadata. The data is updated only by the parent process; content
     63 * processes have read-only access to it.
     64 *
     65 * The total size of this data varies greatly depending on the user's installed
     66 * fonts; and it is not known at startup because we load a lot of the font data
     67 * on first use rather than preloading during initialization (because that's
     68 * too expensive/slow).
     69 *
     70 * Therefore, the shared memory area needs to be able to grow during the
     71 * session; we can't predict how much space will be needed, and we can't afford
     72 * to pre-allocate such a huge block that it could never overflow. To handle
     73 * this, we maintain a (generally short) array of blocks of shared memory,
     74 * and then allocate our Family, Face, etc. objects within these. Because we
     75 * only ever add data (never delete what we've already stored), we can use a
     76 * simplified allocator that doesn't ever need to free blocks; the only time
     77 * the memory is released during a session is the (rare) case where a font is
     78 * installed or deleted while the browser is running, and in this case we just
     79 * delete the entire shared font list and start afresh.
     80 */
     81 class FontList {
     82 public:
     83  friend struct Pointer;
     84 
     85  explicit FontList(uint32_t aGeneration);
     86  ~FontList();
     87 
     88  /**
     89   * Initialize the master list of installed font families. This must be
     90   * set during font-list creation, before the list is shared with any
     91   * content processes. All installed font families known to the browser
     92   * appear in this list, although some may be marked as "hidden" so that
     93   * they are not exposed to the font-family property.
     94   *
     95   * The passed-in array may be modified (to eliminate duplicates of bundled
     96   * fonts, or restrict the available list to a specified subset), so if the
     97   * caller intends to make further use of it this should be kept in mind.
     98   *
     99   * Once initialized, the master family list is immutable; in the (rare)
    100   * event that the system's collection of installed fonts changes, we discard
    101   * the FontList and create a new one.
    102   *
    103   * In some cases, a font family may be known by multiple names (e.g.
    104   * localizations in multiple languages, or there may be legacy family names
    105   * that correspond to specific styled faces like "Arial Black"). Such names
    106   * do not appear in this master list, but are referred to as aliases (see
    107   * SetAliases below); the alias list need not be populated before the font
    108   * list is shared to content processes and used.
    109   *
    110   * Only used in the parent process.
    111   */
    112  void SetFamilyNames(nsTArray<Family::InitData>& aFamilies);
    113 
    114  /**
    115   * Aliases are Family records whose Face entries are already part of another
    116   * family (either because the family has multiple localized names, or because
    117   * the alias family is a legacy name like "Arial Narrow" that is a subset of
    118   * the faces in the main "Arial" family). The table of aliases is initialized
    119   * from a hash of alias family name -> array of Face records.
    120   *
    121   * Like the master family list, the list of family aliases is immutable once
    122   * initialized.
    123   *
    124   * Only used in the parent process.
    125   */
    126  void SetAliases(nsClassHashtable<nsCStringHashKey, AliasData>& aAliasTable);
    127 
    128  /**
    129   * Local names are PostScript or Full font names of individual faces, used
    130   * to look up faces for @font-face { src: local(...) } rules. Some platforms
    131   * (e.g. macOS) can look up local names directly using platform font APIs,
    132   * in which case the local names table here is unused.
    133   *
    134   * The list of local names is immutable once initialized. Local font name
    135   * lookups may occur before this list has been set up, in which case they
    136   * will use the SearchForLocalFace method.
    137   *
    138   * Only used in the parent process.
    139   */
    140  void SetLocalNames(
    141      nsTHashMap<nsCStringHashKey, LocalFaceRec::InitData>& aLocalNameTable);
    142 
    143  /**
    144   * Look up a Family record by name, typically to satisfy the font-family
    145   * property or a font family listed in preferences.
    146   */
    147  Family* FindFamily(const nsCString& aName, bool aPrimaryNameOnly = false);
    148 
    149  /**
    150   * Look up an individual Face by PostScript or Full name, for @font-face
    151   * rules using src:local(...). This requires the local names list to have
    152   * been initialized.
    153   */
    154  LocalFaceRec* FindLocalFace(const nsCString& aName);
    155 
    156  /**
    157   * Search families for a face with local name aName; should only be used if
    158   * the mLocalFaces array has not yet been set up, as this will be a more
    159   * expensive search than FindLocalFace.
    160   */
    161  void SearchForLocalFace(const nsACString& aName, Family** aFamily,
    162                          Face** aFace);
    163 
    164  /**
    165   * Return the localized name for the given family in the current system
    166   * locale (if multiple localizations are available).
    167   */
    168  nsCString LocalizedFamilyName(const Family* aFamily);
    169 
    170  bool Initialized() { return mBlocks.Length() > 0 && NumFamilies() > 0; }
    171 
    172  uint32_t NumFamilies() { return GetHeader().mFamilyCount; }
    173  Family* Families() {
    174    return GetHeader().mFamilies.ToArray<Family>(this, NumFamilies());
    175  }
    176 
    177  uint32_t NumAliases() { return GetHeader().mAliasCount; }
    178  Family* AliasFamilies() {
    179    return GetHeader().mAliases.ToArray<Family>(this, NumAliases());
    180  }
    181 
    182  uint32_t NumLocalFaces() { return GetHeader().mLocalFaceCount; }
    183  LocalFaceRec* LocalFaces() {
    184    return GetHeader().mLocalFaces.ToArray<LocalFaceRec>(this, NumLocalFaces());
    185  }
    186 
    187  /**
    188   * Ask the font list to initialize the character map for a given face.
    189   */
    190  void LoadCharMapFor(Face& aFace, const Family* aFamily);
    191 
    192  /**
    193   * Allocate shared-memory space for a record of aSize bytes. The returned
    194   * pointer will be 32-bit aligned. (This method may trigger the allocation of
    195   * a new shared memory block, if required.)
    196   *
    197   * Only used in the parent process.
    198   */
    199  Pointer Alloc(uint32_t aSize);
    200 
    201  uint32_t GetGeneration() { return GetHeader().mGeneration; }
    202 
    203  /**
    204   * Header fields present in every shared-memory block. The mBlockSize field
    205   * is not modified after initial block creation (before the block has been
    206   * shared to any other process), so does not need to be std::atomic<>.
    207   * The mAllocated field is checked during Pointer::ToPtr(), so we make that
    208   * atomic to avoid data races.
    209   */
    210  struct BlockHeader {
    211    std::atomic<uint32_t> mAllocated;  // Space allocated from this block.
    212    uint32_t mBlockSize;               // Total size of this block.
    213  };
    214 
    215  /**
    216   * Header info that is stored at the beginning of the first shared-memory
    217   * block for the font list.
    218   * (Subsequent blocks have only the mBlockHeader.)
    219   * The mGeneration and mFamilyCount fields are set by the parent process
    220   * during font-list construction, before the list has been shared with any
    221   * other process, and subsequently never change; therefore, we don't need
    222   * to use std::atomic<> for these.
    223   */
    224  struct Header {
    225    BlockHeader mBlockHeader;
    226    uint32_t mGeneration;               // Font-list generation ID
    227    uint32_t mFamilyCount;              // Number of font families in the list
    228    std::atomic<uint32_t> mBlockCount;  // Total number of blocks that exist
    229    std::atomic<uint32_t> mAliasCount;  // Number of family aliases
    230    std::atomic<uint32_t> mLocalFaceCount;  // Number of local face names
    231    Pointer mFamilies;    // Pointer to array of |mFamilyCount| families
    232    Pointer mAliases;     // Pointer to array of |mAliasCount| aliases
    233    Pointer mLocalFaces;  // Pointer to array of |mLocalFaceCount| face records
    234  };
    235 
    236  /**
    237   * Used by the parent process to pass a handle to a shared block to a
    238   * specific child process. This is used when a child process requests
    239   * an additional block that was not already passed to it (because the
    240   * list has changed/grown since the child was first initialized).
    241   */
    242  void ShareShmBlockToProcess(uint32_t aIndex, base::ProcessId aPid,
    243                              ipc::ReadOnlySharedMemoryHandle* aOut) {
    244    MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
    245    if (aIndex >= mReadOnlyShmems.Length()) {
    246      // Block index out of range
    247      *aOut = nullptr;
    248      return;
    249    }
    250    *aOut = mReadOnlyShmems[aIndex].Clone();
    251    if (!*aOut) {
    252      MOZ_CRASH("failed to share block");
    253    }
    254  }
    255 
    256  /**
    257   * Collect an array of handles to all the shmem blocks, ready to be
    258   * shared to the given process. This is used at child process startup
    259   * to pass the complete list at once.
    260   */
    261  void ShareBlocksToProcess(nsTArray<ipc::ReadOnlySharedMemoryHandle>* aBlocks,
    262                            base::ProcessId aPid);
    263 
    264  ipc::ReadOnlySharedMemoryHandle ShareBlockToProcess(uint32_t aIndex,
    265                                                      base::ProcessId aPid);
    266 
    267  void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
    268                     ipc::ReadOnlySharedMemoryHandle aHandle);
    269  /**
    270   * Support for memory reporter.
    271   */
    272  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
    273  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
    274  size_t AllocatedShmemSize() const;
    275 
    276  /**
    277   * Using a larger block size will speed up allocation, at the cost of more
    278   * wasted space in the shared memory (on average).
    279   */
    280 #if ANDROID
    281  // Android devices usually have a much smaller number of fonts than desktop
    282  // systems, and memory is more constrained, so use a smaller default block
    283  // size.
    284  static constexpr uint32_t SHM_BLOCK_SIZE = 64 * 1024;
    285 #elif XP_LINUX
    286  // On Linux, font face descriptors are rather large (serialized FcPatterns),
    287  // so use a larger block size for efficiency.
    288  static constexpr uint32_t SHM_BLOCK_SIZE = 1024 * 1024;
    289 #else
    290  // Default block size for Windows and macOS.
    291  static constexpr uint32_t SHM_BLOCK_SIZE = 256 * 1024;
    292 #endif
    293  static_assert(SHM_BLOCK_SIZE <= (1 << Pointer::kBlockShift),
    294                "SHM_BLOCK_SIZE too large");
    295 
    296 private:
    297  struct ShmBlock {
    298    // Takes ownership of aShmem. In a child process, aShmem will be mapped as
    299    // read-only.
    300    explicit ShmBlock(ipc::ReadOnlySharedMemoryMapping&& aShmem)
    301        : mShmem(std::move(aShmem)) {
    302      MOZ_ASSERT(!XRE_IsParentProcess());
    303    }
    304 
    305    explicit ShmBlock(ipc::SharedMemoryMapping&& aShmem)
    306        : mShmem(std::move(aShmem)) {
    307      MOZ_ASSERT(XRE_IsParentProcess());
    308    }
    309 
    310    // Get pointer to the mapped memory.
    311    void* Memory() const { return mShmem.Address(); }
    312 
    313    void Clear() { mShmem = nullptr; }
    314 
    315    // Only the parent process does allocation, so only it will update this
    316    // field. Content processes read the value when checking Pointer validity.
    317    uint32_t Allocated() const {
    318      return static_cast<BlockHeader*>(Memory())->mAllocated;
    319    }
    320 
    321    void StoreAllocated(uint32_t aSize) {
    322      MOZ_ASSERT(XRE_IsParentProcess());
    323      static_cast<BlockHeader*>(Memory())->mAllocated.store(aSize);
    324    }
    325 
    326    // This is stored by the parent process during block creation and never
    327    // changes, so does not need to be atomic.
    328    // Note that some blocks may be larger than SHM_BLOCK_SIZE, if needed for
    329    // individual large allocations.
    330    uint32_t& BlockSize() const {
    331      MOZ_ASSERT(XRE_IsParentProcess());
    332      return static_cast<BlockHeader*>(Memory())->mBlockSize;
    333    }
    334 
    335   private:
    336    ipc::MutableOrReadOnlySharedMemoryMapping mShmem;
    337  };
    338 
    339  Header& GetHeader() const;
    340 
    341  /**
    342   * Create a new shared memory block and append to the FontList's list
    343   * of blocks.
    344   *
    345   * Only used in the parent process.
    346   */
    347  bool AppendShmBlock(uint32_t aSizeNeeded);
    348 
    349  /**
    350   * Used by child processes to ensure all the blocks are registered.
    351   * Returns false on failure.
    352   * Pass aMustLock=true to take the gfxPlatformFontList lock during the
    353   * update (not required when calling from the constructor).
    354   */
    355  [[nodiscard]] bool UpdateShmBlocks(bool aMustLock);
    356 
    357  /**
    358   * This makes a *sync* IPC call to get a shared block from the parent.
    359   * As such, it may block for a while if the parent is busy; fortunately,
    360   * we'll generally only call this a handful of times in the course of an
    361   * entire session. If the requested block does not yet exist (because the
    362   * child is wanting to allocate an object, and there wasn't room in any
    363   * existing block), the parent will create a new shared block and return it.
    364   * This may (in rare cases) return null, if the parent has recreated the
    365   * font list and we actually need to reinitialize.
    366   */
    367  ShmBlock* GetBlockFromParent(uint32_t aIndex);
    368 
    369  void DetachShmBlocks();
    370 
    371  /**
    372   * Array of pointers to the shared-memory block records.
    373   * NOTE: if mBlocks.Length() < GetHeader().mBlockCount, then the parent has
    374   * added a block (or blocks) to the list, and we need to update!
    375   */
    376  nsTArray<mozilla::UniquePtr<ShmBlock>> mBlocks;
    377 
    378  /**
    379   * Auxiliary array, used only in the parent process; holds read-only handles
    380   * for the shmem blocks; these are what will be shared to child processes.
    381   */
    382  nsTArray<ipc::ReadOnlySharedMemoryHandle> mReadOnlyShmems;
    383 
    384 #ifdef XP_WIN
    385  // Bool array to track whether we have read face names from the name table.
    386  nsTArray<bool> mFaceNamesRead;
    387 #endif
    388 };
    389 
    390 }  // namespace fontlist
    391 }  // namespace mozilla
    392 
    393 #endif /* SharedFontList_impl_h */