Bug 1291515 - Part 1: Introduce a pref for <style scoped>. r?dbaron r=bholley
MozReview-Commit-ID: 1J9IvPrC0xh
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -299,16 +299,17 @@ bool nsContentUtils::sAnimationsAPICoreE
bool nsContentUtils::sAnimationsAPIElementAnimateEnabled = false;
bool nsContentUtils::sGetBoxQuadsEnabled = false;
bool nsContentUtils::sSkipCursorMoveForSameValueSet = false;
bool nsContentUtils::sRequestIdleCallbackEnabled = false;
bool nsContentUtils::sLowerNetworkPriority = false;
#ifndef RELEASE_OR_BETA
bool nsContentUtils::sBypassCSSOMOriginCheck = false;
#endif
+bool nsContentUtils::sIsScopedStyleEnabled = false;
bool nsContentUtils::sIsBytecodeCacheEnabled = false;
int32_t nsContentUtils::sBytecodeCacheStrategy = 0;
nsCString* nsContentUtils::sJSBytecodeMimeType = nullptr;
int32_t nsContentUtils::sPrivacyMaxInnerWidth = 1000;
int32_t nsContentUtils::sPrivacyMaxInnerHeight = 1000;
@@ -701,16 +702,19 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sRequestIdleCallbackEnabled,
"dom.requestIdleCallback.enabled", false);
#ifndef RELEASE_OR_BETA
sBypassCSSOMOriginCheck = getenv("MOZ_BYPASS_CSSOM_ORIGIN_CHECK");
#endif
+ Preferences::AddBoolVarCache(&sIsScopedStyleEnabled,
+ "layout.css.scoped-style.enabled", false);
+
Preferences::AddBoolVarCache(&sLowerNetworkPriority,
"privacy.trackingprotection.lower_network_priority", false);
Preferences::AddBoolVarCache(&sIsBytecodeCacheEnabled,
"dom.script_loader.bytecode_cache.enabled", false);
Preferences::AddIntVarCache(&sBytecodeCacheStrategy,
"dom.script_loader.bytecode_cache.strategy", 0);
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2277,16 +2277,24 @@ public:
#ifdef RELEASE_OR_BETA
return false;
#else
return sBypassCSSOMOriginCheck;
#endif
}
/**
+ * Returns true if the <style scoped> enabling pref is true.
+ */
+ static bool IsScopedStylePrefEnabled()
+ {
+ return sIsScopedStyleEnabled;
+ }
+
+ /**
* Return true if this doc is controlled by a ServiceWorker.
*/
static bool IsControlledByServiceWorker(nsIDocument* aDocument);
/**
* Fire mutation events for changes caused by parsing directly into a
* context node.
*
@@ -3187,16 +3195,17 @@ private:
static bool sAnimationsAPIElementAnimateEnabled;
static bool sGetBoxQuadsEnabled;
static bool sSkipCursorMoveForSameValueSet;
static bool sRequestIdleCallbackEnabled;
static bool sLowerNetworkPriority;
#ifndef RELEASE_OR_BETA
static bool sBypassCSSOMOriginCheck;
#endif
+ static bool sIsScopedStyleEnabled;
static bool sIsBytecodeCacheEnabled;
static int32_t sBytecodeCacheStrategy;
static uint32_t sCookiesLifetimePolicy;
static uint32_t sCookiesBehavior;
static int32_t sPrivacyMaxInnerWidth;
static int32_t sPrivacyMaxInnerHeight;
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1338,16 +1338,17 @@ nsIDocument::nsIDocument()
mFontFaceSetDirty(true),
mGetUserFontSetCalled(false),
mPostedFlushUserFontSet(false),
mDidFireDOMContentLoaded(true),
mHasScrollLinkedEffect(false),
mFrameRequestCallbacksScheduled(false),
mIsTopLevelContentDocument(false),
mIsContentDocument(false),
+ mIsScopedStyleEnabled(eScopedStyle_Unknown),
mCompatMode(eCompatibility_FullStandards),
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
mStyleBackendType(StyleBackendType::None),
#ifdef MOZILLA_INTERNAL_API
mVisibilityState(dom::VisibilityState::Hidden),
#else
mDummy(0),
#endif
@@ -13435,8 +13436,20 @@ nsDocument::IsThirdParty()
mIsThirdParty.emplace(true);
return mIsThirdParty.value();
}
// Fall-through. Document is not a Third-Party Document.
mIsThirdParty.emplace(false);
return mIsThirdParty.value();
}
+
+bool
+nsIDocument::IsScopedStyleEnabled()
+{
+ if (mIsScopedStyleEnabled == eScopedStyle_Unknown) {
+ mIsScopedStyleEnabled = nsContentUtils::IsChromeDoc(this) ||
+ nsContentUtils::IsScopedStylePrefEnabled()
+ ? eScopedStyle_Enabled
+ : eScopedStyle_Disabled;
+ }
+ return mIsScopedStyleEnabled == eScopedStyle_Enabled;
+}
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2943,16 +2943,18 @@ public:
bool PrerenderHref(nsIURI* aHref);
// For more information on Flash classification, see
// toolkit/components/url-classifier/flash-block-lists.rst
virtual mozilla::dom::FlashClassification DocumentFlashClassification() = 0;
virtual bool IsThirdParty() = 0;
+ bool IsScopedStyleEnabled();
+
protected:
bool GetUseCounter(mozilla::UseCounter aUseCounter)
{
return mUseCounters[aUseCounter];
}
void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
{
@@ -3266,16 +3268,20 @@ protected:
// This should generally be updated only via
// UpdateFrameRequestCallbackSchedulingState.
bool mFrameRequestCallbacksScheduled : 1;
bool mIsTopLevelContentDocument : 1;
bool mIsContentDocument : 1;
+ // Whether <style scoped> support is enabled in this document.
+ enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
+ unsigned int mIsScopedStyleEnabled : 2;
+
// Compatibility mode
nsCompatibility mCompatMode;
// Our readyState
ReadyState mReadyState;
// Whether this document has (or will have, once we have a pres shell) a
// Gecko- or Servo-backed style system.
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -219,17 +219,18 @@ nsStyleLinkElement::UpdateStyleSheetInte
static bool
IsScopedStyleElement(nsIContent* aContent)
{
// This is quicker than, say, QIing aContent to nsStyleLinkElement
// and then calling its virtual GetStyleSheetInfo method to find out
// if it is scoped.
return (aContent->IsHTMLElement(nsGkAtoms::style) ||
aContent->IsSVGElement(nsGkAtoms::style)) &&
- aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scoped);
+ aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::scoped) &&
+ aContent->OwnerDoc()->IsScopedStyleEnabled();
}
static bool
HasScopedStyleSheetChild(nsIContent* aContent)
{
for (nsIContent* n = aContent->GetFirstChild(); n; n = n->GetNextSibling()) {
if (IsScopedStyleElement(n)) {
return true;
--- a/dom/html/HTMLStyleElement.cpp
+++ b/dom/html/HTMLStyleElement.cpp
@@ -174,17 +174,18 @@ HTMLStyleElement::AfterSetAttr(int32_t a
const nsAttrValue* aValue,
const nsAttrValue* aOldValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
- } else if (aName == nsGkAtoms::scoped) {
+ } else if (aName == nsGkAtoms::scoped &&
+ OwnerDoc()->IsScopedStyleEnabled()) {
bool isScoped = aValue;
UpdateStyleSheetScopedness(isScoped);
}
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
aOldValue, aNotify);
}
@@ -237,17 +238,18 @@ HTMLStyleElement::GetStyleSheetInfo(nsAS
GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
// The HTML5 spec is formulated in terms of the CSSOM spec, which specifies
// that media queries should be ASCII lowercased during serialization.
nsContentUtils::ASCIIToLower(aMedia);
GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
- *aIsScoped = HasAttr(kNameSpaceID_None, nsGkAtoms::scoped);
+ *aIsScoped = HasAttr(kNameSpaceID_None, nsGkAtoms::scoped) &&
+ OwnerDoc()->IsScopedStyleEnabled();
nsAutoString mimeType;
nsAutoString notUsed;
nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
return;
}
--- a/dom/html/test/test_style_attributes_reflection.html
+++ b/dom/html/test/test_style_attributes_reflection.html
@@ -24,18 +24,20 @@ reflectString({
});
// .type
reflectString({
element: e,
attribute: "type"
});
-// .scoped
-reflectBoolean({
- element: e,
- attribute: "scoped"
-});
+if (SpecialPowers.getBoolPref("layout.css.scoped-style.enabled")) {
+ // .scoped
+ reflectBoolean({
+ element: e,
+ attribute: "scoped"
+ });
+}
</script>
</pre>
</body>
</html>
--- a/dom/svg/SVGStyleElement.cpp
+++ b/dom/svg/SVGStyleElement.cpp
@@ -99,17 +99,18 @@ SVGStyleElement::SetAttr(int32_t aNameSp
{
nsresult rv = SVGStyleElementBase::SetAttr(aNameSpaceID, aName, aPrefix,
aValue, aNotify);
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
- } else if (aName == nsGkAtoms::scoped) {
+ } else if (aName == nsGkAtoms::scoped &&
+ OwnerDoc()->IsScopedStyleEnabled()) {
UpdateStyleSheetScopedness(true);
}
}
return rv;
}
nsresult
@@ -118,17 +119,18 @@ SVGStyleElement::UnsetAttr(int32_t aName
{
nsresult rv = SVGStyleElementBase::UnsetAttr(aNameSpaceID, aAttribute,
aNotify);
if (NS_SUCCEEDED(rv) && aNameSpaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::title ||
aAttribute == nsGkAtoms::media ||
aAttribute == nsGkAtoms::type) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
- } else if (aAttribute == nsGkAtoms::scoped) {
+ } else if (aAttribute == nsGkAtoms::scoped &&
+ OwnerDoc()->IsScopedStyleEnabled()) {
UpdateStyleSheetScopedness(false);
}
}
return rv;
}
bool
@@ -285,17 +287,18 @@ SVGStyleElement::GetStyleSheetInfo(nsASt
// which specifies that media queries are case insensitive.
nsContentUtils::ASCIIToLower(aMedia);
GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
if (aType.IsEmpty()) {
aType.AssignLiteral("text/css");
}
- *aIsScoped = HasAttr(kNameSpaceID_None, nsGkAtoms::scoped);
+ *aIsScoped = HasAttr(kNameSpaceID_None, nsGkAtoms::scoped) &&
+ OwnerDoc()->IsScopedStyleEnabled();
return;
}
CORSMode
SVGStyleElement::GetCORSMode() const
{
return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
--- a/dom/webidl/HTMLStyleElement.webidl
+++ b/dom/webidl/HTMLStyleElement.webidl
@@ -11,13 +11,13 @@
[HTMLConstructor]
interface HTMLStyleElement : HTMLElement {
[Pure]
attribute boolean disabled;
[SetterThrows, Pure]
attribute DOMString media;
[SetterThrows, Pure]
attribute DOMString type;
- [SetterThrows, Pure]
+ [SetterThrows, Pure, Pref="layout.css.scoped-style.enabled"]
attribute boolean scoped;
};
HTMLStyleElement implements LinkStyle;
--- a/dom/webidl/SVGStyleElement.webidl
+++ b/dom/webidl/SVGStyleElement.webidl
@@ -14,13 +14,13 @@ interface SVGStyleElement : SVGElement {
[SetterThrows]
attribute DOMString xmlspace; // Spec claims this should be on SVGElement
[SetterThrows]
attribute DOMString type;
[SetterThrows]
attribute DOMString media;
[SetterThrows]
attribute DOMString title;
- [SetterThrows]
+ [SetterThrows, Pref="layout.css.scoped-style.enabled"]
attribute boolean scoped;
};
SVGStyleElement implements LinkStyle;
--- a/layout/reftests/css-display/reftest.list
+++ b/layout/reftests/css-display/reftest.list
@@ -2,27 +2,27 @@
# http://dev.w3.org/csswg/css-display
fuzzy-if(Android,8,604) == display-contents-acid.html display-contents-acid-ref.html
fuzzy-if(Android,8,604) == display-contents-acid-dyn-1.html display-contents-acid-ref.html
fuzzy-if(Android,8,604) == display-contents-acid-dyn-2.html display-contents-acid-ref.html
fuzzy-if(Android,8,604) == display-contents-acid-dyn-3.html display-contents-acid-ref.html
== display-contents-generated-content.html display-contents-generated-content-ref.html
== display-contents-generated-content-2.html display-contents-generated-content-ref.html
-fails-if(styloVsGecko||stylo) == display-contents-style-inheritance-1.html display-contents-style-inheritance-1-ref.html
-fails-if(styloVsGecko||stylo) == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-ref.html
-fuzzy-if(winWidget,12,100) skip-if(styloVsGecko||stylo) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-ref.html
+fails-if(styloVsGecko||stylo) pref(layout.css.scoped-style.enabled,true) == display-contents-style-inheritance-1.html display-contents-style-inheritance-1-ref.html
+fails-if(styloVsGecko||stylo) pref(layout.css.scoped-style.enabled,true) == display-contents-style-inheritance-1-stylechange.html display-contents-style-inheritance-1-ref.html
+fuzzy-if(winWidget,12,100) skip-if(styloVsGecko||stylo) pref(layout.css.scoped-style.enabled,true) == display-contents-style-inheritance-1-dom-mutations.html display-contents-style-inheritance-1-ref.html
== display-contents-tables.xhtml display-contents-tables-ref.xhtml
== display-contents-tables-2.xhtml display-contents-tables-ref.xhtml
== display-contents-tables-3.xhtml display-contents-tables-3-ref.xhtml
== display-contents-visibility-hidden.html display-contents-visibility-hidden-ref.html
== display-contents-visibility-hidden-2.html display-contents-visibility-hidden-ref.html
== display-contents-495385-2d.html display-contents-495385-2d-ref.html
fuzzy-if(Android,7,3935) == display-contents-xbl.xhtml display-contents-xbl-ref.html
-fuzzy-if(Android,7,1186) pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == display-contents-shadow-dom-1.html display-contents-shadow-dom-1-ref.html
+fuzzy-if(Android,7,1186) fails-if(stylo||styloVsGecko) pref(dom.webcomponents.enabled,true) pref(layout.css.scoped-style.enabled,true) == display-contents-shadow-dom-1.html display-contents-shadow-dom-1-ref.html
== display-contents-xbl-2.xul display-contents-xbl-2-ref.xul
asserts(1) asserts-if(styloVsGecko,2) == display-contents-xbl-3.xul display-contents-xbl-3-ref.xul # bug 1089223
skip == display-contents-xbl-4.xul display-contents-xbl-4-ref.xul # fails (not just asserts) due to bug 1089223
asserts(0-1) fuzzy-if(Android,8,3216) == display-contents-fieldset.html display-contents-fieldset-ref.html # bug 1089223
asserts(1) asserts-if(styloVsGecko,2) == display-contents-xbl-5.xul display-contents-xbl-3-ref.xul # bug 1089223
fails-if(!stylo) == display-contents-xbl-6.xhtml display-contents-xbl-6-ref.html # bug 1345809
== display-contents-xbl-7.xhtml display-contents-xbl-7-ref.html
== display-contents-list-item-child.html display-contents-list-item-child-ref.html
--- a/layout/reftests/css-mediaqueries/reftest.list
+++ b/layout/reftests/css-mediaqueries/reftest.list
@@ -10,10 +10,10 @@ fuzzy-if(Android,8,454) == mq_print_orie
fuzzy-if(Android,8,454) == mq_print_maxheight.xhtml mq_print-ref.xhtml
== mq_print_maxwidth.xhtml mq_print-ref.xhtml
== mq_print_maxwidth_updown.xhtml mq_print-ref.xhtml
== mq_print_maxheight_updown.xhtml mq_print-ref.xhtml
== mq_print_minheight_updown.xhtml mq_print-ref.xhtml
== mq_print_minwidth_updown.xhtml mq_print-ref.xhtml
-== scoped-mq-update.html scoped-mq-update-ref.html
+pref(layout.css.scoped-style.enabled,true) == scoped-mq-update.html scoped-mq-update-ref.html
fails-if(styloVsGecko||stylo) == system-metrics-1.html system-metrics-1-ref.html
--- a/layout/reftests/scoped-style/reftest.list
+++ b/layout/reftests/scoped-style/reftest.list
@@ -1,8 +1,10 @@
+default-preferences pref(layout.css.scoped-style.enabled,true)
+
fails-if(styloVsGecko||stylo) == scoped-style-001.html scoped-style-001-ref.html
fails-if(styloVsGecko||stylo) == scoped-style-002.html scoped-style-002-ref.html
fails-if(styloVsGecko||stylo) == scoped-style-003.html scoped-style-003-ref.html
fails-if(styloVsGecko||stylo) == scoped-style-004.html scoped-style-004-ref.html
fails-if(styloVsGecko||stylo) == scoped-style-005.html scoped-style-005-ref.html
== scoped-style-006.html scoped-style-006-ref.html
== scoped-style-007.html scoped-style-007-ref.html
fails-if(styloVsGecko||stylo) == scoped-style-008.html scoped-style-008-ref.html
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -2851,16 +2851,22 @@ pref("layout.css.prefixes.gradients", tr
// Are webkit-prefixed properties & property-values supported?
pref("layout.css.prefixes.webkit", true);
// Are "-webkit-{min|max}-device-pixel-ratio" media queries supported?
// (Note: this pref has no effect if the master 'layout.css.prefixes.webkit'
// pref is set to false.)
pref("layout.css.prefixes.device-pixel-ratio-webkit", false);
+// Is support for <style scoped> enabled in content documents?
+//
+// If disabled, this will also disable the DOM API (HTMLStyleElement.scoped)
+// in chrome documents.
+pref("layout.css.scoped-style.enabled", true);
+
// Is support for the :scope selector enabled?
pref("layout.css.scope-pseudo.enabled", true);
// Is support for background-blend-mode enabled?
pref("layout.css.background-blend-mode.enabled", true);
// Is support for CSS text-combine-upright (tate-chu-yoko) enabled?
pref("layout.css.text-combine-upright.enabled", true);