2016-05-16 15:04:42 +03:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2019-08-14 07:51:20 +03:00
|
|
|
|
2016-05-16 15:04:42 +03:00
|
|
|
"use strict";
|
|
|
|
|
2019-08-14 07:51:20 +03:00
|
|
|
const Services = require("Services");
|
2020-06-17 22:46:51 +03:00
|
|
|
const { gDevTools } = require("devtools/client/framework/devtools");
|
2018-08-17 17:55:01 +03:00
|
|
|
const Telemetry = require("devtools/client/shared/telemetry");
|
2016-05-16 15:04:42 +03:00
|
|
|
const {
|
2016-08-22 17:25:57 +03:00
|
|
|
FrontClassWithSpec,
|
2018-12-11 19:32:41 +03:00
|
|
|
registerFront,
|
2016-05-16 15:04:42 +03:00
|
|
|
} = require("devtools/shared/protocol.js");
|
2019-10-25 13:08:31 +03:00
|
|
|
const { inspectorSpec } = require("devtools/shared/specs/inspector");
|
2018-10-30 17:47:19 +03:00
|
|
|
loader.lazyRequireGetter(this, "flags", "devtools/shared/flags");
|
2016-05-16 15:04:42 +03:00
|
|
|
|
2019-08-14 07:51:20 +03:00
|
|
|
const TELEMETRY_EYEDROPPER_OPENED = "DEVTOOLS_EYEDROPPER_OPENED_COUNT";
|
|
|
|
const TELEMETRY_EYEDROPPER_OPENED_MENU =
|
|
|
|
"DEVTOOLS_MENU_EYEDROPPER_OPENED_COUNT";
|
|
|
|
const SHOW_ALL_ANONYMOUS_CONTENT_PREF =
|
|
|
|
"devtools.inspector.showAllAnonymousContent";
|
|
|
|
|
|
|
|
const telemetry = new Telemetry();
|
|
|
|
|
2016-05-17 15:34:40 +03:00
|
|
|
/**
|
|
|
|
* Client side of the inspector actor, which is used to create
|
|
|
|
* inspector-related actors, including the walker.
|
|
|
|
*/
|
2018-12-11 19:32:41 +03:00
|
|
|
class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
|
2019-08-14 07:51:20 +03:00
|
|
|
constructor(client, targetFront, parentFront) {
|
|
|
|
super(client, targetFront, parentFront);
|
2018-12-11 19:32:41 +03:00
|
|
|
|
2018-10-30 17:47:19 +03:00
|
|
|
this._client = client;
|
2018-09-03 17:54:04 +03:00
|
|
|
this._highlighters = new Map();
|
2016-05-17 15:34:40 +03:00
|
|
|
|
2019-01-28 21:42:50 +03:00
|
|
|
// Attribute name from which to retrieve the actorID out of the target actor's form
|
|
|
|
this.formAttributeName = "inspectorActor";
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2018-10-30 17:47:19 +03:00
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
// async initialization
|
|
|
|
async initialize() {
|
2019-09-06 11:12:46 +03:00
|
|
|
await Promise.all([
|
|
|
|
this._getWalker(),
|
|
|
|
this._getHighlighter(),
|
|
|
|
this._getPageStyle(),
|
2020-08-03 05:13:04 +03:00
|
|
|
this._startChangesFront(),
|
2019-09-06 11:12:46 +03:00
|
|
|
]);
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2018-10-30 17:47:19 +03:00
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
async _getWalker() {
|
2018-10-30 17:47:19 +03:00
|
|
|
const showAllAnonymousContent = Services.prefs.getBoolPref(
|
|
|
|
SHOW_ALL_ANONYMOUS_CONTENT_PREF
|
|
|
|
);
|
2018-11-05 20:22:45 +03:00
|
|
|
this.walker = await this.getWalker({
|
|
|
|
showAllAnonymousContent,
|
2020-02-14 12:35:55 +03:00
|
|
|
// Backward compatibility for Firefox 74 or older.
|
|
|
|
// getWalker() now uses a single boolean flag to drive the display of
|
|
|
|
// both anonymous content and user-agent shadow roots.
|
|
|
|
// Older servers used separate flags. See Bug 1613773.
|
|
|
|
showUserAgentShadowRoots: showAllAnonymousContent,
|
2018-11-05 20:22:45 +03:00
|
|
|
});
|
2019-11-18 18:06:02 +03:00
|
|
|
|
|
|
|
// 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();
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2018-10-30 17:47:19 +03:00
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
async _getHighlighter() {
|
2018-10-30 17:47:19 +03:00
|
|
|
const autohide = !flags.testing;
|
2020-04-15 17:38:21 +03:00
|
|
|
this.highlighter = await this.getHighlighter(autohide);
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2016-05-17 15:34:40 +03:00
|
|
|
|
2018-09-03 17:54:04 +03:00
|
|
|
hasHighlighter(type) {
|
|
|
|
return this._highlighters.has(type);
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2018-09-03 17:54:04 +03:00
|
|
|
|
2019-09-06 11:12:46 +03:00
|
|
|
async _getPageStyle() {
|
|
|
|
this.pageStyle = await super.getPageStyle();
|
|
|
|
}
|
|
|
|
|
2020-06-10 12:09:00 +03:00
|
|
|
async getCompatibilityFront() {
|
|
|
|
// DevTools supports a Compatibility actor from version FF79 and above.
|
|
|
|
// This check exists to maintain backwards compatibility with older
|
|
|
|
// backend. This check can be removed once FF79 hits the release channel.
|
|
|
|
if (this._compatibility === undefined) {
|
|
|
|
try {
|
|
|
|
this._compatibility = await super.getCompatibility();
|
|
|
|
} catch (error) {
|
|
|
|
this._compatibility = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this._compatibility;
|
|
|
|
}
|
|
|
|
|
2020-08-03 05:13:04 +03:00
|
|
|
async _startChangesFront() {
|
|
|
|
await this.targetFront.getFront("changes");
|
|
|
|
}
|
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
destroy() {
|
2020-06-10 12:09:00 +03:00
|
|
|
this._compatibility = null;
|
2018-11-07 17:35:42 +03:00
|
|
|
// Highlighter fronts are managed by InspectorFront and so will be
|
|
|
|
// automatically destroyed. But we have to clear the `_highlighters`
|
|
|
|
// Map as well as explicitly call `finalize` request on all of them.
|
2018-09-03 17:54:04 +03:00
|
|
|
this.destroyHighlighters();
|
2018-12-11 19:32:41 +03:00
|
|
|
super.destroy();
|
|
|
|
}
|
2016-05-17 15:34:40 +03:00
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
destroyHighlighters() {
|
2018-09-03 17:54:04 +03:00
|
|
|
for (const type of this._highlighters.keys()) {
|
|
|
|
if (this._highlighters.has(type)) {
|
|
|
|
this._highlighters.get(type).finalize();
|
|
|
|
this._highlighters.delete(type);
|
|
|
|
}
|
|
|
|
}
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2018-09-03 17:54:04 +03:00
|
|
|
|
2018-12-18 11:31:43 +03:00
|
|
|
async getHighlighterByType(typeName) {
|
|
|
|
let highlighter = null;
|
|
|
|
try {
|
|
|
|
highlighter = await super.getHighlighterByType(typeName);
|
|
|
|
} catch (_) {
|
|
|
|
throw new Error(
|
|
|
|
"The target doesn't support " +
|
|
|
|
`creating highlighters by types or ${typeName} is unknown`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return highlighter;
|
|
|
|
}
|
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
getKnownHighlighter(type) {
|
2018-09-03 17:54:04 +03:00
|
|
|
return this._highlighters.get(type);
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2018-09-03 17:54:04 +03:00
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
async getOrCreateHighlighterByType(type) {
|
2018-09-03 17:54:04 +03:00
|
|
|
let front = this._highlighters.get(type);
|
|
|
|
if (!front) {
|
|
|
|
front = await this.getHighlighterByType(type);
|
|
|
|
this._highlighters.set(type, front);
|
|
|
|
}
|
|
|
|
return front;
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2018-09-03 17:54:04 +03:00
|
|
|
|
2018-12-11 19:32:41 +03:00
|
|
|
async pickColorFromPage(options) {
|
|
|
|
await super.pickColorFromPage(options);
|
2020-03-20 00:13:38 +03:00
|
|
|
if (options?.fromMenu) {
|
2018-08-17 17:55:01 +03:00
|
|
|
telemetry.getHistogramById(TELEMETRY_EYEDROPPER_OPENED_MENU).add(true);
|
|
|
|
} else {
|
|
|
|
telemetry.getHistogramById(TELEMETRY_EYEDROPPER_OPENED).add(true);
|
|
|
|
}
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2019-08-27 17:42:38 +03:00
|
|
|
|
2019-10-18 12:07:05 +03:00
|
|
|
/**
|
|
|
|
* Given a node grip, return a NodeFront on the right context.
|
|
|
|
*
|
|
|
|
* @param {Object} grip: The node grip.
|
|
|
|
* @returns {Promise<NodeFront|null>} A promise that resolves with a NodeFront or null
|
|
|
|
* if the NodeFront couldn't be created/retrieved.
|
|
|
|
*/
|
|
|
|
async getNodeFrontFromNodeGrip(grip) {
|
|
|
|
const gripHasContentDomReference = "contentDomReference" in grip;
|
|
|
|
|
2020-06-17 22:46:51 +03:00
|
|
|
if (
|
|
|
|
!gDevTools.isFissionContentToolboxEnabled() ||
|
|
|
|
!gripHasContentDomReference
|
|
|
|
) {
|
2019-10-18 12:07:05 +03:00
|
|
|
// Backward compatibility ( < Firefox 71):
|
|
|
|
// If the grip does not have a contentDomReference, we can't know in which browsing
|
|
|
|
// context id the node lives. We fall back on gripToNodeFront that might retrieve
|
|
|
|
// the expected nodeFront.
|
|
|
|
return this.walker.gripToNodeFront(grip);
|
|
|
|
}
|
|
|
|
|
2020-05-06 04:52:36 +03:00
|
|
|
return this.getNodeActorFromContentDomReference(grip.contentDomReference);
|
|
|
|
}
|
2020-01-24 23:14:29 +03:00
|
|
|
|
2020-05-06 04:52:36 +03:00
|
|
|
async getNodeActorFromContentDomReference(contentDomReference) {
|
|
|
|
const { browsingContextId } = contentDomReference;
|
|
|
|
// If the contentDomReference lives in the same browsing context id than the
|
|
|
|
// current one, we can directly use the current walker.
|
|
|
|
if (
|
|
|
|
this.targetFront.browsingContextID === browsingContextId ||
|
2020-06-17 22:46:51 +03:00
|
|
|
!gDevTools.isFissionContentToolboxEnabled()
|
2020-05-06 04:52:36 +03:00
|
|
|
) {
|
2019-10-18 12:07:05 +03:00
|
|
|
return this.walker.getNodeActorFromContentDomReference(
|
|
|
|
contentDomReference
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-01-24 23:14:29 +03:00
|
|
|
// If the contentDomReference has a different browsing context than the current one,
|
|
|
|
// we are either in Fission or in the Multiprocess Browser Toolbox, so we need to
|
|
|
|
// retrieve the walker of the BrowsingContextTarget.
|
2020-04-30 10:59:38 +03:00
|
|
|
// Get the target for this remote frame element
|
|
|
|
const { descriptorFront } = this.targetFront;
|
|
|
|
|
2020-06-09 10:27:27 +03:00
|
|
|
// Tab and Process Descriptors expose a Watcher, which should be used to
|
|
|
|
// fetch the node's target.
|
2020-04-30 10:59:38 +03:00
|
|
|
let target;
|
|
|
|
if (descriptorFront && descriptorFront.traits.watcher) {
|
|
|
|
const watcher = await descriptorFront.getWatcher();
|
|
|
|
target = await watcher.getBrowsingContextTarget(browsingContextId);
|
|
|
|
} else {
|
2020-06-09 10:27:27 +03:00
|
|
|
// For descriptors which don't expose a watcher (e.g. WebExtension)
|
|
|
|
// we used to call RootActor::getBrowsingContextDescriptor, but it was
|
|
|
|
// removed in FF77.
|
|
|
|
// Support for watcher in WebExtension descriptors is Bug 1644341.
|
|
|
|
throw new Error(
|
|
|
|
`Unable to call getNodeActorFromContentDomReference for ${this.targetFront.actorID}`
|
2020-04-30 10:59:38 +03:00
|
|
|
);
|
|
|
|
}
|
2019-10-18 12:07:05 +03:00
|
|
|
const { walker } = await target.getFront("inspector");
|
|
|
|
return walker.getNodeActorFromContentDomReference(contentDomReference);
|
|
|
|
}
|
2018-12-11 19:32:41 +03:00
|
|
|
}
|
2016-05-17 15:34:40 +03:00
|
|
|
|
|
|
|
exports.InspectorFront = InspectorFront;
|
2018-12-11 19:32:41 +03:00
|
|
|
registerFront(InspectorFront);
|