Make disabled attribute can be set on <link> elements from HTML.

This commit is contained in:
Fedor 2020-09-17 08:52:42 +03:00
parent 7a5eecb37c
commit a9f2350492
15 changed files with 127 additions and 46 deletions

View File

@ -789,13 +789,14 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement,
// If this is a fragment parser, we don't want to observe.
// We don't support CORS for processing instructions
bool isAlternate;
bool isExplicitlyEnabled;
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
CORS_NONE, mDocument->GetReferrerPolicy(),
integrity, mRunsToCompletion ? nullptr : this,
&isAlternate);
&isAlternate, &isExplicitlyEnabled);
NS_ENSURE_SUCCESS(rv, rv);
if (!isAlternate && !mRunsToCompletion) {
if ((!isAlternate || isExplicitlyEnabled) && !mRunsToCompletion) {
++mPendingSheetCount;
mScriptLoader->AddParserBlockingScriptExecutionBlocker();
}

View File

@ -393,8 +393,9 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
nsAutoString title, type, media;
bool isScoped;
bool isAlternate;
bool isExplicitlyEnabled;
GetStyleSheetInfo(title, type, media, &isScoped, &isAlternate);
GetStyleSheetInfo(title, type, media, &isScoped, &isAlternate, &isExplicitlyEnabled);
if (!type.LowerCaseEqualsLiteral("text/css")) {
return NS_OK;
@ -425,7 +426,7 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
// Parse the style sheet.
rv = doc->CSSLoader()->
LoadInlineStyle(thisContent, text, mLineNumber, title, media,
scopeElement, aObserver, &doneLoading, &isAlternate);
scopeElement, aObserver, &doneLoading, &isAlternate, &isExplicitlyEnabled);
}
else {
nsAutoString integrity;
@ -452,13 +453,14 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
rv = doc->CSSLoader()->
LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
GetCORSMode(), referrerPolicy, integrity,
aObserver, &isAlternate);
aObserver, &isAlternate, &isExplicitlyEnabled);
if (NS_FAILED(rv)) {
// Don't propagate LoadStyleLink() errors further than this, since some
// consumers (e.g. nsXMLContentSink) will completely abort on innocuous
// things like a stylesheet load being blocked by the security system.
doneLoading = true;
isAlternate = false;
isExplicitlyEnabled = false;
rv = NS_OK;
}
}

View File

