Bug 1420680: Rework how the loadability of font-faces is computed. r=jfkthame,bz

This reworks bug 1440561 so that we only precompute loads that belong to our
user font set, avoiding messing up with fonts in the cache that belong to other
pages.

The loadability of a font is precomputed in PreTraverse in the same way as we
did, but only for the fonts that we may end up loading. This is stored in
FontFaceSet now.

Also, the principal shenanigans that this code did are reworked to be explicit
about when the document principal changes in ResetToURI, instead of having a
member around and a mutable variable. This makes the code easier to follow.

MozReview-Commit-ID: 9ofTbaLDUF7
This commit is contained in:
Emilio Cobos Álvarez 2018-03-23 16:06:56 +01:00
Родитель 71ba656859
Коммит a4433a4de8
7 изменённых файлов: 194 добавлений и 440 удалений

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

@ -2370,6 +2370,10 @@ nsIDocument::ResetToURI(nsIURI* aURI,
}
}
if (mFontFaceSet) {
mFontFaceSet->RefreshStandardFontLoadPrincipal();
}
// Refresh the principal on the compartment.
if (nsPIDOMWindowInner* win = GetInnerWindow()) {
nsGlobalWindowInner::Cast(win)->RefreshCompartmentPrincipal();

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

@ -333,6 +333,16 @@ gfxUserFontFamily::~gfxUserFontFamily()
MOZ_ASSERT(NS_IsMainThread());
}
gfxFontSrcPrincipal*
gfxFontFaceSrc::LoadPrincipal(const gfxUserFontSet& aFontSet) const
{
MOZ_ASSERT(mSourceType == eSourceType_URL);
if (mUseOriginPrincipal && mOriginPrincipal) {
return mOriginPrincipal;
}
return aFontSet.GetStandardFontLoadPrincipal();
}
void
gfxUserFontEntry::GetFamilyNameAndURIForLogging(nsACString& aFamilyName,
nsACString& aURI)
@ -561,95 +571,77 @@ gfxUserFontEntry::DoLoadNextSrc(bool aForceAsync)
}
}
gfxFontSrcPrincipal* principal = nullptr;
bool bypassCache;
nsresult rv = mFontSet->CheckFontLoad(&currSrc, &principal,
&bypassCache);
if (NS_SUCCEEDED(rv) && principal != nullptr) {
if (!bypassCache) {
// see if we have an existing entry for this source
gfxFontEntry* fe = gfxUserFontSet::
UserFontCache::GetFont(currSrc.mURI,
principal,
this,
mFontSet->GetPrivateBrowsing());
if (fe) {
mPlatformFontEntry = fe;
SetLoadState(STATUS_LOADED);
if (LOG_ENABLED()) {
LOG(("userfonts (%p) [src %d] "
"loaded uri from cache: (%s) for (%s)\n",
mFontSet, mSrcIndex,
currSrc.mURI->GetSpecOrDefault().get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
return;
}
// see if we have an existing entry for this source
gfxFontEntry* fe =
gfxUserFontSet::UserFontCache::GetFont(currSrc, *this);
if (fe) {
mPlatformFontEntry = fe;
SetLoadState(STATUS_LOADED);
if (LOG_ENABLED()) {
LOG(("userfonts (%p) [src %d] "
"loaded uri from cache: (%s) for (%s)\n",
mFontSet, mSrcIndex,
currSrc.mURI->GetSpecOrDefault().get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
return;
}
if (ServoStyleSet* set = ServoStyleSet::Current()) {
// If we need to start a font load and we're on a style
// worker thread, we have to defer it.
set->AppendTask(PostTraversalTask::LoadFontEntry(this));
SetLoadState(STATUS_LOAD_PENDING);
if (ServoStyleSet* set = ServoStyleSet::Current()) {
// If we need to start a font load and we're on a style
// worker thread, we have to defer it.
set->AppendTask(PostTraversalTask::LoadFontEntry(this));
SetLoadState(STATUS_LOAD_PENDING);
return;
}
// record the principal we should use for the load for use when
// creating a channel and when caching the loaded entry.
mPrincipal = currSrc.LoadPrincipal(*mFontSet);
bool loadDoesntSpin =
!aForceAsync && currSrc.mURI->SyncLoadIsOK();
if (loadDoesntSpin) {
uint8_t* buffer = nullptr;
uint32_t bufferLength = 0;
// sync load font immediately
nsresult rv = mFontSet->SyncLoadFontData(this, &currSrc, buffer,
bufferLength);
if (NS_SUCCEEDED(rv) &&
LoadPlatformFont(buffer, bufferLength)) {
SetLoadState(STATUS_LOADED);
Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE,
currSrc.mSourceType + 1);
return;
}
// record the principal returned by CheckFontLoad,
// for use when creating a channel
// and when caching the loaded entry
mPrincipal = principal;
bool loadDoesntSpin = false;
if (!aForceAsync) {
loadDoesntSpin = currSrc.mURI->SyncLoadIsOK();
}
if (NS_SUCCEEDED(rv) && loadDoesntSpin) {
uint8_t* buffer = nullptr;
uint32_t bufferLength = 0;
// sync load font immediately
rv = mFontSet->SyncLoadFontData(this, &currSrc, buffer,
bufferLength);
if (NS_SUCCEEDED(rv) &&
LoadPlatformFont(buffer, bufferLength)) {
SetLoadState(STATUS_LOADED);
Telemetry::Accumulate(Telemetry::WEBFONT_SRCTYPE,
currSrc.mSourceType + 1);
return;
} else {
mFontSet->LogMessage(this,
"font load failed",
nsIScriptError::errorFlag,
rv);
}
} else {
// otherwise load font async
rv = mFontSet->StartLoad(this, &currSrc);
bool loadOK = NS_SUCCEEDED(rv);
if (loadOK) {
if (LOG_ENABLED()) {
LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
mFontSet, mSrcIndex,
currSrc.mURI->GetSpecOrDefault().get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
return;
} else {
mFontSet->LogMessage(this,
"download failed",
nsIScriptError::errorFlag,
rv);
}
mFontSet->LogMessage(this,
"font load failed",
nsIScriptError::errorFlag,
rv);
}
} else {
mFontSet->LogMessage(this, "download not allowed",
nsIScriptError::errorFlag, rv);
// otherwise load font async
nsresult rv = mFontSet->StartLoad(this, &currSrc);
bool loadOK = NS_SUCCEEDED(rv);
if (loadOK) {
if (LOG_ENABLED()) {
LOG(("userfonts (%p) [src %d] loading uri: (%s) for (%s)\n",
mFontSet, mSrcIndex,
currSrc.mURI->GetSpecOrDefault().get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
return;
} else {
mFontSet->LogMessage(this,
"download failed",
nsIScriptError::errorFlag,
rv);
}
}
} else {
// We don't log a warning to the web console yet,
@ -937,8 +929,6 @@ gfxUserFontSet::~gfxUserFontSet()
if (fp) {
fp->RemoveUserFontSet(this);
}
UserFontCache::ClearAllowedFontSets(this);
}
already_AddRefed<gfxUserFontEntry>
@ -1292,26 +1282,25 @@ gfxUserFontSet::UserFontCache::ForgetFont(gfxFontEntry* aFontEntry)
}
gfxFontEntry*
gfxUserFontSet::UserFontCache::GetFont(gfxFontSrcURI* aSrcURI,
gfxFontSrcPrincipal* aPrincipal,
gfxUserFontEntry* aUserFontEntry,
bool aPrivate)
gfxUserFontSet::UserFontCache::GetFont(const gfxFontFaceSrc& aSrc,
const gfxUserFontEntry& aUserFontEntry)
{
if (!sUserFonts ||
aUserFontEntry.mFontSet->BypassCache() ||
Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
return nullptr;
}
// Ignore principal when looking up a data: URI.
gfxFontSrcPrincipal* principal;
if (IgnorePrincipal(aSrcURI)) {
principal = nullptr;
} else {
principal = aPrincipal;
}
gfxFontSrcPrincipal* principal = IgnorePrincipal(aSrc.mURI)
? nullptr
: aSrc.LoadPrincipal(*aUserFontEntry.mFontSet);
Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, principal, aUserFontEntry,
aPrivate));
Entry* entry = sUserFonts->GetEntry(
Key(aSrc.mURI,
principal,
const_cast<gfxUserFontEntry*>(&aUserFontEntry),
aUserFontEntry.mFontSet->GetPrivateBrowsing()));
if (!entry) {
return nullptr;
}
@ -1319,79 +1308,13 @@ gfxUserFontSet::UserFontCache::GetFont(gfxFontSrcURI* aSrcURI,
// We have to perform another content policy check here to prevent
// cache poisoning. E.g. a.com loads a font into the cache but
// b.com has a CSP not allowing any fonts to be loaded.
bool allowed = false;
if (ServoStyleSet::IsInServoTraversal()) {
// Use the cached IsFontLoadAllowed results in mAllowedFontSets.
allowed = entry->CheckIsFontSetAllowedAndDispatchViolations(
aUserFontEntry->mFontSet);
} else {
// Call IsFontLoadAllowed directly, since we are on the main thread.
MOZ_ASSERT(NS_IsMainThread());
nsIPrincipal* principal = aPrincipal ? aPrincipal->get() : nullptr;
allowed = aUserFontEntry->mFontSet->IsFontLoadAllowed(
aSrcURI->get(),
principal,
/* aViolations */ nullptr);
MOZ_ASSERT(!entry->IsFontSetAllowedKnown(aUserFontEntry->mFontSet) ||
entry->CheckIsFontSetAllowed(aUserFontEntry->mFontSet) == allowed,
"why does IsFontLoadAllowed return a different value from "
"the cached value in mAllowedFontSets?");
}
if (!allowed) {
if (!aUserFontEntry.mFontSet->IsFontLoadAllowed(aSrc)) {
return nullptr;
}
return entry->GetFontEntry();
}
/* static */ void
gfxUserFontSet::UserFontCache::UpdateAllowedFontSets(
gfxUserFontSet* aUserFontSet)
{
MOZ_ASSERT(NS_IsMainThread());
if (!sUserFonts) {
return;
}
for (auto iter = sUserFonts->Iter(); !iter.Done(); iter.Next()) {
Entry* entry = iter.Get();
if (!entry->IsFontSetAllowedKnown(aUserFontSet)) {
gfxFontSrcPrincipal* principal = entry->GetPrincipal();
if (!principal) {
// This is a data: URI. Just get the standard principal the
// font set uses. (For cases when mUseOriginPrincipal is true,
// we don't use the cached results of IsFontLoadAllowed, and
// instead just process the data: URI load async.)
principal = aUserFontSet->GetStandardFontLoadPrincipal();
}
nsTArray<nsCOMPtr<nsIRunnable>> violations;
bool allowed =
aUserFontSet->IsFontLoadAllowed(entry->GetURI()->get(),
principal->get(),
&violations);
entry->SetIsFontSetAllowed(aUserFontSet, allowed, Move(violations));
}
}
}
/* static */ void
gfxUserFontSet::UserFontCache::ClearAllowedFontSets(
gfxUserFontSet* aUserFontSet)
{
MOZ_ASSERT(NS_IsMainThread());
if (!sUserFonts) {
return;
}
for (auto iter = sUserFonts->Iter(); !iter.Done(); iter.Next()) {
Entry* entry = iter.Get();
entry->ClearIsFontSetAllowed(aUserFontSet);
}
}
void
gfxUserFontSet::UserFontCache::Shutdown()
{
@ -1403,55 +1326,6 @@ gfxUserFontSet::UserFontCache::Shutdown()
MOZ_DEFINE_MALLOC_SIZE_OF(UserFontsMallocSizeOf)
bool
gfxUserFontSet::UserFontCache::Entry::CheckIsFontSetAllowed(
gfxUserFontSet* aUserFontSet) const
{
LoadResultEntry* entry = mAllowedFontSets.GetEntry(aUserFontSet);
MOZ_ASSERT(entry, "UpdateAllowedFontSets should have been called and "
"added an entry to mAllowedFontSets");
return entry->mAllowed;
}
bool
gfxUserFontSet::UserFontCache::Entry::CheckIsFontSetAllowedAndDispatchViolations(
gfxUserFontSet* aUserFontSet) const
{
LoadResultEntry* entry = mAllowedFontSets.GetEntry(aUserFontSet);
MOZ_ASSERT(entry, "UpdateAllowedFontSets should have been called and "
"added an entry to mAllowedFontSets");
if (!entry->mViolations.IsEmpty()) {
aUserFontSet->DispatchFontLoadViolations(entry->mViolations);
}
return entry->mAllowed;
}
bool
gfxUserFontSet::UserFontCache::Entry::IsFontSetAllowedKnown(
gfxUserFontSet* aUserFontSet) const
{
return mAllowedFontSets.Contains(aUserFontSet);
}
void
gfxUserFontSet::UserFontCache::Entry::SetIsFontSetAllowed(
gfxUserFontSet* aUserFontSet,
bool aAllowed,
nsTArray<nsCOMPtr<nsIRunnable>>&& aViolations)
{
MOZ_ASSERT(!IsFontSetAllowedKnown(aUserFontSet));
LoadResultEntry* entry = mAllowedFontSets.PutEntry(aUserFontSet);
entry->mAllowed = aAllowed;
entry->mViolations.SwapElements(aViolations);
}
void
gfxUserFontSet::UserFontCache::Entry::ClearIsFontSetAllowed(
gfxUserFontSet* aUserFontSet)
{
mAllowedFontSets.RemoveEntry(aUserFontSet);
}
void
gfxUserFontSet::UserFontCache::Entry::ReportMemory(
nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)

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

@ -63,6 +63,10 @@ struct gfxFontFaceSrc {
RefPtr<gfxFontSrcPrincipal> mOriginPrincipal; // principal if url
RefPtr<gfxFontFaceBufferSource> mBuffer;
// The principal that should be used for the load. Should only be used for
// URL sources.
gfxFontSrcPrincipal* LoadPrincipal(const gfxUserFontSet&) const;
};
inline bool
@ -265,19 +269,10 @@ public:
// Look up names in a fontlist and return true if any are in the set
bool ContainsUserFontSetFonts(const mozilla::FontFamilyList& aFontList) const;
// check whether the given source is allowed to be loaded;
// returns the Principal (for use in the key when caching the loaded font),
// and whether the load should bypass the cache (force-reload).
virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal,
bool* aBypassCache) = 0;
virtual gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() = 0;
virtual gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() const = 0;
// check whether content policies allow the given URI to load.
virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
nsIPrincipal* aPrincipal,
nsTArray<nsCOMPtr<nsIRunnable>>* aViolations) = 0;
virtual bool IsFontLoadAllowed(const gfxFontFaceSrc&) = 0;
// Dispatches all of the specified runnables to the font face set's
// document's event queue.
@ -320,34 +315,12 @@ public:
// The aPrivate flag is set for requests coming from private windows,
// so we can avoid leaking fonts cached in private windows mode out to
// normal windows.
static gfxFontEntry* GetFont(gfxFontSrcURI* aSrcURI,
gfxFontSrcPrincipal* aPrincipal,
gfxUserFontEntry* aUserFontEntry,
bool aPrivate);
static gfxFontEntry* GetFont(const gfxFontFaceSrc&, const gfxUserFontEntry&);
// Generation number that is incremented whenever an entry is added to
// the cache. (Removals don't increment it.)
static uint32_t Generation() { return sGeneration; }
// For each entry in the user font cache where we haven't recorded
// whether the given user font set is allowed to use the entry,
// call IsFontLoadAllowed and record it.
//
// This function should be called just before a Servo restyle, so
// that we can determine whether a given font load (using a cached
// font) would be allowed without having to call the non-OMT-safe
// IsFontLoadAllowed from the style worker threads.
static void UpdateAllowedFontSets(gfxUserFontSet* aUserFontSet);
// Clears all recorded IsFontLoadAllowed results for the given
// user font set.
//
// This function should be called just before the user font set is
// going away, or when we detect that a document's node principal
// has changed (and thus the already recorded IsFontLoadAllowed
// results are no longer valid).
static void ClearAllowedFontSets(gfxUserFontSet* aUserFontSet);
// Clear everything so that we don't leak URIs and Principals.
static void Shutdown();
@ -415,11 +388,10 @@ public:
{ }
Entry(Entry&& aOther)
: mAllowedFontSets(mozilla::Move(aOther.mAllowedFontSets)),
mURI(mozilla::Move(aOther.mURI)),
mPrincipal(mozilla::Move(aOther.mPrincipal)),
mFontEntry(mozilla::Move(aOther.mFontEntry)),
mPrivate(mozilla::Move(aOther.mPrivate))
: mURI(mozilla::Move(aOther.mURI))
, mPrincipal(mozilla::Move(aOther.mPrincipal))
, mFontEntry(mozilla::Move(aOther.mFontEntry))
, mPrivate(mozilla::Move(aOther.mPrivate))
{ }
~Entry() { }
@ -449,14 +421,6 @@ public:
gfxFontEntry* GetFontEntry() const { return mFontEntry; }
bool IsPrivate() const { return mPrivate; }
bool CheckIsFontSetAllowed(gfxUserFontSet* aUserFontSet) const;
bool CheckIsFontSetAllowedAndDispatchViolations(gfxUserFontSet* aUserFontSet) const;
bool IsFontSetAllowedKnown(gfxUserFontSet* aUserFontSet) const;
void SetIsFontSetAllowed(gfxUserFontSet* aUserFontSet,
bool aAllowed,
nsTArray<nsCOMPtr<nsIRunnable>>&& aViolations);
void ClearIsFontSetAllowed(gfxUserFontSet* aUserFontSet);
void ReportMemory(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize);
@ -477,51 +441,6 @@ public:
aVariations.Length() * sizeof(gfxFontVariation));
}
// An entry in mAllowedFontSets.
class LoadResultEntry : public nsPtrHashKey<gfxUserFontSet>
{
public:
explicit LoadResultEntry(KeyTypePointer aKey)
: nsPtrHashKey(aKey)
, mAllowed(false)
{
}
LoadResultEntry(LoadResultEntry&& aOther)
: nsPtrHashKey(aOther.mKey)
, mAllowed(aOther.mAllowed)
, mViolations(mozilla::Move(aOther.mViolations))
{
}
~LoadResultEntry() {}
// Whether the user font set (the key) is allowed to load this
// entry's font.
bool mAllowed;
// If the load is not allowed, the CSP violation reports that
// must be dispatched when we attempt to use the entry's font.
// (Should be empty if mAllowed is true.)
nsTArray<nsCOMPtr<nsIRunnable>> mViolations;
enum { ALLOW_MEMMOVE = false };
};
// Set of gfxUserFontSets that are allowed to use this cached font
// entry.
//
// This is basically a cache of results of calls to
// gfxUserFontSet::IsFontLoadAllowed for each font set to be used
// when using the cache from style worker threads (where calling
// IsFontLoadAllowed is not possible). Whenever a new entry is
// added to the cache, sGeneration is bumped, and a FontFaceSet
// for a document about to be styled can call UpdateAllowedFontSets
// to record IsFontLoadAllowed results for the new entries. When
// a FontFaceSet is going away, it calls ClearAllowedFontSets
// to remove entries from the mAllowedFontSets tables.
nsTHashtable<LoadResultEntry> mAllowedFontSets;
RefPtr<gfxFontSrcURI> mURI;
RefPtr<gfxFontSrcPrincipal> mPrincipal; // or nullptr for data: URLs
@ -561,6 +480,10 @@ protected:
// Return whether the font set is associated with a private-browsing tab.
virtual bool GetPrivateBrowsing() = 0;
// Return whether the font set is associated with a document that was
// shift-reloaded, for example, and thus should bypass the font cache.
virtual bool BypassCache() = 0;
// parse data for a data URL
virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,
@ -704,6 +627,11 @@ public:
gfxUserFontSet* GetUserFontSet() const { return mFontSet; }
#endif
const nsTArray<gfxFontFaceSrc>& SourceList() const
{
return mSrcList;
}
protected:
const uint8_t* SanitizeOpenTypeData(const uint8_t* aData,
uint32_t aLength,

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

@ -105,6 +105,7 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
FontFaceSet::FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument)
: DOMEventTargetHelper(aWindow)
, mDocument(aDocument)
, mStandardFontLoadPrincipal(new gfxFontSrcPrincipal(mDocument->NodePrincipal()))
, mResolveLazilyCreatedReadyPromise(false)
, mStatus(FontFaceSetLoadStatus::Loaded)
, mNonRuleFacesDirty(false)
@ -113,10 +114,12 @@ FontFaceSet::FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument)
, mDelayedLoadCheck(false)
, mBypassCache(false)
, mPrivateBrowsing(false)
, mHasStandardFontLoadPrincipalChanged(false)
{
MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
mStandardFontLoadPrincipal =
new gfxFontSrcPrincipal(mDocument->NodePrincipal());
// If the pref is not set, don't create the Promise (which the page wouldn't
// be able to get to anyway) as it causes the window.FontFaceSet constructor
// to be created.
@ -1324,77 +1327,71 @@ FontFaceSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
return NS_OK;
}
gfxFontSrcPrincipal*
FontFaceSet::GetStandardFontLoadPrincipal()
void
FontFaceSet::CacheFontLoadability()
{
if (!ServoStyleSet::IsInServoTraversal()) {
UpdateStandardFontLoadPrincipal();
if (!mUserFontSet) {
return;
}
return mStandardFontLoadPrincipal;
}
// TODO(emilio): We could do it a bit more incrementally maybe?
for (auto iter = mUserFontSet->mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
for (const gfxFontEntry* entry : iter.Data()->GetFontList()) {
if (!entry->mIsUserFontContainer) {
continue;
}
nsresult
FontFaceSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal,
bool* aBypassCache)
{
NS_ASSERTION(aFontFaceSrc &&
aFontFaceSrc->mSourceType == gfxFontFaceSrc::eSourceType_URL,
"bad font face url passed to fontloader");
// check same-site origin
NS_ASSERTION(aFontFaceSrc->mURI, "null font uri");
if (!aFontFaceSrc->mURI)
return NS_ERROR_FAILURE;
// use document principal, original principal if flag set
// this enables user stylesheets to load font files via
// @font-face rules
*aPrincipal = GetStandardFontLoadPrincipal();
NS_ASSERTION(aFontFaceSrc->mOriginPrincipal,
"null origin principal in @font-face rule");
if (aFontFaceSrc->mUseOriginPrincipal) {
*aPrincipal = aFontFaceSrc->mOriginPrincipal;
const auto& sourceList =
static_cast<const gfxUserFontEntry*>(entry)->SourceList();
for (const gfxFontFaceSrc& src : sourceList) {
if (src.mSourceType != gfxFontFaceSrc::eSourceType_URL) {
continue;
}
mAllowedFontLoads.LookupForAdd(&src).OrInsert([&] {
return IsFontLoadAllowed(src);
});
}
}
}
*aBypassCache = mBypassCache;
return NS_OK;
}
// @arg aPrincipal: generally this is mDocument->NodePrincipal() but
// might also be the original principal which enables user stylesheets
// to load font files via @font-face rules.
bool
FontFaceSet::IsFontLoadAllowed(nsIURI* aFontLocation,
nsIPrincipal* aPrincipal,
nsTArray<nsCOMPtr<nsIRunnable>>* aViolations)
FontFaceSet::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc)
{
if (aViolations) {
mDocument->StartBufferingCSPViolations();
MOZ_ASSERT(aSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL);
if (ServoStyleSet::IsInServoTraversal()) {
bool* entry = mAllowedFontLoads.GetValue(&aSrc);
MOZ_DIAGNOSTIC_ASSERT(entry, "Missed an update?");
return entry ? *entry : false;
}
MOZ_ASSERT(NS_IsMainThread());
if (!mUserFontSet) {
return false;
}
gfxFontSrcPrincipal* gfxPrincipal =
aSrc.mURI->InheritsSecurityContext()
? nullptr : aSrc.LoadPrincipal(*mUserFontSet);
nsIPrincipal* principal = gfxPrincipal ? gfxPrincipal->get() : nullptr;
nsCOMPtr<nsILoadInfo> secCheckLoadInfo =
new net::LoadInfo(mDocument->NodePrincipal(), // loading principal
aPrincipal, // triggering principal
principal, // triggering principal
mDocument,
nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
nsIContentPolicy::TYPE_FONT);
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
nsresult rv = NS_CheckContentLoadPolicy(aFontLocation,
nsresult rv = NS_CheckContentLoadPolicy(aSrc.mURI->get(),
secCheckLoadInfo,
EmptyCString(), // mime type
&shouldLoad,
nsContentUtils::GetContentPolicy());
if (aViolations) {
mDocument->StopBufferingCSPViolations(*aViolations);
}
return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad);
}
@ -1829,53 +1826,23 @@ FontFaceSet::GetPresContext()
}
void
FontFaceSet::UpdateStandardFontLoadPrincipal()
FontFaceSet::RefreshStandardFontLoadPrincipal()
{
MOZ_ASSERT(NS_IsMainThread());
nsIPrincipal* documentPrincipal = mDocument->NodePrincipal();
if (!mStandardFontLoadPrincipal ||
mStandardFontLoadPrincipal->get() != documentPrincipal) {
if (mStandardFontLoadPrincipal) {
mHasStandardFontLoadPrincipalChanged = true;
}
mStandardFontLoadPrincipal = new gfxFontSrcPrincipal(documentPrincipal);
mStandardFontLoadPrincipal =
new gfxFontSrcPrincipal(mDocument->NodePrincipal());
mAllowedFontLoads.Clear();
if (mUserFontSet) {
mUserFontSet->IncrementGeneration(false);
}
}
// -- FontFaceSet::UserFontSet ------------------------------------------------
/* virtual */ nsresult
FontFaceSet::UserFontSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal,
bool* aBypassCache)
{
if (!mFontFaceSet) {
return NS_ERROR_FAILURE;
}
return mFontFaceSet->CheckFontLoad(aFontFaceSrc, aPrincipal, aBypassCache);
}
/* virtual */ gfxFontSrcPrincipal*
FontFaceSet::UserFontSet::GetStandardFontLoadPrincipal()
{
if (!mFontFaceSet) {
return nullptr;
}
return mFontFaceSet->GetStandardFontLoadPrincipal();
}
/* virtual */ bool
FontFaceSet::UserFontSet::IsFontLoadAllowed(
nsIURI* aFontLocation,
nsIPrincipal* aPrincipal,
nsTArray<nsCOMPtr<nsIRunnable>>* aViolations)
FontFaceSet::UserFontSet::IsFontLoadAllowed(const gfxFontFaceSrc& aSrc)
{
return mFontFaceSet &&
mFontFaceSet->IsFontLoadAllowed(aFontLocation,
aPrincipal,
aViolations);
return mFontFaceSet && mFontFaceSet->IsFontLoadAllowed(aSrc);
}
/* virtual */ void

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

@ -63,16 +63,12 @@ public:
FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() override;
gfxFontSrcPrincipal* GetStandardFontLoadPrincipal() const final
{
return mFontFaceSet ? mFontFaceSet->mStandardFontLoadPrincipal.get() : nullptr;
}
virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal,
bool* aBypassCache) override;
virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
nsIPrincipal* aPrincipal,
nsTArray<nsCOMPtr<nsIRunnable>>* aViolations)
override;
bool IsFontLoadAllowed(const gfxFontFaceSrc&) final;
void DispatchFontLoadViolations(
nsTArray<nsCOMPtr<nsIRunnable>>& aViolations) override;
@ -83,6 +79,11 @@ public:
void RecordFontLoadDone(uint32_t aFontSize,
mozilla::TimeStamp aDoneTime) override;
bool BypassCache() final
{
return mFontFaceSet && mFontFaceSet->mBypassCache;
}
protected:
virtual bool GetPrivateBrowsing() override;
virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
@ -172,14 +173,7 @@ public:
return set ? set->GetPresContext() : nullptr;
}
void UpdateStandardFontLoadPrincipal();
bool HasStandardFontLoadPrincipalChanged()
{
bool changed = mHasStandardFontLoadPrincipalChanged;
mHasStandardFontLoadPrincipalChanged = false;
return changed;
}
void RefreshStandardFontLoadPrincipal();
nsIDocument* Document() const { return mDocument; }
@ -209,6 +203,9 @@ public:
JS::Handle<JS::Value> aThisArg,
mozilla::ErrorResult& aRv);
// For ServoStyleSet to know ahead of time whether a font is loadable.
void CacheFontLoadability();
private:
~FontFaceSet();
@ -282,9 +279,8 @@ private:
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
gfxFontSrcPrincipal** aPrincipal,
bool* aBypassCache);
bool IsFontLoadAllowed(nsIURI* aFontLocation,
nsIPrincipal* aPrincipal,
nsTArray<nsCOMPtr<nsIRunnable>>* aViolations);
bool IsFontLoadAllowed(const gfxFontFaceSrc& aSrc);
void DispatchFontLoadViolations(nsTArray<nsCOMPtr<nsIRunnable>>& aViolations);
nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
const gfxFontFaceSrc* aFontFaceSrc,
@ -342,11 +338,10 @@ private:
//
// This field is used from GetStandardFontLoadPrincipal. When on a
// style worker thread, we use mStandardFontLoadPrincipal assuming
// it is up to date. Because mDocument's principal can change over time,
// its value must be updated by a call to UpdateStandardFontLoadPrincipal
// before a restyle. (When called while on the main thread,
// GetStandardFontLoadPrincipal will call UpdateStandardFontLoadPrincipal
// to ensure its value is up to date.)
// it is up to date.
//
// Because mDocument's principal can change over time,
// its value must be updated by a call to ResetStandardFontLoadPrincipal.
RefPtr<gfxFontSrcPrincipal> mStandardFontLoadPrincipal;
// A Promise that is fulfilled once all of the FontFace objects
@ -375,6 +370,14 @@ private:
// The overall status of the loading or loaded fonts in the FontFaceSet.
mozilla::dom::FontFaceSetLoadStatus mStatus;
// A map from gfxFontFaceSrc pointer identity to whether the load is allowed
// by CSP or other checks. We store this here because querying CSP off the
// main thread is not a great idea.
//
// We could use just the pointer and use this as a hash set, but then we'd
// have no way to verify that we've checked all the loads we should.
nsDataHashtable<nsPtrHashKey<const gfxFontFaceSrc>, bool> mAllowedFontLoads;
// Whether mNonRuleFaces has changed since last time UpdateRules ran.
bool mNonRuleFacesDirty;
@ -397,10 +400,6 @@ private:
// Whether the docshell for our document indicates that we are in private
// browsing mode.
bool mPrivateBrowsing;
// Whether mStandardFontLoadPrincipal has changed since the last call to
// HasStandardFontLoadPrincipalChanged.
bool mHasStandardFontLoadPrincipalChanged;
};
} // namespace dom

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

