Bug 1422931 - Part 2: Make webcomponents preference per-doc. r=smaug
☠☠ backed out by 1ece11256d13 ☠ ☠
authorJessica Jong <jjong@mozilla.com>
Fri, 08 Dec 2017 22:17:40 +0800
changeset 450073 60d9744e3fc44f79eecfa02cfec5f1c144e962a4
parent 450072 cf554d5d70cc841bf167812c299ccfd92832f83f
child 450074 58ab683a6b02a6692204a797fc5c8ddaf101ba56
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1422931
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1422931 - Part 2: Make webcomponents preference per-doc. r=smaug This is to fix the case where preference is restore to false when a testcas ends, but nsDocument::DeleteShell is called afterwards. So, we make the preference per-doc and once it is enabled for a document, it stays enabled.
dom/base/ChildIterator.cpp
dom/base/nsContentUtils.cpp
dom/base/nsDocument.cpp
dom/base/nsDocument.h
dom/base/nsIDocument.h
dom/base/nsTextNode.cpp
dom/base/nsTextNode.h
dom/html/HTMLSlotElement.cpp
dom/webidl/Element.webidl
dom/webidl/HTMLSlotElement.webidl
dom/webidl/ShadowRoot.webidl
dom/webidl/Text.webidl
--- a/dom/base/ChildIterator.cpp
+++ b/dom/base/ChildIterator.cpp
@@ -7,16 +7,17 @@
 #include "ChildIterator.h"
 #include "nsContentUtils.h"
 #include "mozilla/dom/HTMLSlotElement.h"
 #include "mozilla/dom/XBLChildrenElement.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "nsIAnonymousContentCreator.h"
 #include "nsIFrame.h"
 #include "nsCSSAnonBoxes.h"
+#include "nsDocument.h"
 
 namespace mozilla {
 namespace dom {
 
 class MatchedNodes {
 public:
   explicit MatchedNodes()
     : mIsContentElement(false), mChildrenElement(nullptr) {}
@@ -61,17 +62,17 @@ GetMatchedNodesForPoint(nsIContent* aCon
 ExplicitChildIterator::ExplicitChildIterator(const nsIContent* aParent,
                                              bool aStartAtBeginning)
   : mParent(aParent),
     mChild(nullptr),
     mDefaultChild(nullptr),
     mIsFirst(aStartAtBeginning),
     mIndexInInserted(0)
 {
-  mParentAsSlot = nsContentUtils::IsWebComponentsEnabled() ?
+  mParentAsSlot = nsDocument::IsWebComponentsEnabled(mParent) ?
     HTMLSlotElement::FromContent(mParent) : nullptr;
 }
 
 nsIContent*
 ExplicitChildIterator::GetNextChild()
 {
   // If we're already in the inserted-children array, look there first
   if (mIndexInInserted) {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7529,17 +7529,17 @@ nsContentUtils::IsContentInsertionPoint(
   // XXX handle <slot>?
   return false;
 }
 
 // static
 bool
 nsContentUtils::HasDistributedChildren(nsIContent* aContent)
 {
-  if (!IsWebComponentsEnabled() || !aContent) {
+  if (!aContent || !nsDocument::IsWebComponentsEnabled(aContent)) {
     return false;
   }
 
   if (aContent->GetShadowRoot()) {
     // Children of a shadow root host are distributed
     // to content insertion points in the shadow root.
     return true;
   }
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1533,16 +1533,17 @@ nsIDocument::nsIDocument()
     mHasScrollLinkedEffect(false),
     mFrameRequestCallbacksScheduled(false),
     mIsTopLevelContentDocument(false),
     mIsContentDocument(false),
     mDidCallBeginLoad(false),
     mBufferingCSPViolations(false),
     mAllowPaymentRequest(false),
     mEncodingMenuDisabled(false),
+    mIsWebComponentsEnabled(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),
@@ -2715,16 +2716,58 @@ nsDocument::IsSynthesized() {
   bool synthesized = false;
   if (internalChan) {
     DebugOnly<nsresult> rv = internalChan->GetResponseSynthesized(&synthesized);
     MOZ_ASSERT(NS_SUCCEEDED(rv), "GetResponseSynthesized shouldn't fail.");
   }
   return synthesized;
 }
 
+bool
+nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
+{
+  JS::Rooted<JSObject*> obj(aCx, aObject);
+
+  JSAutoCompartment ac(aCx, obj);
+  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
+  nsCOMPtr<nsPIDOMWindowInner> window =
+    do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
+
+  nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
+  if (!doc) {
+    return false;
+  }
+
+  // Once it is enabled for a document, it stays enabled.
+  if (doc->IsWebComponentsEnabled()) {
+    return true;
+  }
+
+  bool enabled = nsContentUtils::IsWebComponentsEnabled();
+  doc->SetWebComponentsEnabled(enabled);
+
+  return enabled;
+}
+
+bool
+nsDocument::IsWebComponentsEnabled(const nsINode* aNode)
+{
+  nsIDocument* doc = aNode->OwnerDoc();
+
+  // Once it is enabled for a document, it stays enabled.
+  if (doc->IsWebComponentsEnabled()) {
+    return true;
+  }
+
+  bool enabled = nsContentUtils::IsWebComponentsEnabled();
+  doc->SetWebComponentsEnabled(enabled);
+
+  return enabled;
+}
+
 nsresult
 nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
                               nsILoadGroup* aLoadGroup,
                               nsISupports* aContainer,
                               nsIStreamListener **aDocListener,
                               bool aReset, nsIContentSink* aSink)
 {
   if (MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -660,16 +660,21 @@ public:
 
   virtual void NotifyLayerManagerRecreated() override;
 
   virtual void ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) override;
   virtual void UnscheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG) override;
   virtual void ResolveScheduledSVGPresAttrs() override;
   bool IsSynthesized();
 
+  // Check whether web components are enabled for the global of aObject.
+  static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
+  // Check whether web components are enabled for the document this node belongs
+  // to.
+  static bool IsWebComponentsEnabled(const nsINode* aNode);
 private:
   void AddOnDemandBuiltInUASheet(mozilla::StyleSheet* aSheet);
   void SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages);
 
 public:
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE_OVERRIDABLE
 
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -3251,16 +3251,26 @@ public:
   {
     MOZ_ASSERT(mIgnoreOpensDuringUnloadCounter);
     --mIgnoreOpensDuringUnloadCounter;
   }
 
   virtual bool AllowPaymentRequest() const = 0;
   virtual void SetAllowPaymentRequest(bool aAllowPaymentRequest) = 0;
 
+  bool IsWebComponentsEnabled() const
+  {
+    return mIsWebComponentsEnabled;
+  }
+
+  void SetWebComponentsEnabled(bool aEnabled)
+  {
+    mIsWebComponentsEnabled = aEnabled;
+  }
+
 protected:
   bool GetUseCounter(mozilla::UseCounter aUseCounter)
   {
     return mUseCounters[aUseCounter];
   }
 
   void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {
@@ -3607,16 +3617,20 @@ protected:
   bool mBufferingCSPViolations : 1;
 
   // True if the document is allowed to use PaymentRequest.
   bool mAllowPaymentRequest : 1;
 
   // True if the encoding menu should be disabled.
   bool mEncodingMenuDisabled : 1;
 
+  // True if dom.webcomponents.enabled pref is set. It can not be unset once
+  // set to true.
+  bool mIsWebComponentsEnabled : 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
--- a/dom/base/nsTextNode.cpp
+++ b/dom/base/nsTextNode.cpp
@@ -16,16 +16,17 @@
 #include "nsIDOMMutationEvent.h"
 #include "nsIDocument.h"
 #include "nsThreadUtils.h"
 #include "nsStubMutationObserver.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #ifdef DEBUG
 #include "nsRange.h"
 #endif
+#include "nsDocument.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 /**
  * class used to implement attr() generated content
  */
 class nsAttributeTextNode final : public nsTextNode,
@@ -152,16 +153,22 @@ nsTextNode::BindToTree(nsIDocument* aDoc
 
 void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   ResetDirectionSetByTextNode(this);
 
   nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
 }
 
+bool
+nsTextNode::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
+{
+  return nsDocument::IsWebComponentsEnabled(aCx, aObject);
+}
+
 #ifdef DEBUG
 void
 nsTextNode::List(FILE* out, int32_t aIndent) const
 {
   int32_t index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
 
   fprintf(out, "Text@%p", static_cast<const void*>(this));
--- a/dom/base/nsTextNode.h
+++ b/dom/base/nsTextNode.h
@@ -70,16 +70,20 @@ public:
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true) override;
 
   nsresult AppendTextForNormalize(const char16_t* aBuffer, uint32_t aLength,
                                   bool aNotify, nsIContent* aNextSibling);
 
   virtual nsIDOMNode* AsDOMNode() override { return this; }
 
+  // Need to have a copy here because including nsDocument.h in this file will
+  // fail to build on Windows.
+  static bool IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject);
+
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const override;
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const override;
 #endif
 
 protected:
   virtual ~nsTextNode();
 
--- a/dom/html/HTMLSlotElement.cpp
+++ b/dom/html/HTMLSlotElement.cpp
@@ -11,17 +11,17 @@
 #include "nsGkAtoms.h"
 #include "nsDocument.h"
 
 nsGenericHTMLElement*
 NS_NewHTMLSlotElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
                       mozilla::dom::FromParser aFromParser)
 {
   RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
-  if (nsContentUtils::IsWebComponentsEnabled()) {
+  if (nsDocument::IsWebComponentsEnabled(nodeInfo->GetDocument())) {
     already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
     return new mozilla::dom::HTMLSlotElement(nodeInfoArg);
   }
 
   already_AddRefed<mozilla::dom::NodeInfo> nodeInfoArg(nodeInfo.forget());
   return new mozilla::dom::HTMLUnknownElement(nodeInfoArg);
 }
 
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -240,29 +240,29 @@ partial interface Element {
 // https://dom.spec.whatwg.org/#dictdef-shadowrootinit
 dictionary ShadowRootInit {
   required ShadowRootMode mode;
 };
 
 // https://dom.spec.whatwg.org/#element
 partial interface Element {
   // Shadow DOM v1
-  [Throws, Pref="dom.webcomponents.enabled"]
+  [Throws, Func="nsDocument::IsWebComponentsEnabled"]
   ShadowRoot attachShadow(ShadowRootInit shadowRootInitDict);
-  [BinaryName="shadowRootByMode", Pref="dom.webcomponents.enabled"]
+  [BinaryName="shadowRootByMode", Func="nsDocument::IsWebComponentsEnabled"]
   readonly attribute ShadowRoot? shadowRoot;
-  [BinaryName="assignedSlotByMode", Pref="dom.webcomponents.enabled"]
+  [BinaryName="assignedSlotByMode", Func="nsDocument::IsWebComponentsEnabled"]
   readonly attribute HTMLSlotElement? assignedSlot;
-  [CEReactions, Unscopable, SetterThrows, Pref="dom.webcomponents.enabled"]
+  [CEReactions, Unscopable, SetterThrows, Func="nsDocument::IsWebComponentsEnabled"]
            attribute DOMString slot;
 
   // [deprecated] Shadow DOM v0
-  [Throws, Pref="dom.webcomponents.enabled"]
+  [Throws, Func="nsDocument::IsWebComponentsEnabled"]
   ShadowRoot createShadowRoot();
-  [Pref="dom.webcomponents.enabled"]
+  [Func="nsDocument::IsWebComponentsEnabled"]
   NodeList getDestinationInsertionPoints();
 };
 
 Element implements ChildNode;
 Element implements NonDocumentTypeChildNode;
 Element implements ParentNode;
 Element implements Animatable;
 Element implements GeometryUtils;
--- a/dom/webidl/HTMLSlotElement.webidl
+++ b/dom/webidl/HTMLSlotElement.webidl
@@ -6,17 +6,17 @@
  * The origin of this IDL file is
  * https://html.spec.whatwg.org/multipage/forms.html#the-dialog-element
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
-[Pref="dom.webcomponents.enabled", Exposed=Window, HTMLConstructor]
+[Func="nsDocument::IsWebComponentsEnabled", Exposed=Window, HTMLConstructor]
 interface HTMLSlotElement : HTMLElement {
   [CEReactions, SetterThrows] attribute DOMString name;
   sequence<Node> assignedNodes(optional AssignedNodesOptions options);
 };
 
 dictionary AssignedNodesOptions {
   boolean flatten = false;
 };
--- a/dom/webidl/ShadowRoot.webidl
+++ b/dom/webidl/ShadowRoot.webidl
@@ -12,17 +12,17 @@
 
 // https://dom.spec.whatwg.org/#enumdef-shadowrootmode
 enum ShadowRootMode {
   "open",
   "closed"
 };
 
 // https://dom.spec.whatwg.org/#shadowroot
-[Pref="dom.webcomponents.enabled"]
+[Func="nsDocument::IsWebComponentsEnabled"]
 interface ShadowRoot : DocumentFragment
 {
   // Shadow DOM v1
   readonly attribute ShadowRootMode mode;
   readonly attribute Element host;
 
   // [deprecated] Shadow DOM v0
   Element? getElementById(DOMString elementId);
--- a/dom/webidl/Text.webidl
+++ b/dom/webidl/Text.webidl
@@ -14,13 +14,13 @@
 interface Text : CharacterData {
   [Throws]
   Text splitText(unsigned long offset);
   [Throws]
   readonly attribute DOMString wholeText;
 };
 
 partial interface Text {
-  [BinaryName="assignedSlotByMode", Pref="dom.webcomponents.enabled"]
+  [BinaryName="assignedSlotByMode", Func="nsTextNode::IsWebComponentsEnabled"]
   readonly attribute HTMLSlotElement? assignedSlot;
 };
 
 Text implements GeometryUtils;