diff --git a/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js b/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js index 8ab7a1d08003..2e45493bd2d1 100644 --- a/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg-dom-mutation-breakpoints.js @@ -15,12 +15,16 @@ Services.scriptloader.loadSubScript( const DMB_TEST_URL = "http://example.com/browser/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html"; -add_task(async function() { - // Enable features +async function enableMutationBreakpoints() { await pushPref("devtools.debugger.features.dom-mutation-breakpoints", true); await pushPref("devtools.markup.mutationBreakpoints.enabled", true); await pushPref("devtools.debugger.dom-mutation-breakpoints-visible", true); +} + +add_task(async function() { + // Enable features + await enableMutationBreakpoints(); info("Switches over to the inspector pane"); const { inspector, toolbox } = await openInspectorForURL(DMB_TEST_URL); @@ -66,6 +70,13 @@ add_task(async function() { await waitForPaused(dbg); await resume(dbg); + info("Changing style to trigger debugger pause"); + SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { + content.document.querySelector("#style-attribute").click(); + }); + await waitForPaused(dbg); + await resume(dbg); + info("Changing subtree to trigger debugger pause"); SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { content.document.querySelector("#subtree").click(); diff --git a/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html b/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html index 5ad60f4c6439..fcd8819f068b 100644 --- a/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html +++ b/devtools/client/debugger/test/mochitest/examples/doc-dom-mutation.html @@ -10,6 +10,7 @@
+ diff --git a/devtools/client/debugger/test/mochitest/examples/dom-mutation.js b/devtools/client/debugger/test/mochitest/examples/dom-mutation.js index 3d3f5c75d8eb..ceb64dea6749 100644 --- a/devtools/client/debugger/test/mochitest/examples/dom-mutation.js +++ b/devtools/client/debugger/test/mochitest/examples/dom-mutation.js @@ -3,6 +3,10 @@ function changeAttribute() { document.body.setAttribute("title", title); } +function changeStyleAttribute() { + document.body.style.color = "blue"; +} + function changeSubtree() { document.body.appendChild(document.createElement("div")); } diff --git a/devtools/server/actors/inspector/walker.js b/devtools/server/actors/inspector/walker.js index aba11d82ce8a..836b4600378d 100644 --- a/devtools/server/actors/inspector/walker.js +++ b/devtools/server/actors/inspector/walker.js @@ -231,8 +231,8 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, { // list contains orphaned nodes that were so retained. this._retainedOrphans = new Set(); - this.onNodeInserted = this.onNodeInserted.bind(this); - this.onNodeInserted[EXCLUDED_LISTENER] = true; + this.onSubtreeModified = this.onSubtreeModified.bind(this); + this.onSubtreeModified[EXCLUDED_LISTENER] = true; this.onNodeRemoved = this.onNodeRemoved.bind(this); this.onNodeRemoved[EXCLUDED_LISTENER] = true; this.onAttributeModified = this.onAttributeModified.bind(this); @@ -2076,65 +2076,58 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, { _updateDocumentMutationListeners(rawDoc) { const docMutationBreakpoints = this._mutationBreakpointsForDoc(rawDoc); if (!docMutationBreakpoints) { + rawDoc.devToolsWatchingDOMMutations = false; return; } - const origFlag = rawDoc.devToolsWatchingDOMMutations; - rawDoc.devToolsWatchingDOMMutations = true; + const anyBreakpoint = + docMutationBreakpoints.counts.subtree > 0 || + docMutationBreakpoints.counts.removal > 0 || + docMutationBreakpoints.counts.attribute > 0; + + rawDoc.devToolsWatchingDOMMutations = anyBreakpoint; if (docMutationBreakpoints.counts.subtree > 0) { - eventListenerService.addSystemEventListener( - rawDoc, - "DOMNodeInserted", - this.onNodeInserted, + this.chromeEventHandler.addEventListener( + "devtoolschildinserted", + this.onSubtreeModified, true /* capture */ ); } else { - eventListenerService.removeSystemEventListener( - rawDoc, - "DOMNodeInserted", - this.onNodeInserted, + this.chromeEventHandler.removeEventListener( + "devtoolschildinserted", + this.onSubtreeModified, true /* capture */ ); } - if ( - docMutationBreakpoints.counts.subtree > 0 || - docMutationBreakpoints.counts.removal > 0 || - docMutationBreakpoints.counts.attribute > 0 - ) { - eventListenerService.addSystemEventListener( - rawDoc, - "DOMNodeRemoved", + if (anyBreakpoint) { + this.chromeEventHandler.addEventListener( + "devtoolschildremoved", this.onNodeRemoved, true /* capture */ ); } else { - eventListenerService.removeSystemEventListener( - rawDoc, - "DOMNodeRemoved", + this.chromeEventHandler.removeEventListener( + "devtoolschildremoved", this.onNodeRemoved, true /* capture */ ); } if (docMutationBreakpoints.counts.attribute > 0) { - eventListenerService.addSystemEventListener( - rawDoc, - "DOMAttrModified", + this.chromeEventHandler.addEventListener( + "devtoolsattrmodified", this.onAttributeModified, true /* capture */ ); } else { - eventListenerService.removeSystemEventListener( - rawDoc, - "DOMAttrModified", + this.chromeEventHandler.removeEventListener( + "devtoolsattrmodified", this.onAttributeModified, true /* capture */ ); } - - rawDoc.devToolsWatchingDOMMutations = origFlag; }, _breakOnMutation: function(mutationType, targetNode, ancestorNode, action) { @@ -2172,20 +2165,15 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, { ); }, - onNodeInserted: function(evt) { - this.onSubtreeModified(evt, "add"); - }, - onNodeRemoved: function(evt) { const mutationBpInfo = this._breakpointInfoForNode(evt.target); const hasNodeRemovalEvent = mutationBpInfo?.removal; this._clearMutationBreakpointsFromSubtree(evt.target); - if (hasNodeRemovalEvent) { this._breakOnMutation("nodeRemoved", evt.target); } else { - this.onSubtreeModified(evt, "remove"); + this.onSubtreeModified(evt); } }, @@ -2196,7 +2184,8 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, { } }, - onSubtreeModified: function(evt, action) { + onSubtreeModified: function(evt) { + const action = evt.type === "devtoolschildinserted" ? "add" : "remove"; let node = evt.target; while ((node = node.parentNode) !== null) { const mutationBpInfo = this._breakpointInfoForNode(node); diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index efbb00cd2ebc..cbd69f616a23 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -9567,8 +9567,7 @@ nsINode* Document::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv) { // Scope firing mutation events so that we don't carry any state that // might be stale { - nsINode* parent = adoptedNode->GetParentNode(); - if (parent) { + if (nsINode* parent = adoptedNode->GetParentNode()) { nsContentUtils::MaybeFireNodeRemoved(adoptedNode, parent); } } @@ -13310,6 +13309,80 @@ already_AddRefed