From 8b5b7ad9987666c53d817113280f1b9e57964b7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Tue, 18 Apr 2023 14:58:34 +0000 Subject: [PATCH] Bug 1827856 - Remove nativeAnonymousChildList observers. r=smaug,credential-management-reviewers,devtools-reviewers,sgalich,nchevobbe You let me know if this seems appealing to you :) Differential Revision: https://phabricator.services.mozilla.com/D175382 --- accessible/generic/DocAccessible.cpp | 15 - devtools/client/fronts/walker.js | 8 +- devtools/client/inspector/markup/markup.js | 1 - .../test/browser_markup_shadowdom_noslot.js | 4 +- .../docs/contributor/tools/inspector-panel.md | 2 +- devtools/server/actors/inspector/node.js | 1 - devtools/server/actors/inspector/walker.js | 75 ++++- dom/base/CharacterData.cpp | 6 - dom/base/Document.cpp | 2 +- dom/base/Document.h | 13 +- dom/base/Element.cpp | 17 +- dom/base/MutationObservers.cpp | 13 - dom/base/MutationObservers.h | 9 - dom/base/nsDOMMutationObserver.cpp | 35 +-- dom/base/nsDOMMutationObserver.h | 13 - dom/base/nsIMutationObserver.h | 17 -- dom/base/nsINode.cpp | 23 +- dom/base/nsINode.h | 2 + dom/base/nsStubMutationObserver.cpp | 6 - dom/base/test/mochitest.ini | 1 - .../test/test_mutationobserver_anonymous.html | 265 ------------------ dom/base/test/test_mutationobservers.html | 4 +- dom/webidl/Document.webidl | 2 +- dom/webidl/MutationObserver.webidl | 2 - layout/base/PresShell.cpp | 10 + layout/base/nsCSSFrameConstructor.cpp | 15 + layout/generic/nsIFrame.cpp | 1 - .../content/SpecialPowersChild.sys.mjs | 7 - .../satchel/nsFormFillController.cpp | 3 - widget/cocoa/nsMenuGroupOwnerX.mm | 2 - xpcom/ds/StaticAtoms.py | 1 - 31 files changed, 137 insertions(+), 438 deletions(-) delete mode 100644 dom/base/test/test_mutationobserver_anonymous.html diff --git a/accessible/generic/DocAccessible.cpp b/accessible/generic/DocAccessible.cpp index 6088534ed595..a67e6cfb75d7 100644 --- a/accessible/generic/DocAccessible.cpp +++ b/accessible/generic/DocAccessible.cpp @@ -796,21 +796,6 @@ void DocAccessible::AttributeWillChange(dom::Element* aElement, } } -void DocAccessible::NativeAnonymousChildListChange(nsIContent* aContent, - bool aIsRemove) { - if (aIsRemove) { -#ifdef A11Y_LOG - if (logging::IsEnabled(logging::eTree)) { - logging::MsgBegin("TREE", "Anonymous content removed; doc: %p", this); - logging::Node("node", aContent); - logging::MsgEnd(); - } -#endif - - ContentRemoved(aContent); - } -} - void DocAccessible::AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType, diff --git a/devtools/client/fronts/walker.js b/devtools/client/fronts/walker.js index cf415e1c399c..5feae2a343d8 100644 --- a/devtools/client/fronts/walker.js +++ b/devtools/client/fronts/walker.js @@ -216,10 +216,7 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) { const emittedMutation = Object.assign(change, { target: targetFront }); - if ( - change.type === "childList" || - change.type === "nativeAnonymousChildList" - ) { + if (change.type === "childList") { // Update the ownership tree according to the mutation record. const addedFronts = []; const removedFronts = []; @@ -287,8 +284,7 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) { if ( change.type === "inlineTextChild" || change.type === "childList" || - change.type === "shadowRootAttached" || - change.type === "nativeAnonymousChildList" + change.type === "shadowRootAttached" ) { if (change.inlineTextChild) { targetFront.inlineTextChild = types diff --git a/devtools/client/inspector/markup/markup.js b/devtools/client/inspector/markup/markup.js index 38bbc611cefd..226c14907fee 100644 --- a/devtools/client/inspector/markup/markup.js +++ b/devtools/client/inspector/markup/markup.js @@ -1571,7 +1571,6 @@ MarkupView.prototype = { container.update(); } else if ( type === "childList" || - type === "nativeAnonymousChildList" || type === "slotchange" || type === "shadowRootAttached" ) { diff --git a/devtools/client/inspector/markup/test/browser_markup_shadowdom_noslot.js b/devtools/client/inspector/markup/test/browser_markup_shadowdom_noslot.js index 2cb9a64a5342..421f38697983 100644 --- a/devtools/client/inspector/markup/test/browser_markup_shadowdom_noslot.js +++ b/devtools/client/inspector/markup/test/browser_markup_shadowdom_noslot.js @@ -72,8 +72,7 @@ add_task(async function() { info( "Move the non-slotted element with class has-before and check the pseudo appears" ); - const mutated = waitForNMutations(inspector, "childList", 2); - const pseudoMutated = waitForMutation(inspector, "nativeAnonymousChildList"); + const mutated = waitForNMutations(inspector, "childList", 3); SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { const root = content.document.querySelector(".root"); const hasBeforeEl = content.document.querySelector( @@ -82,7 +81,6 @@ add_task(async function() { root.appendChild(hasBeforeEl); }); await mutated; - await pseudoMutated; // As the non-slotted has-before is moved into the tree, the before pseudo is expected // to appear. diff --git a/devtools/docs/contributor/tools/inspector-panel.md b/devtools/docs/contributor/tools/inspector-panel.md index ee8abca83b16..944a62eb4f43 100644 --- a/devtools/docs/contributor/tools/inspector-panel.md +++ b/devtools/docs/contributor/tools/inspector-panel.md @@ -70,7 +70,7 @@ __WalkerActor__ - But only has a partial knowledge of the DOM (what is currently displayed/expanded in the MarkupView). It doesn't need to walk the whole tree when you first instantiate it. - Reflects some of the usual DOM APIs like querySelector. - Note that methods like querySelector return arbitrarily nested NodeActors, in which case the WalkerActor also sends the list of parents to link the returned nodes to the closest known nodes, so the UI can display the tree correctly. -- Emits events when there are DOM mutations. These events are sent to the front-end and used to, for example refresh the markup-view. This uses an instance of MutationObserver (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) configured with, in particular, nativeAnonymousChildList set to true, so that mutation events are also sent when pseudo elements are added/removed via css. +- Emits events when there are DOM mutations. These events are sent to the front-end and used to, for example refresh the markup-view. This uses an instance of MutationObserver (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) configured with, in particular, chromeOnlyNodes set to true, so that mutation events are also sent when pseudo elements are added/removed via css. __NodeActor__ diff --git a/devtools/server/actors/inspector/node.js b/devtools/server/actors/inspector/node.js index 1b2b80341729..12af7702f224 100644 --- a/devtools/server/actors/inspector/node.js +++ b/devtools/server/actors/inspector/node.js @@ -265,7 +265,6 @@ class NodeActor extends Actor { const observer = new doc.defaultView.MutationObserver(callback); observer.mergeAttributeRecords = true; observer.observe(node, { - nativeAnonymousChildList: true, attributes: true, characterData: true, characterDataOldValue: true, diff --git a/devtools/server/actors/inspector/walker.js b/devtools/server/actors/inspector/walker.js index 5d5cf10d8da7..625fc4b11744 100644 --- a/devtools/server/actors/inspector/walker.js +++ b/devtools/server/actors/inspector/walker.js @@ -215,6 +215,7 @@ class WalkerActor extends Actor { this._pendingMutations = []; this._activePseudoClassLocks = new Set(); this._mutationBreakpoints = new WeakMap(); + this._anonParents = new WeakMap(); this.customElementWatcher = new CustomElementWatcher( targetActor.chromeEventHandler ); @@ -247,6 +248,8 @@ class WalkerActor extends Actor { this.onMutations = this.onMutations.bind(this); this.onSlotchange = this.onSlotchange.bind(this); this.onShadowrootattached = this.onShadowrootattached.bind(this); + this.onAnonymousrootcreated = this.onAnonymousrootcreated.bind(this); + this.onAnonymousrootremoved = this.onAnonymousrootremoved.bind(this); this.onFrameLoad = this.onFrameLoad.bind(this); this.onFrameUnload = this.onFrameUnload.bind(this); this.onCustomElementDefined = this.onCustomElementDefined.bind(this); @@ -271,9 +274,17 @@ class WalkerActor extends Actor { "shadowrootattached", this.onShadowrootattached ); - + // anonymousrootcreated is a chrome-only event. We enable it below. + this.chromeEventHandler.addEventListener( + "anonymousrootcreated", + this.onAnonymousrootcreated + ); + this.chromeEventHandler.addEventListener( + "anonymousrootremoved", + this.onAnonymousrootremoved + ); for (const { document } of this.targetActor.windows) { - document.shadowRootAttachedEventEnabled = true; + document.devToolsAnonymousAndShadowEventsEnabled = true; } // Ensure that the root document node actor is ready and @@ -384,10 +395,18 @@ class WalkerActor extends Actor { "shadowrootattached", this.onShadowrootattached ); + this.chromeEventHandler.removeEventListener( + "anonymousrootcreated", + this.onAnonymousrootcreated + ); + this.chromeEventHandler.removeEventListener( + "anonymousrootremoved", + this.onAnonymousrootremoved + ); - // This event is just for devtools, so we can unset once we're done. + // This attribute is just for devtools, so we can unset once we're done. for (const { document } of this.targetActor.windows) { - document.shadowRootAttachedEventEnabled = false; + document.devToolsAnonymousAndShadowEventsEnabled = false; } this.onFrameLoad = null; @@ -2169,7 +2188,7 @@ class WalkerActor extends Actor { } else if (type === "characterData") { mutation.newValue = targetNode.nodeValue; this._maybeQueueInlineTextChildMutation(change, targetNode); - } else if (type === "childList" || type === "nativeAnonymousChildList") { + } else if (type === "childList") { // Get the list of removed and added actors that the client has seen // so that it can keep its ownership tree up to date. const removedActors = []; @@ -2262,6 +2281,52 @@ class WalkerActor extends Actor { }); } + /** + * Fires when an anonymous root is created. + * This is needed because regular mutation observers don't fire on some kinds + * of NAC creation. We want to treat this like a regular insertion. + */ + onAnonymousrootcreated(event) { + const root = event.target; + const parent = this.rawParentNode(root); + if (!parent) { + // These events are async. The node might have been removed already, in + // which case there's nothing to do anymore. + return; + } + // By the time onAnonymousrootremoved fires, the node is already detached + // from its parent, so we need to remember it by hand. + this._anonParents.set(root, parent); + this.onMutations([ + { + type: "childList", + target: parent, + addedNodes: [root], + removedNodes: [], + }, + ]); + } + + /** + * @see onAnonymousrootcreated + */ + onAnonymousrootremoved(event) { + const root = event.target; + const parent = this._anonParents.get(root); + if (!parent) { + return; + } + this._anonParents.delete(root); + this.onMutations([ + { + type: "childList", + target: parent, + addedNodes: [], + removedNodes: [root], + }, + ]); + } + onShadowrootattached(event) { const actor = this.getNode(event.target); if (!actor) { diff --git a/dom/base/CharacterData.cpp b/dom/base/CharacterData.cpp index 09a37dc8ddc5..8d5abe028a90 100644 --- a/dom/base/CharacterData.cpp +++ b/dom/base/CharacterData.cpp @@ -459,9 +459,6 @@ nsresult CharacterData::BindToTree(BindContext& aContext, nsINode& aParent) { } MutationObservers::NotifyParentChainChanged(this); - if (!hadParent && IsRootOfNativeAnonymousSubtree()) { - MutationObservers::NotifyNativeAnonymousChildListChange(this, false); - } UpdateEditableState(false); @@ -488,9 +485,6 @@ void CharacterData::UnbindFromTree(bool aNullParent) { HandleShadowDOMRelatedRemovalSteps(aNullParent); if (aNullParent) { - if (IsRootOfNativeAnonymousSubtree()) { - MutationObservers::NotifyNativeAnonymousChildListChange(this, true); - } if (GetParent()) { NS_RELEASE(mParent); } else { diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index 040e95311893..988d16a42b40 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -1366,7 +1366,7 @@ Document::Document(const char* aContentType) mBFCacheDisallowed(false), mHasHadDefaultView(false), mStyleSheetChangeEventsEnabled(false), - mShadowRootAttachedEventEnabled(false), + mDevToolsAnonymousAndShadowEventsEnabled(false), mIsSrcdocDocument(false), mHasDisplayDocument(false), mFontFaceSetDirty(true), diff --git a/dom/base/Document.h b/dom/base/Document.h index 175133ca6151..135bb5eb79e7 100644 --- a/dom/base/Document.h +++ b/dom/base/Document.h @@ -3602,11 +3602,11 @@ class Document : public nsINode, return mStyleSheetChangeEventsEnabled; } - void SetShadowRootAttachedEventEnabled(bool aValue) { - mShadowRootAttachedEventEnabled = aValue; + void SetDevToolsAnonymousAndShadowEventsEnabled(bool aValue) { + mDevToolsAnonymousAndShadowEventsEnabled = aValue; } - bool ShadowRootAttachedEventEnabled() const { - return mShadowRootAttachedEventEnabled; + bool DevToolsAnonymousAndShadowEventsEnabled() const { + return mDevToolsAnonymousAndShadowEventsEnabled; } already_AddRefed BlockParsing(Promise& aPromise, @@ -4740,8 +4740,9 @@ class Document : public nsINode, // Whether style sheet change events will be dispatched for this document bool mStyleSheetChangeEventsEnabled : 1; - // Whether shadowrootattached events will be dispatched for this document. - bool mShadowRootAttachedEventEnabled : 1; + // Whether shadowrootattached/anonymousnodecreated/anonymousnoderemoved events + // will be dispatched for this document. + bool mDevToolsAnonymousAndShadowEventsEnabled : 1; // Whether the document was created by a srcdoc iframe. bool mIsSrcdocDocument : 1; diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 78eb62dabcba..3e2c5a831306 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1275,10 +1275,10 @@ already_AddRefed Element::AttachShadowWithoutNameChecks( SlotAssignmentMode aSlotAssignment) { nsAutoScriptBlocker scriptBlocker; + auto* nim = mNodeInfo->NodeInfoManager(); RefPtr nodeInfo = - mNodeInfo->NodeInfoManager()->GetNodeInfo( - nsGkAtoms::documentFragmentNodeName, nullptr, kNameSpaceID_None, - DOCUMENT_FRAGMENT_NODE); + nim->GetNodeInfo(nsGkAtoms::documentFragmentNodeName, nullptr, + kNameSpaceID_None, DOCUMENT_FRAGMENT_NODE); // If there are no children, the flat tree is not changing due to the presence // of the shadow root, so we don't need to invalidate style / layout. @@ -1296,7 +1296,6 @@ already_AddRefed Element::AttachShadowWithoutNameChecks( * context object's node document, host is context object, * and mode is init's mode. */ - auto* nim = nodeInfo->NodeInfoManager(); RefPtr shadowRoot = new (nim) ShadowRoot( this, aMode, aDelegatesFocus, aSlotAssignment, nodeInfo.forget()); @@ -1320,7 +1319,8 @@ already_AddRefed Element::AttachShadowWithoutNameChecks( SetShadowRoot(shadowRoot); // Dispatch a "shadowrootattached" event for devtools if needed. - if (MOZ_UNLIKELY(nim->GetDocument()->ShadowRootAttachedEventEnabled())) { + if (MOZ_UNLIKELY( + nim->GetDocument()->DevToolsAnonymousAndShadowEventsEnabled())) { AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( this, u"shadowrootattached"_ns, CanBubble::eYes, ChromeOnlyDispatch::eYes, Composed::eYes); @@ -1899,9 +1899,6 @@ nsresult Element::BindToTree(BindContext& aContext, nsINode& aParent) { } MutationObservers::NotifyParentChainChanged(this); - if (!hadParent && IsRootOfNativeAnonymousSubtree()) { - MutationObservers::NotifyNativeAnonymousChildListChange(this, false); - } // Ensure we only run this once, in the case we move the ShadowRoot around. if (aContext.SubtreeRootChanges()) { @@ -2012,10 +2009,6 @@ void Element::UnbindFromTree(bool aNullParent) { } if (aNullParent) { - if (IsRootOfNativeAnonymousSubtree()) { - MutationObservers::NotifyNativeAnonymousChildListChange(this, true); - } - if (GetParent()) { RefPtr p; p.swap(mParent); diff --git a/dom/base/MutationObservers.cpp b/dom/base/MutationObservers.cpp index 37245fa6c18c..ca9bbfa93b16 100644 --- a/dom/base/MutationObservers.cpp +++ b/dom/base/MutationObservers.cpp @@ -163,19 +163,6 @@ void MutationObservers::NotifyContentAppended(nsIContent* aContainer, Notify(aContainer, notifyPresShell, notifyObserver); } -void MutationObservers::NotifyNativeAnonymousChildListChange( - nsIContent* aContent, bool aIsRemove) { - DEFINE_NOTIFIERS(NativeAnonymousChildListChange, (aContent, aIsRemove)); - if (aIsRemove) { - // We can't actually assert that we reach the document if we're connected, - // since this notification runs from UnbindFromTree. - Notify(aContent, notifyPresShell, - notifyObserver); - } else { - Notify(aContent, notifyPresShell, notifyObserver); - } -} - void MutationObservers::NotifyContentInserted(nsINode* aContainer, nsIContent* aChild) { MOZ_ASSERT(aContainer->IsContent() || aContainer->IsDocument(), diff --git a/dom/base/MutationObservers.h b/dom/base/MutationObservers.h index 7ed18e81d7c1..5a649921cb96 100644 --- a/dom/base/MutationObservers.h +++ b/dom/base/MutationObservers.h @@ -88,15 +88,6 @@ class MutationObservers { static void NotifyContentAppended(nsIContent* aContainer, nsIContent* aFirstNewContent); - /** - * Send NativeAnonymousChildList notifications to nsIMutationObservers - * @param aContent Anonymous node that's been added or removed - * @param aIsRemove True if it's a removal, false if an addition - * @see nsIMutationObserver::NativeAnonymousChildListChange - */ - static void NotifyNativeAnonymousChildListChange(nsIContent* aContent, - bool aIsRemove); - /** * Send ContentInserted notifications to nsIMutationObservers * @param aContainer Node into which new child was inserted diff --git a/dom/base/nsDOMMutationObserver.cpp b/dom/base/nsDOMMutationObserver.cpp index a57bf3595061..cb1416f86914 100644 --- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -138,35 +138,6 @@ void nsMutationReceiver::Disconnect(bool aRemoveFromObserver) { } } -void nsMutationReceiver::NativeAnonymousChildListChange(nsIContent* aContent, - bool aIsRemove) { - if (!NativeAnonymousChildList()) { - return; - } - - nsINode* parent = aContent->GetParentNode(); - if (!parent || (!Subtree() && Target() != parent) || - (Subtree() && RegisterTarget()->SubtreeRoot() != parent->SubtreeRoot())) { - return; - } - - nsDOMMutationRecord* m = - Observer()->CurrentRecord(nsGkAtoms::nativeAnonymousChildList); - - if (m->mTarget) { - return; - } - m->mTarget = parent; - - if (aIsRemove) { - m->mRemovedNodes = new nsSimpleContentList(parent); - m->mRemovedNodes->AppendElement(aContent); - } else { - m->mAddedNodes = new nsSimpleContentList(parent); - m->mAddedNodes->AppendElement(aContent); - } -} - void nsMutationReceiver::AttributeWillChange(Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, @@ -637,7 +608,6 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget, bool subtree = aOptions.mSubtree; bool attributeOldValue = aOptions.mAttributeOldValue.WasPassed() && aOptions.mAttributeOldValue.Value(); - bool nativeAnonymousChildList = aOptions.mNativeAnonymousChildList; bool characterDataOldValue = aOptions.mCharacterDataOldValue.WasPassed() && aOptions.mCharacterDataOldValue.Value(); bool animations = aOptions.mAnimations; @@ -654,8 +624,7 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget, characterData = true; } - if (!(childList || attributes || characterData || animations || - nativeAnonymousChildList)) { + if (!(childList || attributes || characterData || animations)) { aRv.ThrowTypeError( "One of 'childList', 'attributes', 'characterData' must not be false."); return; @@ -703,7 +672,6 @@ void nsDOMMutationObserver::Observe(nsINode& aTarget, r->SetSubtree(subtree); r->SetAttributeOldValue(attributeOldValue); r->SetCharacterDataOldValue(characterDataOldValue); - r->SetNativeAnonymousChildList(nativeAnonymousChildList); r->SetAttributeFilter(std::move(filters)); r->SetAllAttributes(allAttrs); r->SetAnimations(animations); @@ -765,7 +733,6 @@ void nsDOMMutationObserver::GetObservingInfo( info.mSubtree = mr->Subtree(); info.mAttributeOldValue.Construct(mr->AttributeOldValue()); info.mCharacterDataOldValue.Construct(mr->CharacterDataOldValue()); - info.mNativeAnonymousChildList = mr->NativeAnonymousChildList(); info.mAnimations = mr->Animations(); nsTArray>& filters = mr->AttributeFilter(); if (filters.Length()) { diff --git a/dom/base/nsDOMMutationObserver.h b/dom/base/nsDOMMutationObserver.h index b0c9250ed762..3426cf468962 100644 --- a/dom/base/nsDOMMutationObserver.h +++ b/dom/base/nsDOMMutationObserver.h @@ -153,15 +153,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver { mCharacterDataOldValue = aOldValue; } - bool NativeAnonymousChildList() const { - return mParent ? mParent->NativeAnonymousChildList() - : mNativeAnonymousChildList; - } - void SetNativeAnonymousChildList(bool aOldValue) { - NS_ASSERTION(!mParent, "Shouldn't have parent"); - mNativeAnonymousChildList = aOldValue; - } - bool Attributes() const { return mParent ? mParent->Attributes() : mAttributes; } @@ -227,7 +218,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver { mChildList(false), mCharacterData(false), mCharacterDataOldValue(false), - mNativeAnonymousChildList(false), mAttributes(false), mAllAttributes(false), mAttributeOldValue(false), @@ -244,7 +234,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver { mChildList(false), mCharacterData(false), mCharacterDataOldValue(false), - mNativeAnonymousChildList(false), mAttributes(false), mAllAttributes(false), mAttributeOldValue(false), @@ -284,7 +273,6 @@ class nsMutationReceiverBase : public nsStubAnimationObserver { bool mChildList : 1; bool mCharacterData : 1; bool mCharacterDataOldValue : 1; - bool mNativeAnonymousChildList : 1; bool mAttributes : 1; bool mAllAttributes : 1; bool mAttributeOldValue : 1; @@ -341,7 +329,6 @@ class nsMutationReceiver : public nsMutationReceiverBase { NS_DECL_ISUPPORTS NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE - NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED diff --git a/dom/base/nsIMutationObserver.h b/dom/base/nsIMutationObserver.h index ddad079bcf7d..ae954359ce6d 100644 --- a/dom/base/nsIMutationObserver.h +++ b/dom/base/nsIMutationObserver.h @@ -204,16 +204,6 @@ class nsIMutationObserver int32_t aModType, const nsAttrValue* aOldValue) = 0; - /** - * Notification that the root of a native anonymous has been added - * or removed. - * - * @param aContent Anonymous node that's been added or removed - * @param aIsRemove True if it's a removal, false if an addition - */ - virtual void NativeAnonymousChildListChange(nsIContent* aContent, - bool aIsRemove) {} - /** * Notification that an attribute of an element has been * set to the value it already had. @@ -331,10 +321,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID) int32_t aNameSpaceID, nsAtom* aAttribute, \ int32_t aModType) override; -#define NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE \ - virtual void NativeAnonymousChildListChange(nsIContent* aContent, \ - bool aIsRemove) override; - #define NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED \ virtual void AttributeChanged(mozilla::dom::Element* aElement, \ int32_t aNameSpaceID, nsAtom* aAttribute, \ @@ -371,7 +357,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID) NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE \ NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED \ NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE \ - NS_DECL_NSIMUTATIONOBSERVER_NATIVEANONYMOUSCHILDLISTCHANGE \ NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED \ NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED \ NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED \ @@ -392,8 +377,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIMutationObserver, NS_IMUTATION_OBSERVER_IID) void _class::AttributeWillChange(mozilla::dom::Element* aElement, \ int32_t aNameSpaceID, nsAtom* aAttribute, \ int32_t aModType) {} \ - void _class::NativeAnonymousChildListChange(nsIContent* aContent, \ - bool aIsRemove) {} \ void _class::AttributeChanged( \ mozilla::dom::Element* aElement, int32_t aNameSpaceID, \ nsAtom* aAttribute, int32_t aModType, const nsAttrValue* aOldValue) {} \ diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 946120e4da52..44ea279c8c53 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -443,6 +443,15 @@ Element* nsINode::GetAnonymousRootElementOfTextEditor( return rootElement; } +void nsINode::QueueDevtoolsAnonymousEvent(bool aIsRemove) { + MOZ_ASSERT(IsRootOfNativeAnonymousSubtree()); + MOZ_ASSERT(OwnerDoc()->DevToolsAnonymousAndShadowEventsEnabled()); + AsyncEventDispatcher* dispatcher = new AsyncEventDispatcher( + this, aIsRemove ? u"anonymousrootremoved"_ns : u"anonymousrootcreated"_ns, + CanBubble::eYes, ChromeOnlyDispatch::eYes, Composed::eYes); + dispatcher->PostDOMEvent(); +} + nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions) { if (aOptions.mComposed) { if (Document* doc = GetComposedDoc()) { @@ -3615,10 +3624,16 @@ ParentObject nsINode::GetParentObject() const { ParentObject p(OwnerDoc()); // Note that mReflectionScope is a no-op for chrome, and other places where we // don't check this value. - if (ShouldUseUAWidgetScope(this)) { - p.mReflectionScope = ReflectionScope::UAWidget; - } else if (ShouldUseNACScope(this)) { - p.mReflectionScope = ReflectionScope::NAC; + if (IsInNativeAnonymousSubtree()) { + if (ShouldUseUAWidgetScope(this)) { + p.mReflectionScope = ReflectionScope::UAWidget; + } else { + MOZ_ASSERT(ShouldUseNACScope(this)); + p.mReflectionScope = ReflectionScope::NAC; + } + } else { + MOZ_ASSERT(!ShouldUseNACScope(this)); + MOZ_ASSERT(!ShouldUseUAWidgetScope(this)); } return p; } diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 25deb7d0ddf8..982ad4dfff28 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -1692,6 +1692,8 @@ class nsINode : public mozilla::dom::EventTarget { */ MOZ_CAN_RUN_SCRIPT_BOUNDARY void FireNodeRemovedForChildren(); + void QueueDevtoolsAnonymousEvent(bool aIsRemove); + private: mozilla::dom::SVGUseElement* DoGetContainingSVGUseShadowHost() const; diff --git a/dom/base/nsStubMutationObserver.cpp b/dom/base/nsStubMutationObserver.cpp index 9ac85b0aa737..fcd8a8fdc576 100644 --- a/dom/base/nsStubMutationObserver.cpp +++ b/dom/base/nsStubMutationObserver.cpp @@ -71,12 +71,6 @@ class MutationObserverWrapper final : public nsIMutationObserver { aOldValue); } - void NativeAnonymousChildListChange(nsIContent* aContent, - bool aIsRemove) override { - MOZ_ASSERT(mOwner); - mOwner->NativeAnonymousChildListChange(aContent, aIsRemove); - } - void AttributeSetToCurrentValue(mozilla::dom::Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute) override { diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index ee34652d89d8..69d8fa37fa59 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -840,7 +840,6 @@ skip-if = os == 'mac' || os == 'linux' || headless skip-if = http3 [test_mozMatchesSelector.html] -[test_mutationobserver_anonymous.html] [test_mutationobservers.html] [test_named_frames.html] [test_navigator_cookieEnabled.html] diff --git a/dom/base/test/test_mutationobserver_anonymous.html b/dom/base/test/test_mutationobserver_anonymous.html deleted file mode 100644 index 191de9a4ea7d..000000000000 --- a/dom/base/test/test_mutationobserver_anonymous.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - Test for Bug 1034110 - - - - - -Mozilla Bug 1034110 - -
- -

