Commit d9041775 authored by bashi@chromium.org's avatar bashi@chromium.org

Webfont CORS-enabled fetching with fallback

Use CORS-enabled fetch method for webfonts. If the CORS-enabled fetch
fails, make a second CORS-disabled request so that we won't break
existing webpages which don't honor the css3 font spec.

We also collect CORS failure counts.

BUG=286681
R=ksakamoto@chromium.org, japhet@chromium.org

Review URL: https://codereview.chromium.org/230383003

git-svn-id: svn://svn.chromium.org/blink/trunk@171423 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 9e4a049c
......@@ -49,6 +49,11 @@ void CSSFontFace::setSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
m_segmentedFontFace = segmentedFontFace;
}
CSSFontSelector* CSSFontFace::fontSelector() const
{
return m_segmentedFontFace ? m_segmentedFontFace->fontSelector() : 0;
}
void CSSFontFace::beginLoadIfNeeded(CSSFontFaceSource* source, CSSFontSelector* fontSelector)
{
if (source->resource() && source->resource()->stillNeedsLoad()) {
......
......@@ -65,6 +65,9 @@ public:
bool isValid() const { return !m_sources.isEmpty(); }
// FIXME: Should not be exposed (used by tentative CORS fallback code).
CSSFontSelector* fontSelector() const;
void addSource(PassOwnPtr<CSSFontFaceSource>);
void beginLoadIfNeeded(CSSFontFaceSource*, CSSFontSelector* = 0);
......
......@@ -88,10 +88,23 @@ bool CSSFontFaceSrcValue::hasFailedOrCanceledSubresources() const
return m_fetched->loadFailedOrCanceled();
}
bool CSSFontFaceSrcValue::shouldSetCrossOriginAccessControl(const KURL& resource, SecurityOrigin* securityOrigin)
{
if (resource.isLocalFile() || resource.protocolIsData())
return false;
if (m_fetched && m_fetched->isCORSFailed())
return false;
return !securityOrigin->canRequest(resource);
}
FontResource* CSSFontFaceSrcValue::fetch(Document* document)
{
if (!m_fetched) {
if (!m_fetched || m_fetched->isCORSFailed()) {
FetchRequest request(ResourceRequest(document->completeURL(m_resource)), FetchInitiatorTypeNames::css);
SecurityOrigin* securityOrigin = document->securityOrigin();
if (shouldSetCrossOriginAccessControl(request.url(), securityOrigin)) {
request.setCrossOriginAccessControl(securityOrigin, DoNotAllowStoredCredentials);
}
m_fetched = document->fetcher()->fetchFont(request);
}
return m_fetched.get();
......
......@@ -84,6 +84,8 @@ private:
{
}
bool shouldSetCrossOriginAccessControl(const KURL& resource, SecurityOrigin*);
String m_resource;
String m_format;
bool m_isLocal;
......
......@@ -5,8 +5,11 @@
#include "config.h"
#include "core/css/RemoteFontFaceSource.h"
#include "FetchInitiatorTypeNames.h"
#include "core/css/CSSCustomFontData.h"
#include "core/css/CSSFontFace.h"
#include "core/css/CSSFontSelector.h"
#include "core/fetch/ResourceFetcher.h"
#include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/SimpleFontData.h"
......@@ -82,6 +85,24 @@ void RemoteFontFaceSource::fontLoadWaitLimitExceeded(FontResource*)
m_histograms.recordFallbackTime(m_font.get());
}
void RemoteFontFaceSource::corsFailed(FontResource*)
{
pruneTable();
if (m_face) {
Document* document = m_face->fontSelector() ? m_face->fontSelector()->document() : 0;
if (document) {
FetchRequest request(ResourceRequest(m_font->url()), FetchInitiatorTypeNames::css);
m_font->removeClient(this);
m_font = document->fetcher()->fetchFont(request);
m_font->addClient(this);
m_face->fontSelector()->beginLoadingFontSoon(m_font.get());
} else {
m_face->fontLoaded(this);
}
}
}
PassRefPtr<SimpleFontData> RemoteFontFaceSource::createFontData(const FontDescription& fontDescription)
{
if (!isLoaded())
......@@ -156,6 +177,12 @@ void RemoteFontFaceSource::FontLoadHistograms::recordRemoteFont(const FontResour
: font->response().wasCached() ? Hit
: Miss;
blink::Platform::current()->histogramEnumeration("WebFont.CacheHit", histogramValue, CacheHitEnumMax);
if (!font->errorOccurred()) {
enum { CORSFail, CORSSuccess, CORSEnumMax };
int corsValue = font->options().corsEnabled == IsCORSEnabled ? CORSSuccess : CORSFail;
blink::Platform::current()->histogramEnumeration("WebFont.CORSSuccess", corsValue, CORSEnumMax);
}
}
}
......
......@@ -31,6 +31,7 @@ public:
virtual void didStartFontLoad(FontResource*) OVERRIDE;
virtual void fontLoaded(FontResource*) OVERRIDE;
virtual void fontLoadWaitLimitExceeded(FontResource*) OVERRIDE;
virtual void corsFailed(FontResource*) OVERRIDE;
// For UMA reporting
virtual bool hadBlankText() OVERRIDE { return m_histograms.hadBlankText(); }
......
......@@ -50,6 +50,7 @@ FontResource::FontResource(const ResourceRequest& resourceRequest)
: Resource(resourceRequest, Font)
, m_loadInitiated(false)
, m_exceedsFontLoadWaitLimit(false)
, m_corsFailed(false)
, m_fontLoadWaitLimitTimer(this, &FontResource::fontLoadWaitLimitCallback)
{
}
......@@ -184,9 +185,16 @@ void FontResource::allClientsRemoved()
void FontResource::checkNotify()
{
m_fontLoadWaitLimitTimer.stop();
ResourceClientWalker<FontResourceClient> w(m_clients);
while (FontResourceClient* c = w.next())
c->fontLoaded(this);
// FIXME: Remove this CORS fallback once we have enough UMA to make a decision.
if (m_corsFailed) {
while (FontResourceClient* client = w.next())
client->corsFailed(this);
} else {
while (FontResourceClient* c = w.next())
c->fontLoaded(this);
}
}
}
......@@ -57,6 +57,9 @@ public:
virtual bool stillNeedsLoad() const OVERRIDE { return !m_loadInitiated; }
bool exceedsFontLoadWaitLimit() const { return m_exceedsFontLoadWaitLimit; }
void setCORSFailed() { m_corsFailed = true; }
bool isCORSFailed() const { return m_corsFailed; }
bool ensureCustomFontData();
FontPlatformData platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth);
......@@ -75,6 +78,7 @@ private:
OwnPtr<FontCustomPlatformData> m_fontData;
bool m_loadInitiated;
bool m_exceedsFontLoadWaitLimit;
bool m_corsFailed;
Timer<FontResource> m_fontLoadWaitLimitTimer;
#if ENABLE(SVG_FONTS)
......@@ -94,6 +98,7 @@ public:
virtual void fontLoaded(FontResource*) { }
virtual void didStartFontLoad(FontResource*) { }
virtual void fontLoadWaitLimitExceeded(FontResource*) { }
virtual void corsFailed(FontResource*) { }
};
}
......
......@@ -588,6 +588,12 @@ bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sour
String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo);
frame()->document()->addConsoleMessage(JSMessageSource, ErrorMessageLevel, resourceType + " from origin '" + SecurityOrigin::create(url)->toString() + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription);
}
// FIXME: Remove later, http://crbug.com/286681
if (resource->type() == Resource::Font) {
FontResource* fontResource = toFontResource(resource);
fontResource->setCORSFailed();
}
return false;
}
return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment