summaryrefslogtreecommitdiffstats
path: root/devtools/client/performance-new/panel
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /devtools/client/performance-new/panel
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/performance-new/panel')
-rw-r--r--devtools/client/performance-new/panel/README.md6
-rw-r--r--devtools/client/performance-new/panel/index.xhtml29
-rw-r--r--devtools/client/performance-new/panel/initializer.js189
-rw-r--r--devtools/client/performance-new/panel/moz.build12
-rw-r--r--devtools/client/performance-new/panel/panel.js107
5 files changed, 343 insertions, 0 deletions
diff --git a/devtools/client/performance-new/panel/README.md b/devtools/client/performance-new/panel/README.md
new file mode 100644
index 0000000000..d2054521d0
--- /dev/null
+++ b/devtools/client/performance-new/panel/README.md
@@ -0,0 +1,6 @@
+This directory contains the files specific to the devtools panel. This panel is
+used in the devtools toolbox attached to a page, but also when profiling
+performance from about:profiling.
+
+The devtools panel also uses the redux store in `store/` as well as react
+components in `components/`.
diff --git a/devtools/client/performance-new/panel/index.xhtml b/devtools/client/performance-new/panel/index.xhtml
new file mode 100644
index 0000000000..161eb850ed
--- /dev/null
+++ b/devtools/client/performance-new/panel/index.xhtml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<!-- 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/. -->
+<html xmlns="http://www.w3.org/1999/xhtml" dir="">
+ <head>
+ <link
+ rel="stylesheet"
+ href="chrome://devtools/skin/widgets.css"
+ type="text/css"
+ />
+ <link
+ rel="stylesheet"
+ href="chrome://devtools/skin/perf.css"
+ type="text/css"
+ />
+ </head>
+ <body class="theme-body">
+ <div id="root"></div>
+ <script src="resource://devtools/client/performance-new/panel/initializer.js"></script>
+ <script
+ src="chrome://devtools/content/shared/theme-switching.js"
+ defer="true"
+ ></script>
+ </body>
+</html>
diff --git a/devtools/client/performance-new/panel/initializer.js b/devtools/client/performance-new/panel/initializer.js
new file mode 100644
index 0000000000..2264e4764f
--- /dev/null
+++ b/devtools/client/performance-new/panel/initializer.js
@@ -0,0 +1,189 @@
+/* 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/. */
+// @ts-check
+/* exported gInit, gDestroy, loader */
+
+/**
+ * @typedef {import("../@types/perf").PerfFront} PerfFront
+ * @typedef {import("../@types/perf").PreferenceFront} PreferenceFront
+ * @typedef {import("../@types/perf").RecordingSettings} RecordingSettings
+ * @typedef {import("../@types/perf").PageContext} PageContext
+ * @typedef {import("../@types/perf").PanelWindow} PanelWindow
+ * @typedef {import("../@types/perf").Store} Store
+ * @typedef {import("../@types/perf").MinimallyTypedGeckoProfile} MinimallyTypedGeckoProfile
+ * @typedef {import("../@types/perf").ProfileCaptureResult} ProfileCaptureResult
+ * @typedef {import("../@types/perf").ProfilerViewMode} ProfilerViewMode
+ * @typedef {import("../@types/perf").RootTraits} RootTraits
+ */
+"use strict";
+
+{
+ // Create the browser loader, but take care not to conflict with
+ // TypeScript. See devtools/client/performance-new/typescript.md and
+ // the section on "Do not overload require" for more information.
+
+ const { BrowserLoader } = ChromeUtils.import(
+ "resource://devtools/shared/loader/browser-loader.js"
+ );
+ const browserLoader = BrowserLoader({
+ baseURI: "resource://devtools/client/performance-new/",
+ window,
+ });
+
+ /**
+ * @type {any} - Coerce the current scope into an `any`, and assign the
+ * loaders to the scope. They can then be used freely below.
+ */
+ const scope = this;
+ scope.require = browserLoader.require;
+ scope.loader = browserLoader.loader;
+}
+
+const ReactDOM = require("resource://devtools/client/shared/vendor/react-dom.js");
+const React = require("resource://devtools/client/shared/vendor/react.js");
+const FluentReact = require("resource://devtools/client/shared/vendor/fluent-react.js");
+const {
+ FluentL10n,
+} = require("resource://devtools/client/shared/fluent-l10n/fluent-l10n.js");
+const Provider = React.createFactory(
+ require("resource://devtools/client/shared/vendor/react-redux.js").Provider
+);
+const LocalizationProvider = React.createFactory(
+ FluentReact.LocalizationProvider
+);
+const DevToolsPanel = React.createFactory(
+ require("resource://devtools/client/performance-new/components/panel/DevToolsPanel.js")
+);
+const ProfilerEventHandling = React.createFactory(
+ require("resource://devtools/client/performance-new/components/panel/ProfilerEventHandling.js")
+);
+const ProfilerPreferenceObserver = React.createFactory(
+ require("resource://devtools/client/performance-new/components/shared/ProfilerPreferenceObserver.js")
+);
+const createStore = require("resource://devtools/client/shared/redux/create-store.js");
+const selectors = require("resource://devtools/client/performance-new/store/selectors.js");
+const reducers = require("resource://devtools/client/performance-new/store/reducers.js");
+const actions = require("resource://devtools/client/performance-new/store/actions.js");
+const {
+ openProfilerTab,
+ sharedLibrariesFromProfile,
+} = require("resource://devtools/client/performance-new/shared/browser.js");
+const { createLocalSymbolicationService } = ChromeUtils.importESModule(
+ "resource://devtools/client/performance-new/shared/symbolication.sys.mjs"
+);
+const {
+ presets,
+ getProfilerViewModeForCurrentPreset,
+ registerProfileCaptureForBrowser,
+} = ChromeUtils.importESModule(
+ "resource://devtools/client/performance-new/shared/background.sys.mjs"
+);
+
+/**
+ * This file initializes the DevTools Panel UI. It is in charge of initializing
+ * the DevTools specific environment, and then passing those requirements into
+ * the UI.
+ */
+
+/**
+ * Initialize the panel by creating a redux store, and render the root component.
+ *
+ * @param {PerfFront} perfFront - The Perf actor's front. Used to start and stop recordings.
+ * @param {RootTraits} traits - The traits coming from the root actor. This
+ * makes it possible to change some code path
+ * depending on the server version.
+ * @param {PageContext} pageContext - The context that the UI is being loaded in under.
+ * @param {(() => void)} openAboutProfiling - Optional call to open about:profiling
+ */
+async function gInit(perfFront, traits, pageContext, openAboutProfiling) {
+ const store = createStore(reducers);
+ const isSupportedPlatform = await perfFront.isSupportedPlatform();
+ const supportedFeatures = await perfFront.getSupportedFeatures();
+
+ {
+ // Expose the store as a global, for testing.
+ const anyWindow = /** @type {any} */ (window);
+ const panelWindow = /** @type {PanelWindow} */ (anyWindow);
+ // The store variable is a `ReduxStore`, not our `Store` type, as defined
+ // in perf.d.ts. Coerce it into the `Store` type.
+ const anyStore = /** @type {any} */ (store);
+ panelWindow.gStore = anyStore;
+ }
+
+ const l10n = new FluentL10n();
+ await l10n.init([
+ "devtools/client/perftools.ftl",
+ // For -brand-shorter-name used in some profiler preset descriptions.
+ "branding/brand.ftl",
+ // Needed for the onboarding UI
+ "devtools/client/toolbox-options.ftl",
+ "toolkit/branding/brandings.ftl",
+ ]);
+
+ // Do some initialization, especially with privileged things that are part of the
+ // the browser.
+ store.dispatch(
+ actions.initializeStore({
+ isSupportedPlatform,
+ presets,
+ supportedFeatures,
+ pageContext,
+ })
+ );
+
+ /**
+ * @param {MinimallyTypedGeckoProfile} profile
+ */
+ const onProfileReceived = async profile => {
+ const objdirs = selectors.getObjdirs(store.getState());
+ const profilerViewMode = getProfilerViewModeForCurrentPreset(pageContext);
+ const sharedLibraries = sharedLibrariesFromProfile(profile);
+ const symbolicationService = createLocalSymbolicationService(
+ sharedLibraries,
+ objdirs,
+ perfFront
+ );
+ const browser = await openProfilerTab(profilerViewMode);
+
+ /**
+ * @type {ProfileCaptureResult}
+ */
+ const profileCaptureResult = { type: "SUCCESS", profile };
+
+ registerProfileCaptureForBrowser(
+ browser,
+ profileCaptureResult,
+ symbolicationService
+ );
+ };
+
+ const onEditSettingsLinkClicked = openAboutProfiling;
+
+ ReactDOM.render(
+ Provider(
+ { store },
+ LocalizationProvider(
+ { bundles: l10n.getBundles() },
+ React.createElement(
+ React.Fragment,
+ null,
+ ProfilerEventHandling({ perfFront, traits }),
+ ProfilerPreferenceObserver(),
+ DevToolsPanel({
+ perfFront,
+ onProfileReceived,
+ onEditSettingsLinkClicked,
+ })
+ )
+ )
+ ),
+ document.querySelector("#root")
+ );
+
+ window.addEventListener("unload", () => gDestroy(), { once: true });
+}
+
+function gDestroy() {
+ ReactDOM.unmountComponentAtNode(document.querySelector("#root"));
+}
diff --git a/devtools/client/performance-new/panel/moz.build b/devtools/client/performance-new/panel/moz.build
new file mode 100644
index 0000000000..298ed5a866
--- /dev/null
+++ b/devtools/client/performance-new/panel/moz.build
@@ -0,0 +1,12 @@
+# vim: set filetype=python:
+# 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/.
+
+DevToolsModules(
+ "initializer.js",
+ "panel.js",
+)
+
+with Files("**"):
+ BUG_COMPONENT = ("DevTools", "Performance Tools (Profiler/Timeline)")
diff --git a/devtools/client/performance-new/panel/panel.js b/devtools/client/performance-new/panel/panel.js
new file mode 100644
index 0000000000..d099f3c296
--- /dev/null
+++ b/devtools/client/performance-new/panel/panel.js
@@ -0,0 +1,107 @@
+/* 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/. */
+// @ts-check
+"use strict";
+
+/**
+ * This file contains the PerformancePanel, which uses a common API for DevTools to
+ * start and load everything. This will call `gInit` from the initializer.js file,
+ * which does the important initialization for the panel. This code is more concerned
+ * with wiring this panel into the rest of DevTools and fetching the Actor's fronts.
+ */
+
+/**
+ * @typedef {import("../@types/perf").PanelWindow} PanelWindow
+ * @typedef {import("../@types/perf").Toolbox} Toolbox
+ * @typedef {import("../@types/perf").Target} Target
+ * @typedef {import("../@types/perf").Commands} Commands
+ */
+
+class PerformancePanel {
+ /**
+ * @param {PanelWindow} iframeWindow
+ * @param {Toolbox} toolbox
+ * @param {Commands} commands
+ */
+ constructor(iframeWindow, toolbox, commands) {
+ this.panelWin = iframeWindow;
+ this.toolbox = toolbox;
+ this.commands = commands;
+
+ const EventEmitter = require("resource://devtools/shared/event-emitter.js");
+ EventEmitter.decorate(this);
+ }
+
+ /**
+ * This is implemented (and overwritten) by the EventEmitter. Is there a way
+ * to use mixins with JSDoc?
+ *
+ * @param {string} eventName
+ */
+ emit(eventName) {}
+
+ /**
+ * Open is effectively an asynchronous constructor.
+ * @return {Promise<PerformancePanel>} Resolves when the Perf tool completes
+ * opening.
+ */
+ open() {
+ if (!this._opening) {
+ this._opening = this._doOpen();
+ }
+ return this._opening;
+ }
+
+ /**
+ * This function is the actual implementation of the open() method.
+ * @returns Promise<PerformancePanel>
+ */
+ async _doOpen() {
+ this.panelWin.gToolbox = this.toolbox;
+ this.panelWin.gIsPanelDestroyed = false;
+
+ const perfFront = await this.commands.client.mainRoot.getFront("perf");
+
+ // Note: we are not using traits in the panel at the moment but we keep the
+ // wiring in case we need it later on.
+ const traits = {};
+
+ await this.panelWin.gInit(
+ perfFront,
+ traits,
+ "devtools",
+ this._openAboutProfiling
+ );
+ return this;
+ }
+
+ _openAboutProfiling() {
+ const {
+ openTrustedLink,
+ } = require("resource://devtools/client/shared/link.js");
+ openTrustedLink("about:profiling", {});
+ }
+
+ // DevToolPanel API:
+
+ /**
+ * @returns {Target} target
+ */
+ get target() {
+ return this.toolbox.target;
+ }
+
+ destroy() {
+ // Make sure this panel is not already destroyed.
+ if (this._destroyed) {
+ return;
+ }
+ this.panelWin.gDestroy();
+ this.emit("destroyed");
+ this._destroyed = true;
+ this.panelWin.gIsPanelDestroyed = true;
+ }
+}
+
+exports.PerformancePanel = PerformancePanel;