123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /* 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 { Ci } = require("chrome");
- const protocol = require("devtools/shared/protocol");
- const { emulationSpec } = require("devtools/shared/specs/emulation");
- const { SimulatorCore } = require("devtools/shared/touch/simulator-core");
- /**
- * This actor overrides various browser features to simulate different environments to
- * test how pages perform under various conditions.
- *
- * The design below, which saves the previous value of each property before setting, is
- * needed because it's possible to have multiple copies of this actor for a single page.
- * When some instance of this actor changes a property, we want it to be able to restore
- * that property to the way it was found before the change.
- *
- * A subtle aspect of the code below is that all get* methods must return non-undefined
- * values, so that the absence of a previous value can be distinguished from the value for
- * "no override" for each of the properties.
- */
- let EmulationActor = protocol.ActorClassWithSpec(emulationSpec, {
- initialize(conn, tabActor) {
- protocol.Actor.prototype.initialize.call(this, conn);
- this.tabActor = tabActor;
- this.docShell = tabActor.docShell;
- this.simulatorCore = new SimulatorCore(tabActor.chromeEventHandler);
- },
- disconnect() {
- this.destroy();
- },
- destroy() {
- this.clearDPPXOverride();
- this.clearNetworkThrottling();
- this.clearTouchEventsOverride();
- this.clearUserAgentOverride();
- this.tabActor = null;
- this.docShell = null;
- this.simulatorCore = null;
- protocol.Actor.prototype.destroy.call(this);
- },
- /**
- * Retrieve the console actor for this tab. This allows us to expose network throttling
- * as part of emulation settings, even though it's internally connected to the network
- * monitor, which for historical reasons is part of the console actor.
- */
- get _consoleActor() {
- if (this.tabActor.exited) {
- return null;
- }
- let form = this.tabActor.form();
- return this.conn._getOrCreateActor(form.consoleActor);
- },
- /* DPPX override */
- _previousDPPXOverride: undefined,
- setDPPXOverride(dppx) {
- if (this.getDPPXOverride() === dppx) {
- return false;
- }
- if (this._previousDPPXOverride === undefined) {
- this._previousDPPXOverride = this.getDPPXOverride();
- }
- this.docShell.contentViewer.overrideDPPX = dppx;
- return true;
- },
- getDPPXOverride() {
- return this.docShell.contentViewer.overrideDPPX;
- },
- clearDPPXOverride() {
- if (this._previousDPPXOverride !== undefined) {
- return this.setDPPXOverride(this._previousDPPXOverride);
- }
- return false;
- },
- /* Network Throttling */
- _previousNetworkThrottling: undefined,
- /**
- * Transform the RDP format into the internal format and then set network throttling.
- */
- setNetworkThrottling({ downloadThroughput, uploadThroughput, latency }) {
- let throttleData = {
- roundTripTimeMean: latency,
- roundTripTimeMax: latency,
- downloadBPSMean: downloadThroughput,
- downloadBPSMax: downloadThroughput,
- uploadBPSMean: uploadThroughput,
- uploadBPSMax: uploadThroughput,
- };
- return this._setNetworkThrottling(throttleData);
- },
- _setNetworkThrottling(throttleData) {
- let current = this._getNetworkThrottling();
- // Check if they are both objects or both null
- let match = throttleData == current;
- // If both objects, check all entries
- if (match && current && throttleData) {
- match = Object.entries(current).every(([ k, v ]) => {
- return throttleData[k] === v;
- });
- }
- if (match) {
- return false;
- }
- if (this._previousNetworkThrottling === undefined) {
- this._previousNetworkThrottling = current;
- }
- let consoleActor = this._consoleActor;
- if (!consoleActor) {
- return false;
- }
- consoleActor.onStartListeners({
- listeners: [ "NetworkActivity" ],
- });
- consoleActor.onSetPreferences({
- preferences: {
- "NetworkMonitor.throttleData": throttleData,
- }
- });
- return true;
- },
- /**
- * Get network throttling and then transform the internal format into the RDP format.
- */
- getNetworkThrottling() {
- let throttleData = this._getNetworkThrottling();
- if (!throttleData) {
- return null;
- }
- let { downloadBPSMax, uploadBPSMax, roundTripTimeMax } = throttleData;
- return {
- downloadThroughput: downloadBPSMax,
- uploadThroughput: uploadBPSMax,
- latency: roundTripTimeMax,
- };
- },
- _getNetworkThrottling() {
- let consoleActor = this._consoleActor;
- if (!consoleActor) {
- return null;
- }
- let prefs = consoleActor.onGetPreferences({
- preferences: [ "NetworkMonitor.throttleData" ],
- });
- return prefs.preferences["NetworkMonitor.throttleData"] || null;
- },
- clearNetworkThrottling() {
- if (this._previousNetworkThrottling !== undefined) {
- return this._setNetworkThrottling(this._previousNetworkThrottling);
- }
- return false;
- },
- /* Touch events override */
- _previousTouchEventsOverride: undefined,
- setTouchEventsOverride(flag) {
- if (this.getTouchEventsOverride() == flag) {
- return false;
- }
- if (this._previousTouchEventsOverride === undefined) {
- this._previousTouchEventsOverride = this.getTouchEventsOverride();
- }
- // Start or stop the touch simulator depending on the override flag
- if (flag == Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_ENABLED) {
- this.simulatorCore.start();
- } else {
- this.simulatorCore.stop();
- }
- this.docShell.touchEventsOverride = flag;
- return true;
- },
- getTouchEventsOverride() {
- return this.docShell.touchEventsOverride;
- },
- clearTouchEventsOverride() {
- if (this._previousTouchEventsOverride !== undefined) {
- return this.setTouchEventsOverride(this._previousTouchEventsOverride);
- }
- return false;
- },
- /* User agent override */
- _previousUserAgentOverride: undefined,
- setUserAgentOverride(userAgent) {
- if (this.getUserAgentOverride() == userAgent) {
- return false;
- }
- if (this._previousUserAgentOverride === undefined) {
- this._previousUserAgentOverride = this.getUserAgentOverride();
- }
- this.docShell.customUserAgent = userAgent;
- return true;
- },
- getUserAgentOverride() {
- return this.docShell.customUserAgent;
- },
- clearUserAgentOverride() {
- if (this._previousUserAgentOverride !== undefined) {
- return this.setUserAgentOverride(this._previousUserAgentOverride);
- }
- return false;
- },
- });
- exports.EmulationActor = EmulationActor;
|