Bug 1771493 - Part 4. Split FontFaceSetDocumentImpl from FontFaceSetImpl. r=emilio

This patch splits document specific functionality from FontFaceSetImpl
into a new class FontFaceSetDocumentImpl. This will make it easier to
fork FontFaceSetImpl for workers.

Differential Revision: https://phabricator.services.mozilla.com/D147819
This commit is contained in:
Andrew Osmond 2022-06-28 21:47:01 +00:00
Родитель 7c2ad16f5c
Коммит 091dc0483c
8 изменённых файлов: 917 добавлений и 687 удалений

Просмотреть файл

@ -16122,8 +16122,7 @@ void Document::FlushUserFontSet() {
}
if (!mFontFaceSet && !rules.IsEmpty()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
mFontFaceSet = new FontFaceSet(window, this);
mFontFaceSet = FontFaceSet::CreateForDocument(this);
}
bool changed = false;
@ -16155,8 +16154,7 @@ void Document::MarkUserFontSetDirty() {
FontFaceSet* Document::Fonts() {
if (!mFontFaceSet) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
mFontFaceSet = new FontFaceSet(window, this);
mFontFaceSet = FontFaceSet::CreateForDocument(this);
FlushUserFontSet();
}
return mFontFaceSet;

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/dom/Event.h"
#include "mozilla/dom/FontFaceImpl.h"
#include "mozilla/dom/FontFaceSetBinding.h"
#include "mozilla/dom/FontFaceSetDocumentImpl.h"
#include "mozilla/dom/FontFaceSetIterator.h"
#include "mozilla/dom/FontFaceSetLoadEvent.h"
#include "mozilla/dom/FontFaceSetLoadEventBinding.h"
@ -93,11 +94,8 @@ NS_IMPL_RELEASE_INHERITED(FontFaceSet, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFaceSet)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
FontFaceSet::FontFaceSet(nsPIDOMWindowInner* aWindow, dom::Document* aDocument)
: DOMEventTargetHelper(aWindow),
mImpl(new FontFaceSetImpl(this, aDocument)) {
mImpl->Initialize();
}
FontFaceSet::FontFaceSet(nsIGlobalObject* aParent)
: DOMEventTargetHelper(aParent) {}
FontFaceSet::~FontFaceSet() {
// Assert that we don't drop any FontFaceSet objects during a Servo traversal,
@ -107,6 +105,16 @@ FontFaceSet::~FontFaceSet() {
Destroy();
}
/* static */ already_AddRefed<FontFaceSet> FontFaceSet::CreateForDocument(
dom::Document* aDocument) {
RefPtr<FontFaceSet> set = new FontFaceSet(aDocument->GetScopeObject());
RefPtr<FontFaceSetDocumentImpl> impl =
new FontFaceSetDocumentImpl(set, aDocument);
impl->Initialize();
set->mImpl = std::move(impl);
return set.forget();
}
JSObject* FontFaceSet::WrapObject(JSContext* aContext,
JS::Handle<JSObject*> aGivenProto) {
return FontFaceSet_Binding::Wrap(aContext, this, aGivenProto);

Просмотреть файл

@ -16,7 +16,7 @@
class nsFontFaceLoader;
class nsIPrincipal;
class nsPIDOMWindowInner;
class nsIGlobalObject;
struct RawServoFontFaceRule;
namespace mozilla {
@ -36,7 +36,8 @@ class FontFaceSet final : public DOMEventTargetHelper {
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
FontFaceSet(nsPIDOMWindowInner* aWindow, dom::Document* aDocument);
static already_AddRefed<FontFaceSet> CreateForDocument(
dom::Document* aDocument);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
@ -112,6 +113,7 @@ class FontFaceSet final : public DOMEventTargetHelper {
private:
friend mozilla::dom::FontFaceSetIterator; // needs GetFontFaceAt()
explicit FontFaceSet(nsIGlobalObject* aParent);
~FontFaceSet();
/**

Просмотреть файл

@ -0,0 +1,694 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FontFaceSetDocumentImpl.h"
#include "FontPreloader.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/PresShell.h"
#include "mozilla/PresShellInlines.h"
#include "mozilla/css/Loader.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/FontFaceImpl.h"
#include "mozilla/dom/FontFaceSet.h"
#include "nsContentPolicyUtils.h"
#include "nsDOMNavigationTiming.h"
#include "nsFontFaceLoader.h"
#include "nsIDocShell.h"
#include "nsINetworkPredictor.h"
#include "nsIWebNavigation.h"
#include "nsPresContext.h"
using namespace mozilla;
using namespace mozilla::css;
using namespace mozilla::dom;
#define LOG(args) \
MOZ_LOG(gfxUserFontSet::GetUserFontsLog(), mozilla::LogLevel::Debug, args)
#define LOG_ENABLED() \
MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), LogLevel::Debug)
NS_IMPL_ISUPPORTS_INHERITED(FontFaceSetDocumentImpl, FontFaceSetImpl,
nsIDOMEventListener, nsICSSLoaderObserver)
FontFaceSetDocumentImpl::FontFaceSetDocumentImpl(FontFaceSet* aOwner,
dom::Document* aDocument)
: FontFaceSetImpl(aOwner), mDocument(aDocument) {}
FontFaceSetDocumentImpl::~FontFaceSetDocumentImpl() = default;
void FontFaceSetDocumentImpl::Initialize() {
MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
// Record the state of the "bypass cache" flags from the docshell now,
// since we want to look at them from style worker threads, and we can
// only get to the docshell through a weak pointer (which is only
// possible on the main thread).
//
// In theory the load type of a docshell could change after the document
// is loaded, but handling that doesn't seem too important.
if (nsCOMPtr<nsIDocShell> docShell = mDocument->GetDocShell()) {
uint32_t loadType;
uint32_t flags;
if ((NS_SUCCEEDED(docShell->GetLoadType(&loadType)) &&
((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)) ||
(NS_SUCCEEDED(docShell->GetDefaultLoadFlags(&flags)) &&
(flags & nsIRequest::LOAD_BYPASS_CACHE))) {
mBypassCache = true;
}
}
// Same for the "private browsing" flag.
if (nsCOMPtr<nsILoadContext> loadContext = mDocument->GetLoadContext()) {
mPrivateBrowsing = loadContext->UsePrivateBrowsing();
}
if (!mDocument->DidFireDOMContentLoaded()) {
mDocument->AddSystemEventListener(u"DOMContentLoaded"_ns, this, false,
false);
} else {
// In some cases we can't rely on CheckLoadingFinished being called from
// the refresh driver. For example, documents in display:none iframes.
// Or if the document has finished loading and painting at the time that
// script requests document.fonts and causes us to get here.
CheckLoadingFinished();
}
mDocument->CSSLoader()->AddObserver(this);
mStandardFontLoadPrincipal = CreateStandardFontLoadPrincipal();
}
void FontFaceSetDocumentImpl::Destroy() {
RemoveDOMContentLoadedListener();
if (mDocument && mDocument->CSSLoader()) {
// We're null checking CSSLoader() since FontFaceSetImpl::Disconnect() might
// be being called during unlink, at which time the loader may already have
// been unlinked from the document.
mDocument->CSSLoader()->RemoveObserver(this);
}
mRuleFaces.Clear();
mDocument = nullptr;
FontFaceSetImpl::Destroy();
}
uint64_t FontFaceSetDocumentImpl::GetInnerWindowID() {
MOZ_ASSERT(NS_IsMainThread());
if (!mDocument) {
return 0;
}
return mDocument->InnerWindowID();
}
nsPresContext* FontFaceSetDocumentImpl::GetPresContext() const {
MOZ_ASSERT(NS_IsMainThread());
if (!mDocument) {
return nullptr;
}
return mDocument->GetPresContext();
}
already_AddRefed<gfxFontSrcPrincipal>
FontFaceSetDocumentImpl::CreateStandardFontLoadPrincipal() const {
MOZ_ASSERT(NS_IsMainThread());
return MakeAndAddRef<gfxFontSrcPrincipal>(mDocument->NodePrincipal(),
mDocument->PartitionedPrincipal());
}
void FontFaceSetDocumentImpl::RemoveDOMContentLoadedListener() {
if (mDocument) {
mDocument->RemoveSystemEventListener(u"DOMContentLoaded"_ns, this, false);
}
}
void FontFaceSetDocumentImpl::FindMatchingFontFaces(
const nsTHashSet<FontFace*>& aMatchingFaces,
nsTArray<FontFace*>& aFontFaces) {
FontFaceSetImpl::FindMatchingFontFaces(aMatchingFaces, aFontFaces);
for (FontFaceRecord& record : mRuleFaces) {
FontFace* owner = record.mFontFace->GetOwner();
if (owner && aMatchingFaces.Contains(owner)) {
aFontFaces.AppendElement(owner);
}
}
}
TimeStamp FontFaceSetDocumentImpl::GetNavigationStartTimeStamp() {
TimeStamp navStart;
RefPtr<nsDOMNavigationTiming> timing(mDocument->GetNavigationTiming());
if (timing) {
navStart = timing->GetNavigationStartTimeStamp();
}
return navStart;
}
void FontFaceSetDocumentImpl::EnsureReady() {
MOZ_ASSERT(NS_IsMainThread());
// There may be outstanding style changes that will trigger the loading of
// new fonts. We need to flush layout to initiate any such loads so that
// if mReady is currently resolved we replace it with a new pending Promise.
// (That replacement will happen under this flush call.)
if (!ReadyPromiseIsPending() && mDocument) {
mDocument->FlushPendingNotifications(FlushType::Layout);
}
}
#ifdef DEBUG
bool FontFaceSetDocumentImpl::HasRuleFontFace(FontFaceImpl* aFontFace) {
for (size_t i = 0; i < mRuleFaces.Length(); i++) {
if (mRuleFaces[i].mFontFace == aFontFace) {
return true;
}
}
return false;
}
#endif
bool FontFaceSetDocumentImpl::Add(FontFaceImpl* aFontFace, ErrorResult& aRv) {
if (!FontFaceSetImpl::Add(aFontFace, aRv)) {
return false;
}
RefPtr<dom::Document> clonedDoc = mDocument->GetLatestStaticClone();
if (clonedDoc) {
// The document is printing, copy the font to the static clone as well.
nsCOMPtr<nsIPrincipal> principal = mDocument->GetPrincipal();
if (principal->IsSystemPrincipal() || nsContentUtils::IsPDFJS(principal)) {
ErrorResult rv;
clonedDoc->Fonts()->Add(*aFontFace->GetOwner(), rv);
MOZ_ASSERT(!rv.Failed());
}
}
return true;
}
nsresult FontFaceSetDocumentImpl::StartLoad(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex) {
nsresult rv;
nsCOMPtr<nsIStreamLoader> streamLoader;
RefPtr<nsFontFaceLoader> fontLoader;
const gfxFontFaceSrc& src = aUserFontEntry->SourceAt(aSrcIndex);
auto preloadKey =
PreloadHashKey::CreateAsFont(src.mURI->get(), CORS_ANONYMOUS);
RefPtr<PreloaderBase> preload =
mDocument->Preloads().LookupPreload(preloadKey);
if (preload) {
fontLoader = new nsFontFaceLoader(aUserFontEntry, aSrcIndex, this,
preload->Channel());
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader,
fontLoader);
NS_ENSURE_SUCCESS(rv, rv);
rv = preload->AsyncConsume(streamLoader);
// We don't want this to hang around regardless of the result, there will be
// no coalescing of later found <link preload> tags for fonts.
preload->RemoveSelf(mDocument);
} else {
// No preload found, open a channel.
rv = NS_ERROR_FAILURE;
}
nsCOMPtr<nsILoadGroup> loadGroup(mDocument->GetDocumentLoadGroup());
if (NS_FAILED(rv)) {
nsCOMPtr<nsIChannel> channel;
rv = FontPreloader::BuildChannel(
getter_AddRefs(channel), src.mURI->get(), CORS_ANONYMOUS,
dom::ReferrerPolicy::_empty /* not used */, aUserFontEntry, &src,
mDocument, loadGroup, nullptr, false);
NS_ENSURE_SUCCESS(rv, rv);
fontLoader = new nsFontFaceLoader(aUserFontEntry, aSrcIndex, this, channel);
if (LOG_ENABLED()) {
nsCOMPtr<nsIURI> referrer = src.mReferrerInfo
? src.mReferrerInfo->GetOriginalReferrer()
: nullptr;
LOG((
"userfonts (%p) download start - font uri: (%s) referrer uri: (%s)\n",
fontLoader.get(), src.mURI->GetSpecOrDefault().get(),
referrer ? referrer->GetSpecOrDefault().get() : ""));
}
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader,
fontLoader);
NS_ENSURE_SUCCESS(rv, rv);
rv = channel->AsyncOpen(streamLoader);
if (NS_FAILED(rv)) {
fontLoader->DropChannel(); // explicitly need to break ref cycle
}
}
mLoaders.PutEntry(fontLoader);
net::PredictorLearn(src.mURI->get(), mDocument->GetDocumentURI(),
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, loadGroup);
if (NS_SUCCEEDED(rv)) {
fontLoader->StartedLoading(streamLoader);
// let the font entry remember the loader, in case we need to cancel it
aUserFontEntry->SetLoader(fontLoader);
}
return rv;
}
bool FontFaceSetDocumentImpl::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc) {
MOZ_ASSERT(aSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL);
if (ServoStyleSet::IsInServoTraversal()) {
auto entry = mAllowedFontLoads.Lookup(&aSrc);
MOZ_DIAGNOSTIC_ASSERT(entry, "Missed an update?");
return entry ? *entry : false;
}
MOZ_ASSERT(NS_IsMainThread());
if (aSrc.mUseOriginPrincipal) {
return true;
}
RefPtr<gfxFontSrcPrincipal> gfxPrincipal =
aSrc.mURI->InheritsSecurityContext() ? nullptr
: aSrc.LoadPrincipal(*this);
nsIPrincipal* principal =
gfxPrincipal ? gfxPrincipal->NodePrincipal() : nullptr;
nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new net::LoadInfo(
mDocument->NodePrincipal(), // loading principal
principal, // triggering principal
mDocument, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
nsIContentPolicy::TYPE_FONT);
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv = NS_CheckContentLoadPolicy(aSrc.mURI->get(), secCheckLoadInfo,
""_ns, // mime type
&shouldLoad,
nsContentUtils::GetContentPolicy());
return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
}
nsresult FontFaceSetDocumentImpl::CreateChannelForSyncLoadFontData(
nsIChannel** aOutChannel, gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc) {
gfxFontSrcPrincipal* principal = aFontToLoad->GetPrincipal();
// Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
// node and a principal. This is because the document where the font is
// being loaded might have a different origin from the principal of the
// stylesheet that initiated the font load.
// Further, we only get here for data: loads, so it doesn't really matter
// whether we use SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT or not, to be
// more restrictive we use SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT.
return NS_NewChannelWithTriggeringPrincipal(
aOutChannel, aFontFaceSrc->mURI->get(), mDocument,
principal ? principal->NodePrincipal() : nullptr,
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
aFontFaceSrc->mUseOriginPrincipal ? nsIContentPolicy::TYPE_UA_FONT
: nsIContentPolicy::TYPE_FONT);
}
bool FontFaceSetDocumentImpl::UpdateRules(
const nsTArray<nsFontFaceRuleContainer>& aRules) {
// If there was a change to the mNonRuleFaces array, then there could
// have been a modification to the user font set.
bool modified = mNonRuleFacesDirty;
mNonRuleFacesDirty = false;
// reuse existing FontFace objects mapped to rules already
nsTHashMap<nsPtrHashKey<RawServoFontFaceRule>, FontFaceImpl*> ruleFaceMap;
for (size_t i = 0, i_end = mRuleFaces.Length(); i < i_end; ++i) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
if (!f || !f->GetOwner()) {
continue;
}
ruleFaceMap.InsertOrUpdate(f->GetRule(), f);
}
// The @font-face rules that make up the user font set have changed,
// so we need to update the set. However, we want to preserve existing
// font entries wherever possible, so that we don't discard and then
// re-download resources in the (common) case where at least some of the
// same rules are still present.
nsTArray<FontFaceRecord> oldRecords = std::move(mRuleFaces);
// Remove faces from the font family records; we need to re-insert them
// because we might end up with faces in a different order even if they're
// the same font entries as before. (The order can affect font selection
// where multiple faces match the requested style, perhaps with overlapping
// unicode-range coverage.)
for (const auto& fontFamily : mFontFamilies.Values()) {
fontFamily->DetachFontEntries();
}
// Sometimes aRules has duplicate @font-face rules in it; we should make
// that not happen, but in the meantime, don't try to insert the same
// FontFace object more than once into mRuleFaces. We track which
// ones we've handled in this table.
nsTHashSet<RawServoFontFaceRule*> handledRules;
for (size_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
// Insert each FontFace objects for each rule into our list, migrating old
// font entries if possible rather than creating new ones; set modified to
// true if we detect that rule ordering has changed, or if a new entry is
// created.
RawServoFontFaceRule* rule = aRules[i].mRule;
if (!handledRules.EnsureInserted(rule)) {
// rule was already present in the hashtable
continue;
}
RefPtr<FontFaceImpl> faceImpl = ruleFaceMap.Get(rule);
RefPtr<FontFace> face = faceImpl ? faceImpl->GetOwner() : nullptr;
if (mOwner && (!faceImpl || !face)) {
face = FontFace::CreateForRule(mOwner->GetParentObject(), mOwner, rule);
faceImpl = face->GetImpl();
}
InsertRuleFontFace(faceImpl, face, aRules[i].mOrigin, oldRecords, modified);
}
for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
// Do the same for the non rule backed FontFace objects.
InsertNonRuleFontFace(mNonRuleFaces[i].mFontFace, modified);
}
// Remove any residual families that have no font entries (i.e., they were
// not defined at all by the updated set of @font-face rules).
for (auto it = mFontFamilies.Iter(); !it.Done(); it.Next()) {
if (!it.Data()->FontListLength()) {
it.Remove();
}
}
// If any FontFace objects for rules are left in the old list, note that the
// set has changed (even if the new set was built entirely by migrating old
// font entries).
if (oldRecords.Length() > 0) {
modified = true;
// Any in-progress loaders for obsolete rules should be cancelled,
// as the resource being downloaded will no longer be required.
// We need to explicitly remove any loaders here, otherwise the loaders
// will keep their "orphaned" font entries alive until they complete,
// even after the oldRules array is deleted.
//
// XXX Now that it is possible for the author to hold on to a rule backed
// FontFace object, we shouldn't cancel loading here; instead we should do
// it when the FontFace is GCed, if we can detect that.
size_t count = oldRecords.Length();
for (size_t i = 0; i < count; ++i) {
RefPtr<FontFaceImpl> f = oldRecords[i].mFontFace;
gfxUserFontEntry* userFontEntry = f->GetUserFontEntry();
if (userFontEntry) {
nsFontFaceLoader* loader = userFontEntry->GetLoader();
if (loader) {
loader->Cancel();
RemoveLoader(loader);
}
}
// Any left over FontFace objects should also cease being rule backed.
f->DisconnectFromRule();
}
}
if (modified) {
IncrementGeneration(true);
mHasLoadingFontFacesIsDirty = true;
CheckLoadingStarted();
CheckLoadingFinished();
}
// if local rules needed to be rebuilt, they have been rebuilt at this point
if (mRebuildLocalRules) {
mLocalRulesUsed = false;
mRebuildLocalRules = false;
}
if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) {
LOG(("userfonts (%p) userfont rules update (%s) rule count: %d", this,
(modified ? "modified" : "not modified"), (int)(mRuleFaces.Length())));
}
return modified;
}
void FontFaceSetDocumentImpl::InsertRuleFontFace(
FontFaceImpl* aFontFace, FontFace* aFontFaceOwner, StyleOrigin aSheetType,
nsTArray<FontFaceRecord>& aOldRecords, bool& aFontSetModified) {
nsAtom* fontFamily = aFontFace->GetFamilyName();
if (!fontFamily) {
// If there is no family name, this rule cannot contribute a
// usable font, so there is no point in processing it further.
return;
}
bool remove = false;
size_t removeIndex;
nsAtomCString family(fontFamily);
// This is a rule backed FontFace. First, we check in aOldRecords; if
// the FontFace for the rule exists there, just move it to the new record
// list, and put the entry into the appropriate family.
for (size_t i = 0; i < aOldRecords.Length(); ++i) {
FontFaceRecord& rec = aOldRecords[i];
if (rec.mFontFace == aFontFace && rec.mOrigin == Some(aSheetType)) {
// if local rules were used, don't use the old font entry
// for rules containing src local usage
if (mLocalRulesUsed && mRebuildLocalRules) {
if (aFontFace->HasLocalSrc()) {
// Remove the old record, but wait to see if we successfully create a
// new user font entry below.
remove = true;
removeIndex = i;
break;
}
}
gfxUserFontEntry* entry = rec.mFontFace->GetUserFontEntry();
MOZ_ASSERT(entry, "FontFace should have a gfxUserFontEntry by now");
AddUserFontEntry(family, entry);
MOZ_ASSERT(!HasRuleFontFace(rec.mFontFace),
"FontFace should not occur in mRuleFaces twice");
mRuleFaces.AppendElement(rec);
aOldRecords.RemoveElementAt(i);
if (mOwner && aFontFaceOwner) {
mOwner->InsertRuleFontFace(aFontFaceOwner, aSheetType);
}
// note the set has been modified if an old rule was skipped to find
// this one - something has been dropped, or ordering changed
if (i > 0) {
aFontSetModified = true;
}
return;
}
}
// this is a new rule:
RefPtr<gfxUserFontEntry> entry =
FindOrCreateUserFontEntryFromFontFace(family, aFontFace, aSheetType);
if (!entry) {
return;
}
if (remove) {
// Although we broke out of the aOldRecords loop above, since we found
// src local usage, and we're not using the old user font entry, we still
// are adding a record to mRuleFaces with the same FontFace object.
// Remove the old record so that we don't have the same FontFace listed
// in both mRuleFaces and oldRecords, which would cause us to call
// DisconnectFromRule on a FontFace that should still be rule backed.
aOldRecords.RemoveElementAt(removeIndex);
}
FontFaceRecord rec;
rec.mFontFace = aFontFace;
rec.mOrigin = Some(aSheetType);
aFontFace->SetUserFontEntry(entry);
MOZ_ASSERT(!HasRuleFontFace(aFontFace),
"FontFace should not occur in mRuleFaces twice");
mRuleFaces.AppendElement(rec);
if (mOwner && aFontFaceOwner) {
mOwner->InsertRuleFontFace(aFontFaceOwner, aSheetType);
}
// this was a new rule and font entry, so note that the set was modified
aFontSetModified = true;
// Add the entry to the end of the list. If an existing userfont entry was
// returned by FindOrCreateUserFontEntryFromFontFace that was already stored
// on the family, gfxUserFontFamily::AddFontEntry(), which AddUserFontEntry
// calls, will automatically remove the earlier occurrence of the same
// userfont entry.
AddUserFontEntry(family, entry);
}
RawServoFontFaceRule* FontFaceSetDocumentImpl::FindRuleForEntry(
gfxFontEntry* aFontEntry) {
NS_ASSERTION(!aFontEntry->mIsUserFontContainer, "only platform font entries");
for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
gfxUserFontEntry* entry = f->GetUserFontEntry();
if (entry && entry->GetPlatformFontEntry() == aFontEntry) {
return f->GetRule();
}
}
return nullptr;
}
RawServoFontFaceRule* FontFaceSetDocumentImpl::FindRuleForUserFontEntry(
gfxUserFontEntry* aUserFontEntry) {
for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
if (f->GetUserFontEntry() == aUserFontEntry) {
return f->GetRule();
}
}
return nullptr;
}
void FontFaceSetDocumentImpl::CacheFontLoadability() {
// TODO(emilio): We could do it a bit more incrementally maybe?
for (const auto& fontFamily : mFontFamilies.Values()) {
fontFamily->ReadLock();
for (const gfxFontEntry* entry : fontFamily->GetFontList()) {
if (!entry->mIsUserFontContainer) {
continue;
}
const auto& sourceList =
static_cast<const gfxUserFontEntry*>(entry)->SourceList();
for (const gfxFontFaceSrc& src : sourceList) {
if (src.mSourceType != gfxFontFaceSrc::eSourceType_URL) {
continue;
}
mAllowedFontLoads.LookupOrInsertWith(
&src, [&] { return IsFontLoadAllowed(src); });
}
}
fontFamily->ReadUnlock();
}
}
void FontFaceSetDocumentImpl::DidRefresh() { CheckLoadingFinished(); }
void FontFaceSetDocumentImpl::UpdateHasLoadingFontFaces() {
FontFaceSetImpl::UpdateHasLoadingFontFaces();
if (mHasLoadingFontFaces) {
return;
}
for (size_t i = 0; i < mRuleFaces.Length(); i++) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
if (f->Status() == FontFaceLoadStatus::Loading) {
mHasLoadingFontFaces = true;
return;
}
}
}
bool FontFaceSetDocumentImpl::MightHavePendingFontLoads() {
if (FontFaceSetImpl::MightHavePendingFontLoads()) {
return true;
}
// Check for pending restyles or reflows, as they might cause fonts to
// load as new styles apply and text runs are rebuilt.
nsPresContext* presContext = GetPresContext();
if (presContext && presContext->HasPendingRestyleOrReflow()) {
return true;
}
if (mDocument) {
// We defer resolving mReady until the document as fully loaded.
if (!mDocument->DidFireDOMContentLoaded()) {
return true;
}
// And we also wait for any CSS style sheets to finish loading, as their
// styles might cause new fonts to load.
if (mDocument->CSSLoader()->HasPendingLoads()) {
return true;
}
}
return false;
}
// nsIDOMEventListener
NS_IMETHODIMP
FontFaceSetDocumentImpl::HandleEvent(Event* aEvent) {
nsString type;
aEvent->GetType(type);
if (!type.EqualsLiteral("DOMContentLoaded")) {
return NS_ERROR_FAILURE;
}
RemoveDOMContentLoadedListener();
CheckLoadingFinished();
return NS_OK;
}
// nsICSSLoaderObserver
NS_IMETHODIMP
FontFaceSetDocumentImpl::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
nsresult aStatus) {
CheckLoadingFinished();
return NS_OK;
}
void FontFaceSetDocumentImpl::FlushUserFontSet() {
if (mDocument) {
mDocument->FlushUserFontSet();
}
}
void FontFaceSetDocumentImpl::MarkUserFontSetDirty() {
if (mDocument) {
// Ensure we trigger at least a style flush, that will eventually flush the
// user font set. Otherwise the font loads that that flush may cause could
// never be triggered.
if (PresShell* presShell = mDocument->GetPresShell()) {
presShell->EnsureStyleFlush();
}
mDocument->MarkUserFontSetDirty();
}
}
#undef LOG_ENABLED
#undef LOG

