Bug 1291515 - Part 1: Introduce a pref for <style scoped>. r?dbaron r=bholley draft
authorCameron McCormack <cam@mcc.id.au>
Wed, 21 Jun 2017 09:25:43 +0800
changeset 600297 ab3fe2c6e11f82cfc62cf35351566f55997d6617
parent 600225 c01aa84ded7eb0b3e691f8bcc5cd887c960a779e
child 600298 13e53487de850ce4800aaa7dd10c12cb65f3d79c
push id65713
push userbmo:cam@mcc.id.au
push dateSun, 25 Jun 2017 21:06:01 +0000
reviewersdbaron, bholley
bugs1291515
milestone56.0a1
Bug 1291515 - Part 1: Introduce a pref for <style scoped>. r?dbaron r=bholley MozReview-Commit-ID: 1J9IvPrC0xh
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/base/nsDocument.cpp
dom/base/nsIDocument.h
dom/base/nsStyleLinkElement.cpp
dom/html/HTMLStyleElement.cpp
dom/html/test/test_style_attributes_reflection.html
dom/svg/SVGStyleElement.cpp
dom/webidl/HTMLStyleElement.webidl
dom/webidl/SVGStyleElement.webidl
layout/reftests/css-display/reftest.list
layout/reftests/css-mediaqueries/reftest.list
layout/reftests/scoped-style/reftest.list
modules/libpref/init/all.js
--- 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);