Bug 1376964 - Part 6: Use gfxFontSrcURI in the user font set and cache. r=jfkthame
MozReview-Commit-ID: 7eWOTs4kF4v
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -526,17 +526,18 @@ gfxUserFontEntry::DoLoadNextSrc(bool aFo
mFontSet, mSrcIndex,
NS_ConvertUTF16toUTF8(currSrc.mLocalName).get(),
NS_ConvertUTF16toUTF8(mFamilyName).get()));
}
}
// src url ==> start the load process
else if (currSrc.mSourceType == gfxFontFaceSrc::eSourceType_URL) {
- if (gfxPlatform::GetPlatform()->IsFontFormatSupported(currSrc.mURI,
+ if (gfxPlatform::GetPlatform()->IsFontFormatSupported(
+ currSrc.mURI->get(),
currSrc.mFormatFlags)) {
if (ServoStyleSet* set = ServoStyleSet::Current()) {
set->AppendTask(PostTraversalTask::LoadFontEntry(this));
SetLoadState(STATUS_LOAD_PENDING);
return;
}
@@ -569,19 +570,17 @@ gfxUserFontEntry::DoLoadNextSrc(bool aFo
// 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) {
- rv = NS_URIChainHasFlags(currSrc.mURI,
- nsIProtocolHandler::URI_SYNC_LOAD_IS_OK,
- &loadDoesntSpin);
+ 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,
@@ -1134,40 +1133,35 @@ gfxUserFontSet::UserFontCache::Flusher::
} else {
NS_NOTREACHED("unexpected topic");
}
return NS_OK;
}
static bool
-IgnorePrincipal(nsIURI* aURI)
+IgnorePrincipal(gfxFontSrcURI* aURI)
{
- nsresult rv;
- bool inherits = false;
- rv = NS_URIChainHasFlags(aURI,
- nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
- &inherits);
- return NS_SUCCEEDED(rv) && inherits;
+ return aURI->InheritsSecurityContext();
}
bool
gfxUserFontSet::UserFontCache::Entry::KeyEquals(const KeyTypePointer aKey) const
{
const gfxFontEntry* fe = aKey->mFontEntry;
- bool result;
- if (NS_FAILED(mURI->Equals(aKey->mURI, &result)) || !result) {
+ if (!mURI->Equals(aKey->mURI)) {
return false;
}
// For data: URIs, we don't care about the principal; otherwise, check it.
if (!IgnorePrincipal(mURI)) {
NS_ASSERTION(mPrincipal && aKey->mPrincipal,
"only data: URIs are allowed to omit the principal");
+ bool result;
if (NS_FAILED(mPrincipal->Equals(aKey->mPrincipal, &result)) ||
!result) {
return false;
}
}
if (mPrivate != aKey->mPrivate) {
return false;
@@ -1266,17 +1260,17 @@ gfxUserFontSet::UserFontCache::ForgetFon
#ifdef DEBUG_USERFONT_CACHE
printf("userfontcache removed fontentry: %p\n", aFontEntry);
Dump();
#endif
}
gfxFontEntry*
-gfxUserFontSet::UserFontCache::GetFont(nsIURI* aSrcURI,
+gfxUserFontSet::UserFontCache::GetFont(gfxFontSrcURI* aSrcURI,
nsIPrincipal* aPrincipal,
gfxUserFontEntry* aUserFontEntry,
bool aPrivate)
{
if (!sUserFonts ||
Preferences::GetBool("gfx.downloadable_fonts.disable_cache")) {
return nullptr;
}
@@ -1300,17 +1294,17 @@ gfxUserFontSet::UserFontCache::GetFont(n
// 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,
+ allowed = aUserFontEntry->mFontSet->IsFontLoadAllowed(aSrcURI->get(),
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) {
@@ -1337,17 +1331,18 @@ gfxUserFontSet::UserFontCache::UpdateAll
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);
+ aUserFontSet->IsFontLoadAllowed(entry->GetURI()->get(),
+ principal);
entry->SetIsFontSetAllowed(aUserFontSet, allowed);
}
}
}
/* static */ void
gfxUserFontSet::UserFontCache::ClearAllowedFontSets(
gfxUserFontSet* aUserFontSet)
@@ -1422,17 +1417,17 @@ gfxUserFontSet::UserFontCache::Entry::Re
NS_ConvertUTF16toUTF8 familyName(mFontEntry->mFamilyName);
path.AppendPrintf("family=%s", familyName.get());
if (mURI) {
nsCString spec = mURI->GetSpecOrDefault();
spec.ReplaceChar('/', '\\');
// Some fonts are loaded using horrendously-long data: URIs;
// truncate those before reporting them.
bool isData;
- if (NS_SUCCEEDED(mURI->SchemeIs("data", &isData)) && isData &&
+ if (NS_SUCCEEDED(mURI->get()->SchemeIs("data", &isData)) && isData &&
spec.Length() > 255) {
spec.Truncate(252);
spec.Append("...");
}
path.AppendPrintf(", url=%s", spec.get());
}
if (mPrincipal) {
nsCOMPtr<nsIURI> uri;
@@ -1508,17 +1503,17 @@ gfxUserFontSet::UserFontCache::Entry::Du
}
}
NS_ASSERTION(mURI, "null URI in userfont cache entry");
printf("userfontcache fontEntry: %p fonturihash: %8.8x "
"family: %s domainset: %s principal: [%s]\n",
mFontEntry,
- nsURIHashKey::HashKey(mURI),
+ mURI->Hash(),
NS_ConvertUTF16toUTF8(mFontEntry->FamilyName()).get(),
setDomain ? "true" : "false",
principalURISpec.get());
}
void
gfxUserFontSet::UserFontCache::Dump()
{
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -3,16 +3,17 @@
* 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 GFX_USER_FONT_SET_H
#define GFX_USER_FONT_SET_H
#include "gfxFont.h"
#include "gfxFontFamilyList.h"
+#include "gfxFontSrcURI.h"
#include "nsRefPtrHashtable.h"
#include "nsCOMPtr.h"
#include "nsIURI.h"
#include "nsIPrincipal.h"
#include "nsIScriptError.h"
#include "nsURIHashKey.h"
#include "mozilla/net/ReferrerPolicy.h"
#include "gfxFontConstants.h"
@@ -50,38 +51,41 @@ struct gfxFontFaceSrc {
bool mUseOriginPrincipal;
// format hint flags, union of all possible formats
// (e.g. TrueType, EOT, SVG, etc.)
// see FLAG_FORMAT_* enum values below
uint32_t mFormatFlags;
nsString mLocalName; // full font name if local
- nsCOMPtr<nsIURI> mURI; // uri if url
+ RefPtr<gfxFontSrcURI> mURI; // uri if url
nsCOMPtr<nsIURI> mReferrer; // referrer url if url
mozilla::net::ReferrerPolicy mReferrerPolicy;
nsCOMPtr<nsIPrincipal> mOriginPrincipal; // principal if url
RefPtr<gfxFontFaceBufferSource> mBuffer;
};
inline bool
operator==(const gfxFontFaceSrc& a, const gfxFontFaceSrc& b)
{
+ // The mReferrer and mOriginPrincipal comparisons aren't safe OMT.
+ MOZ_ASSERT(NS_IsMainThread());
+
if (a.mSourceType != b.mSourceType) {
return false;
}
switch (a.mSourceType) {
case gfxFontFaceSrc::eSourceType_Local:
return a.mLocalName == b.mLocalName;
case gfxFontFaceSrc::eSourceType_URL: {
bool equals;
return a.mUseOriginPrincipal == b.mUseOriginPrincipal &&
a.mFormatFlags == b.mFormatFlags &&
- NS_SUCCEEDED(a.mURI->Equals(b.mURI, &equals)) && equals &&
+ (a.mURI == b.mURI || a.mURI->Equals(b.mURI)) &&
NS_SUCCEEDED(a.mReferrer->Equals(b.mReferrer, &equals)) &&
equals &&
a.mReferrerPolicy == b.mReferrerPolicy &&
a.mOriginPrincipal->Equals(b.mOriginPrincipal);
}
case gfxFontFaceSrc::eSourceType_Buffer:
return a.mBuffer == b.mBuffer;
}
@@ -102,17 +106,17 @@ public:
mCompression(kUnknownCompression),
mPrivate(false), mIsBuffer(false)
{ }
virtual ~gfxUserFontData() { }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
nsTArray<uint8_t> mMetadata; // woff metadata block (compressed), if any
- nsCOMPtr<nsIURI> mURI; // URI of the source, if it was url()
+ RefPtr<gfxFontSrcURI> mURI; // URI of the source, if it was url()
nsCOMPtr<nsIPrincipal> mPrincipal; // principal for the download, if url()
nsString mLocalName; // font name used for the source, if local()
nsString mRealName; // original fullname from the font resource
uint32_t mSrcIndex; // index in the rule's source list
uint32_t mFormat; // format hint for the source used, if any
uint32_t mMetaOrigLen; // length needed to decompress metadata
uint8_t mCompression; // compression type
bool mPrivate; // whether font belongs to a private window
@@ -293,17 +297,17 @@ public:
// refers to it.
static void ForgetFont(gfxFontEntry* aFontEntry);
// Return the gfxFontEntry corresponding to a given URI and principal,
// and the features of the given userfont entry, or nullptr if none is available.
// 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(nsIURI* aSrcURI,
+ static gfxFontEntry* GetFont(gfxFontSrcURI* aSrcURI,
nsIPrincipal* aPrincipal,
gfxUserFontEntry* aUserFontEntry,
bool aPrivate);
// Generation number that is incremented whenever an entry is added to
// the cache. (Removals don't increment it.)
static uint32_t Generation() { return sGeneration; }
@@ -359,24 +363,24 @@ public:
// Key used to look up entries in the user-font cache.
// Note that key comparison does *not* use the mFontEntry field
// as a whole; it only compares specific fields within the entry
// (weight/width/style/features) that could affect font selection
// or rendering, and that must match between a font-set's userfont
// entry and the corresponding "real" font entry.
struct Key {
- nsCOMPtr<nsIURI> mURI;
+ RefPtr<gfxFontSrcURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal; // use nullptr with data: URLs
// The font entry MUST notify the cache when it is destroyed
// (by calling ForgetFont()).
gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry;
bool mPrivate;
- Key(nsIURI* aURI, nsIPrincipal* aPrincipal,
+ Key(gfxFontSrcURI* aURI, nsIPrincipal* aPrincipal,
gfxFontEntry* aFontEntry, bool aPrivate)
: mURI(aURI),
mPrincipal(aPrincipal),
mFontEntry(aFontEntry),
mPrivate(aPrivate)
{ }
};
@@ -406,28 +410,28 @@ public:
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
static PLDHashNumber HashKey(const KeyTypePointer aKey) {
uint32_t principalHash = 0;
if (aKey->mPrincipal) {
aKey->mPrincipal->GetHashValue(&principalHash);
}
return mozilla::HashGeneric(principalHash + int(aKey->mPrivate),
- nsURIHashKey::HashKey(aKey->mURI),
+ aKey->mURI->Hash(),
HashFeatures(aKey->mFontEntry->mFeatureSettings),
mozilla::HashString(aKey->mFontEntry->mFamilyName),
(aKey->mFontEntry->mStyle |
(aKey->mFontEntry->mWeight << 2) |
(aKey->mFontEntry->mStretch << 11) ) ^
aKey->mFontEntry->mLanguageOverride);
}
enum { ALLOW_MEMMOVE = false };
- nsIURI* GetURI() const { return mURI; }
+ gfxFontSrcURI* 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);
@@ -455,17 +459,17 @@ public:
// 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;
+ RefPtr<gfxFontSrcURI> mURI;
nsCOMPtr<nsIPrincipal> mPrincipal; // or nullptr for data: URLs
// The "real" font entry corresponding to this downloaded font.
// The font entry MUST notify the cache when it is destroyed
// (by calling ForgetFont()).
gfxFontEntry* MOZ_NON_OWNING_REF mFontEntry;
// Whether this font was loaded from a private window.
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -2,16 +2,17 @@
/* vim: set ts=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 "FontFaceSet.h"
#include "gfxFontConstants.h"
+#include "gfxFontSrcURI.h"
#include "mozilla/css/Declaration.h"
#include "mozilla/css/Loader.h"
#include "mozilla/dom/FontFaceSetBinding.h"
#include "mozilla/dom/FontFaceSetIterator.h"
#include "mozilla/dom/FontFaceSetLoadEvent.h"
#include "mozilla/dom/FontFaceSetLoadEventBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/AsyncEventDispatcher.h"
@@ -626,26 +627,27 @@ FontFaceSet::StartLoad(gfxUserFontEntry*
nsCOMPtr<nsILoadGroup> loadGroup(mDocument->GetDocumentLoadGroup());
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.
rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
- aFontFaceSrc->mURI,
+ aFontFaceSrc->mURI->get(),
mDocument,
aUserFontEntry->GetPrincipal(),
nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
nsIContentPolicy::TYPE_FONT,
loadGroup);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<nsFontFaceLoader> fontLoader =
- new nsFontFaceLoader(aUserFontEntry, aFontFaceSrc->mURI, this, channel);
+ new nsFontFaceLoader(aUserFontEntry, aFontFaceSrc->mURI->get(), this,
+ channel);
if (LOG_ENABLED()) {
LOG(("userfonts (%p) download start - font uri: (%s) "
"referrer uri: (%s)\n",
fontLoader.get(), aFontFaceSrc->mURI->GetSpecOrDefault().get(),
aFontFaceSrc->mReferrer
? aFontFaceSrc->mReferrer->GetSpecOrDefault().get()
: ""));
@@ -677,17 +679,18 @@ FontFaceSet::StartLoad(gfxUserFontEntry*
nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
if (priorityChannel) {
priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
}
rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
NS_ENSURE_SUCCESS(rv, rv);
- mozilla::net::PredictorLearn(aFontFaceSrc->mURI, mDocument->GetDocumentURI(),
+ mozilla::net::PredictorLearn(aFontFaceSrc->mURI->get(),
+ mDocument->GetDocumentURI(),
nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
loadGroup);
rv = channel->AsyncOpen2(streamLoader);
if (NS_FAILED(rv)) {
fontLoader->DropChannel(); // explicitly need to break ref cycle
}
@@ -1114,17 +1117,18 @@ FontFaceSet::FindOrCreateUserFontEntryFr
case eCSSUnit_Local_Font:
val.GetStringValue(face->mLocalName);
face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
face->mURI = nullptr;
face->mFormatFlags = 0;
break;
case eCSSUnit_URL: {
face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
- face->mURI = val.GetURLValue();
+ nsIURI* uri = val.GetURLValue();
+ face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
URLValue* url = val.GetURLStructValue();
face->mReferrer = url->mExtraData->GetReferrer();
face->mReferrerPolicy = mDocument->GetReferrerPolicy();
face->mOriginPrincipal = url->mExtraData->GetPrincipal();
NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
// agent and user stylesheets are treated slightly differently,
// the same-site origin check and access control headers are
@@ -1395,17 +1399,17 @@ FontFaceSet::SyncLoadFontData(gfxUserFon
// 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_DATA_INHERITS or not, to be more
// restrictive we use SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS.
rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
- aFontFaceSrc->mURI,
+ aFontFaceSrc->mURI->get(),
mDocument,
aFontToLoad->GetPrincipal(),
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
nsIContentPolicy::TYPE_FONT);
NS_ENSURE_SUCCESS(rv, rv);
// blocking stream is OK for data URIs