/* 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/. */ "use strict"; const { Actor } = require("resource://devtools/shared/protocol.js"); const { walkerSpec } = require("resource://devtools/shared/specs/walker.js"); const { LongStringActor, } = require("resource://devtools/server/actors/string.js"); const { EXCLUDED_LISTENER, } = require("resource://devtools/server/actors/inspector/constants.js"); loader.lazyRequireGetter( this, "nodeFilterConstants", "resource://devtools/shared/dom-node-filter-constants.js" ); loader.lazyRequireGetter( this, [ "getFrameElement", "isDirectShadowHostChild", "isFrameBlockedByCSP", "isFrameWithChildTarget", "isShadowHost", "isShadowRoot", "loadSheet", ], "resource://devtools/shared/layout/utils.js", true ); loader.lazyRequireGetter( this, "throttle", "resource://devtools/shared/throttle.js", true ); loader.lazyRequireGetter( this, [ "allAnonymousContentTreeWalkerFilter", "findGridParentContainerForNode", "isNodeDead", "noAnonymousContentTreeWalkerFilter", "nodeDocument", "standardTreeWalkerFilter", ], "resource://devtools/server/actors/inspector/utils.js", true ); loader.lazyRequireGetter( this, "CustomElementWatcher", "resource://devtools/server/actors/inspector/custom-element-watcher.js", true ); loader.lazyRequireGetter( this, ["DocumentWalker", "SKIP_TO_SIBLING"], "resource://devtools/server/actors/inspector/document-walker.js", true ); loader.lazyRequireGetter( this, ["NodeActor", "NodeListActor"], "resource://devtools/server/actors/inspector/node.js", true ); loader.lazyRequireGetter( this, "NodePicker", "resource://devtools/server/actors/inspector/node-picker.js", true ); loader.lazyRequireGetter( this, "LayoutActor", "resource://devtools/server/actors/layout.js", true ); loader.lazyRequireGetter( this, ["getLayoutChangesObserver", "releaseLayoutChangesObserver"], "resource://devtools/server/actors/reflow.js", true ); loader.lazyRequireGetter( this, "WalkerSearch", "resource://devtools/server/actors/utils/walker-search.js", true ); // ContentDOMReference requires ChromeUtils, which isn't available in worker context. const lazy = {}; if (!isWorker) { loader.lazyGetter( lazy, "ContentDOMReference", () => ChromeUtils.importESModule( "resource://gre/modules/ContentDOMReference.sys.mjs", // ContentDOMReference needs to be retrieved from the shared global // since it is a shared singleton. { global: "shared" } ).ContentDOMReference ); } loader.lazyServiceGetter( this, "eventListenerService", "@mozilla.org/eventlistenerservice;1", "nsIEventListenerService" ); // Minimum delay between two "new-mutations" events. const MUTATIONS_THROTTLING_DELAY = 100; // List of mutation types that should -not- be throttled. const IMMEDIATE_MUTATIONS = ["pseudoClassLock"]; const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__"; // The possible completions to a ':' const PSEUDO_SELECTORS = [ "::marker", "::selection", ":active", ":after", ":before", ":checked", ":disabled", ":empty", ":enabled", ":first-child", ":first-letter", ":first-of-type", ":focus", ":hover", ":lang(", ":last-child", ":last-of-type", ":link", ":not(", ":nth-child(", ":nth-last-child(", ":nth-last-of-type(", ":nth-of-type(", ":only-child", ":only-of-type", ":root", ":target", ":visited", ]; const HELPER_SHEET = "data:text/css;charset=utf-8," + encodeURIComponent(` .__fx-devtools-hide-shortcut__ { visibility: hidden !important; } `); /** * We only send nodeValue up to a certain size by default. This stuff * controls that size. */ exports.DEFAULT_VALUE_SUMMARY_LENGTH = 50; var gValueSummaryLength = exports.DEFAULT_VALUE_SUMMARY_LENGTH; exports.getValueSummaryLength = function () { return gValueSummaryLength; }; exports.setValueSummaryLength = function (val) { gValueSummaryLength = val; }; /** * Server side of the DOM walker. */ class WalkerActor extends Actor { /** * Create the WalkerActor * * @param {DevToolsServerConnection} conn * The server connection. * @param {TargetActor} targetActor * The top-level Actor for this tab. * @param {object} options * - {Boolean} showAllAnonymousContent: Show all native anonymous content */ constructor(conn, targetActor, options) { super(conn, walkerSpec); this.targetActor = targetActor; this.rootWin = targetActor.window; this.rootDoc = this.rootWin.document; // Map of already created node actors, keyed by their corresponding DOMNode. this._nodeActorsMap = new Map(); this._pendingMutations = []; this._activePseudoClassLocks = new Set(); this._mutationBreakpoints = new WeakMap(); this._anonParents = new WeakMap(); this.customElementWatcher = new CustomElementWatcher( targetActor.chromeEventHandler ); // In this map, the key-value pairs are the overflow causing elements and their // respective ancestor scrollable node actor. this.overflowCausingElementsMap = new Map(); this.showAllAnonymousContent = options.showAllAnonymousContent; // Allow native anonymous content (like