net";
+const EXAMPLE_COM_URI =
+ "https://example.com/document-builder.sjs?html=
com";
+const EXAMPLE_ORG_URI =
+ "https://example.org/document-builder.sjs?headers=Cross-Origin-Opener-Policy:same-origin&html=
org
";
+
+add_task(async function() {
+ const tab = await addTab(EXAMPLE_NET_URI);
+
+ is(
+ tab.linkedBrowser.browsingContext.watchedByDevTools,
+ false,
+ "watchedByDevTools isn't set when DevTools aren't opened"
+ );
+
+ info(
+ "Open a toolbox for the opened tab and check that watchedByDevTools is set"
+ );
+ await gDevTools.showToolboxForTab(tab, { toolId: "options" });
+
+ is(
+ tab.linkedBrowser.browsingContext.watchedByDevTools,
+ true,
+ "watchedByDevTools is set after opening a toolbox"
+ );
+
+ info(
+ "Check that watchedByDevTools persist when the tab navigates to a different origin"
+ );
+ await navigateTo(EXAMPLE_COM_URI);
+
+ is(
+ tab.linkedBrowser.browsingContext.watchedByDevTools,
+ true,
+ "watchedByDevTools is still set after navigating to a different origin"
+ );
+
+ info(
+ "Check that watchedByDevTools persist when navigating to a page that creates a new browsing context"
+ );
+ const previousBrowsingContextId = tab.linkedBrowser.browsingContext.id;
+ await navigateTo(EXAMPLE_ORG_URI);
+
+ isnot(
+ tab.linkedBrowser.browsingContext.id,
+ previousBrowsingContextId,
+ "A new browsing context was created"
+ );
+
+ is(
+ tab.linkedBrowser.browsingContext.watchedByDevTools,
+ true,
+ "watchedByDevTools is still set after navigating to a new browsing context"
+ );
+
+ info("Check that the flag is reset when the toolbox is closed");
+ await gDevTools.closeToolboxForTab(tab);
+ is(
+ tab.linkedBrowser.browsingContext.watchedByDevTools,
+ false,
+ "watchedByDevTools is reset after closing the toolbox"
+ );
+});
diff --git a/devtools/server/actors/targets/browsing-context.js b/devtools/server/actors/targets/browsing-context.js
index f52712afed66..ad223f997b9f 100644
--- a/devtools/server/actors/targets/browsing-context.js
+++ b/devtools/server/actors/targets/browsing-context.js
@@ -1674,9 +1674,14 @@ DebuggerProgressListener.prototype = {
// - reporting the contents of HTML loaded in the docshells,
// - or capturing stacks for the network monitor.
//
- // This attribute may already have been toggled by a parent BrowsingContext.
- // Typically the parent process or tab target. Both are top level BrowsingContext.
- if (docShell.browsingContext.top == docShell.browsingContext) {
+ // This flag is also set in frame-helper but in the case of the browser toolbox, we
+ // don't have the watcher enabled by default yet, and as a result we need to set it
+ // here for the parent process browsing context.
+ // This should be removed as part of Bug 1709529.
+ if (
+ this._targetActor.typeName === "parentProcessTarget" &&
+ docShell.browsingContext.top == docShell.browsingContext
+ ) {
docShell.browsingContext.watchedByDevTools = true;
}
},
@@ -1711,11 +1716,12 @@ DebuggerProgressListener.prototype = {
this._knownWindowIDs.delete(getWindowID(win));
}
- // We can only toggle this attribute on top level BrowsingContext,
- // this will be propagated over the whole tree of BC.
- // So we only need to set it from Parent Process Target
- // and Tab Target. Tab's BrowsingContext are actually considered as top level BC.
- if (docShell.browsingContext.top == docShell.browsingContext) {
+ // We only reset it for parent process target actor as the flag should be set in parent
+ // process, and thus is set elsewhere for other type of BrowsingContextActor.
+ if (
+ this._targetActor.typeName === "parentProcessTarget" &&
+ docShell.browsingContext.top == docShell.browsingContext
+ ) {
docShell.browsingContext.watchedByDevTools = false;
}
},
diff --git a/devtools/server/actors/watcher/target-helpers/frame-helper.js b/devtools/server/actors/watcher/target-helpers/frame-helper.js
index 612febab9e02..719d0e6fc043 100644
--- a/devtools/server/actors/watcher/target-helpers/frame-helper.js
+++ b/devtools/server/actors/watcher/target-helpers/frame-helper.js
@@ -4,6 +4,7 @@
"use strict";
+const Services = require("Services");
const {
WatcherRegistry,
} = require("devtools/server/actors/watcher/WatcherRegistry.jsm");
@@ -16,6 +17,8 @@ const {
shouldNotifyWindowGlobal,
} = require("devtools/server/actors/watcher/target-helpers/utils.js");
+const browsingContextAttachedObserverByWatcher = new Map();
+
/**
* Force creating targets for all existing BrowsingContext, that, for a given Watcher Actor.
*
@@ -36,6 +39,13 @@ async function createTargets(watcher) {
"Existing WindowGlobal"
);
+ // We need to set the watchedByDevTools flag on all top-level browsing context. In the
+ // case of a content toolbox, this is done in the tab descriptor, but when we're in the
+ // browser toolbox, such descriptor is not created.
+ if (browsingContext.top === browsingContext) {
+ browsingContext.watchedByDevTools = true;
+ }
+
// Await for the query in order to try to resolve only *after* we received these
// already available targets.
const promise = browsingContext.currentWindowGlobal
@@ -48,6 +58,46 @@ async function createTargets(watcher) {
});
promises.push(promise);
}
+
+ // If we have a browserElement, set the watchedByDevTools flag on its related browsing context
+ // TODO: We should also set the flag for the "parent process" browsing context when we're
+ // in the browser toolbox. This is blocked by Bug 1675763, and should be handled as part
+ // of Bug 1709529.
+ if (watcher.browserElement) {
+ // The `watchedByDevTools` enables gecko behavior tied to this flag, such as:
+ // - reporting the contents of HTML loaded in the docshells
+ // - capturing stacks for the network monitor.
+ watcher.browserElement.browsingContext.watchedByDevTools = true;
+ }
+
+ if (!browsingContextAttachedObserverByWatcher.has(watcher)) {
+ // We store the browserId here as watcher.browserElement.browserId can momentary be
+ // set to 0 when there's a navigation to a new browsing context.
+ const browserId = watcher.browserElement?.browserId;
+ const onBrowsingContextAttached = browsingContext => {
+ // We want to set watchedByDevTools on new top-level browsing contexts:
+ // - in the case of the BrowserToolbox/BrowserConsole, that would be the browsing
+ // contexts of all the tabs we want to handle.
+ // - for the regular toolbox, browsing context that are being created when navigating
+ // to a page that forces a new browsing context.
+ if (
+ browsingContext.top === browsingContext &&
+ (!watcher.browserElement || browserId === browsingContext.browserId)
+ ) {
+ browsingContext.watchedByDevTools = true;
+ }
+ };
+ Services.obs.addObserver(
+ onBrowsingContextAttached,
+ "browsing-context-attached"
+ );
+ // We store the observer so we can retrieve it elsewhere (e.g. for removal in destroyTargets).
+ browsingContextAttachedObserverByWatcher.set(
+ watcher,
+ onBrowsingContextAttached
+ );
+ }
+
return Promise.all(promises);
}
@@ -68,6 +118,10 @@ function destroyTargets(watcher) {
"Existing WindowGlobal"
);
+ if (browsingContext.top === browsingContext) {
+ browsingContext.watchedByDevTools = false;
+ }
+
browsingContext.currentWindowGlobal
.getActor("DevToolsFrame")
.destroyTarget({
@@ -75,6 +129,18 @@ function destroyTargets(watcher) {
browserId: watcher.browserId,
});
}
+
+ if (watcher.browserElement) {
+ watcher.browserElement.browsingContext.watchedByDevTools = false;
+ }
+
+ if (browsingContextAttachedObserverByWatcher.has(watcher)) {
+ Services.obs.removeObserver(
+ browsingContextAttachedObserverByWatcher.get(watcher),
+ "browsing-context-attached"
+ );
+ browsingContextAttachedObserverByWatcher.delete(watcher);
+ }
}
/**