Bug 1578242 - Make the inspector use the TargetList. r=gl,pbro

Differential Revision: https://phabricator.services.mozilla.com/D48859

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Alexandre Poirot 2019-11-18 15:06:02 +00:00
parent 0cff796747
commit 27c69caaec
11 changed files with 125 additions and 84 deletions

View File

@ -359,7 +359,7 @@ Toolbox.prototype = {
get nodePicker() {
if (!this._nodePicker) {
this._nodePicker = new NodePicker(this.target, this.selection);
this._nodePicker = new NodePicker(this.targetList, this.selection);
this._nodePicker.on("picker-starting", this._onPickerStarting);
this._nodePicker.on("picker-started", this._onPickerStarted);
this._nodePicker.on("picker-stopped", this._onPickerStopped);

View File

@ -372,7 +372,7 @@ class FontInspector {
return [];
}
const inspectorFronts = await this.inspector.inspectorFront.getAllInspectorFronts();
const inspectorFronts = await this.inspector.getAllInspectorFronts();
let allFonts = [];
for (const { pageStyle } of inspectorFronts) {

View File

@ -153,7 +153,7 @@ class GridInspector {
* @return {Array} The list of LayoutActor fronts
*/
async getLayoutFronts() {
const inspectorFronts = await this.inspector.inspectorFront.getAllInspectorFronts();
const inspectorFronts = await this.inspector.getAllInspectorFronts();
const layoutFronts = [];
for (const { walker } of inspectorFronts) {

View File

@ -513,7 +513,7 @@ SelectorAutocompleter.prototype = {
query += "*";
}
this._lastQuery = this.inspector.inspectorFront
this._lastQuery = this.inspector
// Get all inspectors where we want suggestions from.
.getAllInspectorFronts()
.then(inspectors => {

View File

@ -176,6 +176,8 @@ function Inspector(toolbox) {
this._handleRejectionIfNotDestroyed = this._handleRejectionIfNotDestroyed.bind(
this
);
this._onTargetAvailable = this._onTargetAvailable.bind(this);
this._onTargetDestroyed = this._onTargetDestroyed.bind(this);
this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
this._onMarkupFrameLoad = this._onMarkupFrameLoad.bind(this);
this._updateSearchResultsLabel = this._updateSearchResultsLabel.bind(this);
@ -220,17 +222,11 @@ Inspector.prototype = {
this.currentTarget.threadFront.on("resumed", this.handleThreadResumed);
}
await this.initInspectorFront();
this.currentTarget.on("will-navigate", this._onBeforeNavigate);
await Promise.all([
this._getCssProperties(),
this._getPageStyle(),
this._getDefaultSelection(),
this._getAccessibilityFront(),
this._getChangesFront(),
]);
await this.toolbox.targetList.watchTargets(
[this.toolbox.targetList.TYPES.FRAME],
this._onTargetAvailable,
this._onTargetDestroyed
);
// Store the URL of the target page prior to navigation in order to ensure
// telemetry counts in the Grid Inspector are not double counted on reload.
@ -243,8 +239,56 @@ Inspector.prototype = {
return this._deferredOpen();
},
async initInspectorFront() {
this.inspectorFront = await this.currentTarget.getFront("inspector");
async _onTargetAvailable(type, targetFront, isTopLevel) {
// Ignore all targets but the top level one
if (!isTopLevel) {
return;
}
await this.initInspectorFront(targetFront);
targetFront.on("will-navigate", this._onBeforeNavigate);
await Promise.all([
this._getCssProperties(),
this._getPageStyle(),
this._getDefaultSelection(),
this._getAccessibilityFront(),
this._getChangesFront(),
]);
this.reflowTracker = new ReflowTracker(this.currentTarget);
// When we navigate to another process and switch to a new
// target and the inspector is already ready, we want to
// update the markup view accordingly. So force a new-root event.
// For the initial panel startup, the initial top level target
// update the markup view from _deferredOpen.
// We might want to followup here in order to share the same
// codepath between the initial top level target and the next
// one we switch to. i.e. extract from deferredOpen code
// which has to be called only once on inspector startup.
// Then move the rest to onNewRoot and always call onNewRoot from here.
if (this.isReady) {
this.onNewRoot();
}
},
_onTargetDestroyed(type, targetFront, isTopLevel) {
// Ignore all targets but the top level one
if (!isTopLevel) {
return;
}
targetFront.off("will-navigate", this._onBeforeNavigate);
this._defaultNode = null;
this.selection.setNodeFront(null);
this.reflowTracker.destroy();
this.reflowTracker = null;
},
async initInspectorFront(targetFront) {
this.inspectorFront = await targetFront.getFront("inspector");
this.highlighter = this.inspectorFront.highlighter;
this.walker = this.inspectorFront.walker;
},
@ -253,6 +297,20 @@ Inspector.prototype = {
return this._toolbox;
},
/**
* Get the list of InspectorFront instances that correspond to all of the inspectable
* targets in remote frames nested within the document inspected here, as well as the
* current InspectorFront instance.
*
* @return {Array} The list of InspectorFront instances.
*/
async getAllInspectorFronts() {
return this.toolbox.targetList.getAllFronts(
this.toolbox.targetList.TYPES.FRAME,
"inspector"
);
},
get highlighters() {
if (!this._highlighters) {
this._highlighters = new HighlightersOverlay(this);
@ -503,10 +561,10 @@ Inspector.prototype = {
},
/**
* Target getter.
* Top level target front getter.
*/
get currentTarget() {
return this._target;
return this.toolbox.targetList.targetFront;
},
/**
@ -1418,7 +1476,7 @@ Inspector.prototype = {
this._selectionCssSelectors = {
selectors: cssSelectors,
url: this._target.url,
url: this.currentTarget.url,
};
},
@ -1429,7 +1487,7 @@ Inspector.prototype = {
get selectionCssSelectors() {
if (
this._selectionCssSelectors &&
this._selectionCssSelectors.url === this._target.url
this._selectionCssSelectors.url === this.currentTarget.url
) {
return this._selectionCssSelectors.selectors;
}
@ -1671,10 +1729,15 @@ Inspector.prototype = {
this.teardownToolbar();
this.breadcrumbs.destroy();
this.reflowTracker.destroy();
this.styleChangeTracker.destroy();
this.searchboxShortcuts.destroy();
this.toolbox.targetList.unwatchTargets(
[this.toolbox.targetList.TYPES.FRAME],
this._onTargetAvailable,
this._onTargetDestroyed
);
this._is3PaneModeChromeEnabled = null;
this._is3PaneModeEnabled = null;
this._markupBox = null;

View File

@ -400,7 +400,7 @@ MarkupView.prototype = {
init: async function() {
try {
this.inspectorFronts = await this.inspector.inspectorFront.getAllInspectorFronts();
this.inspectorFronts = await this.inspector.getAllInspectorFronts();
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
// closing.

View File

@ -17,16 +17,16 @@ loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
* walkerFront and selection api. The nodeFront is stateless, with the
* HighlighterFront managing it's own state.
*
* @param {Target} target
* The target the toolbox will debug
* @param {TargetList} targetList
* The TargetList component referencing all the targets to be debugged
* @param {Selection} selection
* The global Selection object
*/
class NodePicker extends EventEmitter {
constructor(target, selection) {
constructor(targetList, selection) {
super();
this.target = target;
this.targetList = targetList;
this.selection = selection;
// Whether or not the node picker is active.
@ -80,8 +80,10 @@ class NodePicker extends EventEmitter {
// Get all the inspector fronts where the picker should start, and cache them locally
// so we can stop the picker when needed for the same list of inspector fronts.
const inspectorFront = await this.target.getFront("inspector");
this._currentInspectorFronts = await inspectorFront.getAllInspectorFronts();
this._currentInspectorFronts = await this.targetList.getAllFronts(
this.targetList.TYPES.FRAME,
"inspector"
);
for (const { walker, highlighter } of this._currentInspectorFronts) {
walker.on("picker-node-hovered", this._onHovered);

View File

@ -24,7 +24,8 @@ function ReflowTracker(target) {
ReflowTracker.prototype = {
destroy() {
if (this.reflowFront) {
// Ensure that the front isn't yet destroyed
if (this.reflowFront && this.reflowFront.actorID) {
this.stopTracking();
this.reflowFront.destroy();
this.reflowFront = null;

View File

@ -33,7 +33,7 @@ class InspectorStyleChangeTracker {
try {
// TODO: Bug 1588868 - Get all the inspector fronts whenever targets changes or
// are added or removed.
this.inspectorFronts = await this.inspector.inspectorFront.getAllInspectorFronts();
this.inspectorFronts = await this.inspector.getAllInspectorFronts();
} catch (e) {
// This call might fail if called asynchrously after the toolbox is finished
// closing.

View File

@ -19,7 +19,6 @@ const TELEMETRY_EYEDROPPER_OPENED_MENU =
const SHOW_ALL_ANONYMOUS_CONTENT_PREF =
"devtools.inspector.showAllAnonymousContent";
const SHOW_UA_SHADOW_ROOTS_PREF = "devtools.inspector.showUserAgentShadowRoots";
const BROWSER_FISSION_ENABLED_PREF = "devtools.browsertoolbox.fission";
const CONTENT_FISSION_ENABLED_PREF = "devtools.contenttoolbox.fission";
const USE_NEW_BOX_MODEL_HIGHLIGHTER_PREF =
"devtools.inspector.use-new-box-model-highlighter";
@ -50,16 +49,6 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
]);
}
get isBrowserFissionEnabled() {
if (this._isBrowserFissionEnabled === undefined) {
this._isBrowserFissionEnabled = Services.prefs.getBoolPref(
BROWSER_FISSION_ENABLED_PREF
);
}
return this._isBrowserFissionEnabled;
}
get isContentFissionEnabled() {
if (this._isContentFissionEnabled === undefined) {
this._isContentFissionEnabled = Services.prefs.getBoolPref(
@ -81,6 +70,11 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
showAllAnonymousContent,
showUserAgentShadowRoots,
});
// We need to reparent the RootNode of remote iframe Walkers
// so that their parent is the NodeFront of the <iframe>
// element, coming from another process/target/WalkerFront.
await this.walker.reparentRemoteFrame();
}
async _getHighlighter() {
@ -151,48 +145,6 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
}
}
/**
* Get the list of InspectorFront instances that correspond to all of the inspectable
* targets in remote frames nested within the document inspected here.
*
* Note that this only returns a non-empty array if the used from the Browser Toolbox
* and with the FISSION_ENABLED pref on.
*
* @return {Array} The list of InspectorFront instances.
*/
async getChildInspectors() {
const childInspectors = [];
const target = this.targetFront;
// this line can be removed when we are ready for fission frames
if (this.isBrowserFissionEnabled && target.chrome && !target.isAddon) {
const { frames } = await target.listRemoteFrames();
// attempt to get targets and filter by targets that could connect
for (const descriptor of frames) {
const remoteTarget = await descriptor.getTarget();
if (remoteTarget) {
// get inspector
const remoteInspectorFront = await remoteTarget.getFront("inspector");
await remoteInspectorFront.walker.reparentRemoteFrame();
childInspectors.push(remoteInspectorFront);
}
}
}
return childInspectors;
}
/**
* Get the list of InspectorFront instances that correspond to all of the inspectable
* targets in remote frames nested within the document inspected here, as well as the
* current InspectorFront instance.
*
* @return {Array} The list of InspectorFront instances.
*/
async getAllInspectorFronts() {
const remoteInspectors = await this.getChildInspectors();
return [this, ...remoteInspectors];
}
/**
* Given a node grip, return a NodeFront on the right context.
*

View File

@ -454,10 +454,33 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
};
}
/**
* Ensure that the RootNode of this Walker has the right parent NodeFront.
*
* This method does nothing if we are on the top level target's WalkerFront,
* as the RootNode won't have any parent.
*
* Otherwise, if we are in an iframe's WalkerFront, we would expect the parent
* of the RootNode (i.e. the NodeFront for the document loaded within the iframe)
* to be the <iframe>'s NodeFront. Because of fission, the two NodeFront may refer
* to DOM Element running in distinct processes and so the NodeFront comes from
* two distinct Targets and two distinct WalkerFront.
* This is why we need this manual "reparent" code to do the glue between the
* two documents.
*/
async reparentRemoteFrame() {
// Get the parent target, which most likely runs in another process
const descriptorFront = this.targetFront.descriptorFront;
// If we are on the top target, descriptorFront will be the RootFront
// and won't have the getParentTarget method.
if (!descriptorFront.getParentTarget) {
return;
}
const parentTarget = await descriptorFront.getParentTarget();
// Don't reparent if we are on the top target
if (parentTarget == this.targetFront) {
return;
}
// Get the NodeFront for the embedder element
// i.e. the <iframe> element which is hosting the document that
const parentWalker = (await parentTarget.getFront("inspector")).walker;