LCOV - code coverage report
Current view: top level - layout/style - FontFaceSet.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 889 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 74 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
       2             : /* vim: set ts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "FontFaceSet.h"
       8             : 
       9             : #include "gfxFontConstants.h"
      10             : #include "gfxFontSrcPrincipal.h"
      11             : #include "gfxFontSrcURI.h"
      12             : #include "mozilla/css/Declaration.h"
      13             : #include "mozilla/css/Loader.h"
      14             : #include "mozilla/dom/FontFaceSetBinding.h"
      15             : #include "mozilla/dom/FontFaceSetIterator.h"
      16             : #include "mozilla/dom/FontFaceSetLoadEvent.h"
      17             : #include "mozilla/dom/FontFaceSetLoadEventBinding.h"
      18             : #include "mozilla/dom/Promise.h"
      19             : #include "mozilla/AsyncEventDispatcher.h"
      20             : #include "mozilla/Logging.h"
      21             : #include "mozilla/Preferences.h"
      22             : #include "mozilla/ServoStyleSet.h"
      23             : #include "mozilla/ServoUtils.h"
      24             : #include "mozilla/SizePrintfMacros.h"
      25             : #include "mozilla/Sprintf.h"
      26             : #include "mozilla/Telemetry.h"
      27             : #include "nsAutoPtr.h"
      28             : #include "nsContentPolicyUtils.h"
      29             : #include "nsCSSParser.h"
      30             : #include "nsDeviceContext.h"
      31             : #include "nsFontFaceLoader.h"
      32             : #include "nsIConsoleService.h"
      33             : #include "nsIContentPolicy.h"
      34             : #include "nsIContentSecurityPolicy.h"
      35             : #include "nsIDocShell.h"
      36             : #include "nsIDocument.h"
      37             : #include "nsILoadContext.h"
      38             : #include "nsINetworkPredictor.h"
      39             : #include "nsIPresShell.h"
      40             : #include "nsIPrincipal.h"
      41             : #include "nsISupportsPriority.h"
      42             : #include "nsIWebNavigation.h"
      43             : #include "nsNetUtil.h"
      44             : #include "nsIProtocolHandler.h"
      45             : #include "nsIInputStream.h"
      46             : #include "nsPresContext.h"
      47             : #include "nsPrintfCString.h"
      48             : #include "nsStyleSet.h"
      49             : #include "nsUTF8Utils.h"
      50             : #include "nsDOMNavigationTiming.h"
      51             : 
      52             : using namespace mozilla;
      53             : using namespace mozilla::css;
      54             : using namespace mozilla::dom;
      55             : 
      56             : #define LOG(args) MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
      57             : #define LOG_ENABLED() MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), \
      58             :                                   LogLevel::Debug)
      59             : 
      60             : #define FONT_LOADING_API_ENABLED_PREF "layout.css.font-loading-api.enabled"
      61             : 
      62             : NS_IMPL_CYCLE_COLLECTION_CLASS(FontFaceSet)
      63             : 
      64           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FontFaceSet, DOMEventTargetHelper)
      65           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument);
      66           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReady);
      67           0 :   for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
      68           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleFaces[i].mFontFace);
      69             :   }
      70           0 :   for (size_t i = 0; i < tmp->mNonRuleFaces.Length(); i++) {
      71           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNonRuleFaces[i].mFontFace);
      72             :   }
      73           0 :   if (tmp->mUserFontSet) {
      74           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUserFontSet->mFontFaceSet);
      75             :   }
      76           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      77             : 
      78           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FontFaceSet, DOMEventTargetHelper)
      79           0 :   tmp->Disconnect();
      80           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument);
      81           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mReady);
      82           0 :   for (size_t i = 0; i < tmp->mRuleFaces.Length(); i++) {
      83           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mRuleFaces[i].mFontFace);
      84             :   }
      85           0 :   for (size_t i = 0; i < tmp->mNonRuleFaces.Length(); i++) {
      86           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mNonRuleFaces[i].mFontFace);
      87             :   }
      88           0 :   if (tmp->mUserFontSet) {
      89           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mUserFontSet->mFontFaceSet);
      90             :   }
      91           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mUserFontSet);
      92           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      93             : 
      94           0 : NS_IMPL_ADDREF_INHERITED(FontFaceSet, DOMEventTargetHelper)
      95           0 : NS_IMPL_RELEASE_INHERITED(FontFaceSet, DOMEventTargetHelper)
      96             : 
      97           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FontFaceSet)
      98           0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
      99           0 :   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
     100           0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
     101             : 
     102           0 : FontFaceSet::FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument)
     103             :   : DOMEventTargetHelper(aWindow)
     104             :   , mDocument(aDocument)
     105             :   , mResolveLazilyCreatedReadyPromise(false)
     106             :   , mStatus(FontFaceSetLoadStatus::Loaded)
     107             :   , mNonRuleFacesDirty(false)
     108             :   , mHasLoadingFontFaces(false)
     109             :   , mHasLoadingFontFacesIsDirty(false)
     110             :   , mDelayedLoadCheck(false)
     111             :   , mBypassCache(false)
     112             :   , mPrivateBrowsing(false)
     113           0 :   , mHasStandardFontLoadPrincipalChanged(false)
     114             : {
     115           0 :   MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
     116             : 
     117           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aWindow);
     118             : 
     119             :   // If the pref is not set, don't create the Promise (which the page wouldn't
     120             :   // be able to get to anyway) as it causes the window.FontFaceSet constructor
     121             :   // to be created.
     122           0 :   if (global && PrefEnabled()) {
     123           0 :     mResolveLazilyCreatedReadyPromise = true;
     124             :   }
     125             : 
     126             :   // Record the state of the "bypass cache" flags from the docshell now,
     127             :   // since we want to look at them from style worker threads, and we can
     128             :   // only get to the docshell through a weak pointer (which is only
     129             :   // possible on the main thread).
     130             :   //
     131             :   // In theory the load type of a docshell could change after the document
     132             :   // is loaded, but handling that doesn't seem too important.
     133           0 :   if (nsCOMPtr<nsIDocShell> docShell = mDocument->GetDocShell()) {
     134             :     uint32_t loadType;
     135             :     uint32_t flags;
     136           0 :     if ((NS_SUCCEEDED(docShell->GetLoadType(&loadType)) &&
     137           0 :          ((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)) ||
     138           0 :         (NS_SUCCEEDED(docShell->GetDefaultLoadFlags(&flags)) &&
     139           0 :          (flags & nsIRequest::LOAD_BYPASS_CACHE))) {
     140           0 :       mBypassCache = true;
     141             :     }
     142             :   }
     143             : 
     144             :   // Same for the "private browsing" flag.
     145           0 :   if (nsCOMPtr<nsILoadContext> loadContext = mDocument->GetLoadContext()) {
     146           0 :     mPrivateBrowsing = loadContext->UsePrivateBrowsing();
     147             :   }
     148             : 
     149           0 :   if (!mDocument->DidFireDOMContentLoaded()) {
     150           0 :     mDocument->AddSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
     151           0 :                                       this, false, false);
     152             :   }
     153             : 
     154           0 :   mDocument->CSSLoader()->AddObserver(this);
     155             : 
     156           0 :   mUserFontSet = new UserFontSet(this);
     157           0 : }
     158             : 
     159           0 : FontFaceSet::~FontFaceSet()
     160             : {
     161             :   // Assert that we don't drop any FontFaceSet objects during a Servo traversal,
     162             :   // since PostTraversalTask objects can hold raw pointers to FontFaceSets.
     163           0 :   MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
     164             : 
     165           0 :   Disconnect();
     166           0 :   for (auto it = mLoaders.Iter(); !it.Done(); it.Next()) {
     167           0 :     it.Get()->GetKey()->Cancel();
     168             :   }
     169           0 : }
     170             : 
     171             : JSObject*
     172           0 : FontFaceSet::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aGivenProto)
     173             : {
     174           0 :   return FontFaceSetBinding::Wrap(aContext, this, aGivenProto);
     175             : }
     176             : 
     177             : void
     178           0 : FontFaceSet::Disconnect()
     179             : {
     180           0 :   RemoveDOMContentLoadedListener();
     181             : 
     182           0 :   if (mDocument && mDocument->CSSLoader()) {
     183             :     // We're null checking CSSLoader() since FontFaceSet::Disconnect() might be
     184             :     // being called during unlink, at which time the loader amy already have
     185             :     // been unlinked from the document.
     186           0 :     mDocument->CSSLoader()->RemoveObserver(this);
     187             :   }
     188           0 : }
     189             : 
     190             : void
     191           0 : FontFaceSet::RemoveDOMContentLoadedListener()
     192             : {
     193           0 :   if (mDocument) {
     194           0 :     mDocument->RemoveSystemEventListener(NS_LITERAL_STRING("DOMContentLoaded"),
     195           0 :                                          this, false);
     196             :   }
     197           0 : }
     198             : 
     199             : void
     200           0 : FontFaceSet::ParseFontShorthandForMatching(
     201             :                             const nsAString& aFont,
     202             :                             RefPtr<FontFamilyListRefCnt>& aFamilyList,
     203             :                             uint32_t& aWeight,
     204             :                             int32_t& aStretch,
     205             :                             uint8_t& aStyle,
     206             :                             ErrorResult& aRv)
     207             : {
     208             :   // Parse aFont as a 'font' property value.
     209           0 :   RefPtr<Declaration> declaration = new Declaration;
     210           0 :   declaration->InitializeEmpty();
     211             : 
     212           0 :   bool changed = false;
     213           0 :   nsCSSParser parser;
     214           0 :   parser.ParseProperty(eCSSProperty_font,
     215             :                        aFont,
     216             :                        mDocument->GetDocumentURI(),
     217             :                        mDocument->GetDocumentURI(),
     218           0 :                        mDocument->NodePrincipal(),
     219             :                        declaration,
     220             :                        &changed,
     221           0 :                        /* aIsImportant */ false);
     222             : 
     223             :   // All of the properties we are interested in should have been set at once.
     224           0 :   MOZ_ASSERT(changed == (declaration->HasProperty(eCSSProperty_font_family) &&
     225             :                          declaration->HasProperty(eCSSProperty_font_style) &&
     226             :                          declaration->HasProperty(eCSSProperty_font_weight) &&
     227             :                          declaration->HasProperty(eCSSProperty_font_stretch)));
     228             : 
     229           0 :   if (!changed) {
     230           0 :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     231           0 :     return;
     232             :   }
     233             : 
     234           0 :   nsCSSCompressedDataBlock* data = declaration->GetNormalBlock();
     235           0 :   MOZ_ASSERT(!declaration->GetImportantBlock());
     236             : 
     237           0 :   const nsCSSValue* family = data->ValueFor(eCSSProperty_font_family);
     238           0 :   if (family->GetUnit() != eCSSUnit_FontFamilyList) {
     239             :     // We got inherit, initial, unset, a system font, or a token stream.
     240           0 :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     241           0 :     return;
     242             :   }
     243             : 
     244             :   aFamilyList =
     245           0 :     static_cast<FontFamilyListRefCnt*>(family->GetFontFamilyListValue());
     246             : 
     247           0 :   int32_t weight = data->ValueFor(eCSSProperty_font_weight)->GetIntValue();
     248             : 
     249             :   // Resolve relative font weights against the initial of font-weight
     250             :   // (normal, which is equivalent to 400).
     251           0 :   if (weight == NS_STYLE_FONT_WEIGHT_BOLDER) {
     252           0 :     weight = NS_FONT_WEIGHT_BOLD;
     253           0 :   } else if (weight == NS_STYLE_FONT_WEIGHT_LIGHTER) {
     254           0 :     weight = NS_FONT_WEIGHT_THIN;
     255             :   }
     256             : 
     257           0 :   aWeight = weight;
     258             : 
     259           0 :   aStretch = data->ValueFor(eCSSProperty_font_stretch)->GetIntValue();
     260           0 :   aStyle = data->ValueFor(eCSSProperty_font_style)->GetIntValue();
     261             : }
     262             : 
     263             : static bool
     264           0 : HasAnyCharacterInUnicodeRange(gfxUserFontEntry* aEntry,
     265             :                               const nsAString& aInput)
     266             : {
     267           0 :   const char16_t* p = aInput.Data();
     268           0 :   const char16_t* end = p + aInput.Length();
     269             : 
     270           0 :   while (p < end) {
     271           0 :     uint32_t c = UTF16CharEnumerator::NextChar(&p, end);
     272           0 :     if (aEntry->CharacterInUnicodeRange(c)) {
     273           0 :       return true;
     274             :     }
     275             :   }
     276           0 :   return false;
     277             : }
     278             : 
     279             : void
     280           0 : FontFaceSet::FindMatchingFontFaces(const nsAString& aFont,
     281             :                                    const nsAString& aText,
     282             :                                    nsTArray<FontFace*>& aFontFaces,
     283             :                                    ErrorResult& aRv)
     284             : {
     285           0 :   RefPtr<FontFamilyListRefCnt> familyList;
     286             :   uint32_t weight;
     287             :   int32_t stretch;
     288             :   uint8_t italicStyle;
     289             :   ParseFontShorthandForMatching(aFont, familyList, weight, stretch, italicStyle,
     290           0 :                                 aRv);
     291           0 :   if (aRv.Failed()) {
     292           0 :     return;
     293             :   }
     294             : 
     295           0 :   gfxFontStyle style;
     296           0 :   style.style = italicStyle;
     297           0 :   style.weight = weight;
     298           0 :   style.stretch = stretch;
     299             : 
     300             :   nsTArray<FontFaceRecord>* arrays[2];
     301           0 :   arrays[0] = &mNonRuleFaces;
     302           0 :   arrays[1] = &mRuleFaces;
     303             : 
     304             :   // Set of FontFaces that we want to return.
     305           0 :   nsTHashtable<nsPtrHashKey<FontFace>> matchingFaces;
     306             : 
     307           0 :   for (const FontFamilyName& fontFamilyName : familyList->GetFontlist()) {
     308             :     RefPtr<gfxFontFamily> family =
     309           0 :       mUserFontSet->LookupFamily(fontFamilyName.mName);
     310             : 
     311           0 :     if (!family) {
     312           0 :       continue;
     313             :     }
     314             : 
     315           0 :     AutoTArray<gfxFontEntry*,4> entries;
     316             :     bool needsBold;
     317           0 :     family->FindAllFontsForStyle(style, entries, needsBold);
     318             : 
     319           0 :     for (gfxFontEntry* e : entries) {
     320           0 :       FontFace::Entry* entry = static_cast<FontFace::Entry*>(e);
     321           0 :       if (HasAnyCharacterInUnicodeRange(entry, aText)) {
     322           0 :         for (FontFace* f : entry->GetFontFaces()) {
     323           0 :           matchingFaces.PutEntry(f);
     324             :         }
     325             :       }
     326             :     }
     327             :   }
     328             : 
     329             :   // Add all FontFaces in matchingFaces to aFontFaces, in the order
     330             :   // they appear in the FontFaceSet.
     331           0 :   for (nsTArray<FontFaceRecord>* array : arrays) {
     332           0 :     for (FontFaceRecord& record : *array) {
     333           0 :       FontFace* f = record.mFontFace;
     334           0 :       if (matchingFaces.Contains(f)) {
     335           0 :         aFontFaces.AppendElement(f);
     336             :       }
     337             :     }
     338             :   }
     339             : }
     340             : 
     341             : TimeStamp
     342           0 : FontFaceSet::GetNavigationStartTimeStamp()
     343             : {
     344           0 :   TimeStamp navStart;
     345           0 :   RefPtr<nsDOMNavigationTiming> timing(mDocument->GetNavigationTiming());
     346           0 :   if (timing) {
     347           0 :     navStart = timing->GetNavigationStartTimeStamp();
     348             :   }
     349           0 :   return navStart;
     350             : }
     351             : 
     352             : already_AddRefed<Promise>
     353           0 : FontFaceSet::Load(JSContext* aCx,
     354             :                   const nsAString& aFont,
     355             :                   const nsAString& aText,
     356             :                   ErrorResult& aRv)
     357             : {
     358           0 :   FlushUserFontSet();
     359             : 
     360           0 :   nsTArray<RefPtr<Promise>> promises;
     361             : 
     362           0 :   nsTArray<FontFace*> faces;
     363           0 :   FindMatchingFontFaces(aFont, aText, faces, aRv);
     364           0 :   if (aRv.Failed()) {
     365           0 :     return nullptr;
     366             :   }
     367             : 
     368           0 :   for (FontFace* f : faces) {
     369           0 :     RefPtr<Promise> promise = f->Load(aRv);
     370           0 :     if (aRv.Failed()) {
     371           0 :       return nullptr;
     372             :     }
     373           0 :     if (!promises.AppendElement(promise, fallible)) {
     374           0 :       aRv.Throw(NS_ERROR_FAILURE);
     375           0 :       return nullptr;
     376             :     }
     377             :   }
     378             : 
     379           0 :   nsIGlobalObject* globalObject = GetParentObject();
     380           0 :   if (!globalObject) {
     381           0 :     aRv.Throw(NS_ERROR_FAILURE);
     382           0 :     return nullptr;
     383             :   }
     384             : 
     385           0 :   JS::Rooted<JSObject*> jsGlobal(aCx, globalObject->GetGlobalJSObject());
     386           0 :   GlobalObject global(aCx, jsGlobal);
     387             : 
     388           0 :   RefPtr<Promise> result = Promise::All(global, promises, aRv);
     389           0 :   return result.forget();
     390             : }
     391             : 
     392             : bool
     393           0 : FontFaceSet::Check(const nsAString& aFont,
     394             :                    const nsAString& aText,
     395             :                    ErrorResult& aRv)
     396             : {
     397           0 :   FlushUserFontSet();
     398             : 
     399           0 :   nsTArray<FontFace*> faces;
     400           0 :   FindMatchingFontFaces(aFont, aText, faces, aRv);
     401           0 :   if (aRv.Failed()) {
     402           0 :     return false;
     403             :   }
     404             : 
     405           0 :   for (FontFace* f : faces) {
     406           0 :     if (f->Status() != FontFaceLoadStatus::Loaded) {
     407           0 :       return false;
     408             :     }
     409             :   }
     410             : 
     411           0 :   return true;
     412             : }
     413             : 
     414             : Promise*
     415           0 : FontFaceSet::GetReady(ErrorResult& aRv)
     416             : {
     417           0 :   MOZ_ASSERT(NS_IsMainThread());
     418             : 
     419           0 :   if (!mReady) {
     420           0 :     nsCOMPtr<nsIGlobalObject> global = GetParentObject();
     421           0 :     mReady = Promise::Create(global, aRv);
     422           0 :     if (!mReady) {
     423           0 :       aRv.Throw(NS_ERROR_FAILURE);
     424           0 :       return nullptr;
     425             :     }
     426           0 :     if (mResolveLazilyCreatedReadyPromise) {
     427           0 :       mReady->MaybeResolve(this);
     428           0 :       mResolveLazilyCreatedReadyPromise = false;
     429             :     }
     430             :   }
     431             : 
     432           0 :   FlushUserFontSet();
     433           0 :   return mReady;
     434             : }
     435             : 
     436             : FontFaceSetLoadStatus
     437           0 : FontFaceSet::Status()
     438             : {
     439           0 :   FlushUserFontSet();
     440           0 :   return mStatus;
     441             : }
     442             : 
     443             : #ifdef DEBUG
     444             : bool
     445           0 : FontFaceSet::HasRuleFontFace(FontFace* aFontFace)
     446             : {
     447           0 :   for (size_t i = 0; i < mRuleFaces.Length(); i++) {
     448           0 :     if (mRuleFaces[i].mFontFace == aFontFace) {
     449           0 :       return true;
     450             :     }
     451             :   }
     452           0 :   return false;
     453             : }
     454             : #endif
     455             : 
     456             : FontFaceSet*
     457           0 : FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv)
     458             : {
     459           0 :   FlushUserFontSet();
     460             : 
     461           0 :   if (aFontFace.IsInFontFaceSet(this)) {
     462           0 :     return this;
     463             :   }
     464             : 
     465           0 :   if (aFontFace.HasRule()) {
     466           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_MODIFICATION_ERR);
     467           0 :     return nullptr;
     468             :   }
     469             : 
     470           0 :   aFontFace.AddFontFaceSet(this);
     471             : 
     472             : #ifdef DEBUG
     473           0 :   for (const FontFaceRecord& rec : mNonRuleFaces) {
     474           0 :     MOZ_ASSERT(rec.mFontFace != &aFontFace,
     475             :                "FontFace should not occur in mNonRuleFaces twice");
     476             :   }
     477             : #endif
     478             : 
     479           0 :   FontFaceRecord* rec = mNonRuleFaces.AppendElement();
     480           0 :   rec->mFontFace = &aFontFace;
     481           0 :   rec->mSheetType = SheetType::Unknown;  // unused for mNonRuleFaces
     482           0 :   rec->mLoadEventShouldFire =
     483           0 :     aFontFace.Status() == FontFaceLoadStatus::Unloaded ||
     484           0 :     aFontFace.Status() == FontFaceLoadStatus::Loading;
     485             : 
     486           0 :   mNonRuleFacesDirty = true;
     487           0 :   RebuildUserFontSet();
     488           0 :   mHasLoadingFontFacesIsDirty = true;
     489           0 :   CheckLoadingStarted();
     490           0 :   return this;
     491             : }
     492             : 
     493             : void
     494           0 : FontFaceSet::Clear()
     495             : {
     496           0 :   FlushUserFontSet();
     497             : 
     498           0 :   if (mNonRuleFaces.IsEmpty()) {
     499           0 :     return;
     500             :   }
     501             : 
     502           0 :   for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
     503           0 :     FontFace* f = mNonRuleFaces[i].mFontFace;
     504           0 :     f->RemoveFontFaceSet(this);
     505             :   }
     506             : 
     507           0 :   mNonRuleFaces.Clear();
     508           0 :   mNonRuleFacesDirty = true;
     509           0 :   RebuildUserFontSet();
     510           0 :   mHasLoadingFontFacesIsDirty = true;
     511           0 :   CheckLoadingFinished();
     512             : }
     513             : 
     514             : bool
     515           0 : FontFaceSet::Delete(FontFace& aFontFace)
     516             : {
     517           0 :   FlushUserFontSet();
     518             : 
     519           0 :   if (aFontFace.HasRule()) {
     520           0 :     return false;
     521             :   }
     522             : 
     523           0 :   bool removed = false;
     524           0 :   for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
     525           0 :     if (mNonRuleFaces[i].mFontFace == &aFontFace) {
     526           0 :       mNonRuleFaces.RemoveElementAt(i);
     527           0 :       removed = true;
     528           0 :       break;
     529             :     }
     530             :   }
     531           0 :   if (!removed) {
     532           0 :     return false;
     533             :   }
     534             : 
     535           0 :   aFontFace.RemoveFontFaceSet(this);
     536             : 
     537           0 :   mNonRuleFacesDirty = true;
     538           0 :   RebuildUserFontSet();
     539           0 :   mHasLoadingFontFacesIsDirty = true;
     540           0 :   CheckLoadingFinished();
     541           0 :   return true;
     542             : }
     543             : 
     544             : bool
     545           0 : FontFaceSet::HasAvailableFontFace(FontFace* aFontFace)
     546             : {
     547           0 :   return aFontFace->IsInFontFaceSet(this);
     548             : }
     549             : 
     550             : bool
     551           0 : FontFaceSet::Has(FontFace& aFontFace)
     552             : {
     553           0 :   FlushUserFontSet();
     554             : 
     555           0 :   return HasAvailableFontFace(&aFontFace);
     556             : }
     557             : 
     558             : FontFace*
     559           0 : FontFaceSet::GetFontFaceAt(uint32_t aIndex)
     560             : {
     561           0 :   FlushUserFontSet();
     562             : 
     563           0 :   if (aIndex < mRuleFaces.Length()) {
     564           0 :     return mRuleFaces[aIndex].mFontFace;
     565             :   }
     566             : 
     567           0 :   aIndex -= mRuleFaces.Length();
     568           0 :   if (aIndex < mNonRuleFaces.Length()) {
     569           0 :     return mNonRuleFaces[aIndex].mFontFace;
     570             :   }
     571             : 
     572           0 :   return nullptr;
     573             : }
     574             : 
     575             : uint32_t
     576           0 : FontFaceSet::Size()
     577             : {
     578           0 :   FlushUserFontSet();
     579             : 
     580             :   // Web IDL objects can only expose array index properties up to INT32_MAX.
     581             : 
     582           0 :   size_t total = mRuleFaces.Length() + mNonRuleFaces.Length();
     583           0 :   return std::min<size_t>(total, INT32_MAX);
     584             : }
     585             : 
     586             : already_AddRefed<FontFaceSetIterator>
     587           0 : FontFaceSet::Entries()
     588             : {
     589           0 :   RefPtr<FontFaceSetIterator> it = new FontFaceSetIterator(this, true);
     590           0 :   return it.forget();
     591             : }
     592             : 
     593             : already_AddRefed<FontFaceSetIterator>
     594           0 : FontFaceSet::Values()
     595             : {
     596           0 :   RefPtr<FontFaceSetIterator> it = new FontFaceSetIterator(this, false);
     597           0 :   return it.forget();
     598             : }
     599             : 
     600             : void
     601           0 : FontFaceSet::ForEach(JSContext* aCx,
     602             :                      FontFaceSetForEachCallback& aCallback,
     603             :                      JS::Handle<JS::Value> aThisArg,
     604             :                      ErrorResult& aRv)
     605             : {
     606           0 :   JS::Rooted<JS::Value> thisArg(aCx, aThisArg);
     607           0 :   for (size_t i = 0; i < Size(); i++) {
     608           0 :     FontFace* face = GetFontFaceAt(i);
     609           0 :     aCallback.Call(thisArg, *face, *face, *this, aRv);
     610           0 :     if (aRv.Failed()) {
     611           0 :       return;
     612             :     }
     613             :   }
     614             : }
     615             : 
     616             : void
     617           0 : FontFaceSet::RemoveLoader(nsFontFaceLoader* aLoader)
     618             : {
     619           0 :   mLoaders.RemoveEntry(aLoader);
     620           0 : }
     621             : 
     622             : nsresult
     623           0 : FontFaceSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
     624             :                        const gfxFontFaceSrc* aFontFaceSrc)
     625             : {
     626             :   nsresult rv;
     627             : 
     628           0 :   nsCOMPtr<nsIStreamLoader> streamLoader;
     629           0 :   nsCOMPtr<nsILoadGroup> loadGroup(mDocument->GetDocumentLoadGroup());
     630           0 :   gfxFontSrcPrincipal* principal = aUserFontEntry->GetPrincipal();
     631             : 
     632           0 :   nsCOMPtr<nsIChannel> channel;
     633             :   // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
     634             :   // node and a principal.  This is because the document where the font is
     635             :   // being loaded might have a different origin from the principal of the
     636             :   // stylesheet that initiated the font load.
     637           0 :   rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
     638             :                                             aFontFaceSrc->mURI->get(),
     639             :                                             mDocument,
     640             :                                             principal ? principal->get() : nullptr,
     641             :                                             nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
     642             :                                             nsIContentPolicy::TYPE_FONT,
     643           0 :                                             loadGroup);
     644           0 :   NS_ENSURE_SUCCESS(rv, rv);
     645             : 
     646             :   RefPtr<nsFontFaceLoader> fontLoader =
     647           0 :     new nsFontFaceLoader(aUserFontEntry, aFontFaceSrc->mURI->get(), this,
     648           0 :                          channel);
     649             : 
     650           0 :   if (LOG_ENABLED()) {
     651           0 :     LOG(("userfonts (%p) download start - font uri: (%s) "
     652             :          "referrer uri: (%s)\n",
     653             :          fontLoader.get(), aFontFaceSrc->mURI->GetSpecOrDefault().get(),
     654             :          aFontFaceSrc->mReferrer
     655             :          ? aFontFaceSrc->mReferrer->GetSpecOrDefault().get()
     656             :          : ""));
     657             :   }
     658             : 
     659           0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     660           0 :   if (httpChannel) {
     661           0 :     rv = httpChannel->SetReferrerWithPolicy(aFontFaceSrc->mReferrer,
     662           0 :                                             mDocument->GetReferrerPolicy());
     663           0 :     Unused << NS_WARN_IF(NS_FAILED(rv));
     664             : 
     665           0 :     nsAutoCString accept("application/font-woff;q=0.9,*/*;q=0.8");
     666           0 :     if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED)) {
     667           0 :       accept.Insert(NS_LITERAL_CSTRING("application/font-woff2;q=1.0,"), 0);
     668             :     }
     669           0 :     rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
     670           0 :                                        accept, false);
     671           0 :     NS_ENSURE_SUCCESS(rv, rv);
     672             : 
     673             :     // For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try
     674             :     // and apply additional compression at the content-encoding layer
     675           0 :     if (aFontFaceSrc->mFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF |
     676             :                                       gfxUserFontSet::FLAG_FORMAT_WOFF2)) {
     677           0 :       rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
     678           0 :                                          NS_LITERAL_CSTRING("identity"), false);
     679           0 :       NS_ENSURE_SUCCESS(rv, rv);
     680             :     }
     681             :   }
     682           0 :   nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
     683           0 :   if (priorityChannel) {
     684           0 :     priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
     685             :   }
     686             : 
     687           0 :   rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
     688           0 :   NS_ENSURE_SUCCESS(rv, rv);
     689             : 
     690           0 :   mozilla::net::PredictorLearn(aFontFaceSrc->mURI->get(),
     691             :                                mDocument->GetDocumentURI(),
     692             :                                nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
     693           0 :                                loadGroup);
     694             : 
     695           0 :   rv = channel->AsyncOpen2(streamLoader);
     696           0 :   if (NS_FAILED(rv)) {
     697           0 :     fontLoader->DropChannel();  // explicitly need to break ref cycle
     698             :   }
     699             : 
     700           0 :   if (NS_SUCCEEDED(rv)) {
     701           0 :     mLoaders.PutEntry(fontLoader);
     702           0 :     fontLoader->StartedLoading(streamLoader);
     703           0 :     aUserFontEntry->SetLoader(fontLoader); // let the font entry remember the
     704             :                                            // loader, in case we need to cancel it
     705             :   }
     706             : 
     707           0 :   return rv;
     708             : }
     709             : 
     710             : bool
     711           0 : FontFaceSet::UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules)
     712             : {
     713           0 :   MOZ_ASSERT(mUserFontSet);
     714             : 
     715             :   // If there was a change to the mNonRuleFaces array, then there could
     716             :   // have been a modification to the user font set.
     717           0 :   bool modified = mNonRuleFacesDirty;
     718           0 :   mNonRuleFacesDirty = false;
     719             : 
     720             :   // reuse existing FontFace objects mapped to rules already
     721           0 :   nsDataHashtable<nsPtrHashKey<nsCSSFontFaceRule>, FontFace*> ruleFaceMap;
     722           0 :   for (size_t i = 0, i_end = mRuleFaces.Length(); i < i_end; ++i) {
     723           0 :     FontFace* f = mRuleFaces[i].mFontFace;
     724           0 :     if (!f) {
     725           0 :       continue;
     726             :     }
     727           0 :     ruleFaceMap.Put(f->GetRule(), f);
     728             :   }
     729             : 
     730             :   // The @font-face rules that make up the user font set have changed,
     731             :   // so we need to update the set. However, we want to preserve existing
     732             :   // font entries wherever possible, so that we don't discard and then
     733             :   // re-download resources in the (common) case where at least some of the
     734             :   // same rules are still present.
     735             : 
     736           0 :   nsTArray<FontFaceRecord> oldRecords;
     737           0 :   mRuleFaces.SwapElements(oldRecords);
     738             : 
     739             :   // Remove faces from the font family records; we need to re-insert them
     740             :   // because we might end up with faces in a different order even if they're
     741             :   // the same font entries as before. (The order can affect font selection
     742             :   // where multiple faces match the requested style, perhaps with overlapping
     743             :   // unicode-range coverage.)
     744           0 :   for (auto it = mUserFontSet->mFontFamilies.Iter(); !it.Done(); it.Next()) {
     745           0 :     it.Data()->DetachFontEntries();
     746             :   }
     747             : 
     748             :   // Sometimes aRules has duplicate @font-face rules in it; we should make
     749             :   // that not happen, but in the meantime, don't try to insert the same
     750             :   // FontFace object more than once into mRuleFaces.  We track which
     751             :   // ones we've handled in this table.
     752           0 :   nsTHashtable<nsPtrHashKey<nsCSSFontFaceRule>> handledRules;
     753             : 
     754           0 :   for (size_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
     755             :     // Insert each FontFace objects for each rule into our list, migrating old
     756             :     // font entries if possible rather than creating new ones; set  modified  to
     757             :     // true if we detect that rule ordering has changed, or if a new entry is
     758             :     // created.
     759           0 :     nsCSSFontFaceRule* rule = aRules[i].mRule;
     760           0 :     if (!handledRules.EnsureInserted(rule)) {
     761             :       // rule was already present in the hashtable
     762           0 :       continue;
     763             :     }
     764           0 :     RefPtr<FontFace> f = ruleFaceMap.Get(rule);
     765           0 :     if (!f.get()) {
     766           0 :       f = FontFace::CreateForRule(GetParentObject(), this, rule);
     767             :     }
     768           0 :     InsertRuleFontFace(f, aRules[i].mSheetType, oldRecords, modified);
     769             :   }
     770             : 
     771           0 :   for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
     772             :     // Do the same for the non rule backed FontFace objects.
     773           0 :     InsertNonRuleFontFace(mNonRuleFaces[i].mFontFace, modified);
     774             :   }
     775             : 
     776             :   // Remove any residual families that have no font entries (i.e., they were
     777             :   // not defined at all by the updated set of @font-face rules).
     778           0 :   for (auto it = mUserFontSet->mFontFamilies.Iter(); !it.Done(); it.Next()) {
     779           0 :     if (it.Data()->GetFontList().IsEmpty()) {
     780           0 :       it.Remove();
     781             :     }
     782             :   }
     783             : 
     784             :   // If any FontFace objects for rules are left in the old list, note that the
     785             :   // set has changed (even if the new set was built entirely by migrating old
     786             :   // font entries).
     787           0 :   if (oldRecords.Length() > 0) {
     788           0 :     modified = true;
     789             :     // Any in-progress loaders for obsolete rules should be cancelled,
     790             :     // as the resource being downloaded will no longer be required.
     791             :     // We need to explicitly remove any loaders here, otherwise the loaders
     792             :     // will keep their "orphaned" font entries alive until they complete,
     793             :     // even after the oldRules array is deleted.
     794             :     //
     795             :     // XXX Now that it is possible for the author to hold on to a rule backed
     796             :     // FontFace object, we shouldn't cancel loading here; instead we should do
     797             :     // it when the FontFace is GCed, if we can detect that.
     798           0 :     size_t count = oldRecords.Length();
     799           0 :     for (size_t i = 0; i < count; ++i) {
     800           0 :       RefPtr<FontFace> f = oldRecords[i].mFontFace;
     801           0 :       gfxUserFontEntry* userFontEntry = f->GetUserFontEntry();
     802           0 :       if (userFontEntry) {
     803           0 :         nsFontFaceLoader* loader = userFontEntry->GetLoader();
     804           0 :         if (loader) {
     805           0 :           loader->Cancel();
     806           0 :           RemoveLoader(loader);
     807             :         }
     808             :       }
     809             : 
     810             :       // Any left over FontFace objects should also cease being rule backed.
     811           0 :       f->DisconnectFromRule();
     812             :     }
     813             :   }
     814             : 
     815           0 :   if (modified) {
     816           0 :     IncrementGeneration(true);
     817           0 :     mHasLoadingFontFacesIsDirty = true;
     818           0 :     CheckLoadingStarted();
     819           0 :     CheckLoadingFinished();
     820             :   }
     821             : 
     822             :   // if local rules needed to be rebuilt, they have been rebuilt at this point
     823           0 :   if (mUserFontSet->mRebuildLocalRules) {
     824           0 :     mUserFontSet->mLocalRulesUsed = false;
     825           0 :     mUserFontSet->mRebuildLocalRules = false;
     826             :   }
     827             : 
     828           0 :   if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) {
     829           0 :     LOG(("userfonts (%p) userfont rules update (%s) rule count: %d",
     830             :          mUserFontSet.get(),
     831             :          (modified ? "modified" : "not modified"),
     832             :          (int)(mRuleFaces.Length())));
     833             :   }
     834             : 
     835           0 :   return modified;
     836             : }
     837             : 
     838             : static bool
     839           0 : HasLocalSrc(const nsCSSValue::Array *aSrcArr)
     840             : {
     841           0 :   size_t numSrc = aSrcArr->Count();
     842           0 :   for (size_t i = 0; i < numSrc; i++) {
     843           0 :     if (aSrcArr->Item(i).GetUnit() == eCSSUnit_Local_Font) {
     844           0 :       return true;
     845             :     }
     846             :   }
     847           0 :   return false;
     848             : }
     849             : 
     850             : void
     851           0 : FontFaceSet::IncrementGeneration(bool aIsRebuild)
     852             : {
     853           0 :   MOZ_ASSERT(mUserFontSet);
     854           0 :   mUserFontSet->IncrementGeneration(aIsRebuild);
     855           0 : }
     856             : 
     857             : void
     858           0 : FontFaceSet::InsertNonRuleFontFace(FontFace* aFontFace,
     859             :                                    bool& aFontSetModified)
     860             : {
     861           0 :   nsAutoString fontfamily;
     862           0 :   if (!aFontFace->GetFamilyName(fontfamily)) {
     863             :     // If there is no family name, this rule cannot contribute a
     864             :     // usable font, so there is no point in processing it further.
     865           0 :     return;
     866             :   }
     867             : 
     868             :   // Just create a new font entry if we haven't got one already.
     869           0 :   if (!aFontFace->GetUserFontEntry()) {
     870             :     // XXX Should we be checking mUserFontSet->mLocalRulesUsed like
     871             :     // InsertRuleFontFace does?
     872             :     RefPtr<gfxUserFontEntry> entry =
     873           0 :       FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace,
     874           0 :                                             SheetType::Doc);
     875           0 :     if (!entry) {
     876           0 :       return;
     877             :     }
     878           0 :     aFontFace->SetUserFontEntry(entry);
     879             :   }
     880             : 
     881           0 :   aFontSetModified = true;
     882           0 :   mUserFontSet->AddUserFontEntry(fontfamily, aFontFace->GetUserFontEntry());
     883             : }
     884             : 
     885             : void
     886           0 : FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
     887             :                                 nsTArray<FontFaceRecord>& aOldRecords,
     888             :                                 bool& aFontSetModified)
     889             : {
     890           0 :   nsAutoString fontfamily;
     891           0 :   if (!aFontFace->GetFamilyName(fontfamily)) {
     892             :     // If there is no family name, this rule cannot contribute a
     893             :     // usable font, so there is no point in processing it further.
     894           0 :     return;
     895             :   }
     896             : 
     897           0 :   bool remove = false;
     898             :   size_t removeIndex;
     899             : 
     900             :   // This is a rule backed FontFace.  First, we check in aOldRecords; if
     901             :   // the FontFace for the rule exists there, just move it to the new record
     902             :   // list, and put the entry into the appropriate family.
     903           0 :   for (size_t i = 0; i < aOldRecords.Length(); ++i) {
     904           0 :     FontFaceRecord& rec = aOldRecords[i];
     905             : 
     906           0 :     if (rec.mFontFace == aFontFace &&
     907           0 :         rec.mSheetType == aSheetType) {
     908             : 
     909             :       // if local rules were used, don't use the old font entry
     910             :       // for rules containing src local usage
     911           0 :       if (mUserFontSet->mLocalRulesUsed &&
     912           0 :           mUserFontSet->mRebuildLocalRules) {
     913           0 :         nsCSSValue val;
     914           0 :         aFontFace->GetDesc(eCSSFontDesc_Src, val);
     915           0 :         nsCSSUnit unit = val.GetUnit();
     916           0 :         if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
     917             :           // Remove the old record, but wait to see if we successfully create a
     918             :           // new user font entry below.
     919           0 :           remove = true;
     920           0 :           removeIndex = i;
     921           0 :           break;
     922             :         }
     923             :       }
     924             : 
     925           0 :       gfxUserFontEntry* entry = rec.mFontFace->GetUserFontEntry();
     926           0 :       MOZ_ASSERT(entry, "FontFace should have a gfxUserFontEntry by now");
     927             : 
     928           0 :       mUserFontSet->AddUserFontEntry(fontfamily, entry);
     929             : 
     930           0 :       MOZ_ASSERT(!HasRuleFontFace(rec.mFontFace),
     931             :                  "FontFace should not occur in mRuleFaces twice");
     932             : 
     933           0 :       mRuleFaces.AppendElement(rec);
     934           0 :       aOldRecords.RemoveElementAt(i);
     935             :       // note the set has been modified if an old rule was skipped to find
     936             :       // this one - something has been dropped, or ordering changed
     937           0 :       if (i > 0) {
     938           0 :         aFontSetModified = true;
     939             :       }
     940           0 :       return;
     941             :     }
     942             :   }
     943             : 
     944             :   // this is a new rule:
     945             :   RefPtr<gfxUserFontEntry> entry =
     946           0 :     FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace, aSheetType);
     947             : 
     948           0 :   if (!entry) {
     949           0 :     return;
     950             :   }
     951             : 
     952           0 :   if (remove) {
     953             :     // Although we broke out of the aOldRecords loop above, since we found
     954             :     // src local usage, and we're not using the old user font entry, we still
     955             :     // are adding a record to mRuleFaces with the same FontFace object.
     956             :     // Remove the old record so that we don't have the same FontFace listed
     957             :     // in both mRuleFaces and oldRecords, which would cause us to call
     958             :     // DisconnectFromRule on a FontFace that should still be rule backed.
     959           0 :     aOldRecords.RemoveElementAt(removeIndex);
     960             :   }
     961             : 
     962           0 :   FontFaceRecord rec;
     963           0 :   rec.mFontFace = aFontFace;
     964           0 :   rec.mSheetType = aSheetType;
     965           0 :   rec.mLoadEventShouldFire =
     966           0 :     aFontFace->Status() == FontFaceLoadStatus::Unloaded ||
     967           0 :     aFontFace->Status() == FontFaceLoadStatus::Loading;
     968             : 
     969           0 :   aFontFace->SetUserFontEntry(entry);
     970             : 
     971           0 :   MOZ_ASSERT(!HasRuleFontFace(aFontFace),
     972             :              "FontFace should not occur in mRuleFaces twice");
     973             : 
     974           0 :   mRuleFaces.AppendElement(rec);
     975             : 
     976             :   // this was a new rule and font entry, so note that the set was modified
     977           0 :   aFontSetModified = true;
     978             : 
     979             :   // Add the entry to the end of the list.  If an existing userfont entry was
     980             :   // returned by FindOrCreateUserFontEntryFromFontFace that was already stored
     981             :   // on the family, gfxUserFontFamily::AddFontEntry(), which AddUserFontEntry
     982             :   // calls, will automatically remove the earlier occurrence of the same
     983             :   // userfont entry.
     984           0 :   mUserFontSet->AddUserFontEntry(fontfamily, entry);
     985             : }
     986             : 
     987             : already_AddRefed<gfxUserFontEntry>
     988           0 : FontFaceSet::FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace)
     989             : {
     990           0 :   nsAutoString fontfamily;
     991           0 :   if (!aFontFace->GetFamilyName(fontfamily)) {
     992             :     // If there is no family name, this rule cannot contribute a
     993             :     // usable font, so there is no point in processing it further.
     994           0 :     return nullptr;
     995             :   }
     996             : 
     997             :   return FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace,
     998           0 :                                                SheetType::Doc);
     999             : }
    1000             : 
    1001             : already_AddRefed<gfxUserFontEntry>
    1002           0 : FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
    1003             :                                                    FontFace* aFontFace,
    1004             :                                                    SheetType aSheetType)
    1005             : {
    1006           0 :   nsCSSValue val;
    1007             :   nsCSSUnit unit;
    1008             : 
    1009           0 :   uint32_t weight = NS_STYLE_FONT_WEIGHT_NORMAL;
    1010           0 :   int32_t stretch = NS_STYLE_FONT_STRETCH_NORMAL;
    1011           0 :   uint8_t italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
    1012           0 :   uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
    1013           0 :   uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
    1014             : 
    1015             :   // set up weight
    1016           0 :   aFontFace->GetDesc(eCSSFontDesc_Weight, val);
    1017           0 :   unit = val.GetUnit();
    1018           0 :   if (unit == eCSSUnit_Integer || unit == eCSSUnit_Enumerated) {
    1019           0 :     weight = val.GetIntValue();
    1020           0 :     if (weight == 0) {
    1021           0 :       weight = NS_STYLE_FONT_WEIGHT_NORMAL;
    1022             :     }
    1023           0 :   } else if (unit == eCSSUnit_Normal) {
    1024           0 :     weight = NS_STYLE_FONT_WEIGHT_NORMAL;
    1025             :   } else {
    1026           0 :     NS_ASSERTION(unit == eCSSUnit_Null,
    1027             :                  "@font-face weight has unexpected unit");
    1028             :   }
    1029             : 
    1030             :   // set up stretch
    1031           0 :   aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
    1032           0 :   unit = val.GetUnit();
    1033           0 :   if (unit == eCSSUnit_Enumerated) {
    1034           0 :     stretch = val.GetIntValue();
    1035           0 :   } else if (unit == eCSSUnit_Normal) {
    1036           0 :     stretch = NS_STYLE_FONT_STRETCH_NORMAL;
    1037             :   } else {
    1038           0 :     NS_ASSERTION(unit == eCSSUnit_Null,
    1039             :                  "@font-face stretch has unexpected unit");
    1040             :   }
    1041             : 
    1042             :   // set up font style
    1043           0 :   aFontFace->GetDesc(eCSSFontDesc_Style, val);
    1044           0 :   unit = val.GetUnit();
    1045           0 :   if (unit == eCSSUnit_Enumerated) {
    1046           0 :     italicStyle = val.GetIntValue();
    1047           0 :   } else if (unit == eCSSUnit_Normal) {
    1048           0 :     italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
    1049             :   } else {
    1050           0 :     NS_ASSERTION(unit == eCSSUnit_Null,
    1051             :                  "@font-face style has unexpected unit");
    1052             :   }
    1053             : 
    1054             :   // set up font display
    1055           0 :   aFontFace->GetDesc(eCSSFontDesc_Display, val);
    1056           0 :   unit = val.GetUnit();
    1057           0 :   if (unit == eCSSUnit_Enumerated) {
    1058           0 :     fontDisplay = val.GetIntValue();
    1059             :   } else {
    1060           0 :     NS_ASSERTION(unit == eCSSUnit_Null,
    1061             :                  "@font-face style has unexpected unit");
    1062             :   }
    1063             : 
    1064             :   // set up font features
    1065           0 :   nsTArray<gfxFontFeature> featureSettings;
    1066           0 :   aFontFace->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
    1067           0 :   unit = val.GetUnit();
    1068           0 :   if (unit == eCSSUnit_Normal) {
    1069             :     // empty list of features
    1070           0 :   } else if (unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep) {
    1071           0 :     nsRuleNode::ComputeFontFeatures(val.GetPairListValue(), featureSettings);
    1072             :   } else {
    1073           0 :     NS_ASSERTION(unit == eCSSUnit_Null,
    1074             :                  "@font-face font-feature-settings has unexpected unit");
    1075             :   }
    1076             : 
    1077             :   // set up font language override
    1078           0 :   aFontFace->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
    1079           0 :   unit = val.GetUnit();
    1080           0 :   if (unit == eCSSUnit_Normal) {
    1081             :     // empty feature string
    1082           0 :   } else if (unit == eCSSUnit_String) {
    1083           0 :     nsString stringValue;
    1084           0 :     val.GetStringValue(stringValue);
    1085           0 :     languageOverride = nsRuleNode::ParseFontLanguageOverride(stringValue);
    1086             :   } else {
    1087           0 :     NS_ASSERTION(unit == eCSSUnit_Null,
    1088             :                  "@font-face font-language-override has unexpected unit");
    1089             :   }
    1090             : 
    1091             :   // set up unicode-range
    1092           0 :   gfxCharacterMap* unicodeRanges = aFontFace->GetUnicodeRangeAsCharacterMap();
    1093             : 
    1094             :   // set up src array
    1095           0 :   nsTArray<gfxFontFaceSrc> srcArray;
    1096             : 
    1097           0 :   if (aFontFace->HasFontData()) {
    1098           0 :     gfxFontFaceSrc* face = srcArray.AppendElement();
    1099           0 :     if (!face)
    1100           0 :       return nullptr;
    1101             : 
    1102           0 :     face->mSourceType = gfxFontFaceSrc::eSourceType_Buffer;
    1103           0 :     face->mBuffer = aFontFace->CreateBufferSource();
    1104             :   } else {
    1105           0 :     aFontFace->GetDesc(eCSSFontDesc_Src, val);
    1106           0 :     unit = val.GetUnit();
    1107           0 :     if (unit == eCSSUnit_Array) {
    1108           0 :       nsCSSValue::Array* srcArr = val.GetArrayValue();
    1109           0 :       size_t numSrc = srcArr->Count();
    1110             : 
    1111           0 :       for (size_t i = 0; i < numSrc; i++) {
    1112           0 :         val = srcArr->Item(i);
    1113           0 :         unit = val.GetUnit();
    1114           0 :         gfxFontFaceSrc* face = srcArray.AppendElements(1);
    1115           0 :         if (!face)
    1116           0 :           return nullptr;
    1117             : 
    1118           0 :         switch (unit) {
    1119             : 
    1120             :         case eCSSUnit_Local_Font:
    1121           0 :           val.GetStringValue(face->mLocalName);
    1122           0 :           face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
    1123           0 :           face->mURI = nullptr;
    1124           0 :           face->mFormatFlags = 0;
    1125           0 :           break;
    1126             :         case eCSSUnit_URL: {
    1127           0 :           face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
    1128           0 :           nsIURI* uri = val.GetURLValue();
    1129           0 :           face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
    1130           0 :           URLValue* url = val.GetURLStructValue();
    1131           0 :           face->mReferrer = url->mExtraData->GetReferrer();
    1132           0 :           face->mReferrerPolicy = mDocument->GetReferrerPolicy();
    1133             :           face->mOriginPrincipal =
    1134           0 :             new gfxFontSrcPrincipal(url->mExtraData->GetPrincipal());
    1135           0 :           NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
    1136             : 
    1137             :           // agent and user stylesheets are treated slightly differently,
    1138             :           // the same-site origin check and access control headers are
    1139             :           // enforced against the sheet principal rather than the document
    1140             :           // principal to allow user stylesheets to include @font-face rules
    1141           0 :           face->mUseOriginPrincipal = (aSheetType == SheetType::User ||
    1142             :                                        aSheetType == SheetType::Agent);
    1143             : 
    1144           0 :           face->mLocalName.Truncate();
    1145           0 :           face->mFormatFlags = 0;
    1146             : 
    1147           0 :           while (i + 1 < numSrc) {
    1148           0 :             val = srcArr->Item(i + 1);
    1149           0 :             if (val.GetUnit() != eCSSUnit_Font_Format)
    1150           0 :               break;
    1151             : 
    1152           0 :             nsDependentString valueString(val.GetStringBufferValue());
    1153           0 :             if (valueString.LowerCaseEqualsASCII("woff")) {
    1154           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF;
    1155           0 :             } else if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED) &&
    1156           0 :                        valueString.LowerCaseEqualsASCII("woff2")) {
    1157           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF2;
    1158           0 :             } else if (valueString.LowerCaseEqualsASCII("opentype")) {
    1159           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_OPENTYPE;
    1160           0 :             } else if (valueString.LowerCaseEqualsASCII("truetype")) {
    1161           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE;
    1162           0 :             } else if (valueString.LowerCaseEqualsASCII("truetype-aat")) {
    1163           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT;
    1164           0 :             } else if (valueString.LowerCaseEqualsASCII("embedded-opentype")) {
    1165           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_EOT;
    1166           0 :             } else if (valueString.LowerCaseEqualsASCII("svg")) {
    1167           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_SVG;
    1168             :             } else {
    1169             :               // unknown format specified, mark to distinguish from the
    1170             :               // case where no format hints are specified
    1171           0 :               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_UNKNOWN;
    1172             :             }
    1173           0 :             i++;
    1174             :           }
    1175           0 :           if (!face->mURI) {
    1176             :             // if URI not valid, omit from src array
    1177           0 :             srcArray.RemoveElementAt(srcArray.Length() - 1);
    1178           0 :             NS_WARNING("null url in @font-face rule");
    1179           0 :             continue;
    1180             :           }
    1181           0 :           break;
    1182             :         }
    1183             :         default:
    1184           0 :           NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
    1185             :                        "strange unit type in font-face src array");
    1186           0 :           break;
    1187             :         }
    1188             :        }
    1189             :     } else {
    1190           0 :       NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
    1191             :     }
    1192             :   }
    1193             : 
    1194           0 :   if (srcArray.IsEmpty()) {
    1195           0 :     return nullptr;
    1196             :   }
    1197             : 
    1198             :   RefPtr<gfxUserFontEntry> entry =
    1199           0 :     mUserFontSet->FindOrCreateUserFontEntry(aFamilyName, srcArray, weight,
    1200             :                                             stretch, italicStyle,
    1201             :                                             featureSettings,
    1202             :                                             languageOverride,
    1203           0 :                                             unicodeRanges, fontDisplay);
    1204           0 :   return entry.forget();
    1205             : }
    1206             : 
    1207             : nsCSSFontFaceRule*
    1208           0 : FontFaceSet::FindRuleForEntry(gfxFontEntry* aFontEntry)
    1209             : {
    1210           0 :   NS_ASSERTION(!aFontEntry->mIsUserFontContainer, "only platform font entries");
    1211           0 :   for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
    1212           0 :     FontFace* f = mRuleFaces[i].mFontFace;
    1213           0 :     gfxUserFontEntry* entry = f->GetUserFontEntry();
    1214           0 :     if (entry && entry->GetPlatformFontEntry() == aFontEntry) {
    1215           0 :       return f->GetRule();
    1216             :     }
    1217             :   }
    1218           0 :   return nullptr;
    1219             : }
    1220             : 
    1221             : nsCSSFontFaceRule*
    1222           0 : FontFaceSet::FindRuleForUserFontEntry(gfxUserFontEntry* aUserFontEntry)
    1223             : {
    1224           0 :   for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
    1225           0 :     FontFace* f = mRuleFaces[i].mFontFace;
    1226           0 :     if (f->GetUserFontEntry() == aUserFontEntry) {
    1227           0 :       return f->GetRule();
    1228             :     }
    1229             :   }
    1230           0 :   return nullptr;
    1231             : }
    1232             : 
    1233             : nsresult
    1234           0 : FontFaceSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
    1235             :                         const char* aMessage,
    1236             :                         uint32_t aFlags,
    1237             :                         nsresult aStatus)
    1238             : {
    1239             :   nsCOMPtr<nsIConsoleService>
    1240           0 :     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
    1241           0 :   if (!console) {
    1242           0 :     return NS_ERROR_NOT_AVAILABLE;
    1243             :   }
    1244             : 
    1245           0 :   nsAutoCString familyName;
    1246           0 :   nsAutoCString fontURI;
    1247           0 :   aUserFontEntry->GetFamilyNameAndURIForLogging(familyName, fontURI);
    1248             : 
    1249             :   char weightKeywordBuf[8]; // plenty to sprintf() a uint16_t
    1250             :   const char* weightKeyword;
    1251             :   const nsCString& weightKeywordString =
    1252           0 :     nsCSSProps::ValueToKeyword(aUserFontEntry->Weight(),
    1253           0 :                                nsCSSProps::kFontWeightKTable);
    1254           0 :   if (weightKeywordString.Length() > 0) {
    1255           0 :     weightKeyword = weightKeywordString.get();
    1256             :   } else {
    1257           0 :     SprintfLiteral(weightKeywordBuf, "%u", aUserFontEntry->Weight());
    1258           0 :     weightKeyword = weightKeywordBuf;
    1259             :   }
    1260             : 
    1261             :   nsPrintfCString message
    1262             :        ("downloadable font: %s "
    1263             :         "(font-family: \"%s\" style:%s weight:%s stretch:%s src index:%d)",
    1264             :         aMessage,
    1265             :         familyName.get(),
    1266           0 :         aUserFontEntry->IsItalic() ? "italic" : "normal",
    1267             :         weightKeyword,
    1268           0 :         nsCSSProps::ValueToKeyword(aUserFontEntry->Stretch(),
    1269           0 :                                    nsCSSProps::kFontStretchKTable).get(),
    1270           0 :         aUserFontEntry->GetSrcIndex());
    1271             : 
    1272           0 :   if (NS_FAILED(aStatus)) {
    1273           0 :     message.AppendLiteral(": ");
    1274           0 :     switch (aStatus) {
    1275             :     case NS_ERROR_DOM_BAD_URI:
    1276           0 :       message.AppendLiteral("bad URI or cross-site access not allowed");
    1277           0 :       break;
    1278             :     case NS_ERROR_CONTENT_BLOCKED:
    1279           0 :       message.AppendLiteral("content blocked");
    1280           0 :       break;
    1281             :     default:
    1282           0 :       message.AppendLiteral("status=");
    1283           0 :       message.AppendInt(static_cast<uint32_t>(aStatus));
    1284           0 :       break;
    1285             :     }
    1286             :   }
    1287           0 :   message.AppendLiteral(" source: ");
    1288           0 :   message.Append(fontURI);
    1289             : 
    1290           0 :   if (LOG_ENABLED()) {
    1291           0 :     LOG(("userfonts (%p) %s", mUserFontSet.get(), message.get()));
    1292             :   }
    1293             : 
    1294             :   // try to give the user an indication of where the rule came from
    1295           0 :   nsCSSFontFaceRule* rule = FindRuleForUserFontEntry(aUserFontEntry);
    1296           0 :   nsString href;
    1297           0 :   nsString text;
    1298             :   nsresult rv;
    1299           0 :   uint32_t line = 0;
    1300           0 :   uint32_t column = 0;
    1301           0 :   if (rule) {
    1302           0 :     rv = rule->GetCssText(text);
    1303           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1304           0 :     StyleSheet* sheet = rule->GetStyleSheet();
    1305             :     // if the style sheet is removed while the font is loading can be null
    1306           0 :     if (sheet) {
    1307           0 :       nsCString spec = sheet->GetSheetURI()->GetSpecOrDefault();
    1308           0 :       CopyUTF8toUTF16(spec, href);
    1309             :     } else {
    1310           0 :       NS_WARNING("null parent stylesheet for @font-face rule");
    1311           0 :       href.AssignLiteral("unknown");
    1312             :     }
    1313           0 :     line = rule->GetLineNumber();
    1314           0 :     column = rule->GetColumnNumber();
    1315             :   }
    1316             : 
    1317             :   nsCOMPtr<nsIScriptError> scriptError =
    1318           0 :     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
    1319           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1320             : 
    1321           0 :   uint64_t innerWindowID = mDocument->InnerWindowID();
    1322           0 :   rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(message),
    1323             :                                      href,         // file
    1324             :                                      text,         // src line
    1325             :                                      line,
    1326             :                                      column,
    1327             :                                      aFlags,       // flags
    1328             :                                      "CSS Loader", // category (make separate?)
    1329             :                                      innerWindowID);
    1330           0 :   if (NS_SUCCEEDED(rv)) {
    1331           0 :     console->LogMessage(scriptError);
    1332             :   }
    1333             : 
    1334           0 :   return NS_OK;
    1335             : }
    1336             : 
    1337             : gfxFontSrcPrincipal*
    1338           0 : FontFaceSet::GetStandardFontLoadPrincipal()
    1339             : {
    1340           0 :   if (!ServoStyleSet::IsInServoTraversal()) {
    1341           0 :     UpdateStandardFontLoadPrincipal();
    1342             :   }
    1343             : 
    1344           0 :   return mStandardFontLoadPrincipal;
    1345             : }
    1346             : 
    1347             : nsresult
    1348           0 : FontFaceSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
    1349             :                            gfxFontSrcPrincipal** aPrincipal,
    1350             :                            bool* aBypassCache)
    1351             : {
    1352           0 :   NS_ASSERTION(aFontFaceSrc &&
    1353             :                aFontFaceSrc->mSourceType == gfxFontFaceSrc::eSourceType_URL,
    1354             :                "bad font face url passed to fontloader");
    1355             : 
    1356             :   // check same-site origin
    1357             : 
    1358           0 :   NS_ASSERTION(aFontFaceSrc->mURI, "null font uri");
    1359           0 :   if (!aFontFaceSrc->mURI)
    1360           0 :     return NS_ERROR_FAILURE;
    1361             : 
    1362             :   // use document principal, original principal if flag set
    1363             :   // this enables user stylesheets to load font files via
    1364             :   // @font-face rules
    1365           0 :   *aPrincipal = GetStandardFontLoadPrincipal();
    1366             : 
    1367           0 :   NS_ASSERTION(aFontFaceSrc->mOriginPrincipal,
    1368             :                "null origin principal in @font-face rule");
    1369           0 :   if (aFontFaceSrc->mUseOriginPrincipal) {
    1370           0 :     *aPrincipal = aFontFaceSrc->mOriginPrincipal;
    1371             :   }
    1372             : 
    1373           0 :   *aBypassCache = mBypassCache;
    1374             : 
    1375           0 :   return NS_OK;
    1376             : }
    1377             : 
    1378             : // @arg aPrincipal: generally this is mDocument->NodePrincipal() but
    1379             : // might also be the original principal which enables user stylesheets
    1380             : // to load font files via @font-face rules.
    1381             : bool
    1382           0 : FontFaceSet::IsFontLoadAllowed(nsIURI* aFontLocation, nsIPrincipal* aPrincipal)
    1383             : {
    1384           0 :   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
    1385           0 :   nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_FONT,
    1386             :                                           aFontLocation,
    1387             :                                           aPrincipal,
    1388             :                                           mDocument,
    1389           0 :                                           EmptyCString(), // mime type
    1390             :                                           nullptr, // aExtra
    1391             :                                           &shouldLoad,
    1392             :                                           nsContentUtils::GetContentPolicy(),
    1393           0 :                                           nsContentUtils::GetSecurityManager());
    1394             : 
    1395           0 :   return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
    1396             : }
    1397             : 
    1398             : nsresult
    1399           0 : FontFaceSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
    1400             :                               const gfxFontFaceSrc* aFontFaceSrc,
    1401             :                               uint8_t*& aBuffer,
    1402             :                               uint32_t& aBufferLength)
    1403             : {
    1404             :   nsresult rv;
    1405             : 
    1406           0 :   gfxFontSrcPrincipal* principal = aFontToLoad->GetPrincipal();
    1407             : 
    1408           0 :   nsCOMPtr<nsIChannel> channel;
    1409             :   // Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
    1410             :   // node and a principal.  This is because the document where the font is
    1411             :   // being loaded might have a different origin from the principal of the
    1412             :   // stylesheet that initiated the font load.
    1413             :   // Further, we only get here for data: loads, so it doesn't really matter
    1414             :   // whether we use SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS or not, to be more
    1415             :   // restrictive we use SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS.
    1416           0 :   rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
    1417             :                                             aFontFaceSrc->mURI->get(),
    1418             :                                             mDocument,
    1419             :                                             principal ? principal->get() : nullptr,
    1420             :                                             nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
    1421           0 :                                             nsIContentPolicy::TYPE_FONT);
    1422             : 
    1423           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1424             : 
    1425             :   // blocking stream is OK for data URIs
    1426           0 :   nsCOMPtr<nsIInputStream> stream;
    1427           0 :   rv = channel->Open2(getter_AddRefs(stream));
    1428           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1429             : 
    1430             :   uint64_t bufferLength64;
    1431           0 :   rv = stream->Available(&bufferLength64);
    1432           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1433           0 :   if (bufferLength64 == 0) {
    1434           0 :     return NS_ERROR_FAILURE;
    1435             :   }
    1436           0 :   if (bufferLength64 > UINT32_MAX) {
    1437           0 :     return NS_ERROR_FILE_TOO_BIG;
    1438             :   }
    1439           0 :   aBufferLength = static_cast<uint32_t>(bufferLength64);
    1440             : 
    1441             :   // read all the decoded data
    1442           0 :   aBuffer = static_cast<uint8_t*> (moz_xmalloc(sizeof(uint8_t) * aBufferLength));
    1443           0 :   if (!aBuffer) {
    1444           0 :     aBufferLength = 0;
    1445           0 :     return NS_ERROR_OUT_OF_MEMORY;
    1446             :   }
    1447             : 
    1448           0 :   uint32_t numRead, totalRead = 0;
    1449           0 :   while (NS_SUCCEEDED(rv =
    1450             :            stream->Read(reinterpret_cast<char*>(aBuffer + totalRead),
    1451           0 :                         aBufferLength - totalRead, &numRead)) &&
    1452           0 :          numRead != 0)
    1453             :   {
    1454           0 :     totalRead += numRead;
    1455           0 :     if (totalRead > aBufferLength) {
    1456           0 :       rv = NS_ERROR_FAILURE;
    1457           0 :       break;
    1458             :     }
    1459             :   }
    1460             : 
    1461             :   // make sure there's a mime type
    1462           0 :   if (NS_SUCCEEDED(rv)) {
    1463           0 :     nsAutoCString mimeType;
    1464           0 :     rv = channel->GetContentType(mimeType);
    1465           0 :     aBufferLength = totalRead;
    1466             :   }
    1467             : 
    1468           0 :   if (NS_FAILED(rv)) {
    1469           0 :     free(aBuffer);
    1470           0 :     aBuffer = nullptr;
    1471           0 :     aBufferLength = 0;
    1472           0 :     return rv;
    1473             :   }
    1474             : 
    1475           0 :   return NS_OK;
    1476             : }
    1477             : 
    1478             : void
    1479           0 : FontFaceSet::OnFontFaceStatusChanged(FontFace* aFontFace)
    1480             : {
    1481           0 :   AssertIsMainThreadOrServoFontMetricsLocked();
    1482             : 
    1483           0 :   MOZ_ASSERT(HasAvailableFontFace(aFontFace));
    1484             : 
    1485           0 :   mHasLoadingFontFacesIsDirty = true;
    1486             : 
    1487           0 :   if (aFontFace->Status() == FontFaceLoadStatus::Loading) {
    1488           0 :     CheckLoadingStarted();
    1489             :   } else {
    1490           0 :     MOZ_ASSERT(aFontFace->Status() == FontFaceLoadStatus::Loaded ||
    1491             :                aFontFace->Status() == FontFaceLoadStatus::Error);
    1492             :     // When a font finishes downloading, nsPresContext::UserFontSetUpdated
    1493             :     // will be called immediately afterwards to request a reflow of the
    1494             :     // relevant elements in the document.  We want to wait until the reflow
    1495             :     // request has been done before the FontFaceSet is marked as Loaded so
    1496             :     // that we don't briefly set the FontFaceSet to Loaded and then Loading
    1497             :     // again once the reflow is pending.  So we go around the event loop
    1498             :     // and call CheckLoadingFinished() after the reflow has been queued.
    1499           0 :     if (!mDelayedLoadCheck) {
    1500           0 :       mDelayedLoadCheck = true;
    1501           0 :       DispatchCheckLoadingFinishedAfterDelay();
    1502             :     }
    1503             :   }
    1504           0 : }
    1505             : 
    1506             : void
    1507           0 : FontFaceSet::DispatchCheckLoadingFinishedAfterDelay()
    1508             : {
    1509           0 :   AssertIsMainThreadOrServoFontMetricsLocked();
    1510             : 
    1511           0 :   if (ServoStyleSet* set = ServoStyleSet::Current()) {
    1512             :     // See comments in Gecko_GetFontMetrics.
    1513             :     //
    1514             :     // We can't just dispatch the runnable below if we're not on the main
    1515             :     // thread, since it needs to take a strong reference to the FontFaceSet,
    1516             :     // and being a DOM object, FontFaceSet doesn't support thread-safe
    1517             :     // refcounting.
    1518           0 :     set->AppendTask(PostTraversalTask::DispatchFontFaceSetCheckLoadingFinishedAfterDelay(this));
    1519           0 :     return;
    1520             :   }
    1521             : 
    1522             :   nsCOMPtr<nsIRunnable> checkTask =
    1523           0 :     NewRunnableMethod("dom::FontFaceSet::CheckLoadingFinishedAfterDelay",
    1524             :                       this,
    1525           0 :                       &FontFaceSet::CheckLoadingFinishedAfterDelay);
    1526           0 :   mDocument->Dispatch("FontFaceSet::CheckLoadingFinishedAfterDelay",
    1527           0 :                       TaskCategory::Other, checkTask.forget());
    1528             : }
    1529             : 
    1530             : void
    1531           0 : FontFaceSet::DidRefresh()
    1532             : {
    1533           0 :   CheckLoadingFinished();
    1534           0 : }
    1535             : 
    1536             : void
    1537           0 : FontFaceSet::CheckLoadingFinishedAfterDelay()
    1538             : {
    1539           0 :   mDelayedLoadCheck = false;
    1540           0 :   CheckLoadingFinished();
    1541           0 : }
    1542             : 
    1543             : void
    1544           0 : FontFaceSet::CheckLoadingStarted()
    1545             : {
    1546           0 :   AssertIsMainThreadOrServoFontMetricsLocked();
    1547             : 
    1548           0 :   if (!HasLoadingFontFaces()) {
    1549           0 :     return;
    1550             :   }
    1551             : 
    1552           0 :   if (mStatus == FontFaceSetLoadStatus::Loading) {
    1553             :     // We have already dispatched a loading event and replaced mReady
    1554             :     // with a fresh, unresolved promise.
    1555           0 :     return;
    1556             :   }
    1557             : 
    1558           0 :   mStatus = FontFaceSetLoadStatus::Loading;
    1559           0 :   DispatchLoadingEventAndReplaceReadyPromise();
    1560             : }
    1561             : 
    1562             : void
    1563           0 : FontFaceSet::DispatchLoadingEventAndReplaceReadyPromise()
    1564             : {
    1565           0 :   AssertIsMainThreadOrServoFontMetricsLocked();
    1566             : 
    1567           0 :   if (ServoStyleSet* set = ServoStyleSet::Current()) {
    1568             :     // See comments in Gecko_GetFontMetrics.
    1569             :     //
    1570             :     // We can't just dispatch the runnable below if we're not on the main
    1571             :     // thread, since it needs to take a strong reference to the FontFaceSet,
    1572             :     // and being a DOM object, FontFaceSet doesn't support thread-safe
    1573             :     // refcounting.  (Also, the Promise object creation must be done on
    1574             :     // the main thread.)
    1575           0 :     set->AppendTask(
    1576           0 :       PostTraversalTask::DispatchLoadingEventAndReplaceReadyPromise(this));
    1577           0 :     return;
    1578             :   }
    1579             : 
    1580           0 :   (new AsyncEventDispatcher(this, NS_LITERAL_STRING("loading"),
    1581           0 :                             false))->PostDOMEvent();
    1582             : 
    1583           0 :   if (PrefEnabled()) {
    1584           0 :     if (mReady) {
    1585           0 :       if (GetParentObject()) {
    1586           0 :         ErrorResult rv;
    1587           0 :         mReady = Promise::Create(GetParentObject(), rv);
    1588             :       }
    1589             :     }
    1590           0 :     if (!mReady) {
    1591           0 :       mResolveLazilyCreatedReadyPromise = false;
    1592             :     }
    1593             :   }
    1594             : }
    1595             : 
    1596             : void
    1597           0 : FontFaceSet::UpdateHasLoadingFontFaces()
    1598             : {
    1599           0 :   mHasLoadingFontFacesIsDirty = false;
    1600           0 :   mHasLoadingFontFaces = false;
    1601           0 :   for (size_t i = 0; i < mRuleFaces.Length(); i++) {
    1602           0 :     FontFace* f = mRuleFaces[i].mFontFace;
    1603           0 :     if (f->Status() == FontFaceLoadStatus::Loading) {
    1604           0 :       mHasLoadingFontFaces = true;
    1605           0 :       return;
    1606             :     }
    1607             :   }
    1608           0 :   for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
    1609           0 :     if (mNonRuleFaces[i].mFontFace->Status() == FontFaceLoadStatus::Loading) {
    1610           0 :       mHasLoadingFontFaces = true;
    1611           0 :       return;
    1612             :     }
    1613             :   }
    1614             : }
    1615             : 
    1616             : bool
    1617           0 : FontFaceSet::HasLoadingFontFaces()
    1618             : {
    1619           0 :   if (mHasLoadingFontFacesIsDirty) {
    1620           0 :     UpdateHasLoadingFontFaces();
    1621             :   }
    1622           0 :   return mHasLoadingFontFaces;
    1623             : }
    1624             : 
    1625             : bool
    1626           0 : FontFaceSet::MightHavePendingFontLoads()
    1627             : {
    1628             :   // Check for FontFace objects in the FontFaceSet that are still loading.
    1629           0 :   if (HasLoadingFontFaces()) {
    1630           0 :     return true;
    1631             :   }
    1632             : 
    1633             :   // Check for pending restyles or reflows, as they might cause fonts to
    1634             :   // load as new styles apply and text runs are rebuilt.
    1635           0 :   nsPresContext* presContext = GetPresContext();
    1636           0 :   if (presContext && presContext->HasPendingRestyleOrReflow()) {
    1637           0 :     return true;
    1638             :   }
    1639             : 
    1640           0 :   if (mDocument) {
    1641             :     // We defer resolving mReady until the document as fully loaded.
    1642           0 :     if (!mDocument->DidFireDOMContentLoaded()) {
    1643           0 :       return true;
    1644             :     }
    1645             : 
    1646             :     // And we also wait for any CSS style sheets to finish loading, as their
    1647             :     // styles might cause new fonts to load.
    1648           0 :     if (mDocument->CSSLoader()->HasPendingLoads()) {
    1649           0 :       return true;
    1650             :     }
    1651             :   }
    1652             : 
    1653           0 :   return false;
    1654             : }
    1655             : 
    1656             : void
    1657           0 : FontFaceSet::CheckLoadingFinished()
    1658             : {
    1659           0 :   MOZ_ASSERT(NS_IsMainThread());
    1660             : 
    1661           0 :   if (mDelayedLoadCheck) {
    1662             :     // Wait until the runnable posted in OnFontFaceStatusChanged calls us.
    1663           0 :     return;
    1664             :   }
    1665             : 
    1666           0 :   if (mStatus == FontFaceSetLoadStatus::Loaded) {
    1667             :     // We've already resolved mReady and dispatched the loadingdone/loadingerror
    1668             :     // events.
    1669           0 :     return;
    1670             :   }
    1671             : 
    1672           0 :   if (MightHavePendingFontLoads()) {
    1673             :     // We're not finished loading yet.
    1674           0 :     return;
    1675             :   }
    1676             : 
    1677           0 :   mStatus = FontFaceSetLoadStatus::Loaded;
    1678           0 :   if (mReady) {
    1679           0 :     mReady->MaybeResolve(this);
    1680             :   } else {
    1681           0 :     mResolveLazilyCreatedReadyPromise = true;
    1682             :   }
    1683             : 
    1684             :   // Now dispatch the loadingdone/loadingerror events.
    1685           0 :   nsTArray<OwningNonNull<FontFace>> loaded;
    1686           0 :   nsTArray<OwningNonNull<FontFace>> failed;
    1687             : 
    1688           0 :   for (size_t i = 0; i < mRuleFaces.Length(); i++) {
    1689           0 :     if (!mRuleFaces[i].mLoadEventShouldFire) {
    1690           0 :       continue;
    1691             :     }
    1692           0 :     FontFace* f = mRuleFaces[i].mFontFace;
    1693           0 :     if (f->Status() == FontFaceLoadStatus::Loaded) {
    1694           0 :       loaded.AppendElement(*f);
    1695           0 :       mRuleFaces[i].mLoadEventShouldFire = false;
    1696           0 :     } else if (f->Status() == FontFaceLoadStatus::Error) {
    1697           0 :       failed.AppendElement(*f);
    1698           0 :       mRuleFaces[i].mLoadEventShouldFire = false;
    1699             :     }
    1700             :   }
    1701             : 
    1702           0 :   for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
    1703           0 :     if (!mNonRuleFaces[i].mLoadEventShouldFire) {
    1704           0 :       continue;
    1705             :     }
    1706           0 :     FontFace* f = mNonRuleFaces[i].mFontFace;
    1707           0 :     if (f->Status() == FontFaceLoadStatus::Loaded) {
    1708           0 :       loaded.AppendElement(*f);
    1709           0 :       mNonRuleFaces[i].mLoadEventShouldFire = false;
    1710           0 :     } else if (f->Status() == FontFaceLoadStatus::Error) {
    1711           0 :       failed.AppendElement(*f);
    1712           0 :       mNonRuleFaces[i].mLoadEventShouldFire = false;
    1713             :     }
    1714             :   }
    1715             : 
    1716           0 :   DispatchLoadingFinishedEvent(NS_LITERAL_STRING("loadingdone"),
    1717           0 :                                Move(loaded));
    1718             : 
    1719           0 :   if (!failed.IsEmpty()) {
    1720           0 :     DispatchLoadingFinishedEvent(NS_LITERAL_STRING("loadingerror"),
    1721           0 :                                  Move(failed));
    1722             :   }
    1723             : }
    1724             : 
    1725             : void
    1726           0 : FontFaceSet::DispatchLoadingFinishedEvent(
    1727             :                                  const nsAString& aType,
    1728             :                                  nsTArray<OwningNonNull<FontFace>>&& aFontFaces)
    1729             : {
    1730           0 :   FontFaceSetLoadEventInit init;
    1731           0 :   init.mBubbles = false;
    1732           0 :   init.mCancelable = false;
    1733           0 :   init.mFontfaces.SwapElements(aFontFaces);
    1734             :   RefPtr<FontFaceSetLoadEvent> event =
    1735           0 :     FontFaceSetLoadEvent::Constructor(this, aType, init);
    1736           0 :   (new AsyncEventDispatcher(this, event))->PostDOMEvent();
    1737           0 : }
    1738             : 
    1739             : // nsIDOMEventListener
    1740             : 
    1741             : NS_IMETHODIMP
    1742           0 : FontFaceSet::HandleEvent(nsIDOMEvent* aEvent)
    1743             : {
    1744           0 :   nsString type;
    1745           0 :   aEvent->GetType(type);
    1746             : 
    1747           0 :   if (!type.EqualsLiteral("DOMContentLoaded")) {
    1748           0 :     return NS_ERROR_FAILURE;
    1749             :   }
    1750             : 
    1751           0 :   RemoveDOMContentLoadedListener();
    1752           0 :   CheckLoadingFinished();
    1753             : 
    1754           0 :   return NS_OK;
    1755             : }
    1756             : 
    1757             : /* static */ bool
    1758           0 : FontFaceSet::PrefEnabled()
    1759             : {
    1760             :   static bool initialized = false;
    1761             :   static bool enabled;
    1762           0 :   if (!initialized) {
    1763           0 :     initialized = true;
    1764           0 :     Preferences::AddBoolVarCache(&enabled, FONT_LOADING_API_ENABLED_PREF);
    1765             :   }
    1766           0 :   return enabled;
    1767             : }
    1768             : 
    1769             : // nsICSSLoaderObserver
    1770             : 
    1771             : NS_IMETHODIMP
    1772           0 : FontFaceSet::StyleSheetLoaded(StyleSheet* aSheet,
    1773             :                               bool aWasAlternate,
    1774             :                               nsresult aStatus)
    1775             : {
    1776           0 :   CheckLoadingFinished();
    1777           0 :   return NS_OK;
    1778             : }
    1779             : 
    1780             : void
    1781           0 : FontFaceSet::FlushUserFontSet()
    1782             : {
    1783           0 :   if (mDocument) {
    1784           0 :     mDocument->FlushUserFontSet();
    1785             :   }
    1786           0 : }
    1787             : 
    1788             : void
    1789           0 : FontFaceSet::RebuildUserFontSet()
    1790             : {
    1791           0 :   if (mDocument) {
    1792           0 :     mDocument->RebuildUserFontSet();
    1793             :   }
    1794           0 : }
    1795             : 
    1796             : nsPresContext*
    1797           0 : FontFaceSet::GetPresContext()
    1798             : {
    1799           0 :   if (!mDocument) {
    1800           0 :     return nullptr;
    1801             :   }
    1802             : 
    1803           0 :   nsIPresShell* shell = mDocument->GetShell();
    1804           0 :   return shell ? shell->GetPresContext() : nullptr;
    1805             : }
    1806             : 
    1807             : void
    1808           0 : FontFaceSet::UpdateStandardFontLoadPrincipal()
    1809             : {
    1810           0 :   MOZ_ASSERT(NS_IsMainThread());
    1811             : 
    1812           0 :   nsIPrincipal* documentPrincipal = mDocument->NodePrincipal();
    1813             : 
    1814           0 :   if (!mStandardFontLoadPrincipal ||
    1815           0 :       mStandardFontLoadPrincipal->get() != documentPrincipal) {
    1816           0 :     if (mStandardFontLoadPrincipal) {
    1817           0 :       mHasStandardFontLoadPrincipalChanged = true;
    1818             :     }
    1819           0 :     mStandardFontLoadPrincipal = new gfxFontSrcPrincipal(documentPrincipal);
    1820             :   }
    1821           0 : }
    1822             : 
    1823             : // -- FontFaceSet::UserFontSet ------------------------------------------------
    1824             : 
    1825             : /* virtual */ nsresult
    1826           0 : FontFaceSet::UserFontSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
    1827             :                                         gfxFontSrcPrincipal** aPrincipal,
    1828             :                                         bool* aBypassCache)
    1829             : {
    1830           0 :   if (!mFontFaceSet) {
    1831           0 :     return NS_ERROR_FAILURE;
    1832             :   }
    1833           0 :   return mFontFaceSet->CheckFontLoad(aFontFaceSrc, aPrincipal, aBypassCache);
    1834             : }
    1835             : 
    1836             : /* virtual */ gfxFontSrcPrincipal*
    1837           0 : FontFaceSet::UserFontSet::GetStandardFontLoadPrincipal()
    1838             : {
    1839           0 :   if (!mFontFaceSet) {
    1840           0 :     return nullptr;
    1841             :   }
    1842           0 :   return mFontFaceSet->GetStandardFontLoadPrincipal();
    1843             : }
    1844             : 
    1845             : /* virtual */ bool
    1846           0 : FontFaceSet::UserFontSet::IsFontLoadAllowed(nsIURI* aFontLocation,
    1847             :                                             nsIPrincipal* aPrincipal)
    1848             : {
    1849           0 :   return mFontFaceSet &&
    1850           0 :          mFontFaceSet->IsFontLoadAllowed(aFontLocation, aPrincipal);
    1851             : }
    1852             : 
    1853             : /* virtual */ nsresult
    1854           0 : FontFaceSet::UserFontSet::StartLoad(gfxUserFontEntry* aUserFontEntry,
    1855             :                                     const gfxFontFaceSrc* aFontFaceSrc)
    1856             : {
    1857           0 :   if (!mFontFaceSet) {
    1858           0 :     return NS_ERROR_FAILURE;
    1859             :   }
    1860           0 :   return mFontFaceSet->StartLoad(aUserFontEntry, aFontFaceSrc);
    1861             : }
    1862             : 
    1863             : void
    1864           0 : FontFaceSet::UserFontSet::RecordFontLoadDone(uint32_t aFontSize,
    1865             :                                              TimeStamp aDoneTime)
    1866             : {
    1867           0 :   mDownloadCount++;
    1868           0 :   mDownloadSize += aFontSize;
    1869           0 :   Telemetry::Accumulate(Telemetry::WEBFONT_SIZE, aFontSize / 1024);
    1870             : 
    1871           0 :   if (!mFontFaceSet) {
    1872           0 :     return;
    1873             :   }
    1874             : 
    1875           0 :   TimeStamp navStart = mFontFaceSet->GetNavigationStartTimeStamp();
    1876           0 :   TimeStamp zero;
    1877           0 :   if (navStart != zero) {
    1878             :     Telemetry::AccumulateTimeDelta(Telemetry::WEBFONT_DOWNLOAD_TIME_AFTER_START,
    1879           0 :                                    navStart, aDoneTime);
    1880             :   }
    1881             : }
    1882             : 
    1883             : /* virtual */ nsresult
    1884           0 : FontFaceSet::UserFontSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
    1885             :                                      const char* aMessage,
    1886             :                                      uint32_t aFlags,
    1887             :                                      nsresult aStatus)
    1888             : {
    1889           0 :   if (!mFontFaceSet) {
    1890           0 :     return NS_ERROR_FAILURE;
    1891             :   }
    1892           0 :   return mFontFaceSet->LogMessage(aUserFontEntry, aMessage, aFlags, aStatus);
    1893             : }
    1894             : 
    1895             : /* virtual */ nsresult
    1896           0 : FontFaceSet::UserFontSet::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
    1897             :                                            const gfxFontFaceSrc* aFontFaceSrc,
    1898             :                                            uint8_t*& aBuffer,
    1899             :                                            uint32_t& aBufferLength)
    1900             : {
    1901           0 :   if (!mFontFaceSet) {
    1902           0 :     return NS_ERROR_FAILURE;
    1903             :   }
    1904           0 :   return mFontFaceSet->SyncLoadFontData(aFontToLoad, aFontFaceSrc,
    1905           0 :                                         aBuffer, aBufferLength);
    1906             : }
    1907             : 
    1908             : /* virtual */ bool
    1909           0 : FontFaceSet::UserFontSet::GetPrivateBrowsing()
    1910             : {
    1911           0 :   return mFontFaceSet && mFontFaceSet->mPrivateBrowsing;
    1912             : }
    1913             : 
    1914             : /* virtual */ void
    1915           0 : FontFaceSet::UserFontSet::DoRebuildUserFontSet()
    1916             : {
    1917           0 :   if (!mFontFaceSet) {
    1918           0 :     return;
    1919             :   }
    1920           0 :   mFontFaceSet->RebuildUserFontSet();
    1921             : }
    1922             : 
    1923             : /* virtual */ already_AddRefed<gfxUserFontEntry>
    1924           0 : FontFaceSet::UserFontSet::CreateUserFontEntry(
    1925             :                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
    1926             :                                uint32_t aWeight,
    1927             :                                int32_t aStretch,
    1928             :                                uint8_t aStyle,
    1929             :                                const nsTArray<gfxFontFeature>& aFeatureSettings,
    1930             :                                uint32_t aLanguageOverride,
    1931             :                                gfxCharacterMap* aUnicodeRanges,
    1932             :                                uint8_t aFontDisplay)
    1933             : {
    1934             :   RefPtr<gfxUserFontEntry> entry =
    1935             :     new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aStyle,
    1936             :                         aFeatureSettings, aLanguageOverride, aUnicodeRanges,
    1937           0 :                         aFontDisplay);
    1938           0 :   return entry.forget();
    1939             : }
    1940             : 
    1941             : #undef LOG_ENABLED
    1942             : #undef LOG

Generated by: LCOV version 1.13