@ -104,7 +104,6 @@ ServoStyleSet::ServoStyleSet()
, mAuthorStyleDisabled(false)
, mStylistState(StylistState::NotDirty)
, mUserFontSetUpdateGeneration(0)
, mUserFontCacheUpdateGeneration(0)
, mNeedsRestyleAfterEnsureUniqueInner(false)
{
}
@ -467,26 +466,10 @@ ServoStyleSet::PreTraverseSync()
// Ensure that the @font-face data is not stale
uint64_t generation = userFontSet->GetGeneration();
if (generation != mUserFontSetUpdateGeneration) {
mDocument->GetFonts()->CacheFontLoadability();
presContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
mUserFontSetUpdateGeneration = generation;
}
// Ensure that the FontFaceSet's cached document principal is up to date.
FontFaceSet* fontFaceSet =
static_cast<FontFaceSet::UserFontSet*>(userFontSet)->GetFontFaceSet();
fontFaceSet->UpdateStandardFontLoadPrincipal();
bool principalChanged = fontFaceSet->HasStandardFontLoadPrincipalChanged();
// Ensure that the user font cache holds up-to-date data on whether
// our font set is allowed to re-use fonts from the cache.
uint32_t cacheGeneration = gfxUserFontSet::UserFontCache::Generation();
if (principalChanged) {
gfxUserFontSet::UserFontCache::ClearAllowedFontSets(userFontSet);
}
if (cacheGeneration != mUserFontCacheUpdateGeneration || principalChanged) {
gfxUserFontSet::UserFontCache::UpdateAllowedFontSets(userFontSet);
mUserFontCacheUpdateGeneration = cacheGeneration;
}
}
MOZ_ASSERT(!StylistNeedsUpdate());

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

@ -577,7 +577,6 @@ private:
bool mAuthorStyleDisabled;
StylistState mStylistState;
uint64_t mUserFontSetUpdateGeneration;
uint32_t mUserFontCacheUpdateGeneration;
bool mNeedsRestyleAfterEnsureUniqueInner;