mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1376964 - Part 4: Call FontLoadAllowed ahead of time and cache the results for style worker threads. r=jfkthame
Handling a document's node principal changing is done in part 9. MozReview-Commit-ID: 1gPtRpddys5 --HG-- extra : rebase_source : 5b1d40af5ad0484440075e7229dc9ae3d5a13764
This commit is contained in:
parent
5b5b4e145c
commit
b2cd9f4a51
@ -909,6 +909,8 @@ gfxUserFontSet::~gfxUserFontSet()
|
||||
if (fp) {
|
||||
fp->RemoveUserFontSet(this);
|
||||
}
|
||||
|
||||
UserFontCache::ClearAllowedFontSets(this);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxUserFontEntry>
|
||||
@ -1279,13 +1281,6 @@ gfxUserFontSet::UserFontCache::GetFont(nsIURI* aSrcURI,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (!aUserFontEntry->mFontSet->IsFontLoadAllowed(aSrcURI, aPrincipal)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Ignore principal when looking up a data: URI.
|
||||
nsIPrincipal* principal;
|
||||
if (IgnorePrincipal(aSrcURI)) {
|
||||
@ -1296,11 +1291,77 @@ gfxUserFontSet::UserFontCache::GetFont(nsIURI* aSrcURI,
|
||||
|
||||
Entry* entry = sUserFonts->GetEntry(Key(aSrcURI, principal, aUserFontEntry,
|
||||
aPrivate));
|
||||
if (entry) {
|
||||
return entry->GetFontEntry();
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
// 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->IsFontSetAllowed(aUserFontEntry->mFontSet);
|
||||
} else {
|
||||
// Call IsFontLoadAllowed directly, since we are on the main thread.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
allowed = aUserFontEntry->mFontSet->IsFontLoadAllowed(aSrcURI,
|
||||
aPrincipal);
|
||||
MOZ_ASSERT(!entry->IsFontSetAllowedKnown(aUserFontEntry->mFontSet) ||
|
||||
entry->IsFontSetAllowed(aUserFontEntry->mFontSet) == allowed,
|
||||
"why does IsFontLoadAllowed return a different value from "
|
||||
"the cached value in mAllowedFontSets?");
|
||||
}
|
||||
|
||||
if (!allowed) {
|
||||
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)) {
|
||||
nsIPrincipal* 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();
|
||||
}
|
||||
bool allowed =
|
||||
aUserFontSet->IsFontLoadAllowed(entry->GetURI(), principal);
|
||||
entry->SetIsFontSetAllowed(aUserFontSet, allowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -1314,6 +1375,40 @@ gfxUserFontSet::UserFontCache::Shutdown()
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(UserFontsMallocSizeOf)
|
||||
|
||||
bool
|
||||
gfxUserFontSet::UserFontCache::Entry::IsFontSetAllowed(
|
||||
gfxUserFontSet* aUserFontSet) const
|
||||
{
|
||||
bool allowed = false;
|
||||
DebugOnly<bool> found = mAllowedFontSets.Get(aUserFontSet, &allowed);
|
||||
MOZ_ASSERT(found, "UpdateAllowedFontSets should have been called and "
|
||||
"added an entry to mAllowedFontSets");
|
||||
return allowed;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxUserFontSet::UserFontCache::Entry::IsFontSetAllowedKnown(
|
||||
gfxUserFontSet* aUserFontSet) const
|
||||
{
|
||||
return mAllowedFontSets.Contains(aUserFontSet);
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontSet::UserFontCache::Entry::SetIsFontSetAllowed(
|
||||
gfxUserFontSet* aUserFontSet,
|
||||
bool aAllowed)
|
||||
{
|
||||
MOZ_ASSERT(!IsFontSetAllowedKnown(aUserFontSet));
|
||||
mAllowedFontSets.Put(aUserFontSet, aAllowed);
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontSet::UserFontCache::Entry::ClearIsFontSetAllowed(
|
||||
gfxUserFontSet* aUserFontSet)
|
||||
{
|
||||
mAllowedFontSets.Remove(aUserFontSet);
|
||||
}
|
||||
|
||||
void
|
||||
gfxUserFontSet::UserFontCache::Entry::ReportMemory(
|
||||
nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize)
|
||||
|
@ -256,6 +256,8 @@ public:
|
||||
nsIPrincipal** aPrincipal,
|
||||
bool* aBypassCache) = 0;
|
||||
|
||||
virtual nsIPrincipal* GetStandardFontLoadPrincipal() = 0;
|
||||
|
||||
// check whether content policies allow the given URI to load.
|
||||
virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
|
||||
nsIPrincipal* aPrincipal) = 0;
|
||||
@ -305,6 +307,25 @@ public:
|
||||
// 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();
|
||||
|
||||
@ -401,10 +422,16 @@ public:
|
||||
|
||||
enum { ALLOW_MEMMOVE = false };
|
||||
|
||||
nsIURI* GetURI() const { return mURI; }
|
||||
nsIPrincipal* GetPrincipal() const { return mPrincipal; }
|
||||
gfxFontEntry* GetFontEntry() const { return mFontEntry; }
|
||||
|
||||
bool IsPrivate() const { return mPrivate; }
|
||||
|
||||
bool IsFontSetAllowed(gfxUserFontSet* aUserFontSet) const;
|
||||
bool IsFontSetAllowedKnown(gfxUserFontSet* aUserFontSet) const;
|
||||
void SetIsFontSetAllowed(gfxUserFontSet* aUserFontSet, bool aAllowed);
|
||||
void ClearIsFontSetAllowed(gfxUserFontSet* aUserFontSet);
|
||||
|
||||
void ReportMemory(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize);
|
||||
|
||||
@ -419,6 +446,20 @@ public:
|
||||
aFeatures.Length() * sizeof(gfxFontFeature));
|
||||
}
|
||||
|
||||
// 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.
|
||||
nsDataHashtable<nsPtrHashKey<gfxUserFontSet>, bool> mAllowedFontSets;
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal; // or nullptr for data: URLs
|
||||
|
||||
|
@ -1326,6 +1326,12 @@ FontFaceSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
FontFaceSet::GetStandardFontLoadPrincipal()
|
||||
{
|
||||
return mDocument->NodePrincipal();
|
||||
}
|
||||
|
||||
nsresult
|
||||
FontFaceSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
|
||||
nsIPrincipal** aPrincipal,
|
||||
@ -1344,7 +1350,7 @@ FontFaceSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
|
||||
// use document principal, original principal if flag set
|
||||
// this enables user stylesheets to load font files via
|
||||
// @font-face rules
|
||||
*aPrincipal = mDocument->NodePrincipal();
|
||||
*aPrincipal = GetStandardFontLoadPrincipal();
|
||||
|
||||
NS_ASSERTION(aFontFaceSrc->mOriginPrincipal,
|
||||
"null origin principal in @font-face rule");
|
||||
@ -1797,6 +1803,15 @@ FontFaceSet::UserFontSet::CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
|
||||
return mFontFaceSet->CheckFontLoad(aFontFaceSrc, aPrincipal, aBypassCache);
|
||||
}
|
||||
|
||||
/* virtual */ nsIPrincipal*
|
||||
FontFaceSet::UserFontSet::GetStandardFontLoadPrincipal()
|
||||
{
|
||||
if (!mFontFaceSet) {
|
||||
return nullptr;
|
||||
}
|
||||
return mFontFaceSet->GetStandardFontLoadPrincipal();
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
FontFaceSet::UserFontSet::IsFontLoadAllowed(nsIURI* aFontLocation,
|
||||
nsIPrincipal* aPrincipal)
|
||||
|
@ -63,6 +63,8 @@ public:
|
||||
|
||||
FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
|
||||
|
||||
nsIPrincipal* GetStandardFontLoadPrincipal() override;
|
||||
|
||||
virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
|
||||
nsIPrincipal** aPrincipal,
|
||||
bool* aBypassCache) override;
|
||||
@ -261,6 +263,7 @@ private:
|
||||
|
||||
nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
|
||||
const gfxFontFaceSrc* aFontFaceSrc);
|
||||
nsIPrincipal* GetStandardFontLoadPrincipal();
|
||||
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
|
||||
nsIPrincipal** aPrincipal,
|
||||
bool* aBypassCache);
|
||||
|
@ -40,6 +40,7 @@ ServoStyleSet::ServoStyleSet()
|
||||
, mAuthorStyleDisabled(false)
|
||||
, mStylistState(StylistState::NotDirty)
|
||||
, mUserFontSetUpdateGeneration(0)
|
||||
, mUserFontCacheUpdateGeneration(0)
|
||||
, mNeedsRestyleAfterEnsureUniqueInner(false)
|
||||
{
|
||||
}
|
||||
@ -298,13 +299,21 @@ ServoStyleSet::PreTraverseSync()
|
||||
// it so force computation early.
|
||||
mPresContext->Document()->GetDocumentState();
|
||||
|
||||
// Ensure that the @font-face data is not stale
|
||||
if (gfxUserFontSet* userFontSet = mPresContext->Document()->GetUserFontSet()) {
|
||||
// Ensure that the @font-face data is not stale
|
||||
uint64_t generation = userFontSet->GetGeneration();
|
||||
if (generation != mUserFontSetUpdateGeneration) {
|
||||
mPresContext->DeviceContext()->UpdateFontCacheUserFonts(userFontSet);
|
||||
mUserFontSetUpdateGeneration = generation;
|
||||
}
|
||||
|
||||
// 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 (cacheGeneration != mUserFontCacheUpdateGeneration) {
|
||||
gfxUserFontSet::UserFontCache::UpdateAllowedFontSets(userFontSet);
|
||||
mUserFontCacheUpdateGeneration = cacheGeneration;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStylistIfNeeded();
|
||||
|
@ -583,6 +583,7 @@ private:
|
||||
bool mAuthorStyleDisabled;
|
||||
StylistState mStylistState;
|
||||
uint64_t mUserFontSetUpdateGeneration;
|
||||
uint32_t mUserFontCacheUpdateGeneration;
|
||||
|
||||
bool mNeedsRestyleAfterEnsureUniqueInner;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user