LCOV - code coverage report
Current view: top level - gfx/thebes - gfxUserFontSet.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 635 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 70 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       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             : #include "mozilla/Logging.h"
       7             : 
       8             : #include "gfxUserFontSet.h"
       9             : #include "gfxPlatform.h"
      10             : #include "gfxPrefs.h"
      11             : #include "nsIProtocolHandler.h"
      12             : #include "gfxFontConstants.h"
      13             : #include "mozilla/Preferences.h"
      14             : #include "mozilla/Services.h"
      15             : #include "mozilla/Telemetry.h"
      16             : #include "mozilla/gfx/2D.h"
      17             : #include "gfxPlatformFontList.h"
      18             : #include "mozilla/ServoStyleSet.h"
      19             : #include "mozilla/PostTraversalTask.h"
      20             : 
      21             : #include "opentype-sanitiser.h"
      22             : #include "ots-memory-stream.h"
      23             : 
      24             : using namespace mozilla;
      25             : 
      26             : mozilla::LogModule*
      27           0 : gfxUserFontSet::GetUserFontsLog()
      28             : {
      29             :     static LazyLogModule sLog("userfonts");
      30           0 :     return sLog;
      31             : }
      32             : 
      33             : #define LOG(args) MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
      34             : #define LOG_ENABLED() MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug)
      35             : 
      36             : static uint64_t sFontSetGeneration = 0;
      37             : 
      38             : // Based on ots::ExpandingMemoryStream from ots-memory-stream.h,
      39             : // adapted to use Mozilla allocators and to allow the final
      40             : // memory buffer to be adopted by the client.
      41             : class ExpandingMemoryStream : public ots::OTSStream {
      42             : public:
      43           0 :     ExpandingMemoryStream(size_t initial, size_t limit)
      44           0 :         : mLength(initial), mLimit(limit), mOff(0) {
      45           0 :         mPtr = moz_xmalloc(mLength);
      46           0 :     }
      47             : 
      48           0 :     ~ExpandingMemoryStream() {
      49           0 :         free(mPtr);
      50           0 :     }
      51             : 
      52             :     // Return the buffer, resized to fit its contents (as it may have been
      53             :     // over-allocated during growth), and give up ownership of it so the
      54             :     // caller becomes responsible to call free() when finished with it.
      55           0 :     void* forget() {
      56           0 :         void* p = moz_xrealloc(mPtr, mOff);
      57           0 :         mPtr = nullptr;
      58           0 :         return p;
      59             :     }
      60             : 
      61           0 :     bool WriteRaw(const void* data, size_t length) {
      62           0 :         if ((mOff + length > mLength) ||
      63           0 :             (mLength > std::numeric_limits<size_t>::max() - mOff)) {
      64           0 :             if (mLength == mLimit) {
      65           0 :                 return false;
      66             :             }
      67           0 :             size_t newLength = (mLength + 1) * 2;
      68           0 :             if (newLength < mLength) {
      69           0 :                 return false;
      70             :             }
      71           0 :             if (newLength > mLimit) {
      72           0 :                 newLength = mLimit;
      73             :             }
      74           0 :             mPtr = moz_xrealloc(mPtr, newLength);
      75           0 :             mLength = newLength;
      76           0 :             return WriteRaw(data, length);
      77             :         }
      78           0 :         std::memcpy(static_cast<char*>(mPtr) + mOff, data, length);
      79           0 :         mOff += length;
      80           0 :         return true;
      81             :     }
      82             : 
      83           0 :     bool Seek(off_t position) {
      84           0 :         if (position < 0) {
      85           0 :             return false;
      86             :         }
      87           0 :         if (static_cast<size_t>(position) > mLength) {
      88           0 :             return false;
      89             :         }
      90           0 :         mOff = position;
      91           0 :         return true;
      92             :     }
      93             : 
      94           0 :     off_t Tell() const {
      95           0 :         return mOff;
      96             :     }
      97             : 
      98             : private:
      99             :     void*        mPtr;
     100             :     size_t       mLength;
     101             :     const size_t mLimit;
     102             :     off_t        mOff;
     103             : };
     104             : 
     105           0 : gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
     106             :              const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
     107             :              uint32_t aWeight,
     108             :              int32_t aStretch,
     109             :              uint8_t aStyle,
     110             :              const nsTArray<gfxFontFeature>& aFeatureSettings,
     111             :              uint32_t aLanguageOverride,
     112             :              gfxCharacterMap* aUnicodeRanges,
     113           0 :              uint8_t aFontDisplay)
     114           0 :     : gfxFontEntry(NS_LITERAL_STRING("userfont")),
     115             :       mUserFontLoadState(STATUS_NOT_LOADED),
     116             :       mFontDataLoadingState(NOT_LOADING),
     117             :       mUnsupportedFormat(false),
     118             :       mFontDisplay(aFontDisplay),
     119             :       mLoader(nullptr),
     120           0 :       mFontSet(aFontSet)
     121             : {
     122           0 :     MOZ_ASSERT(aWeight != 0,
     123             :                "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
     124           0 :     mIsUserFontContainer = true;
     125           0 :     mSrcList = aFontFaceSrcList;
     126           0 :     mSrcIndex = 0;
     127           0 :     mWeight = aWeight;
     128           0 :     mStretch = aStretch;
     129           0 :     mStyle = aStyle;
     130           0 :     mFeatureSettings.AppendElements(aFeatureSettings);
     131           0 :     mLanguageOverride = aLanguageOverride;
     132           0 :     mCharacterMap = aUnicodeRanges;
     133           0 : }
     134             : 
     135           0 : gfxUserFontEntry::~gfxUserFontEntry()
     136             : {
     137             :     // Assert that we don't drop any gfxUserFontEntry objects during a Servo
     138             :     // traversal, since PostTraversalTask objects can hold raw pointers to
     139             :     // gfxUserFontEntry objects.
     140           0 :     MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
     141           0 : }
     142             : 
     143             : bool
     144           0 : gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
     145             :                           uint32_t aWeight,
     146             :                           int32_t aStretch,
     147             :                           uint8_t aStyle,
     148             :                           const nsTArray<gfxFontFeature>& aFeatureSettings,
     149             :                           uint32_t aLanguageOverride,
     150             :                           gfxCharacterMap* aUnicodeRanges,
     151             :                           uint8_t aFontDisplay)
     152             : {
     153           0 :     return mWeight == aWeight &&
     154           0 :            mStretch == aStretch &&
     155           0 :            mStyle == aStyle &&
     156           0 :            mFeatureSettings == aFeatureSettings &&
     157           0 :            mLanguageOverride == aLanguageOverride &&
     158           0 :            mSrcList == aFontFaceSrcList &&
     159           0 :            mFontDisplay == aFontDisplay &&
     160           0 :            ((!aUnicodeRanges && !mCharacterMap) ||
     161           0 :             (aUnicodeRanges && mCharacterMap && mCharacterMap->Equals(aUnicodeRanges)));
     162             : }
     163             : 
     164             : gfxFont*
     165           0 : gfxUserFontEntry::CreateFontInstance(const gfxFontStyle* aFontStyle, bool aNeedsBold)
     166             : {
     167           0 :     NS_NOTREACHED("should only be creating a gfxFont"
     168             :                   " with an actual platform font entry");
     169             : 
     170             :     // userfont entry is a container, can't create font from the container
     171           0 :     return nullptr;
     172             : }
     173             : 
     174           0 : class gfxOTSContext : public ots::OTSContext {
     175             : public:
     176           0 :     explicit gfxOTSContext(gfxUserFontEntry* aUserFontEntry)
     177           0 :         : mUserFontEntry(aUserFontEntry)
     178             :     {
     179             :         // Whether to apply OTS validation to OpenType Layout tables
     180           0 :         mCheckOTLTables = gfxPrefs::ValidateOTLTables();
     181             :         // Whether to preserve Variation tables in downloaded fonts
     182           0 :         mKeepVariationTables = gfxPrefs::KeepVariationTables();
     183           0 :     }
     184             : 
     185           0 :     virtual ots::TableAction GetTableAction(uint32_t aTag) override {
     186             :         // Preserve Graphite, color glyph and SVG tables,
     187             :         // and possibly OTL and Variation tables (depending on prefs)
     188           0 :         if ((!mCheckOTLTables &&
     189           0 :              (aTag == TRUETYPE_TAG('G', 'D', 'E', 'F') ||
     190           0 :               aTag == TRUETYPE_TAG('G', 'P', 'O', 'S') ||
     191           0 :               aTag == TRUETYPE_TAG('G', 'S', 'U', 'B'))) ||
     192           0 :             (mKeepVariationTables &&
     193           0 :              (aTag == TRUETYPE_TAG('a', 'v', 'a', 'r') ||
     194           0 :               aTag == TRUETYPE_TAG('c', 'v', 'a', 'r') ||
     195           0 :               aTag == TRUETYPE_TAG('f', 'v', 'a', 'r') ||
     196           0 :               aTag == TRUETYPE_TAG('g', 'v', 'a', 'r') ||
     197           0 :               aTag == TRUETYPE_TAG('H', 'V', 'A', 'R') ||
     198           0 :               aTag == TRUETYPE_TAG('M', 'V', 'A', 'R') ||
     199           0 :               aTag == TRUETYPE_TAG('V', 'V', 'A', 'R'))) ||
     200           0 :             aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
     201           0 :             aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
     202           0 :             aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
     203           0 :             aTag == TRUETYPE_TAG('G', 'l', 'a', 't') ||
     204           0 :             aTag == TRUETYPE_TAG('F', 'e', 'a', 't') ||
     205           0 :             aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') ||
     206           0 :             aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') ||
     207             :             aTag == TRUETYPE_TAG('C', 'P', 'A', 'L')) {
     208           0 :             return ots::TABLE_ACTION_PASSTHRU;
     209             :         }
     210           0 :         return ots::TABLE_ACTION_DEFAULT;
     211             :     }
     212             : 
     213           0 :     virtual void Message(int level, const char* format,
     214             :                          ...) MSGFUNC_FMT_ATTR override {
     215             :         va_list va;
     216           0 :         va_start(va, format);
     217             : 
     218           0 :         nsCString msg;
     219           0 :         msg.AppendPrintf(format, va);
     220             : 
     221           0 :         va_end(va);
     222             : 
     223           0 :         if (level > 0) {
     224             :             // For warnings (rather than errors that cause the font to fail),
     225             :             // we only report the first instance of any given message.
     226           0 :             if (mWarningsIssued.Contains(msg)) {
     227           0 :                 return;
     228             :             }
     229           0 :             mWarningsIssued.PutEntry(msg);
     230             :         }
     231             : 
     232           0 :         mUserFontEntry->mFontSet->LogMessage(mUserFontEntry, msg.get());
     233             :     }
     234             : 
     235             : private:
     236             :     gfxUserFontEntry* mUserFontEntry;
     237             :     nsTHashtable<nsCStringHashKey> mWarningsIssued;
     238             :     bool mCheckOTLTables;
     239             :     bool mKeepVariationTables;
     240             : };
     241             : 
     242             : // Call the OTS library to sanitize an sfnt before attempting to use it.
     243             : // Returns a newly-allocated block, or nullptr in case of fatal errors.
     244             : const uint8_t*
     245           0 : gfxUserFontEntry::SanitizeOpenTypeData(const uint8_t* aData,
     246             :                                        uint32_t       aLength,
     247             :                                        uint32_t&      aSaneLength,
     248             :                                        gfxUserFontType aFontType)
     249             : {
     250           0 :     if (aFontType == GFX_USERFONT_UNKNOWN) {
     251           0 :         aSaneLength = 0;
     252           0 :         return nullptr;
     253             :     }
     254             : 
     255           0 :     uint32_t lengthHint = aLength;
     256           0 :     if (aFontType == GFX_USERFONT_WOFF) {
     257           0 :         lengthHint *= 2;
     258           0 :     } else if (aFontType == GFX_USERFONT_WOFF2) {
     259           0 :         lengthHint *= 3;
     260             :     }
     261             : 
     262             :     // limit output/expansion to 256MB
     263           0 :     ExpandingMemoryStream output(lengthHint, 1024 * 1024 * 256);
     264             : 
     265           0 :     gfxOTSContext otsContext(this);
     266           0 :     if (!otsContext.Process(&output, aData, aLength)) {
     267             :         // Failed to decode/sanitize the font, so discard it.
     268           0 :         aSaneLength = 0;
     269           0 :         return nullptr;
     270             :     }
     271             : 
     272           0 :     aSaneLength = output.Tell();
     273           0 :     return static_cast<const uint8_t*>(output.forget());
     274             : }
     275             : 
     276             : void
     277           0 : gfxUserFontEntry::StoreUserFontData(gfxFontEntry* aFontEntry,
     278             :                                     bool aPrivate,
     279             :                                     const nsAString& aOriginalName,
     280             :                                     FallibleTArray<uint8_t>* aMetadata,
     281             :                                     uint32_t aMetaOrigLen,
     282             :                                     uint8_t aCompression)
     283             : {
     284           0 :     if (!aFontEntry->mUserFontData) {
     285           0 :         aFontEntry->mUserFontData = MakeUnique<gfxUserFontData>();
     286             :     }
     287           0 :     gfxUserFontData* userFontData = aFontEntry->mUserFontData.get();
     288           0 :     userFontData->mSrcIndex = mSrcIndex;
     289           0 :     const gfxFontFaceSrc& src = mSrcList[mSrcIndex];
     290           0 :     switch (src.mSourceType) {
     291             :         case gfxFontFaceSrc::eSourceType_Local:
     292           0 :             userFontData->mLocalName = src.mLocalName;
     293           0 :             break;
     294             :         case gfxFontFaceSrc::eSourceType_URL:
     295           0 :             userFontData->mURI = src.mURI;
     296           0 :             userFontData->mPrincipal = mPrincipal;
     297           0 :             break;
     298             :         case gfxFontFaceSrc::eSourceType_Buffer:
     299           0 :             userFontData->mIsBuffer = true;
     300           0 :             break;
     301             :     }
     302           0 :     userFontData->mPrivate = aPrivate;
     303           0 :     userFontData->mFormat = src.mFormatFlags;
     304           0 :     userFontData->mRealName = aOriginalName;
     305           0 :     if (aMetadata) {
     306           0 :         userFontData->mMetadata.SwapElements(*aMetadata);
     307           0 :         userFontData->mMetaOrigLen = aMetaOrigLen;
     308           0 :         userFontData->mCompression = aCompression;
     309             :     }
     310           0 : }
     311             : 
     312             : size_t
     313           0 : gfxUserFontData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
     314             : {
     315           0 :     return aMallocSizeOf(this)
     316           0 :            + mMetadata.ShallowSizeOfExcludingThis(aMallocSizeOf)
     317           0 :            + mLocalName.SizeOfExcludingThisIfUnshared(aMallocSizeOf)
     318           0 :            + mRealName.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     319             :     // Not counting mURI and mPrincipal, as those will be shared.
     320             : }
     321             : 
     322             : /*virtual*/
     323           0 : gfxUserFontFamily::~gfxUserFontFamily()
     324             : {
     325             :   // Should not be dropped by stylo
     326           0 :   MOZ_ASSERT(NS_IsMainThread());
     327           0 : }
     328             : 
     329             : void
     330           0 : gfxUserFontEntry::GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
     331             :                                                 nsACString& aURI)
     332             : {
     333           0 :   aFamilyName.Assign(NS_ConvertUTF16toUTF8(mFamilyName));
     334             : 
     335           0 :   aURI.Truncate();
     336           0 :   if (mSrcIndex == mSrcList.Length()) {
     337           0 :     aURI.AppendLiteral("(end of source list)");
     338             :   } else {
     339           0 :     if (mSrcList[mSrcIndex].mURI) {
     340           0 :       mSrcList[mSrcIndex].mURI->GetSpec(aURI);
     341             :       // If the source URI was very long, elide the middle of it.
     342             :       // In principle, the byte-oriented chopping here could leave us
     343             :       // with partial UTF-8 characters at the point where we cut it,
     344             :       // but it really doesn't matter as this is just for logging.
     345           0 :       const uint32_t kMaxURILengthForLogging = 256;
     346             :       // UTF-8 ellipsis, with spaces to allow additional wrap opportunities
     347             :       // in the resulting log message
     348           0 :       const char kEllipsis[] = { ' ', '\xE2', '\x80', '\xA6', ' ' };
     349           0 :       if (aURI.Length() > kMaxURILengthForLogging) {
     350           0 :         aURI.Replace(kMaxURILengthForLogging / 2,
     351           0 :                      aURI.Length() - kMaxURILengthForLogging,
     352           0 :                      kEllipsis, ArrayLength(kEllipsis));
     353             :       }
     354             :     } else {
     355           0 :       aURI.AppendLiteral("(invalid URI)");
     356             :     }
     357             :   }
     358           0 : }
     359             : 
     360             : struct WOFFHeader {
     361             :     AutoSwap_PRUint32 signature;
     362             :     AutoSwap_PRUint32 flavor;
     363             :     AutoSwap_PRUint32 length;
     364             :     AutoSwap_PRUint16 numTables;
     365             :     AutoSwap_PRUint16 reserved;
     366             :     AutoSwap_PRUint32 totalSfntSize;
     367             :     AutoSwap_PRUint16 majorVersion;
     368             :     AutoSwap_PRUint16 minorVersion;
     369             :     AutoSwap_PRUint32 metaOffset;
     370             :     AutoSwap_PRUint32 metaCompLen;
     371             :     AutoSwap_PRUint32 metaOrigLen;
     372             :     AutoSwap_PRUint32 privOffset;
     373             :     AutoSwap_PRUint32 privLen;
     374             : };
     375             : 
     376             : struct WOFF2Header {
     377             :     AutoSwap_PRUint32 signature;
     378             :     AutoSwap_PRUint32 flavor;
     379             :     AutoSwap_PRUint32 length;
     380             :     AutoSwap_PRUint16 numTables;
     381             :     AutoSwap_PRUint16 reserved;
     382             :     AutoSwap_PRUint32 totalSfntSize;
     383             :     AutoSwap_PRUint32 totalCompressedSize;
     384             :     AutoSwap_PRUint16 majorVersion;
     385             :     AutoSwap_PRUint16 minorVersion;
     386             :     AutoSwap_PRUint32 metaOffset;
     387             :     AutoSwap_PRUint32 metaCompLen;
     388             :     AutoSwap_PRUint32 metaOrigLen;
     389             :     AutoSwap_PRUint32 privOffset;
     390             :     AutoSwap_PRUint32 privLen;
     391             : };
     392             : 
     393             : template<typename HeaderT>
     394             : void
     395           0 : CopyWOFFMetadata(const uint8_t* aFontData,
     396             :                  uint32_t aLength,
     397             :                  FallibleTArray<uint8_t>* aMetadata,
     398             :                  uint32_t* aMetaOrigLen)
     399             : {
     400             :     // This function may be called with arbitrary, unvalidated "font" data
     401             :     // from @font-face, so it needs to be careful to bounds-check, etc.,
     402             :     // before trying to read anything.
     403             :     // This just saves a copy of the compressed data block; it does NOT check
     404             :     // that the block can be successfully decompressed, or that it contains
     405             :     // well-formed/valid XML metadata.
     406           0 :     if (aLength < sizeof(HeaderT)) {
     407           0 :         return;
     408             :     }
     409             :     const HeaderT* woff =
     410           0 :         reinterpret_cast<const HeaderT*>(aFontData);
     411           0 :     uint32_t metaOffset = woff->metaOffset;
     412           0 :     uint32_t metaCompLen = woff->metaCompLen;
     413           0 :     if (!metaOffset || !metaCompLen || !woff->metaOrigLen) {
     414           0 :         return;
     415             :     }
     416           0 :     if (metaOffset >= aLength || metaCompLen > aLength - metaOffset) {
     417           0 :         return;
     418             :     }
     419           0 :     if (!aMetadata->SetLength(woff->metaCompLen, fallible)) {
     420           0 :         return;
     421             :     }
     422           0 :     memcpy(aMetadata->Elements(), aFontData + metaOffset, metaCompLen);
     423           0 :     *aMetaOrigLen = woff->metaOrigLen;
     424             : }
     425             : 
     426             : void
     427           0 : gfxUserFontEntry::LoadNextSrc()
     428             : {
     429           0 :     NS_ASSERTION(mSrcIndex < mSrcList.Length(),
     430             :                  "already at the end of the src list for user font");
     431           0 :     NS_ASSERTION((mUserFontLoadState == STATUS_NOT_LOADED ||
     432             :                   mUserFontLoadState == STATUS_LOAD_PENDING ||
     433             :                   mUserFontLoadState == STATUS_LOADING) &&
     434             :                  mFontDataLoadingState < LOADING_FAILED,
     435             :                  "attempting to load a font that has either completed or failed");
     436             : 
     437           0 :     if (mUserFontLoadState == STATUS_NOT_LOADED) {
     438           0 :         SetLoadState(STATUS_LOADING);
     439           0 :         mFontDataLoadingState = LOADING_STARTED;
     440           0 :         mUnsupportedFormat = false;
     441             :     } else {
     442             :         // we were already loading; move to the next source,
     443             :         // but don't reset state - if we've already timed out,
     444             :         // that counts against the new download
     445           0 :         mSrcIndex++;
     446             :     }
     447             : 
     448           0 :     DoLoadNextSrc(false);
     449           0 : }
     450             : 
     451             : void
     452           0 : gfxUserFontEntry::ContinueLoad()
     453             : {
     454           0 :     MOZ_ASSERT(mUserFontLoadState == STATUS_LOAD_PENDING);
     455           0 :     MOZ_ASSERT(mSrcList[mSrcIndex].mSourceType == gfxFontFaceSrc::eSourceType_URL);
     456             : 
     457           0 :     SetLoadState(STATUS_LOADING);
     458           0 :     DoLoadNextSrc(true);
     459           0 :     if (LoadState() != STATUS_LOADING) {
     460           0 :       MOZ_ASSERT(mUserFontLoadState != STATUS_LOAD_PENDING,
     461             :                  "Not in parallel traversal, shouldn't get LOAD_PENDING again");
     462             :       // Loading is synchronously finished (loaded from cache or failed). We
     463             :       // need to increment the generation so that we flush the style data to
     464             :       // use the new loaded font face.
     465             :       // Without parallel traversal, we would simply get the right font data
     466             :       // after the first call to DoLoadNextSrc() in this case, so we don't need
     467             :       // to touch the generation to trigger another restyle.
     468             :       // XXX We may want to return synchronously in parallel traversal in those
     469             :       // cases as well if possible, so that we don't have an additional restyle.
     470             :       // That doesn't work currently because nsIDocument::GetDocShell (called
     471             :       // from FontFaceSet::CheckFontLoad) dereferences a weak pointer, which is
     472             :       // not allowed in parallel traversal.
     473           0 :       IncrementGeneration();
     474             :     }
     475           0 : }
     476             : 
     477             : static bool
     478           0 : IgnorePrincipal(gfxFontSrcURI* aURI)
     479             : {
     480           0 :     return aURI->InheritsSecurityContext();
     481             : }
     482             : 
     483             : void
     484           0 : gfxUserFontEntry::DoLoadNextSrc(bool aForceAsync)
     485             : {
     486           0 :     uint32_t numSrc = mSrcList.Length();
     487             : 
     488             :     // load each src entry in turn, until a local face is found
     489             :     // or a download begins successfully
     490           0 :     while (mSrcIndex < numSrc) {
     491           0 :         gfxFontFaceSrc& currSrc = mSrcList[mSrcIndex];
     492             : 
     493             :         // src local ==> lookup and load immediately
     494             : 
     495           0 :         if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Local) {
     496             :             // Don't look up local fonts if the font whitelist is being used.
     497           0 :             gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
     498           0 :             gfxFontEntry* fe = pfl && pfl->IsFontFamilyWhitelistActive() ?
     499             :                 nullptr :
     500           0 :                 gfxPlatform::GetPlatform()->LookupLocalFont(currSrc.mLocalName,
     501           0 :                                                             mWeight,
     502           0 :                                                             mStretch,
     503           0 :                                                             mStyle);
     504           0 :             nsTArray<gfxUserFontSet*> fontSets;
     505           0 :             GetUserFontSets(fontSets);
     506           0 :             for (gfxUserFontSet* fontSet : fontSets) {
     507             :                 // We need to note on each gfxUserFontSet that contains the user
     508             :                 // font entry that we used a local() rule.
     509           0 :                 fontSet->SetLocalRulesUsed();
     510             :             }
     511           0 :             if (fe) {
     512           0 :                 LOG(("userfonts (%p) [src %d] loaded local: (%s) for (%s) gen: %8.8x\n",
     513             :                      mFontSet, mSrcIndex,
     514             :                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
     515             :                      NS_ConvertUTF16toUTF8(mFamilyName).get(),
     516             :                      uint32_t(mFontSet->mGeneration)));
     517           0 :                 fe->mFeatureSettings.AppendElements(mFeatureSettings);
     518           0 :                 fe->mLanguageOverride = mLanguageOverride;
     519           0 :                 fe->mFamilyName = mFamilyName;
     520             :                 // For src:local(), we don't care whether the request is from
     521             :                 // a private window as there's no issue of caching resources;
     522             :                 // local fonts are just available all the time.
     523           0 :                 StoreUserFontData(fe, false, nsString(), nullptr, 0,
     524           0 :                                   gfxUserFontData::kUnknownCompression);
     525           0 :                 mPlatformFontEntry = fe;
     526           0 :                 SetLoadState(STATUS_LOADED);
     527           0 :                 Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE,
     528           0 :                                       currSrc.mSourceType + 1);
     529           0 :                 return;
     530             :             } else {
     531           0 :                 LOG(("userfonts (%p) [src %d] failed local: (%s) for (%s)\n",
     532             :                      mFontSet, mSrcIndex,
     533             :                      NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
     534             :                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
     535             :             }
     536             :         }
     537             : 
     538             :         // src url ==> start the load process
     539           0 :         else if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL) {
     540           0 :             if (gfxPlatform::GetPlatform()->IsFontFormatSupported(
     541           0 :                     currSrc.mFormatFlags)) {
     542             : 
     543           0 :                 if (ServoStyleSet* set = ServoStyleSet::Current()) {
     544             :                     // Only support style worker threads synchronously getting
     545             :                     // entries from the font cache when it's not a data: URI
     546             :                     // @font-face that came from UA or user sheets, since we
     547             :                     // were not able to call IsFontLoadAllowed ahead of time
     548             :                     // for these entries.
     549           0 :                     if (currSrc.mUseOriginPrincipal && IgnorePrincipal(currSrc.mURI)) {
     550           0 :                         set->AppendTask(PostTraversalTask::LoadFontEntry(this));
     551           0 :                         SetLoadState(STATUS_LOAD_PENDING);
     552           0 :                         return;
     553             :                     }
     554             :                 }
     555             : 
     556           0 :                 gfxFontSrcPrincipal* principal = nullptr;
     557             :                 bool bypassCache;
     558           0 :                 nsresult rv = mFontSet->CheckFontLoad(&currSrc, &principal,
     559           0 :                                                       &bypassCache);
     560             : 
     561           0 :                 if (NS_SUCCEEDED(rv) && principal != nullptr) {
     562           0 :                     if (!bypassCache) {
     563             :                         // see if we have an existing entry for this source
     564             :                         gfxFontEntry* fe = gfxUserFontSet::
     565           0 :                             UserFontCache::GetFont(currSrc.mURI,
     566             :                                                    principal,
     567             :                                                    this,
     568           0 :                                                    mFontSet->GetPrivateBrowsing());
     569           0 :                         if (fe) {
     570           0 :                             mPlatformFontEntry = fe;
     571           0 :                             SetLoadState(STATUS_LOADED);
     572           0 :                             if (LOG_ENABLED()) {
     573           0 :                                 LOG(("userfonts (%p) [src %d] "
     574             :                                      "loaded uri from cache: (%s) for (%s)\n",
     575             :                                      mFontSet, mSrcIndex,
     576             :                                      currSrc.mURI->GetSpecOrDefault().get(),
     577             :                                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
     578             :                             }
     579           0 :                             return;
     580             :                         }
     581             :                     }
     582             : 
     583           0 :                     if (ServoStyleSet* set = ServoStyleSet::Current()) {
     584             :                         // If we need to start a font load and we're on a style
     585             :                         // worker thread, we have to defer it.
     586           0 :                         set->AppendTask(PostTraversalTask::LoadFontEntry(this));
     587           0 :                         SetLoadState(STATUS_LOAD_PENDING);
     588           0 :                         return;
     589             :                     }
     590             : 
     591             :                     // record the principal returned by CheckFontLoad,
     592             :                     // for use when creating a channel
     593             :                     // and when caching the loaded entry
     594           0 :                     mPrincipal = principal;
     595             : 
     596           0 :                     bool loadDoesntSpin = false;
     597           0 :                     if (!aForceAsync) {
     598           0 :                         loadDoesntSpin = currSrc.mURI->SyncLoadIsOK();
     599             :                     }
     600             : 
     601           0 :                     if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
     602           0 :                         uint8_t* buffer = nullptr;
     603           0 :                         uint32_t bufferLength = 0;
     604             : 
     605             :                         // sync load font immediately
     606           0 :                         rv = mFontSet->SyncLoadFontData(this, &currSrc, buffer,
     607           0 :                                                         bufferLength);
     608             : 
     609           0 :                         if (NS_SUCCEEDED(rv) &&
     610           0 :                             LoadPlatformFont(buffer, bufferLength)) {
     611           0 :                             SetLoadState(STATUS_LOADED);
     612           0 :                             Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE,
     613           0 :                                                   currSrc.mSourceType + 1);
     614           0 :                             return;
     615             :                         } else {
     616           0 :                             mFontSet->LogMessage(this,
     617             :                                                  "font load failed",
     618             :                                                  nsIScriptError::errorFlag,
     619           0 :                                                  rv);
     620             :                         }
     621             : 
     622             :                     } else {
     623             :                         // otherwise load font async
     624           0 :                         rv = mFontSet->StartLoad(this, &currSrc);
     625           0 :                         bool loadOK = NS_SUCCEEDED(rv);
     626             : 
     627           0 :                         if (loadOK) {
     628           0 :                             if (LOG_ENABLED()) {
     629           0 :                                 LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
     630             :                                      mFontSet, mSrcIndex,
     631             :                                      currSrc.mURI->GetSpecOrDefault().get(),
     632             :                                      NS_ConvertUTF16toUTF8(mFamilyName).get()));
     633             :                             }
     634           0 :                             return;
     635             :                         } else {
     636           0 :                             mFontSet->LogMessage(this,
     637             :                                                  "download failed",
     638             :                                                  nsIScriptError::errorFlag,
     639           0 :                                                  rv);
     640             :                         }
     641             :                     }
     642             :                 } else {
     643           0 :                     mFontSet->LogMessage(this, "download not allowed",
     644           0 :                                          nsIScriptError::errorFlag, rv);
     645             :                 }
     646             :             } else {
     647             :                 // We don't log a warning to the web console yet,
     648             :                 // as another source may load successfully
     649           0 :                 mUnsupportedFormat = true;
     650             :             }
     651             :         }
     652             : 
     653             :         // FontFace buffer ==> load immediately
     654             : 
     655             :         else {
     656           0 :             MOZ_ASSERT(currSrc.mSourceType == gfxFontFaceSrc::eSourceType_Buffer);
     657             : 
     658           0 :             uint8_t* buffer = nullptr;
     659           0 :             uint32_t bufferLength = 0;
     660             : 
     661             :             // sync load font immediately
     662           0 :             currSrc.mBuffer->TakeBuffer(buffer, bufferLength);
     663           0 :             if (buffer && LoadPlatformFont(buffer, bufferLength)) {
     664             :                 // LoadPlatformFont takes ownership of the buffer, so no need
     665             :                 // to free it here.
     666           0 :                 SetLoadState(STATUS_LOADED);
     667           0 :                 Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE,
     668           0 :                                       currSrc.mSourceType + 1);
     669           0 :                 return;
     670             :             } else {
     671           0 :                 mFontSet->LogMessage(this,
     672             :                                      "font load failed",
     673           0 :                                      nsIScriptError::errorFlag);
     674             :             }
     675             :         }
     676             : 
     677           0 :         mSrcIndex++;
     678             :     }
     679             : 
     680           0 :     if (mUnsupportedFormat) {
     681           0 :         mFontSet->LogMessage(this, "no supported format found",
     682           0 :                              nsIScriptError::warningFlag);
     683             :     }
     684             : 
     685             :     // all src's failed; mark this entry as unusable (so fallback will occur)
     686           0 :     LOG(("userfonts (%p) failed all src for (%s)\n",
     687             :         mFontSet, NS_ConvertUTF16toUTF8(mFamilyName).get()));
     688           0 :     mFontDataLoadingState = LOADING_FAILED;
     689           0 :     SetLoadState(STATUS_FAILED);
     690             : }
     691             : 
     692             : void
     693           0 : gfxUserFontEntry::SetLoadState(UserFontLoadState aLoadState)
     694             : {
     695           0 :     mUserFontLoadState = aLoadState;
     696           0 : }
     697             : 
     698           0 : MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(UserFontMallocSizeOfOnAlloc)
     699             : 
     700             : bool
     701           0 : gfxUserFontEntry::LoadPlatformFont(const uint8_t* aFontData, uint32_t& aLength)
     702             : {
     703           0 :     NS_ASSERTION((mUserFontLoadState == STATUS_NOT_LOADED ||
     704             :                   mUserFontLoadState == STATUS_LOAD_PENDING ||
     705             :                   mUserFontLoadState == STATUS_LOADING) &&
     706             :                  mFontDataLoadingState < LOADING_FAILED,
     707             :                  "attempting to load a font that has either completed or failed");
     708             : 
     709           0 :     gfxFontEntry* fe = nullptr;
     710             : 
     711             :     gfxUserFontType fontType =
     712           0 :         gfxFontUtils::DetermineFontDataType(aFontData, aLength);
     713           0 :     Telemetry::Accumulate(Telemetry::WEBFONT_FONTTYPE, uint32_t(fontType));
     714             : 
     715             :     // Unwrap/decompress/sanitize or otherwise munge the downloaded data
     716             :     // to make a usable sfnt structure.
     717             : 
     718             :     // Because platform font activation code may replace the name table
     719             :     // in the font with a synthetic one, we save the original name so that
     720             :     // it can be reported via the nsIDOMFontFace API.
     721           0 :     nsAutoString originalFullName;
     722             : 
     723             :     // Call the OTS sanitizer; this will also decode WOFF to sfnt
     724             :     // if necessary. The original data in aFontData is left unchanged.
     725             :     uint32_t saneLen;
     726           0 :     uint32_t fontCompressionRatio = 0;
     727           0 :     size_t computedSize = 0;
     728             :     const uint8_t* saneData =
     729           0 :         SanitizeOpenTypeData(aFontData, aLength, saneLen, fontType);
     730           0 :     if (!saneData) {
     731           0 :         mFontSet->LogMessage(this, "rejected by sanitizer");
     732             :     } else {
     733             :         // Check whether saneData is a known OpenType format; it might be
     734             :         // a TrueType Collection, which OTS would accept but we don't yet
     735             :         // know how to handle. If so, discard.
     736           0 :         if (gfxFontUtils::DetermineFontDataType(saneData, saneLen) !=
     737             :             GFX_USERFONT_OPENTYPE) {
     738           0 :             mFontSet->LogMessage(this, "not a supported OpenType format");
     739           0 :             free((void*)saneData);
     740           0 :             saneData = nullptr;
     741             :         }
     742             :     }
     743           0 :     if (saneData) {
     744           0 :         if (saneLen) {
     745           0 :             fontCompressionRatio = uint32_t(100.0 * aLength / saneLen + 0.5);
     746           0 :             if (fontType == GFX_USERFONT_WOFF ||
     747             :                 fontType == GFX_USERFONT_WOFF2) {
     748           0 :                 Telemetry::Accumulate(fontType == GFX_USERFONT_WOFF ?
     749             :                                       Telemetry::WEBFONT_COMPRESSION_WOFF :
     750             :                                       Telemetry::WEBFONT_COMPRESSION_WOFF2,
     751           0 :                                       fontCompressionRatio);
     752             :                 }
     753             :         }
     754             : 
     755             :         // The sanitizer ensures that we have a valid sfnt and a usable
     756             :         // name table, so this should never fail unless we're out of
     757             :         // memory, and GetFullNameFromSFNT is not directly exposed to
     758             :         // arbitrary/malicious data from the web.
     759             :         gfxFontUtils::GetFullNameFromSFNT(saneData, saneLen,
     760           0 :                                           originalFullName);
     761             : 
     762             :         // Record size for memory reporting purposes. We measure this now
     763             :         // because by the time we potentially want to collect reports, this
     764             :         // data block may have been handed off to opaque OS font APIs that
     765             :         // don't allow us to retrieve or measure it directly.
     766             :         // The *OnAlloc function will also tell DMD about this block, as the
     767             :         // OS font code may hold on to it for an extended period.
     768           0 :         computedSize = UserFontMallocSizeOfOnAlloc(saneData);
     769             : 
     770             :         // Here ownership of saneData is passed to the platform,
     771             :         // which will delete it when no longer required
     772           0 :         fe = gfxPlatform::GetPlatform()->MakePlatformFont(mName,
     773           0 :                                                           mWeight,
     774           0 :                                                           mStretch,
     775           0 :                                                           mStyle,
     776             :                                                           saneData,
     777           0 :                                                           saneLen);
     778           0 :         if (!fe) {
     779           0 :             mFontSet->LogMessage(this, "not usable by platform");
     780             :         }
     781             :     }
     782             : 
     783           0 :     if (fe) {
     784           0 :         fe->mComputedSizeOfUserFont = computedSize;
     785             : 
     786             :         // Save a copy of the metadata block (if present) for nsIDOMFontFace
     787             :         // to use if required. Ownership of the metadata block will be passed
     788             :         // to the gfxUserFontData record below.
     789           0 :         FallibleTArray<uint8_t> metadata;
     790           0 :         uint32_t metaOrigLen = 0;
     791           0 :         uint8_t compression = gfxUserFontData::kUnknownCompression;
     792           0 :         if (fontType == GFX_USERFONT_WOFF) {
     793           0 :             CopyWOFFMetadata<WOFFHeader>(aFontData, aLength,
     794           0 :                                          &metadata, &metaOrigLen);
     795           0 :             compression = gfxUserFontData::kZlibCompression;
     796           0 :         } else if (fontType == GFX_USERFONT_WOFF2) {
     797           0 :             CopyWOFFMetadata<WOFF2Header>(aFontData, aLength,
     798           0 :                                           &metadata, &metaOrigLen);
     799           0 :             compression = gfxUserFontData::kBrotliCompression;
     800             :         }
     801             : 
     802             :         // copy OpenType feature/language settings from the userfont entry to the
     803             :         // newly-created font entry
     804           0 :         fe->mFeatureSettings.AppendElements(mFeatureSettings);
     805           0 :         fe->mLanguageOverride = mLanguageOverride;
     806           0 :         fe->mFamilyName = mFamilyName;
     807           0 :         StoreUserFontData(fe, mFontSet->GetPrivateBrowsing(), originalFullName,
     808           0 :                           &metadata, metaOrigLen, compression);
     809           0 :         if (LOG_ENABLED()) {
     810           0 :             LOG(("userfonts (%p) [src %d] loaded uri: (%s) for (%s) "
     811             :                  "(%p) gen: %8.8x compress: %d%%\n",
     812             :                  mFontSet, mSrcIndex,
     813             :                  mSrcList[mSrcIndex].mURI->GetSpecOrDefault().get(),
     814             :                  NS_ConvertUTF16toUTF8(mFamilyName).get(),
     815             :                  this, uint32_t(mFontSet->mGeneration), fontCompressionRatio));
     816             :         }
     817           0 :         mPlatformFontEntry = fe;
     818           0 :         SetLoadState(STATUS_LOADED);
     819           0 :         gfxUserFontSet::UserFontCache::CacheFont(fe);
     820             :     } else {
     821           0 :         if (LOG_ENABLED()) {
     822           0 :             LOG(("userfonts (%p) [src %d] failed uri: (%s) for (%s)"
     823             :                  " error making platform font\n",
     824             :                  mFontSet, mSrcIndex,
     825             :                  mSrcList[mSrcIndex].mURI->GetSpecOrDefault().get(),
     826             :                  NS_ConvertUTF16toUTF8(mFamilyName).get()));
     827             :         }
     828             :     }
     829             : 
     830             :     // The downloaded data can now be discarded; the font entry is using the
     831             :     // sanitized copy
     832           0 :     free((void*)aFontData);
     833             : 
     834           0 :     return fe != nullptr;
     835             : }
     836             : 
     837             : void
     838           0 : gfxUserFontEntry::Load()
     839             : {
     840           0 :     if (mUserFontLoadState == STATUS_NOT_LOADED) {
     841           0 :         LoadNextSrc();
     842             :     }
     843           0 : }
     844             : 
     845             : void
     846           0 : gfxUserFontEntry::IncrementGeneration()
     847             : {
     848           0 :     nsTArray<gfxUserFontSet*> fontSets;
     849           0 :     GetUserFontSets(fontSets);
     850           0 :     for (gfxUserFontSet* fontSet : fontSets) {
     851           0 :         fontSet->IncrementGeneration();
     852             :     }
     853           0 : }
     854             : 
     855             : // This is called when a font download finishes.
     856             : // Ownership of aFontData passes in here, and the font set must
     857             : // ensure that it is eventually deleted via free().
     858             : bool
     859           0 : gfxUserFontEntry::FontDataDownloadComplete(const uint8_t* aFontData,
     860             :                                            uint32_t aLength,
     861             :                                            nsresult aDownloadStatus)
     862             : {
     863             :     // forget about the loader, as we no longer potentially need to cancel it
     864             :     // if the entry is obsoleted
     865           0 :     mLoader = nullptr;
     866             : 
     867             :     // download successful, make platform font using font data
     868           0 :     if (NS_SUCCEEDED(aDownloadStatus) &&
     869           0 :         mFontDataLoadingState != LOADING_TIMED_OUT) {
     870           0 :         bool loaded = LoadPlatformFont(aFontData, aLength);
     871           0 :         aFontData = nullptr;
     872             : 
     873           0 :         if (loaded) {
     874           0 :             IncrementGeneration();
     875           0 :             return true;
     876             :         }
     877             : 
     878             :     } else {
     879             :         // download failed
     880           0 :         mFontSet->LogMessage(this,
     881           0 :                              (mFontDataLoadingState != LOADING_TIMED_OUT ?
     882             :                               "download failed" : "download timed out"),
     883             :                              nsIScriptError::errorFlag,
     884           0 :                              aDownloadStatus);
     885             :     }
     886             : 
     887           0 :     if (aFontData) {
     888           0 :         free((void*)aFontData);
     889             :     }
     890             : 
     891             :     // error occurred, load next src if load not yet timed out
     892           0 :     if (mFontDataLoadingState != LOADING_TIMED_OUT) {
     893           0 :       LoadNextSrc();
     894             :     }
     895             : 
     896             :     // We ignore the status returned by LoadNext();
     897             :     // even if loading failed, we need to bump the font-set generation
     898             :     // and return true in order to trigger reflow, so that fallback
     899             :     // will be used where the text was "masked" by the pending download
     900           0 :     IncrementGeneration();
     901           0 :     return true;
     902             : }
     903             : 
     904             : void
     905           0 : gfxUserFontEntry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult)
     906             : {
     907           0 :     aResult.Clear();
     908           0 :     aResult.AppendElement(mFontSet);
     909           0 : }
     910             : 
     911           0 : gfxUserFontSet::gfxUserFontSet()
     912             :     : mFontFamilies(4),
     913             :       mLocalRulesUsed(false),
     914             :       mRebuildLocalRules(false),
     915             :       mDownloadCount(0),
     916           0 :       mDownloadSize(0)
     917             : {
     918           0 :     IncrementGeneration(true);
     919           0 :     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     920           0 :     if (fp) {
     921           0 :         fp->AddUserFontSet(this);
     922             :     }
     923           0 : }
     924             : 
     925           0 : gfxUserFontSet::~gfxUserFontSet()
     926             : {
     927           0 :     gfxPlatformFontList* fp = gfxPlatformFontList::PlatformFontList();
     928           0 :     if (fp) {
     929           0 :         fp->RemoveUserFontSet(this);
     930             :     }
     931             : 
     932           0 :     UserFontCache::ClearAllowedFontSets(this);
     933           0 : }
     934             : 
     935             : already_AddRefed<gfxUserFontEntry>
     936           0 : gfxUserFontSet::FindOrCreateUserFontEntry(
     937             :                                const nsAString& aFamilyName,
     938             :                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
     939             :                                uint32_t aWeight,
     940             :                                int32_t aStretch,
     941             :                                uint8_t aStyle,
     942             :                                const nsTArray<gfxFontFeature>& aFeatureSettings,
     943             :                                uint32_t aLanguageOverride,
     944             :                                gfxCharacterMap* aUnicodeRanges,
     945             :                                uint8_t aFontDisplay)
     946             : {
     947           0 :     RefPtr<gfxUserFontEntry> entry;
     948             : 
     949             :     // If there's already a userfont entry in the family whose descriptors all match,
     950             :     // we can just move it to the end of the list instead of adding a new
     951             :     // face that will always "shadow" the old one.
     952             :     // Note that we can't do this for platform font entries, even if the
     953             :     // style descriptors match, as they might have had a different source list,
     954             :     // but we no longer have the old source list available to check.
     955           0 :     gfxUserFontFamily* family = LookupFamily(aFamilyName);
     956           0 :     if (family) {
     957             :         entry = FindExistingUserFontEntry(family, aFontFaceSrcList, aWeight,
     958             :                                           aStretch, aStyle,
     959             :                                           aFeatureSettings, aLanguageOverride,
     960           0 :                                           aUnicodeRanges, aFontDisplay);
     961             :     }
     962             : 
     963           0 :     if (!entry) {
     964           0 :       entry = CreateUserFontEntry(aFontFaceSrcList, aWeight, aStretch,
     965             :                                   aStyle, aFeatureSettings,
     966             :                                   aLanguageOverride, aUnicodeRanges,
     967           0 :                                   aFontDisplay);
     968           0 :       entry->mFamilyName = aFamilyName;
     969             :     }
     970             : 
     971           0 :     return entry.forget();
     972             : }
     973             : 
     974             : already_AddRefed<gfxUserFontEntry>
     975           0 : gfxUserFontSet::CreateUserFontEntry(
     976             :                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
     977             :                                uint32_t aWeight,
     978             :                                int32_t aStretch,
     979             :                                uint8_t aStyle,
     980             :                                const nsTArray<gfxFontFeature>& aFeatureSettings,
     981             :                                uint32_t aLanguageOverride,
     982             :                                gfxCharacterMap* aUnicodeRanges,
     983             :                                uint8_t aFontDisplay)
     984             : {
     985             : 
     986             :     RefPtr<gfxUserFontEntry> userFontEntry =
     987             :         new gfxUserFontEntry(this, aFontFaceSrcList, aWeight,
     988             :                               aStretch, aStyle, aFeatureSettings,
     989           0 :                               aLanguageOverride, aUnicodeRanges, aFontDisplay);
     990           0 :     return userFontEntry.forget();
     991             : }
     992             : 
     993             : gfxUserFontEntry*
     994           0 : gfxUserFontSet::FindExistingUserFontEntry(
     995             :                                gfxUserFontFamily* aFamily,
     996             :                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
     997             :                                uint32_t aWeight,
     998             :                                int32_t aStretch,
     999             :                                uint8_t aStyle,
    1000             :                                const nsTArray<gfxFontFeature>& aFeatureSettings,
    1001             :                                uint32_t aLanguageOverride,
    1002             :                                gfxCharacterMap* aUnicodeRanges,
    1003             :                                uint8_t aFontDisplay)
    1004             : {
    1005           0 :     MOZ_ASSERT(aWeight != 0,
    1006             :                "aWeight must not be 0; use NS_FONT_WEIGHT_NORMAL instead");
    1007             : 
    1008           0 :     nsTArray<RefPtr<gfxFontEntry>>& fontList = aFamily->GetFontList();
    1009             : 
    1010           0 :     for (size_t i = 0, count = fontList.Length(); i < count; i++) {
    1011           0 :         if (!fontList[i]->mIsUserFontContainer) {
    1012           0 :             continue;
    1013             :         }
    1014             : 
    1015             :         gfxUserFontEntry* existingUserFontEntry =
    1016           0 :             static_cast<gfxUserFontEntry*>(fontList[i].get());
    1017           0 :         if (!existingUserFontEntry->Matches(aFontFaceSrcList,
    1018             :                                             aWeight, aStretch, aStyle,
    1019             :                                             aFeatureSettings, aLanguageOverride,
    1020             :                                             aUnicodeRanges, aFontDisplay)) {
    1021           0 :             continue;
    1022             :         }
    1023             : 
    1024           0 :         return existingUserFontEntry;
    1025             :     }
    1026             : 
    1027           0 :     return nullptr;
    1028             : }
    1029             : 
    1030             : void
    1031           0 : gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
    1032             :                                  gfxUserFontEntry* aUserFontEntry)
    1033             : {
    1034           0 :     gfxUserFontFamily* family = GetFamily(aFamilyName);
    1035           0 :     family->AddFontEntry(aUserFontEntry);
    1036             : 
    1037           0 :     if (LOG_ENABLED()) {
    1038           0 :         LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %d "
    1039             :              "stretch: %d display: %d",
    1040             :              this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry,
    1041             :              (aUserFontEntry->IsItalic() ? "italic" :
    1042             :               (aUserFontEntry->IsOblique() ? "oblique" : "normal")),
    1043             :              aUserFontEntry->Weight(), aUserFontEntry->Stretch(),
    1044             :              aUserFontEntry->GetFontDisplay()));
    1045             :     }
    1046           0 : }
    1047             : 
    1048             : void
    1049           0 : gfxUserFontSet::IncrementGeneration(bool aIsRebuild)
    1050             : {
    1051             :     // add one, increment again if zero
    1052           0 :     ++sFontSetGeneration;
    1053           0 :     if (sFontSetGeneration == 0)
    1054           0 :        ++sFontSetGeneration;
    1055           0 :     mGeneration = sFontSetGeneration;
    1056           0 :     if (aIsRebuild) {
    1057           0 :         mRebuildGeneration = mGeneration;
    1058             :     }
    1059           0 : }
    1060             : 
    1061             : void
    1062           0 : gfxUserFontSet::RebuildLocalRules()
    1063             : {
    1064           0 :     if (mLocalRulesUsed) {
    1065           0 :         mRebuildLocalRules = true;
    1066           0 :         DoRebuildUserFontSet();
    1067             :     }
    1068           0 : }
    1069             : 
    1070             : gfxUserFontFamily*
    1071           0 : gfxUserFontSet::LookupFamily(const nsAString& aFamilyName) const
    1072             : {
    1073           0 :     nsAutoString key(aFamilyName);
    1074           0 :     ToLowerCase(key);
    1075             : 
    1076           0 :     return mFontFamilies.GetWeak(key);
    1077             : }
    1078             : 
    1079             : bool
    1080           0 : gfxUserFontSet::ContainsUserFontSetFonts(const FontFamilyList& aFontList) const
    1081             : {
    1082           0 :     for (const FontFamilyName& name : aFontList.GetFontlist()) {
    1083           0 :         if (name.mType != eFamily_named &&
    1084           0 :             name.mType != eFamily_named_quoted) {
    1085           0 :             continue;
    1086             :         }
    1087           0 :         if (LookupFamily(name.mName)) {
    1088           0 :             return true;
    1089             :         }
    1090             :     }
    1091           0 :     return false;
    1092             : }
    1093             : 
    1094             : gfxUserFontFamily*
    1095           0 : gfxUserFontSet::GetFamily(const nsAString& aFamilyName)
    1096             : {
    1097           0 :     nsAutoString key(aFamilyName);
    1098           0 :     ToLowerCase(key);
    1099             : 
    1100           0 :     gfxUserFontFamily* family = mFontFamilies.GetWeak(key);
    1101           0 :     if (!family) {
    1102           0 :         family = new gfxUserFontFamily(aFamilyName);
    1103           0 :         mFontFamilies.Put(key, family);
    1104             :     }
    1105           0 :     return family;
    1106             : }
    1107             : 
    1108             : ///////////////////////////////////////////////////////////////////////////////
    1109             : // gfxUserFontSet::UserFontCache - re-use platform font entries for user fonts
    1110             : // across pages/fontsets rather than instantiating new platform fonts.
    1111             : //
    1112             : // Entries are added to this cache when a platform font is instantiated from
    1113             : // downloaded data, and removed when the platform font entry is destroyed.
    1114             : // We don't need to use a timed expiration scheme here because the gfxFontEntry
    1115             : // for a downloaded font will be kept alive by its corresponding gfxFont
    1116             : // instance(s) until they are deleted, and *that* happens using an expiration
    1117             : // tracker (gfxFontCache). The result is that the downloaded font instances
    1118             : // recorded here will persist between pages and can get reused (provided the
    1119             : // source URI and principal match, of course).
    1120             : ///////////////////////////////////////////////////////////////////////////////
    1121             : 
    1122             : nsTHashtable<gfxUserFontSet::UserFontCache::Entry>*
    1123             : gfxUserFontSet::UserFontCache::sUserFonts = nullptr;
    1124             : 
    1125             : uint32_t
    1126             : gfxUserFontSet::UserFontCache::sGeneration = 0;
    1127             : 
    1128           0 : NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::Flusher, nsIObserver)
    1129             : 
    1130             : NS_IMETHODIMP
    1131           0 : gfxUserFontSet::UserFontCache::Flusher::Observe(nsISupports* aSubject,
    1132             :                                                 const char* aTopic,
    1133             :                                                 const char16_t* aData)
    1134             : {
    1135           0 :     if (!sUserFonts) {
    1136           0 :         return NS_OK;
    1137             :     }
    1138             : 
    1139           0 :     if (!strcmp(aTopic, "cacheservice:empty-cache")) {
    1140           0 :         for (auto i = sUserFonts->Iter(); !i.Done(); i.Next()) {
    1141           0 :             i.Remove();
    1142             :         }
    1143           0 :     } else if (!strcmp(aTopic, "last-pb-context-exited")) {
    1144           0 :         for (auto i = sUserFonts->Iter(); !i.Done(); i.Next()) {
    1145           0 :             if (i.Get()->IsPrivate()) {
    1146           0 :                 i.Remove();
    1147             :             }
    1148             :         }
    1149           0 :     } else if (!strcmp(aTopic, "xpcom-shutdown")) {
    1150           0 :         for (auto i = sUserFonts->Iter(); !i.Done(); i.Next()) {
    1151           0 :             i.Get()->GetFontEntry()->DisconnectSVG();
    1152             :         }
    1153             :     } else {
    1154           0 :         NS_NOTREACHED("unexpected topic");
    1155             :     }
    1156             : 
    1157           0 :     return NS_OK;
    1158             : }
    1159             : 
    1160             : bool
    1161           0 : gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
    1162             : {
    1163           0 :     const gfxFontEntry* fe = aKey->mFontEntry;
    1164             : 
    1165           0 :     if (!mURI->Equals(aKey->mURI)) {
    1166           0 :         return false;
    1167             :     }
    1168             : 
    1169             :     // For data: URIs, we don't care about the principal; otherwise, check it.
    1170           0 :     if (!IgnorePrincipal(mURI)) {
    1171           0 :         NS_ASSERTION(mPrincipal && aKey->mPrincipal,
    1172             :                      "only data: URIs are allowed to omit the principal");
    1173           0 :         if (!mPrincipal->Equals(aKey->mPrincipal)) {
    1174           0 :             return false;
    1175             :         }
    1176             :     }
    1177             : 
    1178           0 :     if (mPrivate != aKey->mPrivate) {
    1179           0 :         return false;
    1180             :     }
    1181             : 
    1182           0 :     if (mFontEntry->mStyle            != fe->mStyle     ||
    1183           0 :         mFontEntry->mWeight           != fe->mWeight          ||
    1184           0 :         mFontEntry->mStretch          != fe->mStretch         ||
    1185           0 :         mFontEntry->mFeatureSettings  != fe->mFeatureSettings ||
    1186           0 :         mFontEntry->mLanguageOverride != fe->mLanguageOverride ||
    1187           0 :         mFontEntry->mFamilyName       != fe->mFamilyName) {
    1188           0 :         return false;
    1189             :     }
    1190             : 
    1191           0 :     return true;
    1192             : }
    1193             : 
    1194             : void
    1195           0 : gfxUserFontSet::UserFontCache::CacheFont(gfxFontEntry* aFontEntry)
    1196             : {
    1197           0 :     NS_ASSERTION(aFontEntry->mFamilyName.Length() != 0,
    1198             :                  "caching a font associated with no family yet");
    1199             : 
    1200             :     // if caching is disabled, simply return
    1201           0 :     if (Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
    1202           0 :         return;
    1203             :     }
    1204             : 
    1205           0 :     gfxUserFontData* data = aFontEntry->mUserFontData.get();
    1206           0 :     if (data->mIsBuffer) {
    1207             : #ifdef DEBUG_USERFONT_CACHE
    1208             :         printf("userfontcache skipped fontentry with buffer source: %p\n",
    1209             :                aFontEntry);
    1210             : #endif
    1211           0 :         return;
    1212             :     }
    1213             : 
    1214           0 :     if (!sUserFonts) {
    1215           0 :         sUserFonts = new nsTHashtable<Entry>;
    1216             : 
    1217             :         nsCOMPtr<nsIObserverService> obs =
    1218           0 :             mozilla::services::GetObserverService();
    1219           0 :         if (obs) {
    1220           0 :             Flusher* flusher = new Flusher;
    1221           0 :             obs->AddObserver(flusher, "cacheservice:empty-cache",
    1222           0 :                              false);
    1223           0 :             obs->AddObserver(flusher, "last-pb-context-exited", false);
    1224           0 :             obs->AddObserver(flusher, "xpcom-shutdown", false);
    1225             :         }
    1226             : 
    1227             :         // Create and register a memory reporter for sUserFonts.
    1228             :         // This reporter is never unregistered, but that's OK because
    1229             :         // the reporter checks whether sUserFonts is null, so it would
    1230             :         // be safe to call even after UserFontCache::Shutdown has deleted
    1231             :         // the cache.
    1232           0 :         RegisterStrongMemoryReporter(new MemoryReporter());
    1233             :     }
    1234             : 
    1235             :     // For data: URIs, the principal is ignored; anyone who has the same
    1236             :     // data: URI is able to load it and get an equivalent font.
    1237             :     // Otherwise, the principal is used as part of the cache key.
    1238             :     gfxFontSrcPrincipal* principal;
    1239           0 :     if (IgnorePrincipal(data->mURI)) {
    1240           0 :         principal = nullptr;
    1241             :     } else {
    1242           0 :         principal = data->mPrincipal;
    1243             :     }
    1244           0 :     sUserFonts->PutEntry(Key(data->mURI, principal, aFontEntry,
    1245           0 :                              data->mPrivate));
    1246             : 
    1247           0 :     ++sGeneration;
    1248             : 
    1249             : #ifdef DEBUG_USERFONT_CACHE
    1250             :     printf("userfontcache added fontentry: %p\n", aFontEntry);
    1251             :     Dump();
    1252             : #endif
    1253             : }
    1254             : 
    1255             : void
    1256           0 : gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry* aFontEntry)
    1257             : {
    1258           0 :     if (!sUserFonts) {
    1259             :         // if we've already deleted the cache (i.e. during shutdown),
    1260             :         // just ignore this
    1261           0 :         return;
    1262             :     }
    1263             : 
    1264             :     // We can't simply use RemoveEntry here because it's possible the principal
    1265             :     // may have changed since the font was cached, in which case the lookup
    1266             :     // would no longer find the entry (bug 838105).
    1267           0 :     for (auto i = sUserFonts->Iter(); !i.Done(); i.Next()) {
    1268           0 :         if (i.Get()->GetFontEntry() == aFontEntry)  {
    1269           0 :             i.Remove();
    1270             :         }
    1271             :     }
    1272             : 
    1273             : #ifdef DEBUG_USERFONT_CACHE
    1274             :     printf("userfontcache removed fontentry: %p\n", aFontEntry);
    1275             :     Dump();
    1276             : #endif
    1277             : }
    1278             : 
    1279             : gfxFontEntry*
    1280           0 : gfxUserFontSet::UserFontCache::GetFont(gfxFontSrcURI* aSrcURI,
    1281             :                                        gfxFontSrcPrincipal* aPrincipal,
    1282             :                                        gfxUserFontEntry* aUserFontEntry,
    1283             :                                        bool aPrivate)
    1284             : {
    1285           0 :     if (!sUserFonts ||
    1286           0 :         Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
    1287           0 :         return nullptr;
    1288             :     }
    1289             : 
    1290             :     // Ignore principal when looking up a data: URI.
    1291             :     gfxFontSrcPrincipal* principal;
    1292           0 :     if (IgnorePrincipal(aSrcURI)) {
    1293           0 :         principal = nullptr;
    1294             :     } else {
    1295           0 :         principal = aPrincipal;
    1296             :     }
    1297             : 
    1298           0 :     Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, principal, aUserFontEntry,
    1299           0 :                                             aPrivate));
    1300           0 :     if (!entry) {
    1301           0 :         return nullptr;
    1302             :     }
    1303             : 
    1304             :     // We have to perform another content policy check here to prevent
    1305             :     // cache poisoning. E.g. a.com loads a font into the cache but
    1306             :     // b.com has a CSP not allowing any fonts to be loaded.
    1307           0 :     bool allowed = false;
    1308           0 :     if (ServoStyleSet::IsInServoTraversal()) {
    1309             :         // Use the cached IsFontLoadAllowed results in mAllowedFontSets.
    1310           0 :         allowed = entry->IsFontSetAllowed(aUserFontEntry->mFontSet);
    1311             :     } else {
    1312             :         // Call IsFontLoadAllowed directly, since we are on the main thread.
    1313           0 :         MOZ_ASSERT(NS_IsMainThread());
    1314           0 :         nsIPrincipal* principal = aPrincipal ? aPrincipal->get() : nullptr;
    1315           0 :         allowed = aUserFontEntry->mFontSet->IsFontLoadAllowed(aSrcURI->get(),
    1316           0 :                                                               principal);
    1317           0 :         MOZ_ASSERT(!entry->IsFontSetAllowedKnown(aUserFontEntry->mFontSet) ||
    1318             :                    entry->IsFontSetAllowed(aUserFontEntry->mFontSet) == allowed,
    1319             :                    "why does IsFontLoadAllowed return a different value from "
    1320             :                    "the cached value in mAllowedFontSets?");
    1321             :     }
    1322             : 
    1323           0 :     if (!allowed) {
    1324           0 :         return nullptr;
    1325             :     }
    1326             : 
    1327           0 :     return entry->GetFontEntry();
    1328             : }
    1329             : 
    1330             : /* static */ void
    1331           0 : gfxUserFontSet::UserFontCache::UpdateAllowedFontSets(
    1332             :     gfxUserFontSet* aUserFontSet)
    1333             : {
    1334           0 :     MOZ_ASSERT(NS_IsMainThread());
    1335             : 
    1336           0 :     if (!sUserFonts) {
    1337           0 :         return;
    1338             :     }
    1339             : 
    1340           0 :     for (auto iter = sUserFonts->Iter(); !iter.Done(); iter.Next()) {
    1341           0 :         Entry* entry = iter.Get();
    1342           0 :         if (!entry->IsFontSetAllowedKnown(aUserFontSet)) {
    1343           0 :             gfxFontSrcPrincipal* principal = entry->GetPrincipal();
    1344           0 :             if (!principal) {
    1345             :                 // This is a data: URI.  Just get the standard principal the
    1346             :                 // font set uses.  (For cases when mUseOriginPrincipal is true,
    1347             :                 // we don't use the cached results of IsFontLoadAllowed, and
    1348             :                 // instead just process the data: URI load async.)
    1349           0 :                 principal = aUserFontSet->GetStandardFontLoadPrincipal();
    1350             :             }
    1351             :             bool allowed =
    1352           0 :                 aUserFontSet->IsFontLoadAllowed(entry->GetURI()->get(),
    1353           0 :                 principal->get());
    1354           0 :             entry->SetIsFontSetAllowed(aUserFontSet, allowed);
    1355             :         }
    1356             :     }
    1357             : }
    1358             : 
    1359             : /* static */ void
    1360           0 : gfxUserFontSet::UserFontCache::ClearAllowedFontSets(
    1361             :     gfxUserFontSet* aUserFontSet)
    1362             : {
    1363           0 :     MOZ_ASSERT(NS_IsMainThread());
    1364             : 
    1365           0 :     if (!sUserFonts) {
    1366           0 :         return;
    1367             :     }
    1368             : 
    1369           0 :     for (auto iter = sUserFonts->Iter(); !iter.Done(); iter.Next()) {
    1370           0 :         Entry* entry = iter.Get();
    1371           0 :         entry->ClearIsFontSetAllowed(aUserFontSet);
    1372             :     }
    1373             : }
    1374             : 
    1375             : void
    1376           0 : gfxUserFontSet::UserFontCache::Shutdown()
    1377             : {
    1378           0 :     if (sUserFonts) {
    1379           0 :         delete sUserFonts;
    1380           0 :         sUserFonts = nullptr;
    1381             :     }
    1382           0 : }
    1383             : 
    1384           0 : MOZ_DEFINE_MALLOC_SIZE_OF(UserFontsMallocSizeOf)
    1385             : 
    1386             : bool
    1387           0 : gfxUserFontSet::UserFontCache::Entry::IsFontSetAllowed(
    1388             :     gfxUserFontSet* aUserFontSet) const
    1389             : {
    1390           0 :     bool allowed = false;
    1391           0 :     DebugOnly<bool> found = mAllowedFontSets.Get(aUserFontSet, &allowed);
    1392           0 :     MOZ_ASSERT(found, "UpdateAllowedFontSets should have been called and "
    1393             :                       "added an entry to mAllowedFontSets");
    1394           0 :     return allowed;
    1395             : }
    1396             : 
    1397             : bool
    1398           0 : gfxUserFontSet::UserFontCache::Entry::IsFontSetAllowedKnown(
    1399             :     gfxUserFontSet* aUserFontSet) const
    1400             : {
    1401           0 :     return mAllowedFontSets.Contains(aUserFontSet);
    1402             : }
    1403             : 
    1404             : void
    1405           0 : gfxUserFontSet::UserFontCache::Entry::SetIsFontSetAllowed(
    1406             :     gfxUserFontSet* aUserFontSet,
    1407             :     bool aAllowed)
    1408             : {
    1409           0 :     MOZ_ASSERT(!IsFontSetAllowedKnown(aUserFontSet));
    1410           0 :     mAllowedFontSets.Put(aUserFontSet, aAllowed);
    1411           0 : }
    1412             : 
    1413             : void
    1414           0 : gfxUserFontSet::UserFontCache::Entry::ClearIsFontSetAllowed(
    1415             :     gfxUserFontSet* aUserFontSet)
    1416             : {
    1417           0 :     mAllowedFontSets.Remove(aUserFontSet);
    1418           0 : }
    1419             : 
    1420             : void
    1421           0 : gfxUserFontSet::UserFontCache::Entry::ReportMemory(
    1422             :     nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
    1423             : {
    1424           0 :     MOZ_ASSERT(mFontEntry);
    1425           0 :     nsAutoCString path("explicit/gfx/user-fonts/font(");
    1426             : 
    1427           0 :     if (aAnonymize) {
    1428           0 :         path.AppendPrintf("<anonymized-%p>", this);
    1429             :     } else {
    1430           0 :         NS_ConvertUTF16toUTF8 familyName(mFontEntry->mFamilyName);
    1431           0 :         path.AppendPrintf("family=%s", familyName.get());
    1432           0 :         if (mURI) {
    1433           0 :             nsCString spec = mURI->GetSpecOrDefault();
    1434           0 :             spec.ReplaceChar('/', '\\');
    1435             :             // Some fonts are loaded using horrendously-long data: URIs;
    1436             :             // truncate those before reporting them.
    1437             :             bool isData;
    1438           0 :             if (NS_SUCCEEDED(mURI->get()->SchemeIs("data", &isData)) && isData &&
    1439           0 :                 spec.Length() > 255) {
    1440           0 :                 spec.Truncate(252);
    1441           0 :                 spec.Append("...");
    1442             :             }
    1443           0 :             path.AppendPrintf(", url=%s", spec.get());
    1444             :         }
    1445           0 :         if (mPrincipal) {
    1446           0 :             nsCOMPtr<nsIURI> uri;
    1447           0 :             mPrincipal->get()->GetURI(getter_AddRefs(uri));
    1448           0 :             if (uri) {
    1449           0 :                 nsCString spec = uri->GetSpecOrDefault();
    1450           0 :                 if (!spec.IsEmpty()) {
    1451             :                     // Include a clue as to who loaded this resource. (Note
    1452             :                     // that because of font entry sharing, other pages may now
    1453             :                     // be using this resource, and the original page may not
    1454             :                     // even be loaded any longer.)
    1455           0 :                     spec.ReplaceChar('/', '\\');
    1456           0 :                     path.AppendPrintf(", principal=%s", spec.get());
    1457             :                 }
    1458             :             }
    1459             :         }
    1460             :     }
    1461           0 :     path.Append(')');
    1462             : 
    1463           0 :     aHandleReport->Callback(
    1464           0 :         EmptyCString(), path,
    1465             :         nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::UNITS_BYTES,
    1466           0 :         mFontEntry->ComputedSizeOfExcludingThis(UserFontsMallocSizeOf),
    1467           0 :         NS_LITERAL_CSTRING("Memory used by @font-face resource."),
    1468           0 :         aData);
    1469           0 : }
    1470             : 
    1471           0 : NS_IMPL_ISUPPORTS(gfxUserFontSet::UserFontCache::MemoryReporter,
    1472             :                   nsIMemoryReporter)
    1473             : 
    1474             : NS_IMETHODIMP
    1475           0 : gfxUserFontSet::UserFontCache::MemoryReporter::CollectReports(
    1476             :     nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
    1477             : {
    1478           0 :     if (!sUserFonts) {
    1479           0 :         return NS_OK;
    1480             :     }
    1481             : 
    1482           0 :     for (auto it = sUserFonts->Iter(); !it.Done(); it.Next()) {
    1483           0 :         it.Get()->ReportMemory(aHandleReport, aData, aAnonymize);
    1484             :     }
    1485             : 
    1486           0 :     MOZ_COLLECT_REPORT(
    1487             :         "explicit/gfx/user-fonts/cache-overhead", KIND_HEAP, UNITS_BYTES,
    1488             :         sUserFonts->ShallowSizeOfIncludingThis(UserFontsMallocSizeOf),
    1489             :         "Memory used by the @font-face cache, not counting the actual font "
    1490           0 :         "resources.");
    1491             : 
    1492           0 :     return NS_OK;
    1493             : }
    1494             : 
    1495             : #ifdef DEBUG_USERFONT_CACHE
    1496             : 
    1497             : void
    1498             : gfxUserFontSet::UserFontCache::Entry::Dump()
    1499             : {
    1500             :     nsresult rv;
    1501             : 
    1502             :     nsAutoCString principalURISpec("(null)");
    1503             :     bool setDomain = false;
    1504             : 
    1505             :     if (mPrincipal) {
    1506             :         nsCOMPtr<nsIURI> principalURI;
    1507             :         rv = mPrincipal->get()->GetURI(getter_AddRefs(principalURI));
    1508             :         if (NS_SUCCEEDED(rv)) {
    1509             :             principalURI->GetSpec(principalURISpec);
    1510             :         }
    1511             : 
    1512             :         nsCOMPtr<nsIURI> domainURI;
    1513             :         mPrincipal->get()->GetDomain(getter_AddRefs(domainURI));
    1514             :         if (domainURI) {
    1515             :             setDomain = true;
    1516             :         }
    1517             :     }
    1518             : 
    1519             :     NS_ASSERTION(mURI, "null URI in userfont cache entry");
    1520             : 
    1521             :     printf("userfontcache fontEntry: %p fonturihash: %8.8x "
    1522             :            "family: %s domainset: %s principal: [%s]\n",
    1523             :            mFontEntry,
    1524             :            mURI->Hash(),
    1525             :            NS_ConvertUTF16toUTF8(mFontEntry->FamilyName()).get(),
    1526             :            setDomain ? "true" : "false",
    1527             :            principalURISpec.get());
    1528             : }
    1529             : 
    1530             : void
    1531             : gfxUserFontSet::UserFontCache::Dump()
    1532             : {
    1533             :     if (!sUserFonts) {
    1534             :         return;
    1535             :     }
    1536             : 
    1537             :     printf("userfontcache dump count: %d ========\n", sUserFonts->Count());
    1538             :     for (auto it = sUserFonts->Iter(); !it.Done(); it.Next()) {
    1539             :         it.Get()->Dump();
    1540             :     }
    1541             :     printf("userfontcache dump ==================\n");
    1542             : }
    1543             : 
    1544             : #endif
    1545             : 
    1546             : #undef LOG
    1547             : #undef LOG_ENABLED

Generated by: LCOV version 1.13