Просмотреть файл

@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_FontFaceSetDocumentImpl_h
#define mozilla_dom_FontFaceSetDocumentImpl_h
#include "mozilla/dom/FontFaceSetImpl.h"
#include "nsICSSLoaderObserver.h"
#include "nsIDOMEventListener.h"
namespace mozilla::dom {
class FontFaceSetDocumentImpl final : public FontFaceSetImpl,
public nsIDOMEventListener,
public nsICSSLoaderObserver {
NS_DECL_ISUPPORTS_INHERITED
public:
NS_DECL_NSIDOMEVENTLISTENER
FontFaceSetDocumentImpl(FontFaceSet* aOwner, dom::Document* aDocument);
void Initialize();
void Destroy() override;
dom::Document* Document() const override { return mDocument; }
// gfxUserFontSet
nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex) override;
bool IsFontLoadAllowed(const gfxFontFaceSrc&) override;
nsPresContext* GetPresContext() const override;
bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules) override;
RawServoFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry) override;
/**
* Notification method called by the nsPresContext to indicate that the
* refresh driver ticked and flushed style and layout.
* were just flushed.
*/
void DidRefresh() override;
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
nsresult aStatus) override;
// For ServoStyleSet to know ahead of time whether a font is loadable.
void CacheFontLoadability() override;
void EnsureReady() override;
bool Add(FontFaceImpl* aFontFace, ErrorResult& aRv) override;
void FlushUserFontSet() override;
void MarkUserFontSetDirty() override;
private:
~FontFaceSetDocumentImpl() override;
uint64_t GetInnerWindowID() override;
void RemoveDOMContentLoadedListener();
nsresult CreateChannelForSyncLoadFontData(
nsIChannel** aOutChannel, gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc) override;
// search for @font-face rule that matches a userfont font entry
RawServoFontFaceRule* FindRuleForUserFontEntry(
gfxUserFontEntry* aUserFontEntry) override;
void FindMatchingFontFaces(const nsTHashSet<FontFace*>& aMatchingFaces,
nsTArray<FontFace*>& aFontFaces) override;
void InsertRuleFontFace(FontFaceImpl* aFontFace, FontFace* aFontFaceOwner,
StyleOrigin aOrigin,
nsTArray<FontFaceRecord>& aOldRecords,
bool& aFontSetModified);
// Helper function for HasLoadingFontFaces.
void UpdateHasLoadingFontFaces() override;
/**
* Returns whether there might be any pending font loads, which should cause
* the mReady Promise not to be resolved yet.
*/
bool MightHavePendingFontLoads() override;
#ifdef DEBUG
bool HasRuleFontFace(FontFaceImpl* aFontFace);
#endif
already_AddRefed<gfxFontSrcPrincipal> CreateStandardFontLoadPrincipal()
const override;
TimeStamp GetNavigationStartTimeStamp() override;
// The document this is a FontFaceSet for.
RefPtr<dom::Document> mDocument;
// The @font-face rule backed FontFace objects in the FontFaceSet.
nsTArray<FontFaceRecord> mRuleFaces;
};
} // namespace mozilla::dom
#endif // !defined(mozilla_dom_FontFaceSetDocumentImpl_h)

