| 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);
|
|
|