tor-browser

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

gfxUserFontSet.h (30253B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #ifndef GFX_USER_FONT_SET_H
      7 #define GFX_USER_FONT_SET_H
      8 
      9 #include <new>
     10 #include "PLDHashTable.h"
     11 #include "gfxFontEntry.h"
     12 #include "gfxFontUtils.h"
     13 #include "mozilla/AlreadyAddRefed.h"
     14 #include "mozilla/Atomics.h"
     15 #include "mozilla/Attributes.h"
     16 #include "mozilla/FontPropertyTypes.h"
     17 #include "mozilla/MemoryReporting.h"
     18 #include "mozilla/RecursiveMutex.h"
     19 #include "mozilla/RefPtr.h"
     20 #include "nsCOMPtr.h"
     21 #include "nsHashKeys.h"
     22 #include "nsIMemoryReporter.h"
     23 #include "nsIObserver.h"
     24 #include "nsIScriptError.h"
     25 #include "nsISupports.h"
     26 #include "nsRefPtrHashtable.h"
     27 #include "nsString.h"
     28 #include "nsTArray.h"
     29 #include "nscore.h"
     30 
     31 // Only needed for function bodies.
     32 #include <utility>                // for move, forward
     33 #include "MainThreadUtils.h"      // for NS_IsMainThread
     34 #include "gfxFontFeatures.h"      // for gfxFontFeature
     35 #include "gfxFontSrcPrincipal.h"  // for gfxFontSrcPrincipal
     36 #include "gfxFontSrcURI.h"        // for gfxFontSrcURI
     37 #include "mozilla/Assertions.h"  // for AssertionConditionType, MOZ_ASSERT_HELPER2, MOZ_ASSERT, MOZ_ASSERT_UNREACHABLE, MOZ_ASSER...
     38 #include "mozilla/HashFunctions.h"      // for HashBytes, HashGeneric
     39 #include "mozilla/TimeStamp.h"          // for TimeStamp
     40 #include "mozilla/gfx/FontVariation.h"  // for FontVariation
     41 #include "nsDebug.h"                    // for NS_WARNING
     42 #include "nsIReferrerInfo.h"            // for nsIReferrerInfo
     43 
     44 class gfxFont;
     45 class gfxUserFontSet;
     46 class nsIFontLoadCompleteCallback;
     47 class nsIRunnable;
     48 struct gfxFontStyle;
     49 struct gfxFontVariationAxis;
     50 struct gfxFontVariationInstance;
     51 template <class T>
     52 class nsMainThreadPtrHandle;
     53 
     54 namespace mozilla {
     55 class LogModule;
     56 class PostTraversalTask;
     57 enum class StyleFontDisplay : uint8_t;
     58 }  // namespace mozilla
     59 class nsFontFaceLoader;
     60 
     61 // #define DEBUG_USERFONT_CACHE
     62 
     63 class gfxFontFaceBufferSource {
     64  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxFontFaceBufferSource)
     65 public:
     66  virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength) = 0;
     67 
     68 protected:
     69  virtual ~gfxFontFaceBufferSource() = default;
     70 };
     71 
     72 // parsed CSS @font-face rule information
     73 // lifetime: from when @font-face rule processed until font is loaded
     74 struct gfxFontFaceSrc {
     75  enum SourceType { eSourceType_Local, eSourceType_URL, eSourceType_Buffer };
     76 
     77  SourceType mSourceType;
     78 
     79  // if url, whether to use the origin principal or not
     80  bool mUseOriginPrincipal = false;
     81 
     82  // Required font technologies.
     83  mozilla::StyleFontFaceSourceTechFlags mTechFlags;
     84 
     85  // Format hint, if any was specified.
     86  mozilla::StyleFontFaceSourceFormatKeyword mFormatHint;
     87 
     88  nsCString mLocalName;                     // full font name if local
     89  RefPtr<gfxFontSrcURI> mURI;               // uri if url
     90  nsCOMPtr<nsIReferrerInfo> mReferrerInfo;  // referrer info if url
     91  RefPtr<gfxFontSrcPrincipal>
     92      mOriginPrincipal;  // principal if url and mUseOriginPrincipal
     93 
     94  RefPtr<gfxFontFaceBufferSource> mBuffer;
     95 
     96  // The principal that should be used for the load. Should only be used for
     97  // URL sources.
     98  already_AddRefed<gfxFontSrcPrincipal> LoadPrincipal(
     99      const gfxUserFontSet&) const;
    100 };
    101 
    102 inline bool operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b) {
    103  if (a.mSourceType != b.mSourceType) {
    104    return false;
    105  }
    106  switch (a.mSourceType) {
    107    case gfxFontFaceSrc::eSourceType_Local:
    108      return a.mLocalName == b.mLocalName;
    109    case gfxFontFaceSrc::eSourceType_URL: {
    110      if (a.mUseOriginPrincipal != b.mUseOriginPrincipal) {
    111        return false;
    112      }
    113      if (a.mUseOriginPrincipal) {
    114        if (!a.mOriginPrincipal->Equals(b.mOriginPrincipal)) {
    115          return false;
    116        }
    117      }
    118      bool equals;
    119      return a.mFormatHint == b.mFormatHint && a.mTechFlags == b.mTechFlags &&
    120             (a.mURI == b.mURI || a.mURI->Equals(b.mURI)) &&
    121             NS_SUCCEEDED(a.mReferrerInfo->Equals(b.mReferrerInfo, &equals)) &&
    122             equals;
    123    }
    124    case gfxFontFaceSrc::eSourceType_Buffer:
    125      return a.mBuffer == b.mBuffer;
    126  }
    127  NS_WARNING("unexpected mSourceType");
    128  return false;
    129 }
    130 
    131 // Subclassed to store platform-specific code cleaned out when font entry is
    132 // deleted.
    133 // Lifetime: from when platform font is created until it is deactivated.
    134 // If the platform does not need to add any platform-specific code/data here,
    135 // then the gfxUserFontSet will allocate a base gfxUserFontData and attach
    136 // to the entry to track the basic user font info fields here.
    137 class gfxUserFontData {
    138 public:
    139  gfxUserFontData()
    140      : mSrcIndex(0),
    141        mMetaOrigLen(0),
    142        mTechFlags(mozilla::StyleFontFaceSourceTechFlags::Empty()),
    143        mFormatHint(mozilla::StyleFontFaceSourceFormatKeyword::None),
    144        mCompression(kUnknownCompression),
    145        mPrivate(false),
    146        mIsBuffer(false) {}
    147  virtual ~gfxUserFontData() = default;
    148 
    149  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
    150 
    151  nsTArray<uint8_t> mMetadata;  // woff metadata block (compressed), if any
    152  RefPtr<gfxFontSrcURI> mURI;   // URI of the source, if it was url()
    153  RefPtr<gfxFontSrcPrincipal>
    154      mPrincipal;         // principal for the download, if url()
    155  nsCString mLocalName;   // font name used for the source, if local()
    156  nsCString mRealName;    // original fullname from the font resource
    157  uint32_t mSrcIndex;     // index in the rule's source list
    158  uint32_t mMetaOrigLen;  // length needed to decompress metadata
    159  mozilla::StyleFontFaceSourceTechFlags mTechFlags;  // required font tech
    160  mozilla::StyleFontFaceSourceFormatKeyword
    161      mFormatHint;       // format hint for the source used, if any
    162  uint8_t mCompression;  // compression type
    163  bool mPrivate;         // whether font belongs to a private window
    164  bool mIsBuffer;        // whether the font source was a buffer
    165 
    166  enum {
    167    kUnknownCompression = 0,
    168    kZlibCompression = 1,
    169    kBrotliCompression = 2
    170  };
    171 };
    172 
    173 // initially contains a set of userfont font entry objects, replaced with
    174 // platform/user fonts as downloaded
    175 
    176 class gfxUserFontFamily : public gfxFontFamily {
    177 public:
    178  friend class gfxUserFontSet;
    179 
    180  explicit gfxUserFontFamily(const nsACString& aName)
    181      : gfxFontFamily(aName, FontVisibility::Webfont) {}
    182 
    183  virtual ~gfxUserFontFamily();
    184 
    185  // Add the given font entry to the end of the family's list.
    186  void AddFontEntry(gfxFontEntry* aFontEntry) {
    187    mozilla::AutoWriteLock lock(mLock);
    188    MOZ_ASSERT(!mIsSimpleFamily, "not valid for user-font families");
    189 
    190    // If this entry is already the last in the list, we can bail out without
    191    // doing any work.
    192    if (!mAvailableFonts.IsEmpty()) {
    193      if (mAvailableFonts.LastElement() == aFontEntry) {
    194        return;
    195      }
    196    }
    197 
    198    // Append new entry: we will search faces from the end, so that the last-
    199    // defined font is the first one in the fontlist used for matching, as per
    200    // CSS Fonts spec.
    201    // (It is possible that the entry is already present earlier in the list,
    202    // but duplication is harmless and it's not worth the cost of searching for
    203    // an existing entry here.)
    204    mAvailableFonts.AppendElement(aFontEntry);
    205 
    206    if (aFontEntry->mFamilyName.IsEmpty()) {
    207      aFontEntry->mFamilyName = Name();
    208    } else {
    209 #ifdef DEBUG
    210      nsCString thisName = Name();
    211      nsCString entryName = aFontEntry->mFamilyName;
    212      ToLowerCase(thisName);
    213      ToLowerCase(entryName);
    214      MOZ_ASSERT(thisName.Equals(entryName));
    215 #endif
    216    }
    217    ResetCharacterMap();
    218  }
    219 
    220  void RemoveFontEntry(gfxFontEntry* aFontEntry) {
    221    mozilla::AutoWriteLock lock(mLock);
    222    MOZ_ASSERT(!mIsSimpleFamily, "not valid for user-font families");
    223    mAvailableFonts.RemoveElement(aFontEntry);
    224  }
    225 
    226  // Remove all font entries from the family
    227  void DetachFontEntries() {
    228    mozilla::AutoWriteLock lock(mLock);
    229    mAvailableFonts.Clear();
    230  }
    231 };
    232 
    233 class gfxUserFontEntry;
    234 class gfxOTSMessageContext;
    235 
    236 struct gfxUserFontAttributes {
    237  using FontStretch = mozilla::FontStretch;
    238  using StretchRange = mozilla::StretchRange;
    239  using FontSlantStyle = mozilla::FontSlantStyle;
    240  using SlantStyleRange = mozilla::SlantStyleRange;
    241  using FontWeight = mozilla::FontWeight;
    242  using WeightRange = mozilla::WeightRange;
    243  using StyleFontFaceSourceListComponent =
    244      mozilla::StyleFontFaceSourceListComponent;
    245  using RangeFlags = gfxFontEntry::RangeFlags;
    246 
    247  WeightRange mWeight = WeightRange(FontWeight::NORMAL);
    248  StretchRange mStretch = StretchRange(FontStretch::NORMAL);
    249  SlantStyleRange mStyle = SlantStyleRange(FontSlantStyle::NORMAL);
    250  RangeFlags mRangeFlags = RangeFlags::eAutoWeight | RangeFlags::eAutoStretch |
    251                           RangeFlags::eAutoSlantStyle;
    252  mozilla::StyleFontDisplay mFontDisplay = mozilla::StyleFontDisplay::Auto;
    253  float mAscentOverride = -1.0;
    254  float mDescentOverride = -1.0;
    255  float mLineGapOverride = -1.0;
    256  float mSizeAdjust = 1.0;
    257  uint32_t mLanguageOverride = NO_FONT_LANGUAGE_OVERRIDE;
    258  nsTArray<gfxFontFeature> mFeatureSettings;
    259  nsTArray<gfxFontVariation> mVariationSettings;
    260  RefPtr<gfxCharacterMap> mUnicodeRanges;
    261 
    262  nsCString mFamilyName;
    263  AutoTArray<StyleFontFaceSourceListComponent, 8> mSources;
    264 };
    265 
    266 class gfxUserFontSet {
    267  friend class gfxUserFontEntry;
    268  friend class gfxOTSMessageContext;
    269 
    270 public:
    271  using FontStretch = mozilla::FontStretch;
    272  using StretchRange = mozilla::StretchRange;
    273  using FontSlantStyle = mozilla::FontSlantStyle;
    274  using SlantStyleRange = mozilla::SlantStyleRange;
    275  using FontWeight = mozilla::FontWeight;
    276  using WeightRange = mozilla::WeightRange;
    277  using RangeFlags = gfxFontEntry::RangeFlags;
    278 
    279  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
    280 
    281  gfxUserFontSet();
    282 
    283  void Destroy();
    284 
    285  // creates a font face without adding it to a particular family
    286  // weight - [100, 900] (multiples of 100)
    287  // stretch = [FontStretch::UltraCondensed(), FontStretch::UltraExpanded()]
    288  // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
    289  // language override = result of calling
    290  // nsLayoutUtils::ParseFontLanguageOverride
    291  // TODO: support for unicode ranges not yet implemented
    292  virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
    293      nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
    294      gfxUserFontAttributes&& aAttr) = 0;
    295 
    296  // creates a font face for the specified family, or returns an existing
    297  // matching entry on the family if there is one
    298  already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntry(
    299      nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
    300      gfxUserFontAttributes&& aAttr);
    301 
    302  // add in a font face for which we have the gfxUserFontEntry already
    303  void AddUserFontEntry(const nsCString& aFamilyName,
    304                        gfxUserFontEntry* aUserFontEntry);
    305 
    306  // Look up and return the gfxUserFontFamily in mFontFamilies with
    307  // the given name
    308  virtual already_AddRefed<gfxUserFontFamily> LookupFamily(
    309      const nsACString& aName) const;
    310 
    311  virtual already_AddRefed<gfxFontSrcPrincipal> GetStandardFontLoadPrincipal()
    312      const = 0;
    313  virtual FontVisibilityProvider* GetFontVisibilityProvider() const = 0;
    314 
    315  // check whether content policies allow the given URI to load.
    316  virtual bool IsFontLoadAllowed(const gfxFontFaceSrc&) = 0;
    317 
    318  // initialize the process that loads external font data, which upon
    319  // completion will call FontDataDownloadComplete method
    320  virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
    321                             uint32_t aSrcIndex) = 0;
    322 
    323  // generation - each time a face is loaded, generation is
    324  // incremented so that the change can be recognized
    325  uint64_t GetGeneration() { return mGeneration; }
    326 
    327  // increment the generation on font load
    328  void IncrementGeneration(bool aIsRebuild = false) {
    329    mozilla::RecursiveMutexAutoLock lock(mMutex);
    330    IncrementGenerationLocked(aIsRebuild);
    331  }
    332  void IncrementGenerationLocked(bool aIsRebuild = false) MOZ_REQUIRES(mMutex);
    333 
    334  // Generation is bumped on font loads but that doesn't affect name-style
    335  // mappings. Rebuilds do however affect name-style mappings so need to
    336  // lookup fontlists again when that happens.
    337  uint64_t GetRebuildGeneration() { return mRebuildGeneration; }
    338 
    339  // rebuild if local rules have been used
    340  void RebuildLocalRules();
    341 
    342  // Discard any font entries created for src:local(), so that they will
    343  // be reloaded next time they're needed. This is called when the platform
    344  // font list has changed, which means local font entries that were set up
    345  // may no longer be valid.
    346  virtual void ForgetLocalFaces();
    347 
    348  class UserFontCache {
    349   public:
    350    // Record a loaded user-font in the cache. This requires that the
    351    // font-entry's userFontData has been set up already, as it relies
    352    // on the URI and Principal recorded there.
    353    static void CacheFont(gfxFontEntry* aFontEntry);
    354 
    355    // The given gfxFontEntry is being destroyed, so remove any record that
    356    // refers to it.
    357    static void ForgetFont(gfxFontEntry* aFontEntry);
    358 
    359    // Return the gfxFontEntry corresponding to a given URI and principal,
    360    // and the features of the given userfont entry, or nullptr if none is
    361    // available. The aPrivate flag is set for requests coming from private
    362    // windows, so we can avoid leaking fonts cached in private windows mode out
    363    // to normal windows.
    364    static gfxFontEntry* GetFont(const gfxFontFaceSrc&,
    365                                 const gfxUserFontEntry&);
    366 
    367    // Clear everything so that we don't leak URIs and Principals.
    368    static void Shutdown();
    369 
    370    // Memory-reporting support.
    371    class MemoryReporter final : public nsIMemoryReporter {
    372     private:
    373      ~MemoryReporter() = default;
    374 
    375     public:
    376      NS_DECL_ISUPPORTS
    377      NS_DECL_NSIMEMORYREPORTER
    378    };
    379 
    380 #ifdef DEBUG_USERFONT_CACHE
    381    // dump contents
    382    static void Dump();
    383 #endif
    384 
    385   private:
    386    // Helper that we use to observe the empty-cache notification
    387    // from nsICacheService.
    388    class Flusher : public nsIObserver {
    389      virtual ~Flusher() = default;
    390 
    391     public:
    392      NS_DECL_ISUPPORTS
    393      NS_DECL_NSIOBSERVER
    394      Flusher() = default;
    395    };
    396 
    397    // Key used to look up entries in the user-font cache.
    398    // Note that key comparison does *not* use the mFontEntry field
    399    // as a whole; it only compares specific fields within the entry
    400    // (weight/width/style/features) that could affect font selection
    401    // or rendering, and that must match between a font-set's userfont
    402    // entry and the corresponding "real" font entry.
    403    struct Key {
    404      RefPtr<gfxFontSrcURI> mURI;
    405      RefPtr<gfxFontSrcPrincipal> mPrincipal;  // use nullptr with data: URLs
    406      // The font entry MUST notify the cache when it is destroyed
    407      // (by calling ForgetFont()).
    408      gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry;
    409      bool mPrivate;
    410 
    411      Key(gfxFontSrcURI* aURI, gfxFontSrcPrincipal* aPrincipal,
    412          gfxFontEntry* aFontEntry, bool aPrivate)
    413          : mURI(aURI),
    414            mPrincipal(aPrincipal),
    415            mFontEntry(aFontEntry),
    416            mPrivate(aPrivate) {}
    417    };
    418 
    419    class Entry : public PLDHashEntryHdr {
    420     public:
    421      typedef const Key& KeyType;
    422      typedef const Key* KeyTypePointer;
    423 
    424      explicit Entry(KeyTypePointer aKey)
    425          : mURI(aKey->mURI),
    426            mPrincipal(aKey->mPrincipal),
    427            mFontEntry(aKey->mFontEntry),
    428            mPrivate(aKey->mPrivate) {}
    429 
    430      Entry(Entry&& aOther)
    431          : PLDHashEntryHdr(std::move(aOther)),
    432            mURI(std::move(aOther.mURI)),
    433            mPrincipal(std::move(aOther.mPrincipal)),
    434            mFontEntry(std::move(aOther.mFontEntry)),
    435            mPrivate(std::move(aOther.mPrivate)) {}
    436 
    437      ~Entry() = default;
    438 
    439      bool KeyEquals(const KeyTypePointer aKey) const;
    440 
    441      static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
    442 
    443      static PLDHashNumber HashKey(const KeyTypePointer aKey) {
    444        PLDHashNumber principalHash =
    445            aKey->mPrincipal ? aKey->mPrincipal->Hash() : 0;
    446        return mozilla::HashGeneric(
    447            principalHash + int(aKey->mPrivate), aKey->mURI->Hash(),
    448            HashFeatures(aKey->mFontEntry->mFeatureSettings),
    449            HashVariations(aKey->mFontEntry->mVariationSettings),
    450            mozilla::HashString(aKey->mFontEntry->mFamilyName),
    451            aKey->mFontEntry->Weight().AsScalar(),
    452            aKey->mFontEntry->SlantStyle().AsScalar(),
    453            aKey->mFontEntry->Stretch().AsScalar(),
    454            aKey->mFontEntry->AutoRangeFlags(),
    455            aKey->mFontEntry->mLanguageOverride);
    456      }
    457 
    458      enum { ALLOW_MEMMOVE = false };
    459 
    460      gfxFontSrcURI* GetURI() const { return mURI; }
    461      gfxFontSrcPrincipal* GetPrincipal() const { return mPrincipal; }
    462      gfxFontEntry* GetFontEntry() const { return mFontEntry; }
    463      bool IsPrivate() const { return mPrivate; }
    464 
    465      void ReportMemory(nsIHandleReportCallback* aHandleReport,
    466                        nsISupports* aData, bool aAnonymize);
    467 
    468 #ifdef DEBUG_USERFONT_CACHE
    469      void Dump();
    470 #endif
    471 
    472     private:
    473      static uint32_t HashFeatures(const nsTArray<gfxFontFeature>& aFeatures) {
    474        return mozilla::HashBytes(aFeatures.Elements(),
    475                                  aFeatures.Length() * sizeof(gfxFontFeature));
    476      }
    477 
    478      static uint32_t HashVariations(
    479          const nsTArray<mozilla::gfx::FontVariation>& aVariations) {
    480        return mozilla::HashBytes(
    481            aVariations.Elements(),
    482            aVariations.Length() * sizeof(mozilla::gfx::FontVariation));
    483      }
    484 
    485      RefPtr<gfxFontSrcURI> mURI;
    486      RefPtr<gfxFontSrcPrincipal> mPrincipal;  // or nullptr for data: URLs
    487 
    488      // The "real" font entry corresponding to this downloaded font.
    489      // The font entry MUST notify the cache when it is destroyed
    490      // (by calling ForgetFont()).
    491      gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry;
    492 
    493      // Whether this font was loaded from a private window.
    494      bool mPrivate;
    495    };
    496 
    497    static nsTHashtable<Entry>* sUserFonts;
    498  };
    499 
    500  void SetLocalRulesUsed() { mLocalRulesUsed = true; }
    501 
    502  static mozilla::LogModule* GetUserFontsLog();
    503 
    504  // record statistics about font completion
    505  virtual void RecordFontLoadDone(uint32_t aFontSize,
    506                                  mozilla::TimeStamp aDoneTime) {}
    507 
    508  void GetLoadStatistics(uint32_t& aLoadCount, uint64_t& aLoadSize) const {
    509    aLoadCount = mDownloadCount;
    510    aLoadSize = mDownloadSize;
    511  }
    512 
    513 protected:
    514  // Protected destructor, to discourage deletion outside of Release():
    515  virtual ~gfxUserFontSet();
    516 
    517  // Return whether the font set is associated with a private-browsing tab.
    518  virtual bool GetPrivateBrowsing() = 0;
    519 
    520  // Return whether the font set is associated with a document that was
    521  // shift-reloaded, for example, and thus should bypass the font cache.
    522  virtual bool BypassCache() = 0;
    523 
    524  // parse data for a data URL
    525  virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
    526                                    const gfxFontFaceSrc* aFontFaceSrc,
    527                                    uint8_t*& aBuffer,
    528                                    uint32_t& aBufferLength) = 0;
    529 
    530  // report a problem of some kind (implemented in nsUserFontSet)
    531  virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
    532                              uint32_t aSrcIndex, const char* aMessage,
    533                              uint32_t aFlags = nsIScriptError::errorFlag,
    534                              nsresult aStatus = NS_OK) = 0;
    535 
    536  // helper method for performing the actual userfont set rebuild
    537  virtual void DoRebuildUserFontSet() = 0;
    538 
    539  // forget about a loader that has been cancelled
    540  virtual void RemoveLoader(nsFontFaceLoader* aLoader) = 0;
    541 
    542  // helper method for FindOrCreateUserFontEntry
    543  gfxUserFontEntry* FindExistingUserFontEntry(
    544      gfxUserFontFamily* aFamily,
    545      const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
    546      const gfxUserFontAttributes& aAttr);
    547 
    548  // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
    549  // family if there is one
    550  virtual already_AddRefed<gfxUserFontFamily> GetFamily(
    551      const nsACString& aFamilyName);
    552 
    553  void ForgetLocalFace(gfxUserFontFamily* aFontFamily);
    554 
    555  // font families defined by @font-face rules
    556  nsRefPtrHashtable<nsCStringHashKey, gfxUserFontFamily> mFontFamilies;
    557 
    558  mozilla::Atomic<uint64_t> mGeneration;  // bumped on any font load change
    559  uint64_t mRebuildGeneration;            // only bumped on rebuilds
    560 
    561  // true when local names have been looked up, false otherwise
    562  bool mLocalRulesUsed;
    563 
    564  // true when rules using local names need to be redone
    565  bool mRebuildLocalRules;
    566 
    567  // performance stats
    568  uint32_t mDownloadCount;
    569  uint64_t mDownloadSize;
    570 
    571  mutable mozilla::RecursiveMutex mMutex;
    572 };
    573 
    574 // acts a placeholder until the real font is downloaded
    575 
    576 class gfxUserFontEntry : public gfxFontEntry {
    577  friend class mozilla::PostTraversalTask;
    578  friend class gfxUserFontSet;
    579  friend class nsUserFontSet;
    580  friend class nsFontFaceLoader;
    581  friend class gfxOTSMessageContext;
    582 
    583 public:
    584  enum UserFontLoadState {
    585    STATUS_NOT_LOADED = 0,
    586    STATUS_LOAD_PENDING,
    587    STATUS_LOADING,
    588    STATUS_LOADED,
    589    STATUS_FAILED
    590  };
    591 
    592  gfxUserFontEntry(nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
    593                   gfxUserFontAttributes&& aAttr);
    594 
    595  ~gfxUserFontEntry() override;
    596 
    597  // Update the attributes of the entry to the given values, without disturbing
    598  // the associated platform font entry or in-progress downloads.
    599  void UpdateAttributes(gfxUserFontAttributes&& aAttr);
    600 
    601  // Return whether the entry matches the given list of attributes
    602  bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
    603               const gfxUserFontAttributes& aAttr);
    604 
    605  gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle) override;
    606 
    607  gfxFontEntry* GetPlatformFontEntry() const { return mPlatformFontEntry; }
    608 
    609  // is the font loading or loaded, or did it fail?
    610  UserFontLoadState LoadState() const { return mUserFontLoadState; }
    611 
    612  void LoadCanceled() {
    613    MOZ_ASSERT(NS_IsMainThread());
    614 
    615    mUserFontLoadState = STATUS_NOT_LOADED;
    616    mFontDataLoadingState = NOT_LOADING;
    617    mLoader = nullptr;
    618    // Reset mCurrentSrcIndex so that all potential sources are re-considered.
    619    mCurrentSrcIndex = 0;
    620    mSeenLocalSource = false;
    621  }
    622 
    623  // whether to wait before using fallback font or not
    624  bool WaitForUserFont() const {
    625    return (mUserFontLoadState == STATUS_LOAD_PENDING ||
    626            mUserFontLoadState == STATUS_LOADING) &&
    627           mFontDataLoadingState < LOADING_SLOWLY;
    628  }
    629 
    630  // For userfonts, cmap is used to store the unicode range data,
    631  // and is inert once set, so locking is not required here.
    632  // no cmap ==> all codepoints permitted
    633  bool CharacterInUnicodeRange(uint32_t ch) const {
    634    if (const auto* map = GetUnicodeRangeMap()) {
    635      return map->test(ch);
    636    }
    637    return true;
    638  }
    639 
    640  gfxCharacterMap* GetUnicodeRangeMap() const { return GetCharacterMap(); }
    641  void SetUnicodeRangeMap(RefPtr<gfxCharacterMap>&& aCharMap) {
    642    auto* oldCmap = GetUnicodeRangeMap();
    643    if (oldCmap != aCharMap) {
    644      auto* newCmap = aCharMap.forget().take();
    645      if (mCharacterMap.compareExchange(oldCmap, newCmap)) {
    646        NS_IF_RELEASE(oldCmap);
    647      } else {
    648        NS_IF_RELEASE(newCmap);
    649      }
    650    }
    651  }
    652 
    653  mozilla::StyleFontDisplay GetFontDisplay() const { return mFontDisplay; }
    654 
    655  // load the font - starts the loading of sources which continues until
    656  // a valid font resource is found or all sources fail
    657  void Load();
    658 
    659  // Invalidates appropriately when the load finishes.
    660  void FontLoadComplete();
    661 
    662  // methods to expose some information to FontFaceSet::UserFontSet
    663  // since we can't make that class a friend
    664  void SetLoader(nsFontFaceLoader* aLoader) {
    665    MOZ_ASSERT(NS_IsMainThread());
    666    mLoader = aLoader;
    667  }
    668 
    669  nsFontFaceLoader* GetLoader() const {
    670    MOZ_ASSERT(NS_IsMainThread());
    671    return mLoader;
    672  }
    673 
    674  gfxFontSrcPrincipal* GetPrincipal() const { return mPrincipal; }
    675  void GetFamilyNameAndURIForLogging(uint32_t aSrcIndex,
    676                                     nsACString& aFamilyName, nsACString& aURI);
    677 
    678  gfxFontEntry* Clone() const override {
    679    MOZ_ASSERT_UNREACHABLE("cannot Clone user fonts");
    680    return nullptr;
    681  }
    682 
    683  virtual already_AddRefed<gfxUserFontSet> GetUserFontSet() const = 0;
    684 
    685  const nsTArray<gfxFontFaceSrc>& SourceList() const { return mSrcList; }
    686 
    687  // Returns a weak reference to the requested source record, which is owned
    688  // by the gfxUserFontEntry.
    689  const gfxFontFaceSrc& SourceAt(uint32_t aSrcIndex) const {
    690    return mSrcList[aSrcIndex];
    691  }
    692 
    693  // The variation-query APIs should not be called on placeholders.
    694  bool HasVariations() override {
    695    MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
    696    return false;
    697  }
    698  void GetVariationAxes(nsTArray<gfxFontVariationAxis>&) override {
    699    MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
    700  }
    701  void GetVariationInstances(nsTArray<gfxFontVariationInstance>&) override {
    702    MOZ_ASSERT_UNREACHABLE("not meaningful for a userfont placeholder");
    703  }
    704 
    705 protected:
    706  struct OTSMessage {
    707    nsCString mMessage;
    708    int mLevel;  // see OTSContext in gfx/ots/include/opentype-sanitizer.h
    709  };
    710 
    711  const uint8_t* SanitizeOpenTypeData(const uint8_t* aData, uint32_t aLength,
    712                                      uint32_t& aSanitaryLength,
    713                                      gfxUserFontType& aFontType,
    714                                      nsTArray<OTSMessage>& aMessages);
    715 
    716  // attempt to load the next resource in the src list.
    717  void LoadNextSrc();
    718  void ContinueLoad();
    719  void DoLoadNextSrc(bool aIsContinue);
    720 
    721  // change the load state
    722  virtual void SetLoadState(UserFontLoadState aLoadState);
    723 
    724  // when download has been completed, pass back data here
    725  // aDownloadStatus == NS_OK ==> download succeeded, error otherwise
    726  // Ownership of aFontData is passed in here; the font set must
    727  // ensure that it is eventually deleted with free().
    728  void FontDataDownloadComplete(uint32_t aSrcIndex, const uint8_t* aFontData,
    729                                uint32_t aLength, nsresult aDownloadStatus,
    730                                nsIFontLoadCompleteCallback* aCallback);
    731 
    732  // helper method for creating a platform font
    733  // returns true if platform font creation successful
    734  // Ownership of aFontData is passed in here; the font must
    735  // ensure that it is eventually deleted with free().
    736  bool LoadPlatformFontSync(uint32_t aSrcIndex, const uint8_t* aFontData,
    737                            uint32_t aLength);
    738 
    739  void LoadPlatformFontAsync(uint32_t aSrcIndex, const uint8_t* aFontData,
    740                             uint32_t aLength,
    741                             nsIFontLoadCompleteCallback* aCallback);
    742 
    743  // helper method for LoadPlatformFontAsync; runs on a background thread
    744  void StartPlatformFontLoadOnBackgroundThread(
    745      uint32_t aSrcIndex, const uint8_t* aFontData, uint32_t aLength,
    746      nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback);
    747 
    748  // helper method for LoadPlatformFontAsync; runs on the main thread
    749  void ContinuePlatformFontLoadOnMainThread(
    750      uint32_t aSrcIndex, const uint8_t* aOriginalFontData,
    751      uint32_t aOriginalLength, gfxUserFontType aFontType,
    752      const uint8_t* aSanitizedFontData, uint32_t aSanitizedLength,
    753      nsTArray<OTSMessage>&& aMessages,
    754      nsMainThreadPtrHandle<nsIFontLoadCompleteCallback> aCallback);
    755 
    756  // helper method for LoadPlatformFontSync and
    757  // ContinuePlatformFontLoadOnMainThread; runs on the main thread
    758  bool LoadPlatformFont(uint32_t aSrcIndex, const uint8_t* aOriginalFontData,
    759                        uint32_t aOriginalLength, gfxUserFontType aFontType,
    760                        const uint8_t* aSanitizedFontData,
    761                        uint32_t aSanitizedLength,
    762                        nsTArray<OTSMessage>&& aMessages);
    763 
    764  // helper method for FontDataDownloadComplete and
    765  // ContinuePlatformFontLoadOnMainThread; runs on the main thread
    766  void FontLoadFailed(nsIFontLoadCompleteCallback* aCallback);
    767 
    768  // store metadata and src details for current src into aFontEntry
    769  void StoreUserFontData(gfxFontEntry* aFontEntry, uint32_t aSrcIndex,
    770                         bool aPrivate, const nsACString& aOriginalName,
    771                         FallibleTArray<uint8_t>* aMetadata,
    772                         uint32_t aMetaOrigLen, uint8_t aCompression);
    773 
    774  // Clears and then adds to aResult all of the user font sets that this user
    775  // font entry has been added to.  This will at least include the owner of this
    776  // user font entry.
    777  virtual void GetUserFontSets(nsTArray<RefPtr<gfxUserFontSet>>& aResult);
    778 
    779  // general load state
    780  UserFontLoadState mUserFontLoadState;
    781 
    782  // detailed load state while font data is loading
    783  // used to determine whether to use fallback font or not
    784  // note that code depends on the ordering of these values!
    785  enum FontDataLoadingState {
    786    NOT_LOADING = 0,      // not started to load any font resources yet
    787    LOADING_STARTED,      // loading has started; hide fallback font
    788    LOADING_ALMOST_DONE,  // timeout happened but we're nearly done,
    789                          // so keep hiding fallback font
    790    LOADING_SLOWLY,       // timeout happened and we're not nearly done,
    791                          // so use the fallback font
    792    LOADING_TIMED_OUT,    // font load took too long
    793    LOADING_FAILED        // failed to load any source: use fallback
    794  };
    795  FontDataLoadingState mFontDataLoadingState;
    796 
    797  bool mSeenLocalSource;
    798  bool mUnsupportedFormat;
    799  mozilla::StyleFontDisplay mFontDisplay;  // timing of userfont fallback
    800 
    801  RefPtr<gfxFontEntry> mPlatformFontEntry;
    802  nsTArray<gfxFontFaceSrc> mSrcList;
    803  uint32_t mCurrentSrcIndex;  // index of src item to be loaded next
    804  // This field is managed by the nsFontFaceLoader. In the destructor and
    805  // Cancel() methods of nsFontFaceLoader this reference is nulled out.
    806  nsFontFaceLoader* MOZ_NON_OWNING_REF
    807      mLoader;  // current loader for this entry, if any
    808  RefPtr<gfxUserFontSet> mLoadingFontSet;
    809  RefPtr<gfxFontSrcPrincipal> mPrincipal;
    810 };
    811 
    812 #endif /* GFX_USER_FONT_SET_H */