Просмотреть файл

@ -9,7 +9,6 @@
#include "gfxFontConstants.h"
#include "gfxFontSrcPrincipal.h"
#include "gfxFontSrcURI.h"
#include "FontPreloader.h"
#include "mozilla/css/Loader.h"
#include "mozilla/dom/CSSFontFaceRule.h"
#include "mozilla/dom/DocumentInlines.h"
@ -36,16 +35,13 @@
#include "mozilla/Telemetry.h"
#include "mozilla/LoadInfo.h"
#include "nsComponentManagerUtils.h"
#include "nsContentPolicyUtils.h"
#include "nsContentUtils.h"
#include "nsDeviceContext.h"
#include "nsFontFaceLoader.h"
#include "nsIConsoleService.h"
#include "nsIContentPolicy.h"
#include "nsIDocShell.h"
#include "mozilla/dom/Document.h"
#include "nsILoadContext.h"
#include "nsINetworkPredictor.h"
#include "nsIPrincipal.h"
#include "nsIWebNavigation.h"
#include "nsNetUtil.h"
@ -66,13 +62,10 @@ using namespace mozilla::dom;
#define LOG_ENABLED() \
MOZ_LOG_TEST(gfxUserFontSet::GetUserFontsLog(), LogLevel::Debug)
NS_IMPL_ISUPPORTS(FontFaceSetImpl, nsIDOMEventListener, nsICSSLoaderObserver)
NS_IMPL_ISUPPORTS0(FontFaceSetImpl)
FontFaceSetImpl::FontFaceSetImpl(FontFaceSet* aOwner, dom::Document* aDocument)
FontFaceSetImpl::FontFaceSetImpl(FontFaceSet* aOwner)
: mOwner(aOwner),
mDocument(aDocument),
mStandardFontLoadPrincipal(new gfxFontSrcPrincipal(
mDocument->NodePrincipal(), mDocument->PartitionedPrincipal())),
mStatus(FontFaceSetLoadStatus::Loaded),
mNonRuleFacesDirty(false),
mHasLoadingFontFaces(false),
@ -89,81 +82,29 @@ FontFaceSetImpl::~FontFaceSetImpl() {
Destroy();
}
void FontFaceSetImpl::Initialize() {
MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
// Record the state of the "bypass cache" flags from the docshell now,
// since we want to look at them from style worker threads, and we can
// only get to the docshell through a weak pointer (which is only
// possible on the main thread).
//
// In theory the load type of a docshell could change after the document
// is loaded, but handling that doesn't seem too important.
if (nsCOMPtr<nsIDocShell> docShell = mDocument->GetDocShell()) {
uint32_t loadType;
uint32_t flags;
if ((NS_SUCCEEDED(docShell->GetLoadType(&loadType)) &&
((loadType >> 16) & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)) ||
(NS_SUCCEEDED(docShell->GetDefaultLoadFlags(&flags)) &&
(flags & nsIRequest::LOAD_BYPASS_CACHE))) {
mBypassCache = true;
}
}
// Same for the "private browsing" flag.
if (nsCOMPtr<nsILoadContext> loadContext = mDocument->GetLoadContext()) {
mPrivateBrowsing = loadContext->UsePrivateBrowsing();
}
if (!mDocument->DidFireDOMContentLoaded()) {
mDocument->AddSystemEventListener(u"DOMContentLoaded"_ns, this, false,
false);
} else {
// In some cases we can't rely on CheckLoadingFinished being called from
// the refresh driver. For example, documents in display:none iframes.
// Or if the document has finished loading and painting at the time that
// script requests document.fonts and causes us to get here.
CheckLoadingFinished();
}
mDocument->CSSLoader()->AddObserver(this);
}
void FontFaceSetImpl::Destroy() {
RemoveDOMContentLoadedListener();
if (mDocument && mDocument->CSSLoader()) {
// We're null checking CSSLoader() since FontFaceSetImpl::Disconnect() might
// be being called during unlink, at which time the loader may already have
// been unlinked from the document.
mDocument->CSSLoader()->RemoveObserver(this);
}
for (const auto& key : mLoaders.Keys()) {
key->Cancel();
}
mLoaders.Clear();
mDocument = nullptr;
mRuleFaces.Clear();
mNonRuleFaces.Clear();
gfxUserFontSet::Destroy();
}
void FontFaceSetImpl::RemoveDOMContentLoadedListener() {
if (mDocument) {
mDocument->RemoveSystemEventListener(u"DOMContentLoaded"_ns, this, false);
}
}
void FontFaceSetImpl::ParseFontShorthandForMatching(
const nsACString& aFont, StyleFontFamilyList& aFamilyList,
FontWeight& aWeight, FontStretch& aStretch, FontSlantStyle& aStyle,
ErrorResult& aRv) {
RefPtr<URLExtraData> url = ServoCSSParser::GetURLExtraData(mDocument);
auto* doc = Document();
if (NS_WARN_IF(!doc)) {
aRv.ThrowInvalidStateError("Missing document");
return;
}
RefPtr<URLExtraData> url = ServoCSSParser::GetURLExtraData(doc);
if (!ServoCSSParser::ParseFontShorthandForMatching(
aFont, url, aFamilyList, aStyle, aStretch, aWeight)) {
aRv.ThrowSyntaxError("Invalid font shorthand");
@ -204,10 +145,6 @@ void FontFaceSetImpl::FindMatchingFontFaces(const nsACString& aFont,
style.weight = weight;
style.stretch = stretch;
nsTArray<FontFaceRecord>* arrays[2];
arrays[0] = &mNonRuleFaces;
arrays[1] = &mRuleFaces;
// Set of FontFaces that we want to return.
nsTHashSet<FontFace*> matchingFaces;
@ -239,59 +176,35 @@ void FontFaceSetImpl::FindMatchingFontFaces(const nsACString& aFont,
}
}
if (matchingFaces.IsEmpty()) {
return;
}
// Add all FontFaces in matchingFaces to aFontFaces, in the order
// they appear in the FontFaceSet.
for (nsTArray<FontFaceRecord>* array : arrays) {
for (FontFaceRecord& record : *array) {
FontFace* owner = record.mFontFace->GetOwner();
if (owner && matchingFaces.Contains(owner)) {
aFontFaces.AppendElement(owner);
}
}
}
FindMatchingFontFaces(matchingFaces, aFontFaces);
}
TimeStamp FontFaceSetImpl::GetNavigationStartTimeStamp() {
TimeStamp navStart;
RefPtr<nsDOMNavigationTiming> timing(mDocument->GetNavigationTiming());
if (timing) {
navStart = timing->GetNavigationStartTimeStamp();
void FontFaceSetImpl::FindMatchingFontFaces(
const nsTHashSet<FontFace*>& aMatchingFaces,
nsTArray<FontFace*>& aFontFaces) {
for (FontFaceRecord& record : mNonRuleFaces) {
FontFace* owner = record.mFontFace->GetOwner();
if (owner && aMatchingFaces.Contains(owner)) {
aFontFaces.AppendElement(owner);
}
}
return navStart;
}
bool FontFaceSetImpl::ReadyPromiseIsPending() const {
return mOwner && mOwner->ReadyPromiseIsPending();
}
void FontFaceSetImpl::EnsureReady() {
MOZ_ASSERT(NS_IsMainThread());
// There may be outstanding style changes that will trigger the loading of
// new fonts. We need to flush layout to initiate any such loads so that
// if mReady is currently resolved we replace it with a new pending Promise.
// (That replacement will happen under this flush call.)
if (!ReadyPromiseIsPending() && mDocument) {
mDocument->FlushPendingNotifications(FlushType::Layout);
}
}
FontFaceSetLoadStatus FontFaceSetImpl::Status() {
FlushUserFontSet();
return mStatus;
}
#ifdef DEBUG
bool FontFaceSetImpl::HasRuleFontFace(FontFaceImpl* aFontFace) {
for (size_t i = 0; i < mRuleFaces.Length(); i++) {
if (mRuleFaces[i].mFontFace == aFontFace) {
return true;
}
}
return false;
}
#endif
bool FontFaceSetImpl::Add(FontFaceImpl* aFontFace, ErrorResult& aRv) {
FlushUserFontSet();
@ -322,17 +235,6 @@ bool FontFaceSetImpl::Add(FontFaceImpl* aFontFace, ErrorResult& aRv) {
MarkUserFontSetDirty();
mHasLoadingFontFacesIsDirty = true;
CheckLoadingStarted();
RefPtr<dom::Document> clonedDoc = mDocument->GetLatestStaticClone();
if (clonedDoc) {
// The document is printing, copy the font to the static clone as well.
nsCOMPtr<nsIPrincipal> principal = mDocument->GetPrincipal();
if (principal->IsSystemPrincipal() || nsContentUtils::IsPDFJS(principal)) {
ErrorResult rv;
clonedDoc->Fonts()->Add(*aFontFace->GetOwner(), rv);
MOZ_ASSERT(!rv.Failed());
}
}
return true;
}
@ -391,207 +293,6 @@ void FontFaceSetImpl::RemoveLoader(nsFontFaceLoader* aLoader) {
mLoaders.RemoveEntry(aLoader);
}
nsresult FontFaceSetImpl::StartLoad(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex) {
nsresult rv;
nsCOMPtr<nsIStreamLoader> streamLoader;
RefPtr<nsFontFaceLoader> fontLoader;
const gfxFontFaceSrc& src = aUserFontEntry->SourceAt(aSrcIndex);
auto preloadKey =
PreloadHashKey::CreateAsFont(src.mURI->get(), CORS_ANONYMOUS);
RefPtr<PreloaderBase> preload =
mDocument->Preloads().LookupPreload(preloadKey);
if (preload) {
fontLoader = new nsFontFaceLoader(aUserFontEntry, aSrcIndex, this,
preload->Channel());
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader,
fontLoader);
NS_ENSURE_SUCCESS(rv, rv);
rv = preload->AsyncConsume(streamLoader);
// We don't want this to hang around regardless of the result, there will be
// no coalescing of later found <link preload> tags for fonts.
preload->RemoveSelf(mDocument);
} else {
// No preload found, open a channel.
rv = NS_ERROR_FAILURE;
}
nsCOMPtr<nsILoadGroup> loadGroup(mDocument->GetDocumentLoadGroup());
if (NS_FAILED(rv)) {
nsCOMPtr<nsIChannel> channel;
rv = FontPreloader::BuildChannel(
getter_AddRefs(channel), src.mURI->get(), CORS_ANONYMOUS,
dom::ReferrerPolicy::_empty /* not used */, aUserFontEntry, &src,
mDocument, loadGroup, nullptr, false);
NS_ENSURE_SUCCESS(rv, rv);
fontLoader = new nsFontFaceLoader(aUserFontEntry, aSrcIndex, this, channel);
if (LOG_ENABLED()) {
nsCOMPtr<nsIURI> referrer = src.mReferrerInfo
? src.mReferrerInfo->GetOriginalReferrer()
: nullptr;
LOG((
"userfonts (%p) download start - font uri: (%s) referrer uri: (%s)\n",
fontLoader.get(), src.mURI->GetSpecOrDefault().get(),
referrer ? referrer->GetSpecOrDefault().get() : ""));
}
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader,
fontLoader);
NS_ENSURE_SUCCESS(rv, rv);
rv = channel->AsyncOpen(streamLoader);
if (NS_FAILED(rv)) {
fontLoader->DropChannel(); // explicitly need to break ref cycle
}
}
mLoaders.PutEntry(fontLoader);
net::PredictorLearn(src.mURI->get(), mDocument->GetDocumentURI(),
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE, loadGroup);
if (NS_SUCCEEDED(rv)) {
fontLoader->StartedLoading(streamLoader);
// let the font entry remember the loader, in case we need to cancel it
aUserFontEntry->SetLoader(fontLoader);
}
return rv;
}
bool FontFaceSetImpl::UpdateRules(
const nsTArray<nsFontFaceRuleContainer>& aRules) {
// If there was a change to the mNonRuleFaces array, then there could
// have been a modification to the user font set.
bool modified = mNonRuleFacesDirty;
mNonRuleFacesDirty = false;
// reuse existing FontFace objects mapped to rules already
nsTHashMap<nsPtrHashKey<RawServoFontFaceRule>, FontFaceImpl*> ruleFaceMap;
for (size_t i = 0, i_end = mRuleFaces.Length(); i < i_end; ++i) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
if (!f || !f->GetOwner()) {
continue;
}
ruleFaceMap.InsertOrUpdate(f->GetRule(), f);
}
// The @font-face rules that make up the user font set have changed,
// so we need to update the set. However, we want to preserve existing
// font entries wherever possible, so that we don't discard and then
// re-download resources in the (common) case where at least some of the
// same rules are still present.
nsTArray<FontFaceRecord> oldRecords = std::move(mRuleFaces);
// Remove faces from the font family records; we need to re-insert them
// because we might end up with faces in a different order even if they're
// the same font entries as before. (The order can affect font selection
// where multiple faces match the requested style, perhaps with overlapping
// unicode-range coverage.)
for (const auto& fontFamily : mFontFamilies.Values()) {
fontFamily->DetachFontEntries();
}
// Sometimes aRules has duplicate @font-face rules in it; we should make
// that not happen, but in the meantime, don't try to insert the same
// FontFace object more than once into mRuleFaces. We track which
// ones we've handled in this table.
nsTHashSet<RawServoFontFaceRule*> handledRules;
for (size_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
// Insert each FontFace objects for each rule into our list, migrating old
// font entries if possible rather than creating new ones; set modified to
// true if we detect that rule ordering has changed, or if a new entry is
// created.
RawServoFontFaceRule* rule = aRules[i].mRule;
if (!handledRules.EnsureInserted(rule)) {
// rule was already present in the hashtable
continue;
}
RefPtr<FontFaceImpl> faceImpl = ruleFaceMap.Get(rule);
RefPtr<FontFace> face = faceImpl ? faceImpl->GetOwner() : nullptr;
if (mOwner && (!faceImpl || !face)) {
face = FontFace::CreateForRule(mOwner->GetParentObject(), mOwner, rule);
faceImpl = face->GetImpl();
}
InsertRuleFontFace(faceImpl, face, aRules[i].mOrigin, oldRecords, modified);
}
for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
// Do the same for the non rule backed FontFace objects.
InsertNonRuleFontFace(mNonRuleFaces[i].mFontFace, modified);
}
// Remove any residual families that have no font entries (i.e., they were
// not defined at all by the updated set of @font-face rules).
for (auto it = mFontFamilies.Iter(); !it.Done(); it.Next()) {
if (!it.Data()->FontListLength()) {
it.Remove();
}
}
// If any FontFace objects for rules are left in the old list, note that the
// set has changed (even if the new set was built entirely by migrating old
// font entries).
if (oldRecords.Length() > 0) {
modified = true;
// Any in-progress loaders for obsolete rules should be cancelled,
// as the resource being downloaded will no longer be required.
// We need to explicitly remove any loaders here, otherwise the loaders
// will keep their "orphaned" font entries alive until they complete,
// even after the oldRules array is deleted.
//
// XXX Now that it is possible for the author to hold on to a rule backed
// FontFace object, we shouldn't cancel loading here; instead we should do
// it when the FontFace is GCed, if we can detect that.
size_t count = oldRecords.Length();
for (size_t i = 0; i < count; ++i) {
RefPtr<FontFaceImpl> f = oldRecords[i].mFontFace;
gfxUserFontEntry* userFontEntry = f->GetUserFontEntry();
if (userFontEntry) {
nsFontFaceLoader* loader = userFontEntry->GetLoader();
if (loader) {
loader->Cancel();
RemoveLoader(loader);
}
}
// Any left over FontFace objects should also cease being rule backed.
f->DisconnectFromRule();
}
}
if (modified) {
IncrementGeneration(true);
mHasLoadingFontFacesIsDirty = true;
CheckLoadingStarted();
CheckLoadingFinished();
}
// if local rules needed to be rebuilt, they have been rebuilt at this point
if (mRebuildLocalRules) {
mLocalRulesUsed = false;
mRebuildLocalRules = false;
}
if (LOG_ENABLED() && !mRuleFaces.IsEmpty()) {
LOG(("userfonts (%p) userfont rules update (%s) rule count: %d", this,
(modified ? "modified" : "not modified"), (int)(mRuleFaces.Length())));
}
return modified;
}
void FontFaceSetImpl::InsertNonRuleFontFace(FontFaceImpl* aFontFace,
bool& aFontSetModified) {
nsAtom* fontFamily = aFontFace->GetFamilyName();
@ -618,110 +319,6 @@ void FontFaceSetImpl::InsertNonRuleFontFace(FontFaceImpl* aFontFace,
AddUserFontEntry(family, aFontFace->GetUserFontEntry());
}
void FontFaceSetImpl::InsertRuleFontFace(FontFaceImpl* aFontFace,
FontFace* aFontFaceOwner,
StyleOrigin aSheetType,
nsTArray<FontFaceRecord>& aOldRecords,
bool& aFontSetModified) {
nsAtom* fontFamily = aFontFace->GetFamilyName();
if (!fontFamily) {
// If there is no family name, this rule cannot contribute a
// usable font, so there is no point in processing it further.
return;
}
bool remove = false;
size_t removeIndex;
nsAtomCString family(fontFamily);
// This is a rule backed FontFace. First, we check in aOldRecords; if
// the FontFace for the rule exists there, just move it to the new record
// list, and put the entry into the appropriate family.
for (size_t i = 0; i < aOldRecords.Length(); ++i) {
FontFaceRecord& rec = aOldRecords[i];
if (rec.mFontFace == aFontFace && rec.mOrigin == Some(aSheetType)) {
// if local rules were used, don't use the old font entry
// for rules containing src local usage
if (mLocalRulesUsed && mRebuildLocalRules) {
if (aFontFace->HasLocalSrc()) {
// Remove the old record, but wait to see if we successfully create a
// new user font entry below.
remove = true;
removeIndex = i;
break;
}
}
gfxUserFontEntry* entry = rec.mFontFace->GetUserFontEntry();
MOZ_ASSERT(entry, "FontFace should have a gfxUserFontEntry by now");
AddUserFontEntry(family, entry);
MOZ_ASSERT(!HasRuleFontFace(rec.mFontFace),
"FontFace should not occur in mRuleFaces twice");
mRuleFaces.AppendElement(rec);
aOldRecords.RemoveElementAt(i);
if (mOwner && aFontFaceOwner) {
mOwner->InsertRuleFontFace(aFontFaceOwner, aSheetType);
}
// note the set has been modified if an old rule was skipped to find
// this one - something has been dropped, or ordering changed
if (i > 0) {
aFontSetModified = true;
}
return;
}
}
// this is a new rule:
RefPtr<gfxUserFontEntry> entry =
FindOrCreateUserFontEntryFromFontFace(family, aFontFace, aSheetType);
if (!entry) {
return;
}
if (remove) {
// Although we broke out of the aOldRecords loop above, since we found
// src local usage, and we're not using the old user font entry, we still
// are adding a record to mRuleFaces with the same FontFace object.
// Remove the old record so that we don't have the same FontFace listed
// in both mRuleFaces and oldRecords, which would cause us to call
// DisconnectFromRule on a FontFace that should still be rule backed.
aOldRecords.RemoveElementAt(removeIndex);
}
FontFaceRecord rec;
rec.mFontFace = aFontFace;
rec.mOrigin = Some(aSheetType);
aFontFace->SetUserFontEntry(entry);
MOZ_ASSERT(!HasRuleFontFace(aFontFace),
"FontFace should not occur in mRuleFaces twice");
mRuleFaces.AppendElement(rec);
if (mOwner && aFontFaceOwner) {
mOwner->InsertRuleFontFace(aFontFaceOwner, aSheetType);
}
// this was a new rule and font entry, so note that the set was modified
aFontSetModified = true;
// Add the entry to the end of the list. If an existing userfont entry was
// returned by FindOrCreateUserFontEntryFromFontFace that was already stored
// on the family, gfxUserFontFamily::AddFontEntry(), which AddUserFontEntry
// calls, will automatically remove the earlier occurrence of the same
// userfont entry.
AddUserFontEntry(family, entry);
}
/* static */
already_AddRefed<gfxUserFontEntry>
FontFaceSetImpl::FindOrCreateUserFontEntryFromFontFace(
@ -995,30 +592,6 @@ FontFaceSetImpl::FindOrCreateUserFontEntryFromFontFace(
return entry.forget();
}
RawServoFontFaceRule* FontFaceSetImpl::FindRuleForEntry(
gfxFontEntry* aFontEntry) {
NS_ASSERTION(!aFontEntry->mIsUserFontContainer, "only platform font entries");
for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
gfxUserFontEntry* entry = f->GetUserFontEntry();
if (entry && entry->GetPlatformFontEntry() == aFontEntry) {
return f->GetRule();
}
}
return nullptr;
}
RawServoFontFaceRule* FontFaceSetImpl::FindRuleForUserFontEntry(
gfxUserFontEntry* aUserFontEntry) {
for (uint32_t i = 0; i < mRuleFaces.Length(); ++i) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
if (f->GetUserFontEntry() == aUserFontEntry) {
return f->GetRule();
}
}
return nullptr;
}
nsresult FontFaceSetImpl::LogMessage(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex, const char* aMessage,
uint32_t aFlags, nsresult aStatus) {
@ -1096,14 +669,13 @@ nsresult FontFaceSetImpl::LogMessage(gfxUserFontEntry* aUserFontEntry,
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
uint64_t innerWindowID = mDocument->InnerWindowID();
rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(message),
href, // file
NS_ConvertUTF8toUTF16(text), // src line
line, column,
aFlags, // flags
"CSS Loader", // category (make separate?)
innerWindowID);
GetInnerWindowID());
if (NS_SUCCEEDED(rv)) {
console->LogMessage(scriptError);
}
@ -1111,89 +683,13 @@ nsresult FontFaceSetImpl::LogMessage(gfxUserFontEntry* aUserFontEntry,
return NS_OK;
}
void FontFaceSetImpl::CacheFontLoadability() {
// TODO(emilio): We could do it a bit more incrementally maybe?
for (const auto& fontFamily : mFontFamilies.Values()) {
fontFamily->ReadLock();
for (const gfxFontEntry* entry : fontFamily->GetFontList()) {
if (!entry->mIsUserFontContainer) {
continue;
}
const auto& sourceList =
static_cast<const gfxUserFontEntry*>(entry)->SourceList();
for (const gfxFontFaceSrc& src : sourceList) {
if (src.mSourceType != gfxFontFaceSrc::eSourceType_URL) {
continue;
}
mAllowedFontLoads.LookupOrInsertWith(
&src, [&] { return IsFontLoadAllowed(src); });
}
}
fontFamily->ReadUnlock();
}
}
bool FontFaceSetImpl::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc) {
MOZ_ASSERT(aSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL);
if (ServoStyleSet::IsInServoTraversal()) {
auto entry = mAllowedFontLoads.Lookup(&aSrc);
MOZ_DIAGNOSTIC_ASSERT(entry, "Missed an update?");
return entry ? *entry : false;
}
MOZ_ASSERT(NS_IsMainThread());
if (aSrc.mUseOriginPrincipal) {
return true;
}
RefPtr<gfxFontSrcPrincipal> gfxPrincipal =
aSrc.mURI->InheritsSecurityContext() ? nullptr
: aSrc.LoadPrincipal(*this);
nsIPrincipal* principal =
gfxPrincipal ? gfxPrincipal->NodePrincipal() : nullptr;
nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new net::LoadInfo(
mDocument->NodePrincipal(), // loading principal
principal, // triggering principal
mDocument, nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
nsIContentPolicy::TYPE_FONT);
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv = NS_CheckContentLoadPolicy(aSrc.mURI->get(), secCheckLoadInfo,
""_ns, // mime type
&shouldLoad,
nsContentUtils::GetContentPolicy());
return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
}
nsresult FontFaceSetImpl::SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,
uint8_t*& aBuffer,
uint32_t& aBufferLength) {
nsresult rv;
gfxFontSrcPrincipal* principal = aFontToLoad->GetPrincipal();
nsCOMPtr<nsIChannel> channel;
// Note we are calling NS_NewChannelWithTriggeringPrincipal() with both a
// node and a principal. This is because the document where the font is
// being loaded might have a different origin from the principal of the
// stylesheet that initiated the font load.
// Further, we only get here for data: loads, so it doesn't really matter
// whether we use SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT or not, to be
// more restrictive we use SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT.
rv = NS_NewChannelWithTriggeringPrincipal(
getter_AddRefs(channel), aFontFaceSrc->mURI->get(), mDocument,
principal ? principal->NodePrincipal() : nullptr,
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
aFontFaceSrc->mUseOriginPrincipal ? nsIContentPolicy::TYPE_UA_FONT
: nsIContentPolicy::TYPE_FONT);
nsresult rv = CreateChannelForSyncLoadFontData(getter_AddRefs(channel),
aFontToLoad, aFontFaceSrc);
NS_ENSURE_SUCCESS(rv, rv);
// blocking stream is OK for data URIs
@ -1290,14 +786,17 @@ void FontFaceSetImpl::DispatchCheckLoadingFinishedAfterDelay() {
return;
}
auto* doc = Document();
if (NS_WARN_IF(!doc)) {
return;
}
nsCOMPtr<nsIRunnable> checkTask =
NewRunnableMethod("dom::FontFaceSetImpl::CheckLoadingFinishedAfterDelay",
this, &FontFaceSetImpl::CheckLoadingFinishedAfterDelay);
mDocument->Dispatch(TaskCategory::Other, checkTask.forget());
doc->Dispatch(TaskCategory::Other, checkTask.forget());
}
void FontFaceSetImpl::DidRefresh() { CheckLoadingFinished(); }
void FontFaceSetImpl::CheckLoadingFinishedAfterDelay() {
mDelayedLoadCheck = false;
CheckLoadingFinished();
@ -1325,13 +824,6 @@ void FontFaceSetImpl::CheckLoadingStarted() {
void FontFaceSetImpl::UpdateHasLoadingFontFaces() {
mHasLoadingFontFacesIsDirty = false;
mHasLoadingFontFaces = false;
for (size_t i = 0; i < mRuleFaces.Length(); i++) {
FontFaceImpl* f = mRuleFaces[i].mFontFace;
if (f->Status() == FontFaceLoadStatus::Loading) {
mHasLoadingFontFaces = true;
return;
}
}
for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
if (mNonRuleFaces[i].mFontFace->Status() == FontFaceLoadStatus::Loading) {
mHasLoadingFontFaces = true;
@ -1349,31 +841,7 @@ bool FontFaceSetImpl::HasLoadingFontFaces() {
bool FontFaceSetImpl::MightHavePendingFontLoads() {
// Check for FontFace objects in the FontFaceSet that are still loading.
if (HasLoadingFontFaces()) {
return true;
}
// Check for pending restyles or reflows, as they might cause fonts to
// load as new styles apply and text runs are rebuilt.
nsPresContext* presContext = GetPresContext();
if (presContext && presContext->HasPendingRestyleOrReflow()) {
return true;
}
if (mDocument) {
// We defer resolving mReady until the document as fully loaded.
if (!mDocument->DidFireDOMContentLoaded()) {
return true;
}
// And we also wait for any CSS style sheets to finish loading, as their
// styles might cause new fonts to load.
if (mDocument->CSSLoader()->HasPendingLoads()) {
return true;
}
}
return false;
return HasLoadingFontFaces();
}
void FontFaceSetImpl::CheckLoadingFinished() {
@ -1401,67 +869,13 @@ void FontFaceSetImpl::CheckLoadingFinished() {
}
}
// nsIDOMEventListener
NS_IMETHODIMP
FontFaceSetImpl::HandleEvent(Event* aEvent) {
nsString type;
aEvent->GetType(type);
if (!type.EqualsLiteral("DOMContentLoaded")) {
return NS_ERROR_FAILURE;
}
RemoveDOMContentLoadedListener();
CheckLoadingFinished();
return NS_OK;
}
/* static */
bool FontFaceSetImpl::PrefEnabled() {
return StaticPrefs::layout_css_font_loading_api_enabled();
}
// nsICSSLoaderObserver
NS_IMETHODIMP
FontFaceSetImpl::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
nsresult aStatus) {
CheckLoadingFinished();
return NS_OK;
}
void FontFaceSetImpl::FlushUserFontSet() {
if (mDocument) {
mDocument->FlushUserFontSet();
}
}
void FontFaceSetImpl::MarkUserFontSetDirty() {
if (mDocument) {
// Ensure we trigger at least a style flush, that will eventually flush the
// user font set. Otherwise the font loads that that flush may cause could
// never be triggered.
if (PresShell* presShell = mDocument->GetPresShell()) {
presShell->EnsureStyleFlush();
}
mDocument->MarkUserFontSetDirty();
}
}
nsPresContext* FontFaceSetImpl::GetPresContext() const {
if (!mDocument) {
return nullptr;
}
return mDocument->GetPresContext();
}
void FontFaceSetImpl::RefreshStandardFontLoadPrincipal() {
MOZ_ASSERT(NS_IsMainThread());
mStandardFontLoadPrincipal = new gfxFontSrcPrincipal(
mDocument->NodePrincipal(), mDocument->PartitionedPrincipal());
mStandardFontLoadPrincipal = CreateStandardFontLoadPrincipal();
mAllowedFontLoads.Clear();
IncrementGeneration(false);
}
@ -1469,6 +883,14 @@ void FontFaceSetImpl::RefreshStandardFontLoadPrincipal() {
// -- gfxUserFontSet
// ------------------------------------------------
already_AddRefed<gfxFontSrcPrincipal>
FontFaceSetImpl::GetStandardFontLoadPrincipal() const {
if (!mStandardFontLoadPrincipal) {
mStandardFontLoadPrincipal = CreateStandardFontLoadPrincipal();
}
return RefPtr{mStandardFontLoadPrincipal}.forget();
}
void FontFaceSetImpl::RecordFontLoadDone(uint32_t aFontSize,
TimeStamp aDoneTime) {
mDownloadCount++;

Просмотреть файл

@ -19,6 +19,7 @@ struct gfxFontFaceSrc;
class gfxFontSrcPrincipal;
class gfxUserFontEntry;
class nsFontFaceLoader;
class nsIChannel;
class nsIPrincipal;
class nsPIDOMWindowInner;
struct RawServoFontFaceRule;
@ -33,31 +34,24 @@ class FontFace;
namespace mozilla::dom {
class FontFaceSetImpl final : public gfxUserFontSet,
public nsIDOMEventListener,
public nsICSSLoaderObserver {
class FontFaceSetImpl : public nsISupports, public gfxUserFontSet {
NS_DECL_THREADSAFE_ISUPPORTS
public:
// gfxUserFontSet
already_AddRefed<gfxFontSrcPrincipal> GetStandardFontLoadPrincipal()
const override {
return RefPtr{mStandardFontLoadPrincipal}.forget();
}
nsPresContext* GetPresContext() const override;
bool IsFontLoadAllowed(const gfxFontFaceSrc&) override;
nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
uint32_t aSrcIndex) override;
const override;
void RecordFontLoadDone(uint32_t aFontSize, TimeStamp aDoneTime) override;
bool BypassCache() final { return mBypassCache; }
protected:
virtual nsresult CreateChannelForSyncLoadFontData(
nsIChannel** aOutChannel, gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc) = 0;
// gfxUserFontSet
bool GetPrivateBrowsing() override { return mPrivateBrowsing; }
@ -80,22 +74,25 @@ class FontFaceSetImpl final : public gfxUserFontSet,
float aAscentOverride, float aDescentOverride, float aLineGapOverride,
float aSizeAdjust) override;
explicit FontFaceSetImpl(FontFaceSet* aOwner);
public:
NS_DECL_NSIDOMEVENTLISTENER
FontFaceSetImpl(FontFaceSet* aOwner, dom::Document* aDocument);
void Initialize();
void Destroy();
virtual void Destroy();
// Called by nsFontFaceLoader when the loader has completed normally.
// It's removed from the mLoaders set.
void RemoveLoader(nsFontFaceLoader* aLoader);
bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
virtual bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules) {
MOZ_ASSERT_UNREACHABLE("Not implemented!");
return false;
}
// search for @font-face rule that matches a platform font entry
RawServoFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
virtual RawServoFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry) {
MOZ_ASSERT_UNREACHABLE("Not implemented!");
return nullptr;
}
/**
* Finds an existing entry in the user font cache or creates a new user
@ -115,18 +112,14 @@ class FontFaceSetImpl final : public gfxUserFontSet,
* refresh driver ticked and flushed style and layout.
* were just flushed.
*/
void DidRefresh();
virtual void DidRefresh() { MOZ_ASSERT_UNREACHABLE("Not implemented!"); }
/**
* Returns whether the "layout.css.font-loading-api.enabled" pref is true.
*/
static bool PrefEnabled();
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
nsresult aStatus) override;
void FlushUserFontSet();
virtual void FlushUserFontSet() {}
static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet) {
const auto* set = static_cast<FontFaceSetImpl*>(aUserFontSet);
@ -135,21 +128,23 @@ class FontFaceSetImpl final : public gfxUserFontSet,
void RefreshStandardFontLoadPrincipal();
dom::Document* Document() const { return mDocument; }
virtual dom::Document* Document() const { return nullptr; }
// -- Web IDL --------------------------------------------------------------
void EnsureReady();
virtual void EnsureReady() {}
dom::FontFaceSetLoadStatus Status();
bool Add(FontFaceImpl* aFontFace, ErrorResult& aRv);
virtual bool Add(FontFaceImpl* aFontFace, ErrorResult& aRv);
void Clear();
bool Delete(FontFaceImpl* aFontFace);
// For ServoStyleSet to know ahead of time whether a font is loadable.
void CacheFontLoadability();
virtual void CacheFontLoadability() {
MOZ_ASSERT_UNREACHABLE("Not implemented!");
}
void MarkUserFontSetDirty();
virtual void MarkUserFontSetDirty() {}
/**
* Checks to see whether it is time to resolve mReady and dispatch any
@ -162,21 +157,21 @@ class FontFaceSetImpl final : public gfxUserFontSet,
void DispatchCheckLoadingFinishedAfterDelay();
private:
~FontFaceSetImpl();
protected:
~FontFaceSetImpl() override;
virtual uint64_t GetInnerWindowID() = 0;
/**
* Returns whether the given FontFace is currently "in" the FontFaceSet.
*/
bool HasAvailableFontFace(FontFaceImpl* aFontFace);
void RemoveDOMContentLoadedListener();
/**
* Returns whether there might be any pending font loads, which should cause
* the mReady Promise not to be resolved yet.
*/
bool MightHavePendingFontLoads();
virtual bool MightHavePendingFontLoads();
/**
* Checks to see whether it is time to replace mReady and dispatch a
@ -203,23 +198,20 @@ class FontFaceSetImpl final : public gfxUserFontSet,
FontFaceImpl* aFontFace, StyleOrigin);
// search for @font-face rule that matches a userfont font entry
RawServoFontFaceRule* FindRuleForUserFontEntry(
gfxUserFontEntry* aUserFontEntry);
virtual RawServoFontFaceRule* FindRuleForUserFontEntry(
gfxUserFontEntry* aUserFontEntry) {
return nullptr;
}
virtual void FindMatchingFontFaces(
const nsTHashSet<FontFace*>& aMatchingFaces,
nsTArray<FontFace*>& aFontFaces);
already_AddRefed<gfxFontSrcPrincipal> GetStandardFontLoadPrincipal();
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal, bool* aBypassCache);
void InsertRuleFontFace(FontFaceImpl* aFontFace, FontFace* aFontFaceOwner,
StyleOrigin aOrigin,
nsTArray<FontFaceRecord>& aOldRecords,
bool& aFontSetModified);
void InsertNonRuleFontFace(FontFaceImpl* aFontFace, bool& aFontSetModified);
#ifdef DEBUG
bool HasRuleFontFace(FontFaceImpl* aFontFace);
#endif
/**
* Returns whether we have any loading FontFace objects in the FontFaceSet.
*/
@ -229,20 +221,20 @@ class FontFaceSetImpl final : public gfxUserFontSet,
bool ReadyPromiseIsPending() const;
// Helper function for HasLoadingFontFaces.
void UpdateHasLoadingFontFaces();
virtual void UpdateHasLoadingFontFaces();
void ParseFontShorthandForMatching(const nsACString& aFont,
StyleFontFamilyList& aFamilyList,
FontWeight& aWeight, FontStretch& aStretch,
FontSlantStyle& aStyle, ErrorResult& aRv);
TimeStamp GetNavigationStartTimeStamp();
virtual TimeStamp GetNavigationStartTimeStamp() = 0;
virtual already_AddRefed<gfxFontSrcPrincipal>
CreateStandardFontLoadPrincipal() const = 0;
FontFaceSet* MOZ_NON_OWNING_REF mOwner;
// The document this is a FontFaceSet for.
RefPtr<dom::Document> mDocument;
// The document's node principal, which is the principal font loads for
// this FontFaceSet will generally use. (This principal is not used for
// @font-face rules in UA and user sheets, where the principal of the
@ -254,16 +246,13 @@ class FontFaceSetImpl final : public gfxUserFontSet,
//
// Because mDocument's principal can change over time,
// its value must be updated by a call to ResetStandardFontLoadPrincipal.
RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal;
mutable RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal;
// Set of all loaders pointing to us. These are not strong pointers,
// but that's OK because nsFontFaceLoader always calls RemoveLoader on
// us before it dies (unless we die first).
nsTHashtable<nsPtrHashKey<nsFontFaceLoader>> mLoaders;
// The @font-face rule backed FontFace objects in the FontFaceSet.
nsTArray<FontFaceRecord> mRuleFaces;
// The non rule backed FontFace objects that have been added to this
// FontFaceSet.
nsTArray<FontFaceRecord> mNonRuleFaces;

Просмотреть файл

@ -142,6 +142,7 @@ EXPORTS.mozilla.dom += [
"FontFace.h",
"FontFaceImpl.h",
"FontFaceSet.h",
"FontFaceSetDocumentImpl.h",
"FontFaceSetImpl.h",
"FontFaceSetIterator.h",
"MediaList.h",
@ -192,6 +193,7 @@ UNIFIED_SOURCES += [
"FontFace.cpp",
"FontFaceImpl.cpp",
"FontFaceSet.cpp",
"FontFaceSetDocumentImpl.cpp",
"FontFaceSetImpl.cpp",
"FontFaceSetIterator.cpp",
"FontPreloader.cpp",