- - -
-
-
- - diff --git a/dom/base/test/test_mutationobservers.html b/dom/base/test/test_mutationobservers.html index 69b27253db39..80e42713f79d 100644 --- a/dom/base/test/test_mutationobservers.html +++ b/dom/base/test/test_mutationobservers.html @@ -840,10 +840,10 @@ function testAttributeRecordMerging4() { } function testChromeOnly() { - // Content can't access nativeAnonymousChildList + // Content can't access chromeOnlyNodes try { var mo = new M(function(records, observer) { }); - mo.observe(div, { nativeAnonymousChildList: true }); + mo.observe(div, { chromeOnlyNodes: true }); ok(false, "Should have thrown when trying to observe with chrome-only init"); } catch (e) { ok(true, "Throws when trying to observe with chrome-only init"); diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index e97a303205d2..30dde0b4ad57 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -441,7 +441,7 @@ partial interface Document { attribute boolean styleSheetChangeEventsEnabled; [ChromeOnly] - attribute boolean shadowRootAttachedEventEnabled; + attribute boolean devToolsAnonymousAndShadowEventsEnabled; [ChromeOnly] readonly attribute DOMString contentLanguage; diff --git a/dom/webidl/MutationObserver.webidl b/dom/webidl/MutationObserver.webidl index 445725dcdec1..ae43e1b48aca 100644 --- a/dom/webidl/MutationObserver.webidl +++ b/dom/webidl/MutationObserver.webidl @@ -66,8 +66,6 @@ dictionary MutationObserverInit { boolean attributeOldValue; boolean characterDataOldValue; [ChromeOnly] - boolean nativeAnonymousChildList = false; - [ChromeOnly] boolean chromeOnlyNodes = false; [ChromeOnly] boolean animations = false; diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp index ab8ddd3ed55f..940b07bbdb8d 100644 --- a/layout/base/PresShell.cpp +++ b/layout/base/PresShell.cpp @@ -2161,6 +2161,16 @@ static nsIContent* GetNativeAnonymousSubtreeRoot(nsIContent* aContent) { void PresShell::NativeAnonymousContentRemoved(nsIContent* aAnonContent) { MOZ_ASSERT(aAnonContent->IsRootOfNativeAnonymousSubtree()); + mPresContext->EventStateManager()->NativeAnonymousContentRemoved( + aAnonContent); +#ifdef ACCESSIBILITY + if (nsAccessibilityService* accService = GetAccService()) { + accService->ContentRemoved(this, aAnonContent); + } +#endif + if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) { + aAnonContent->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ true); + } if (nsIContent* root = GetNativeAnonymousSubtreeRoot(mCurrentEventContent)) { if (aAnonContent == root) { mCurrentEventContent = aAnonContent->GetFlattenedTreeParent(); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 9de4b4fceeb8..fbd282892a78 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -1896,6 +1896,10 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem( return; } + if (mDocument->DevToolsAnonymousAndShadowEventsEnabled()) { + container->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false); + } + // Servo has already eagerly computed the style for the container, so we can // just stick the style on the element and avoid an additional traversal. // @@ -3999,6 +4003,13 @@ nsresult nsCSSFrameConstructor::GetAnonymousContent( return rv; } + if (aContent.IsEmpty()) { + return NS_OK; + } + + const bool devtoolsEventsEnabled = + mDocument->DevToolsAnonymousAndShadowEventsEnabled(); + MOZ_ASSERT(aParent->IsElement()); for (const auto& info : aContent) { // get our child's content and set its parent to our content @@ -4012,6 +4023,10 @@ nsresult nsCSSFrameConstructor::GetAnonymousContent( content->UnbindFromTree(); return rv; } + + if (devtoolsEventsEnabled) { + content->QueueDevtoolsAnonymousEvent(/* aIsRemove = */ false); + } } // Some situations where we don't cache anonymous content styles: diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index ece2dc28308f..3bb6f1c8a07d 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -221,7 +221,6 @@ static void SetOrUpdateRectValuedProperty( void nsIFrame::DestroyAnonymousContent( nsPresContext* aPresContext, already_AddRefed&& aContent) { if (nsCOMPtr content = aContent) { - aPresContext->EventStateManager()->NativeAnonymousContentRemoved(content); aPresContext->PresShell()->NativeAnonymousContentRemoved(content); content->UnbindFromTree(); } diff --git a/testing/specialpowers/content/SpecialPowersChild.sys.mjs b/testing/specialpowers/content/SpecialPowersChild.sys.mjs index 79933804605f..7c134f0ee560 100644 --- a/testing/specialpowers/content/SpecialPowersChild.sys.mjs +++ b/testing/specialpowers/content/SpecialPowersChild.sys.mjs @@ -2144,13 +2144,6 @@ export class SpecialPowersChild extends JSWindowActorChild { }; } - observeMutationEvents(mo, node, nativeAnonymousChildList, subtree) { - lazy.WrapPrivileged.unwrap(mo).observe(lazy.WrapPrivileged.unwrap(node), { - nativeAnonymousChildList, - subtree, - }); - } - /** * Which commands are available can be determined by checking which commands * are registered. See \ref diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp index ae2888db16f0..601f492f8d3f 100644 --- a/toolkit/components/satchel/nsFormFillController.cpp +++ b/toolkit/components/satchel/nsFormFillController.cpp @@ -195,9 +195,6 @@ void nsFormFillController::AttributeWillChange(mozilla::dom::Element* aElement, nsAtom* aAttribute, int32_t aModType) {} -void nsFormFillController::NativeAnonymousChildListChange(nsIContent* aContent, - bool aIsRemove) {} - void nsFormFillController::ParentChainChanged(nsIContent* aContent) {} void nsFormFillController::ARIAAttributeDefaultWillChange( diff --git a/widget/cocoa/nsMenuGroupOwnerX.mm b/widget/cocoa/nsMenuGroupOwnerX.mm index 345a0478e205..e7a0d2cf8774 100644 --- a/widget/cocoa/nsMenuGroupOwnerX.mm +++ b/widget/cocoa/nsMenuGroupOwnerX.mm @@ -58,8 +58,6 @@ void nsMenuGroupOwnerX::NodeWillBeDestroyed(nsINode* aNode) {} void nsMenuGroupOwnerX::AttributeWillChange(dom::Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType) {} -void nsMenuGroupOwnerX::NativeAnonymousChildListChange(nsIContent* aContent, bool aIsRemove) {} - void nsMenuGroupOwnerX::AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID, nsAtom* aAttribute, int32_t aModType, const nsAttrValue* aOldValue) { diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py index 57749ae71ae9..72e602bcea30 100644 --- a/xpcom/ds/StaticAtoms.py +++ b/xpcom/ds/StaticAtoms.py @@ -707,7 +707,6 @@ STATIC_ATOMS = [ Atom("namespaceUri", "namespace-uri"), Atom("NaN", "NaN"), Atom("n", "n"), - Atom("nativeAnonymousChildList", "nativeAnonymousChildList"), Atom("nav", "nav"), Atom("ne", "ne"), Atom("never", "never"),