Index: third_party/WebKit/Source/core/html/LinkStyle.cpp |
diff --git a/third_party/WebKit/Source/core/html/LinkStyle.cpp b/third_party/WebKit/Source/core/html/LinkStyle.cpp |
index 4a3297d1c4fea51b953efa142e0df9dac0edd0a3..db3cfc470485ac3df6f0a5aaab57dc7905cd3fe3 100644 |
--- a/third_party/WebKit/Source/core/html/LinkStyle.cpp |
+++ b/third_party/WebKit/Source/core/html/LinkStyle.cpp |
@@ -4,17 +4,22 @@ |
#include "core/html/LinkStyle.h" |
+#include "core/HTMLNames.h" |
#include "core/css/StyleSheetContents.h" |
+#include "core/fetch/FetchRequest.h" |
#include "core/frame/LocalFrame.h" |
#include "core/frame/SubresourceIntegrity.h" |
#include "core/frame/csp/ContentSecurityPolicy.h" |
#include "core/html/CrossOriginAttribute.h" |
#include "core/html/HTMLLinkElement.h" |
+#include "core/html/imports/HTMLImportsController.h" |
#include "core/loader/FrameLoaderClient.h" |
#include "core/loader/resource/CSSStyleSheetResource.h" |
#include "platform/ContentType.h" |
#include "platform/Histogram.h" |
#include "platform/MIMETypeRegistry.h" |
+#include "platform/weborigin/KURL.h" |
+#include "wtf/text/WTFString.h" |
namespace blink { |
@@ -45,6 +50,10 @@ Document& LinkStyle::document() { |
return m_owner->document(); |
} |
+const Document& LinkStyle::document() const { |
+ return m_owner->document(); |
+} |
+ |
enum StyleSheetCacheStatus { |
StyleSheetNewEntry, |
StyleSheetInDiskCache, |
@@ -107,8 +116,7 @@ void LinkStyle::setCSSStyleSheet( |
} |
} |
- CSSParserContext parserContext(m_owner->document(), nullptr, baseURL, |
- charset); |
+ CSSParserContext parserContext(document(), nullptr, baseURL, charset); |
DEFINE_STATIC_LOCAL(EnumerationHistogram, restoredCachedStyleSheetHistogram, |
("Blink.RestoredCachedStyleSheet", 2)); |
@@ -128,7 +136,7 @@ void LinkStyle::setCSSStyleSheet( |
m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); |
if (m_owner->isInDocumentTree()) |
setSheetTitle(m_owner->title()); |
- setCrossOriginStylesheetStatus(m_sheet.get()); |
+ setCrossOriginStylesheetStatus(); |
m_loading = false; |
restoredSheet->checkLoaded(); |
@@ -153,10 +161,10 @@ void LinkStyle::setCSSStyleSheet( |
m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media())); |
if (m_owner->isInDocumentTree()) |
setSheetTitle(m_owner->title()); |
- setCrossOriginStylesheetStatus(m_sheet.get()); |
+ setCrossOriginStylesheetStatus(); |
styleSheet->parseAuthorStyleSheet(cachedStyleSheet, |
- m_owner->document().getSecurityOrigin()); |
+ document().getSecurityOrigin()); |
m_loading = false; |
styleSheet->notifyLoadedSheet(cachedStyleSheet); |
@@ -213,7 +221,7 @@ void LinkStyle::addPendingSheet(PendingSheetType type) { |
if (m_pendingSheetType == NonBlocking) |
return; |
- m_owner->document().styleEngine().addPendingSheet(m_styleEngineContext); |
+ document().styleEngine().addPendingSheet(m_styleEngineContext); |
} |
void LinkStyle::removePendingSheet() { |
@@ -225,82 +233,103 @@ void LinkStyle::removePendingSheet() { |
return; |
if (type == NonBlocking) { |
// Tell StyleEngine to re-compute styleSheets of this m_owner's treescope. |
- m_owner->document().styleEngine().modifiedStyleSheetCandidateNode(*m_owner); |
+ document().styleEngine().modifiedStyleSheetCandidateNode(*m_owner); |
return; |
} |
- m_owner->document().styleEngine().removePendingSheet(*m_owner, |
- m_styleEngineContext); |
+ document().styleEngine().removePendingSheet(*m_owner, m_styleEngineContext); |
} |
void LinkStyle::setDisabledState(bool disabled) { |
LinkStyle::DisabledState oldDisabledState = m_disabledState; |
m_disabledState = disabled ? Disabled : EnabledViaScript; |
- if (oldDisabledState != m_disabledState) { |
- // If we change the disabled state while the sheet is still loading, then we |
- // have to perform three checks: |
- if (styleSheetIsLoading()) { |
- // Check #1: The sheet becomes disabled while loading. |
- if (m_disabledState == Disabled) |
- removePendingSheet(); |
- |
- // Check #2: An alternate sheet becomes enabled while it is still loading. |
- if (m_owner->relAttribute().isAlternate() && |
- m_disabledState == EnabledViaScript) |
- addPendingSheet(Blocking); |
- |
- // Check #3: A main sheet becomes enabled while it was still loading and |
- // after it was disabled via script. It takes really terrible code to make |
- // this happen (a double toggle for no reason essentially). This happens |
- // on virtualplastic.net, which manages to do about 12 enable/disables on |
- // only 3 sheets. :) |
- if (!m_owner->relAttribute().isAlternate() && |
- m_disabledState == EnabledViaScript && oldDisabledState == Disabled) |
- addPendingSheet(Blocking); |
- |
- // If the sheet is already loading just bail. |
- return; |
- } |
+ if (oldDisabledState == m_disabledState) |
+ return; |
- if (m_sheet) { |
- m_sheet->setDisabled(disabled); |
- return; |
- } |
+ // If we change the disabled state while the sheet is still loading, then we |
+ // have to perform three checks: |
+ if (styleSheetIsLoading()) { |
+ // Check #1: The sheet becomes disabled while loading. |
+ if (m_disabledState == Disabled) |
+ removePendingSheet(); |
+ |
+ // Check #2: An alternate sheet becomes enabled while it is still loading. |
+ if (m_owner->relAttribute().isAlternate() && |
+ m_disabledState == EnabledViaScript) |
+ addPendingSheet(Blocking); |
+ |
+ // Check #3: A main sheet becomes enabled while it was still loading and |
+ // after it was disabled via script. It takes really terrible code to make |
+ // this happen (a double toggle for no reason essentially). This happens |
+ // on virtualplastic.net, which manages to do about 12 enable/disables on |
+ // only 3 sheets. :) |
+ if (!m_owner->relAttribute().isAlternate() && |
+ m_disabledState == EnabledViaScript && oldDisabledState == Disabled) |
+ addPendingSheet(Blocking); |
+ |
+ // If the sheet is already loading just bail. |
+ return; |
+ } |
- if (m_disabledState == EnabledViaScript && m_owner->shouldProcessStyle()) |
- process(); |
+ if (m_sheet) { |
+ m_sheet->setDisabled(disabled); |
+ return; |
} |
+ |
+ if (m_disabledState == EnabledViaScript && m_owner->shouldProcessStyle()) |
+ process(); |
} |
-void LinkStyle::setCrossOriginStylesheetStatus(CSSStyleSheet* sheet) { |
+void LinkStyle::setCrossOriginStylesheetStatus() { |
if (m_fetchFollowingCORS && resource() && !resource()->errorOccurred()) { |
// Record the security origin the CORS access check succeeded at, if cross |
// origin. Only origins that are script accessible to it may access the |
// stylesheet's rules. |
- sheet->setAllowRuleAccessFromOrigin( |
- m_owner->document().getSecurityOrigin()); |
+ m_sheet->setAllowRuleAccessFromOrigin(document().getSecurityOrigin()); |
} |
m_fetchFollowingCORS = false; |
} |
+bool LinkStyle::shouldLoadResource() const { |
+ return document().frame() || document().importsController(); |
+} |
+ |
// TODO(yoav): move that logic to LinkLoader |
-LinkStyle::LoadReturnValue LinkStyle::loadStylesheetIfNeeded( |
- const LinkRequestBuilder& builder, |
- const String& type) { |
+void LinkStyle::loadStylesheetIfNeeded(const String& type) { |
+ const KURL& href = m_owner->getNonEmptyURLAttribute(hrefAttr); |
+ |
if (m_disabledState == Disabled || !m_owner->relAttribute().isStyleSheet() || |
!styleSheetTypeIsSupported(type) || !shouldLoadResource() || |
- !builder.url().isValid()) |
- return NotNeeded; |
+ !href.isValid()) { |
+ if (!m_sheet) |
+ return; |
+ |
+ // we no longer contain a stylesheet, e.g. perhaps rel or type was changed |
+ StyleSheet* removedSheet = m_sheet.get(); |
+ clearSheet(); |
+ document().styleEngine().setNeedsActiveStyleUpdate(removedSheet, |
+ FullStyleUpdate); |
+ return; |
+ } |
if (resource()) { |
removePendingSheet(); |
clearResource(); |
- clearFetchFollowingCORS(); |
+ m_fetchFollowingCORS = false; |
} |
- if (!m_owner->shouldLoadLink()) |
- return Bail; |
+ if (m_owner->shouldLoadLink()) |
+ loadStylesheet(); |
+} |
+ |
+LocalFrame* LinkStyle::loadingFrame() const { |
+ HTMLImportsController* importsController = document().importsController(); |
+ if (!importsController) |
+ return document().frame(); |
+ return importsController->master()->frame(); |
+} |
+void LinkStyle::loadStylesheet() { |
m_loading = true; |
String title = m_owner->title(); |
@@ -324,17 +353,21 @@ LinkStyle::LoadReturnValue LinkStyle::loadStylesheetIfNeeded( |
m_owner->isCreatedByParser(); |
addPendingSheet(blocking ? Blocking : NonBlocking); |
+ FetchRequest request = m_owner->createFetchRequest(); |
+ |
// Load stylesheets that are not needed for the layout immediately with low |
// priority. When the link element is created by scripts, load the |
// stylesheets asynchronously but in high priority. |
- bool lowPriority = !mediaQueryMatches || m_owner->isAlternate(); |
- FetchRequest request = builder.build(lowPriority); |
+ if (!mediaQueryMatches || m_owner->isAlternate()) |
+ request.setDefer(FetchRequest::LazyLoad); |
+ |
CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue( |
m_owner->fastGetAttribute(HTMLNames::crossoriginAttr)); |
if (crossOrigin != CrossOriginAttributeNotSet) { |
request.setCrossOriginAccessControl(document().getSecurityOrigin(), |
crossOrigin); |
- setFetchFollowingCORS(); |
+ DCHECK(!m_fetchFollowingCORS); |
+ m_fetchFollowingCORS = true; |
} |
String integrityAttr = m_owner->fastGetAttribute(HTMLNames::integrityAttr); |
@@ -345,35 +378,36 @@ LinkStyle::LoadReturnValue LinkStyle::loadStylesheetIfNeeded( |
} |
setResource(CSSStyleSheetResource::fetch(request, document().fetcher())); |
- if (m_loading && !resource()) { |
- // The request may have been denied if (for example) the stylesheet is |
- // local and the document is remote, or if there was a Content Security |
- // Policy Failure. setCSSStyleSheet() can be called synchronuosly in |
- // setResource() and thus resource() is null and |m_loading| is false in |
- // such cases even if the request succeeds. |
- m_loading = false; |
- removePendingSheet(); |
- notifyLoadedSheetAndAllCriticalSubresources( |
- Node::ErrorOccurredLoadingSubresource); |
- } |
- return Loaded; |
+ if (!m_loading || resource()) |
+ return; |
+ |
+ // The request may have been denied if (for example) the stylesheet is |
+ // local and the document is remote, or if there was a Content Security |
+ // Policy Failure. setCSSStyleSheet() can be called synchronuosly in |
+ // setResource() and thus resource() is null and |m_loading| is false in |
+ // such cases even if the request succeeds. |
+ m_loading = false; |
+ removePendingSheet(); |
+ notifyLoadedSheetAndAllCriticalSubresources( |
+ Node::ErrorOccurredLoadingSubresource); |
} |
void LinkStyle::process() { |
DCHECK(m_owner->shouldProcessStyle()); |
+ |
String type = m_owner->typeValue().lower(); |
String as = m_owner->asValue().lower(); |
String media = m_owner->media().lower(); |
- LinkRequestBuilder builder(m_owner); |
- if (m_owner->relAttribute().getIconType() != InvalidIcon && |
- builder.url().isValid() && !builder.url().isEmpty()) { |
+ const KURL& href = m_owner->getNonEmptyURLAttribute(hrefAttr); |
+ |
+ if (m_owner->relAttribute().getIconType() != InvalidIcon && href.isValid() && |
+ !href.isEmpty()) { |
if (!m_owner->shouldLoadLink()) |
return; |
- if (!document().getSecurityOrigin()->canDisplay(builder.url())) |
+ if (!document().getSecurityOrigin()->canDisplay(href)) |
return; |
- if (!document().contentSecurityPolicy()->allowImageFromSource( |
- builder.url())) |
+ if (!document().contentSecurityPolicy()->allowImageFromSource(href)) |
return; |
if (document().frame() && document().frame()->loader().client()) { |
document().frame()->loader().client()->dispatchDidChangeIcons( |
@@ -381,17 +415,8 @@ void LinkStyle::process() { |
} |
} |
- if (!m_owner->loadLink(type, as, media, m_owner->referrerPolicy(), |
- builder.url())) |
- return; |
- |
- if (loadStylesheetIfNeeded(builder, type) == NotNeeded && m_sheet) { |
- // we no longer contain a stylesheet, e.g. perhaps rel or type was changed |
- StyleSheet* removedSheet = m_sheet.get(); |
- clearSheet(); |
- document().styleEngine().setNeedsActiveStyleUpdate(removedSheet, |
- FullStyleUpdate); |
- } |
+ if (m_owner->loadLink(type, as, media, m_owner->referrerPolicy(), href)) |
+ loadStylesheetIfNeeded(type); |
} |
void LinkStyle::setSheetTitle( |
@@ -406,7 +431,7 @@ void LinkStyle::setSheetTitle( |
if (title.isEmpty() || !isUnset() || m_owner->isAlternate()) |
return; |
- KURL href = m_owner->getNonEmptyURLAttribute(hrefAttr); |
+ const KURL& href = m_owner->getNonEmptyURLAttribute(hrefAttr); |
if (href.isValid() && !href.isEmpty()) { |
document().styleEngine().setPreferredStylesheetSetNameIfNotSet( |
title, updateActiveSheets); |