@ -98,7 +98,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) = 0;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) = 0;
virtual mozilla::CORSMode GetCORSMode() const
{

View File

@ -33,6 +33,8 @@
#define LINK_ELEMENT_FLAG_BIT(n_) \
NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
#define LINK_DISABLED Preferences::GetBool("dom.link.disabled_attribute.enabled", true)
// Link element specific bits
enum {
// Indicates that a DNS Prefetch has been requested from this Link element.
@ -92,9 +94,14 @@ NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
NS_IMPL_ELEMENT_CLONE(HTMLLinkElement)
bool
HTMLLinkElement::Disabled()
HTMLLinkElement::Disabled() const
{
if (LINK_DISABLED) {
return GetBoolAttr(nsGkAtoms::disabled);
}
StyleSheet* ss = GetSheet();
return ss && ss->Disabled();
}
@ -107,8 +114,12 @@ HTMLLinkElement::GetMozDisabled(bool* aDisabled)
}
void
HTMLLinkElement::SetDisabled(bool aDisabled)
{
HTMLLinkElement::SetDisabled(bool aDisabled, ErrorResult& aRv)
{
if (LINK_DISABLED) {
return SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aRv);
}
if (StyleSheet* ss = GetSheet()) {
ss->SetDisabled(aDisabled);
}
@ -117,11 +128,11 @@ HTMLLinkElement::SetDisabled(bool aDisabled)
NS_IMETHODIMP
HTMLLinkElement::SetMozDisabled(bool aDisabled)
{
SetDisabled(aDisabled);
return NS_OK;
ErrorResult rv;
SetDisabled(aDisabled, rv);
return rv.StealNSResult();
}
NS_IMPL_STRING_ATTR(HTMLLinkElement, Charset, charset)
NS_IMPL_URI_ATTR(HTMLLinkElement, Href, href)
NS_IMPL_STRING_ATTR(HTMLLinkElement, Hreflang, hreflang)
@ -370,7 +381,8 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type)) {
aName == nsGkAtoms::type ||
(LINK_DISABLED && aName == nsGkAtoms::disabled))) {
bool dropSheet = false;
if (aName == nsGkAtoms::rel) {
nsAutoString value;
@ -397,17 +409,24 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
dropSheet ||
(aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type));
aName == nsGkAtoms::type ||
(LINK_DISABLED && aName == nsGkAtoms::disabled)));
}
} else {
// Since removing href or rel makes us no longer link to a
// stylesheet, force updates for those too.
if (aNameSpaceID == kNameSpaceID_None) {
// If the disabled attribute is removed from a link element, the
// stylesheet may be explicitly enabled.
if (aNameSpaceID == kNameSpaceID_None && LINK_DISABLED) {
if (aName == nsGkAtoms::disabled) {
mExplicitlyEnabled = true;
}
// Since removing href or rel makes us no longer link to a
// stylesheet, force updates for those too.
if (aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type) {
aName == nsGkAtoms::type ||
(LINK_DISABLED && aName == nsGkAtoms::disabled)) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
}
if (aName == nsGkAtoms::href ||
@ -500,13 +519,15 @@ HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
aTitle.Truncate();
aType.Truncate();
aMedia.Truncate();
*aIsScoped = false;
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
nsAutoString rel;
GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
@ -516,6 +537,20 @@ HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
return;
}
if (LINK_DISABLED) {
// Is the link disabled?
if (Disabled()) {
return;
}
// Is it explicitly enabled?
if (mExplicitlyEnabled) {
*aIsExplicitlyEnabled = true;
}
}
nsAutoString title;
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
title.CompressWhitespace();

View File

@ -86,8 +86,8 @@ public:
virtual bool HasDeferredDNSPrefetchRequest() override;
// WebIDL
bool Disabled();
void SetDisabled(bool aDisabled);
bool Disabled() const;
void SetDisabled(bool aDisabled, ErrorResult& aRv);
// XPCOM GetHref is fine.
void SetHref(const nsAString& aHref, ErrorResult& aRv)
{
@ -181,10 +181,18 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
protected:
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
RefPtr<nsDOMTokenList> mRelList;
// The "explicitly enabled" flag. This flag is set whenever the 'disabled'
// attribute is explicitly unset, and makes alternate stylesheets not be
// disabled by default anymore.
//
// See https://github.com/whatwg/html/issues/3840#issuecomment-481034206.
bool mExplicitlyEnabled = false;
private:
RefPtr<ImportLoader> mImportLoader;
};

View File

@ -66,7 +66,7 @@ HTMLStyleElement::GetMozDisabled(bool* aDisabled)
}
bool
HTMLStyleElement::Disabled()
HTMLStyleElement::Disabled() const
{
StyleSheet* ss = GetSheet();
return ss && ss->Disabled();
@ -223,12 +223,14 @@ HTMLStyleElement::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
aTitle.Truncate();
aType.Truncate();
aMedia.Truncate();
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
nsAutoString title;
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);

View File

@ -59,7 +59,7 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
bool Disabled();
bool Disabled() const;
void SetDisabled(bool aDisabled);
void SetMedia(const nsAString& aMedia, ErrorResult& aError)
{
@ -88,7 +88,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
/**
* Common method to call from the various mutation observer methods.
* aContent is a content node that's either the one that changed or its

View File

@ -271,9 +271,11 @@ SVGStyleElement::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
nsAutoString title;
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);

View File

@ -95,7 +95,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
virtual CORSMode GetCORSMode() const override;
/**

View File

@ -14,7 +14,7 @@
// http://www.whatwg.org/specs/web-apps/current-work/#the-link-element
[HTMLConstructor]
interface HTMLLinkElement : HTMLElement {
[Pure]
[CEReactions, SetterThrows, Pure]
attribute boolean disabled;
[CEReactions, SetterThrows, Pure]
attribute DOMString href;

View File

@ -131,13 +131,15 @@ XMLStylesheetProcessingInstruction::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
aTitle.Truncate();
aType.Truncate();
aMedia.Truncate();
*aIsScoped = false;
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
// xml-stylesheet PI is special only in prolog
if (!nsContentUtils::InProlog(this)) {

View File

@ -82,7 +82,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
bool aCloneText) const override;
};

View File

@ -1278,7 +1278,8 @@ Loader::PrepareSheet(StyleSheet* aSheet,
const nsSubstring& aMediaString,
nsMediaList* aMediaList,
Element* aScopeElement,
bool isAlternate)
bool isAlternate,
bool isExplicitlyEnabled)
{
NS_PRECONDITION(aSheet, "Must have a sheet!");
@ -1307,7 +1308,7 @@ Loader::PrepareSheet(StyleSheet* aSheet,
sheet->SetMedia(mediaList);
sheet->SetTitle(aTitle);
sheet->SetEnabled(!isAlternate);
sheet->SetEnabled(!isAlternate || isExplicitlyEnabled);
sheet->SetScopeElement(aScopeElement);
}
@ -1985,7 +1986,8 @@ Loader::LoadInlineStyle(nsIContent* aElement,
Element* aScopeElement,
nsICSSLoaderObserver* aObserver,
bool* aCompleted,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
LOG(("css::Loader::LoadInlineStyle"));
NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
@ -2017,8 +2019,9 @@ Loader::LoadInlineStyle(nsIContent* aElement,
"Inline sheets should not be cached");
LOG((" Sheet is alternate: %d", *aIsAlternate));
LOG((" Sheet is explicitly enabled: %d", *aIsExplicitlyEnabled));
PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, *aIsAlternate);
PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, *aIsAlternate, *aIsExplicitlyEnabled);
if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
ShadowRoot* containingShadow = aElement->GetContainingShadow();
@ -2059,7 +2062,8 @@ Loader::LoadStyleLink(nsIContent* aElement,
ReferrerPolicy aReferrerPolicy,
const nsAString& aIntegrity,
nsICSSLoaderObserver* aObserver,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
LOG(("css::Loader::LoadStyleLink"));
NS_PRECONDITION(aURL, "Must have URL to load");
@ -2112,8 +2116,9 @@ Loader::LoadStyleLink(nsIContent* aElement,
NS_ENSURE_SUCCESS(rv, rv);
LOG((" Sheet is alternate: %d", *aIsAlternate));
LOG((" Sheet is explicitly enabled: %d", *aIsExplicitlyEnabled));
PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate);
PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate, *aIsExplicitlyEnabled);
rv = InsertSheetInDoc(sheet, aElement, mDocument);
NS_ENSURE_SUCCESS(rv, rv);
@ -2138,9 +2143,10 @@ Loader::LoadStyleLink(nsIContent* aElement,
aObserver, principal, requestingNode);
NS_ADDREF(data);
// If we have to parse and it's an alternate non-inline, defer it
// If we have to parse and it's an alternate non-inline, defer it unless
// it's explicitly enabled.
if (aURL && state == eSheetNeedsParser && mSheets->mLoadingDatas.Count() != 0 &&
*aIsAlternate) {
*aIsAlternate && !*aIsExplicitlyEnabled) {
LOG((" Deferring alternate sheet load"));
URIPrincipalReferrerPolicyAndCORSModeHashKey key(data->mURI,
data->mLoaderPrincipal,
@ -2276,8 +2282,9 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
parentData ? parentData->mSyncLoad : false,
false, empty, state, &isAlternate, &sheet);
NS_ENSURE_SUCCESS(rv, rv);
PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
// For now, child sheets are not explicitly enabled (seventh argument is
// always false here).
PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate, false);
}
rv = InsertChildSheet(sheet, aParentSheet, aParentRule);
@ -2399,7 +2406,10 @@ Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
false, empty, state, &isAlternate, &sheet);
NS_ENSURE_SUCCESS(rv, rv);
PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate);
// Sheets can only be explicitly enabled after creation and preparation, so
// we always pass false for the initial value of the explicitly enabled flag
// when calling PrepareSheet.
PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate, false);
if (state == eSheetComplete) {
LOG((" Sheet already complete"));

View File

@ -230,6 +230,8 @@ public:
* @param [out] aCompleted whether parsing of the sheet completed.
* @param [out] aIsAlternate whether the stylesheet ended up being an
* alternate sheet.
* @param [out] aIsExplicitlyEnabled whether the stylesheet was explicitly
* enabled by having the disabled attribute removed.
*/
nsresult LoadInlineStyle(nsIContent* aElement,
const nsAString& aBuffer,
@ -239,7 +241,8 @@ public:
mozilla::dom::Element* aScopeElement,
nsICSSLoaderObserver* aObserver,
bool* aCompleted,
bool* aIsAlternate);
bool* aIsAlternate,
bool* aIsExplicitlyEnabled);
/**
* Load a linked (document) stylesheet. If a successful result is returned,
@ -260,6 +263,8 @@ public:
* @param [out] aIsAlternate whether the stylesheet actually ended up beinga
* an alternate sheet. Note that this need not match
* aHasAlternateRel.
* @param [out] aIsExplicitlyEnabled whether the stylesheet was explicitly
* enabled by having the disabled attribute removed.
*/
nsresult LoadStyleLink(nsIContent* aElement,
nsIURI* aURL,
@ -270,7 +275,8 @@ public:
ReferrerPolicy aReferrerPolicy,
const nsAString& aIntegrity,
nsICSSLoaderObserver* aObserver,
bool* aIsAlternate);
bool* aIsAlternate,
bool* aIsExplicitlyEnabled);
/**
* Load a child (@import-ed) style sheet. In addition to loading the sheet,
@ -476,7 +482,8 @@ private:
const nsAString& aMediaString,
nsMediaList* aMediaList,
dom::Element* aScopeElement,
bool isAlternate);
bool isAlternate,
bool isExplicitlyEnabled);
nsresult InsertSheetInDoc(StyleSheet* aSheet,
nsIContent* aLinkingContent,

View File

@ -1189,6 +1189,14 @@ pref("dom.storage.default_quota", 5120);
pref("dom.send_after_paint_to_content", false);
// Whether the disabled attribute in HTMLLinkElement disables the sheet loading
// altogether, or forwards to the inner stylesheet method without attribute
// reflection.
//
// Historical behavior is the second, the first is being discussed at:
// https://github.com/whatwg/html/issues/3840
pref("dom.link.disabled_attribute.enabled", true);
// Timeout clamp in ms for timeouts we clamp
pref("dom.min_timeout_value", 4);
// And for background windows