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) ...@@ -49,6 +49,11 @@ void CSSFontFace::setSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
m_segmentedFontFace = segmentedFontFace; m_segmentedFontFace = segmentedFontFace;
} }
CSSFontSelector* CSSFontFace::fontSelector() const
{
return m_segmentedFontFace ? m_segmentedFontFace->fontSelector() : 0;
}
void CSSFontFace::beginLoadIfNeeded(CSSFontFaceSource* source, CSSFontSelector* fontSelector) void CSSFontFace::beginLoadIfNeeded(CSSFontFaceSource* source, CSSFontSelector* fontSelector)
{ {
if (source->resource() && source->resource()->stillNeedsLoad()) { if (source->resource() && source->resource()->stillNeedsLoad()) {
......
...@@ -65,6 +65,9 @@ public: ...@@ -65,6 +65,9 @@ public:
bool isValid() const { return !m_sources.isEmpty(); } 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 addSource(PassOwnPtr<CSSFontFaceSource>);
void beginLoadIfNeeded(CSSFontFaceSource*, CSSFontSelector* = 0); void beginLoadIfNeeded(CSSFontFaceSource*, CSSFontSelector* = 0);
......
...@@ -88,10 +88,23 @@ bool CSSFontFaceSrcValue::hasFailedOrCanceledSubresources() const ...@@ -88,10 +88,23 @@ bool CSSFontFaceSrcValue::hasFailedOrCanceledSubresources() const
return m_fetched->loadFailedOrCanceled(); 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) FontResource* CSSFontFaceSrcValue::fetch(Document* document)
{ {
if (!m_fetched) { if (!m_fetched || m_fetched->isCORSFailed()) {
FetchRequest request(ResourceRequest(document->completeURL(m_resource)), FetchInitiatorTypeNames::css); 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); m_fetched = document->fetcher()->fetchFont(request);
} }
return m_fetched.get(); return m_fetched.get();
......
...@@ -84,6 +84,8 @@ private: ...@@ -84,6 +84,8 @@ private:
{ {
} }
bool shouldSetCrossOriginAccessControl(const KURL& resource, SecurityOrigin*);
String m_resource; String m_resource;
String m_format; String m_format;
bool m_isLocal; bool m_isLocal;
......
...@@ -5,8 +5,11 @@ ...@@ -5,8 +5,11 @@
#include "config.h" #include "config.h"
#include "core/css/RemoteFontFaceSource.h" #include "core/css/RemoteFontFaceSource.h"
#include "FetchInitiatorTypeNames.h"
#include "core/css/CSSCustomFontData.h" #include "core/css/CSSCustomFontData.h"
#include "core/css/CSSFontFace.h" #include "core/css/CSSFontFace.h"
#include "core/css/CSSFontSelector.h"
#include "core/fetch/ResourceFetcher.h"
#include "platform/fonts/FontCache.h" #include "platform/fonts/FontCache.h"
#include "platform/fonts/FontDescription.h" #include "platform/fonts/FontDescription.h"
#include "platform/fonts/SimpleFontData.h" #include "platform/fonts/SimpleFontData.h"
...@@ -82,6 +85,24 @@ void RemoteFontFaceSource::fontLoadWaitLimitExceeded(FontResource*) ...@@ -82,6 +85,24 @@ void RemoteFontFaceSource::fontLoadWaitLimitExceeded(FontResource*)
m_histograms.recordFallbackTime(m_font.get()); 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) PassRefPtr<SimpleFontData> RemoteFontFaceSource::createFontData(const FontDescription& fontDescription)
{ {
if (!isLoaded()) if (!isLoaded())
...@@ -156,6 +177,12 @@ void RemoteFontFaceSource::FontLoadHistograms::recordRemoteFont(const FontResour ...@@ -156,6 +177,12 @@ void RemoteFontFaceSource::FontLoadHistograms::recordRemoteFont(const FontResour
: font->response().wasCached() ? Hit : font->response().wasCached() ? Hit
: Miss; : Miss;
blink::Platform::current()->histogramEnumeration("WebFont.CacheHit", histogramValue, CacheHitEnumMax); 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: ...@@ -31,6 +31,7 @@ public:
virtual void didStartFontLoad(FontResource*) OVERRIDE; virtual void didStartFontLoad(FontResource*) OVERRIDE;
virtual void fontLoaded(FontResource*) OVERRIDE; virtual void fontLoaded(FontResource*) OVERRIDE;
virtual void fontLoadWaitLimitExceeded(FontResource*) OVERRIDE; virtual void fontLoadWaitLimitExceeded(FontResource*) OVERRIDE;
virtual void corsFailed(FontResource*) OVERRIDE;
// For UMA reporting // For UMA reporting
virtual bool hadBlankText() OVERRIDE { return m_histograms.hadBlankText(); } virtual bool hadBlankText() OVERRIDE { return m_histograms.hadBlankText(); }
......
...@@ -50,6 +50,7 @@ FontResource::FontResource(const ResourceRequest& resourceRequest) ...@@ -50,6 +50,7 @@ FontResource::FontResource(const ResourceRequest& resourceRequest)
: Resource(resourceRequest, Font) : Resource(resourceRequest, Font)
, m_loadInitiated(false) , m_loadInitiated(false)
, m_exceedsFontLoadWaitLimit(false) , m_exceedsFontLoadWaitLimit(false)
, m_corsFailed(false)
, m_fontLoadWaitLimitTimer(this, &FontResource::fontLoadWaitLimitCallback) , m_fontLoadWaitLimitTimer(this, &FontResource::fontLoadWaitLimitCallback)
{ {
} }
...@@ -184,9 +185,16 @@ void FontResource::allClientsRemoved() ...@@ -184,9 +185,16 @@ void FontResource::allClientsRemoved()
void FontResource::checkNotify() void FontResource::checkNotify()
{ {
m_fontLoadWaitLimitTimer.stop(); m_fontLoadWaitLimitTimer.stop();
ResourceClientWalker<FontResourceClient> w(m_clients); ResourceClientWalker<FontResourceClient> w(m_clients);
while (FontResourceClient* c = w.next()) // FIXME: Remove this CORS fallback once we have enough UMA to make a decision.
c->fontLoaded(this); 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: ...@@ -57,6 +57,9 @@ public:
virtual bool stillNeedsLoad() const OVERRIDE { return !m_loadInitiated; } virtual bool stillNeedsLoad() const OVERRIDE { return !m_loadInitiated; }
bool exceedsFontLoadWaitLimit() const { return m_exceedsFontLoadWaitLimit; } bool exceedsFontLoadWaitLimit() const { return m_exceedsFontLoadWaitLimit; }
void setCORSFailed() { m_corsFailed = true; }
bool isCORSFailed() const { return m_corsFailed; }
bool ensureCustomFontData(); bool ensureCustomFontData();
FontPlatformData platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth); FontPlatformData platformDataFromCustomData(float size, bool bold, bool italic, FontOrientation = Horizontal, FontWidthVariant = RegularWidth);
...@@ -75,6 +78,7 @@ private: ...@@ -75,6 +78,7 @@ private:
OwnPtr<FontCustomPlatformData> m_fontData; OwnPtr<FontCustomPlatformData> m_fontData;
bool m_loadInitiated; bool m_loadInitiated;
bool m_exceedsFontLoadWaitLimit; bool m_exceedsFontLoadWaitLimit;
bool m_corsFailed;
Timer<FontResource> m_fontLoadWaitLimitTimer; Timer<FontResource> m_fontLoadWaitLimitTimer;
#if ENABLE(SVG_FONTS) #if ENABLE(SVG_FONTS)
...@@ -94,6 +98,7 @@ public: ...@@ -94,6 +98,7 @@ public:
virtual void fontLoaded(FontResource*) { } virtual void fontLoaded(FontResource*) { }
virtual void didStartFontLoad(FontResource*) { } virtual void didStartFontLoad(FontResource*) { }
virtual void fontLoadWaitLimitExceeded(FontResource*) { } virtual void fontLoadWaitLimitExceeded(FontResource*) { }
virtual void corsFailed(FontResource*) { }
}; };
} }
......
...@@ -588,6 +588,12 @@ bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sour ...@@ -588,6 +588,12 @@ bool ResourceFetcher::canAccessResource(Resource* resource, SecurityOrigin* sour
String resourceType = Resource::resourceTypeToString(resource->type(), resource->options().initiatorInfo); 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); 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 false;
} }
return true; 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