mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 05:35:31 +00:00
150c12737b
--HG-- rename : browser/devtools/profiler/test/browser_profiler_categories.js => browser/devtools/performance/test/browser_profiler_categories.js rename : browser/devtools/profiler/test/browser_profiler_content-check.js => browser/devtools/performance/test/browser_profiler_content-check.js rename : browser/devtools/profiler/test/browser_profiler_tree-abstract-01.js => browser/devtools/performance/test/browser_profiler_tree-abstract-01.js rename : browser/devtools/profiler/test/browser_profiler_tree-abstract-02.js => browser/devtools/performance/test/browser_profiler_tree-abstract-02.js rename : browser/devtools/profiler/test/browser_profiler_tree-abstract-03.js => browser/devtools/performance/test/browser_profiler_tree-abstract-03.js rename : browser/devtools/profiler/test/browser_profiler_tree-abstract-04.js => browser/devtools/performance/test/browser_profiler_tree-abstract-04.js rename : browser/devtools/profiler/test/browser_profiler_tree-frame-node.js => browser/devtools/performance/test/browser_profiler_tree-frame-node.js rename : browser/devtools/profiler/test/browser_profiler_tree-model-01.js => browser/devtools/performance/test/browser_profiler_tree-model-01.js rename : browser/devtools/profiler/test/browser_profiler_tree-model-02.js => browser/devtools/performance/test/browser_profiler_tree-model-02.js rename : browser/devtools/profiler/test/browser_profiler_tree-model-03.js => browser/devtools/performance/test/browser_profiler_tree-model-03.js rename : browser/devtools/profiler/test/browser_profiler_tree-model-04.js => browser/devtools/performance/test/browser_profiler_tree-model-04.js rename : browser/devtools/profiler/test/browser_profiler_tree-model-05.js => browser/devtools/performance/test/browser_profiler_tree-model-05.js rename : browser/devtools/profiler/test/browser_profiler_tree-view-01.js => browser/devtools/performance/test/browser_profiler_tree-view-01.js rename : browser/devtools/profiler/test/browser_profiler_tree-view-02.js => browser/devtools/performance/test/browser_profiler_tree-view-02.js rename : browser/devtools/profiler/test/browser_profiler_tree-view-03.js => browser/devtools/performance/test/browser_profiler_tree-view-03.js rename : browser/devtools/profiler/test/browser_profiler_tree-view-04.js => browser/devtools/performance/test/browser_profiler_tree-view-04.js rename : browser/devtools/profiler/test/browser_profiler_tree-view-05.js => browser/devtools/performance/test/browser_profiler_tree-view-05.js rename : browser/devtools/profiler/test/browser_profiler_tree-view-06.js => browser/devtools/performance/test/browser_profiler_tree-view-06.js rename : browser/devtools/profiler/test/browser_profiler_tree-view-07.js => browser/devtools/performance/test/browser_profiler_tree-view-07.js rename : browser/devtools/timeline/test/browser_timeline_blueprint.js => browser/devtools/performance/test/browser_timeline_blueprint.js rename : browser/devtools/profiler/utils/global.js => browser/devtools/shared/profiler/global.js rename : browser/devtools/profiler/utils/tree-model.js => browser/devtools/shared/profiler/tree-model.js rename : browser/devtools/profiler/utils/tree-view.js => browser/devtools/shared/profiler/tree-view.js rename : browser/devtools/timeline/widgets/global.js => browser/devtools/shared/timeline/global.js rename : browser/devtools/timeline/widgets/marker-details.js => browser/devtools/shared/timeline/marker-details.js rename : browser/devtools/timeline/widgets/markers-overview.js => browser/devtools/shared/timeline/markers-overview.js rename : browser/devtools/timeline/widgets/memory-overview.js => browser/devtools/shared/timeline/memory-overview.js rename : browser/devtools/timeline/widgets/waterfall.js => browser/devtools/shared/timeline/waterfall.js
628 lines
19 KiB
JavaScript
628 lines
19 KiB
JavaScript
/* 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 { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/Task.jsm");
|
|
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
|
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
|
Cu.import("resource:///modules/devtools/gDevTools.jsm");
|
|
|
|
devtools.lazyRequireGetter(this, "promise");
|
|
devtools.lazyRequireGetter(this, "EventEmitter",
|
|
"devtools/toolkit/event-emitter");
|
|
|
|
devtools.lazyRequireGetter(this, "MarkersOverview",
|
|
"devtools/shared/timeline/markers-overview", true);
|
|
devtools.lazyRequireGetter(this, "MemoryOverview",
|
|
"devtools/shared/timeline/memory-overview", true);
|
|
devtools.lazyRequireGetter(this, "Waterfall",
|
|
"devtools/shared/timeline/waterfall", true);
|
|
devtools.lazyRequireGetter(this, "MarkerDetails",
|
|
"devtools/shared/timeline/marker-details", true);
|
|
devtools.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
|
|
"devtools/shared/timeline/global", true);
|
|
|
|
devtools.lazyImporter(this, "CanvasGraphUtils",
|
|
"resource:///modules/devtools/Graphs.jsm");
|
|
|
|
devtools.lazyImporter(this, "PluralForm",
|
|
"resource://gre/modules/PluralForm.jsm");
|
|
|
|
const OVERVIEW_UPDATE_INTERVAL = 200;
|
|
const OVERVIEW_INITIAL_SELECTION_RATIO = 0.15;
|
|
|
|
/**
|
|
* Preference for devtools.timeline.hiddenMarkers.
|
|
* Stores which markers should be hidden.
|
|
*/
|
|
const Prefs = new ViewHelpers.Prefs("devtools.timeline", {
|
|
hiddenMarkers: ["Json", "hiddenMarkers"]
|
|
});
|
|
|
|
// The panel's window global is an EventEmitter firing the following events:
|
|
const EVENTS = {
|
|
// When a recording is started or stopped, via the `stopwatch` button.
|
|
RECORDING_STARTED: "Timeline:RecordingStarted",
|
|
RECORDING_ENDED: "Timeline:RecordingEnded",
|
|
|
|
// When the overview graphs are populated with new markers.
|
|
OVERVIEW_UPDATED: "Timeline:OverviewUpdated",
|
|
|
|
// When the waterfall view is populated with new markers.
|
|
WATERFALL_UPDATED: "Timeline:WaterfallUpdated"
|
|
};
|
|
|
|
/**
|
|
* The current target and the timeline front, set by this tool's host.
|
|
*/
|
|
let gToolbox, gTarget, gFront;
|
|
|
|
/**
|
|
* Initializes the timeline controller and views.
|
|
*/
|
|
let startupTimeline = Task.async(function*() {
|
|
yield TimelineView.initialize();
|
|
yield TimelineController.initialize();
|
|
});
|
|
|
|
/**
|
|
* Destroys the timeline controller and views.
|
|
*/
|
|
let shutdownTimeline = Task.async(function*() {
|
|
yield TimelineView.destroy();
|
|
yield TimelineController.destroy();
|
|
yield gFront.stop();
|
|
});
|
|
|
|
/**
|
|
* Functions handling the timeline frontend controller.
|
|
*/
|
|
let TimelineController = {
|
|
/**
|
|
* Permanent storage for the markers and the memory measurements streamed by
|
|
* the backend, along with the start and end timestamps.
|
|
*/
|
|
_starTime: 0,
|
|
_endTime: 0,
|
|
_markers: [],
|
|
_memory: [],
|
|
_frames: [],
|
|
|
|
/**
|
|
* Initialization function, called when the tool is started.
|
|
*/
|
|
initialize: function() {
|
|
this._onRecordingTick = this._onRecordingTick.bind(this);
|
|
this._onMarkers = this._onMarkers.bind(this);
|
|
this._onMemory = this._onMemory.bind(this);
|
|
this._onFrames = this._onFrames.bind(this);
|
|
|
|
gFront.on("markers", this._onMarkers);
|
|
gFront.on("memory", this._onMemory);
|
|
gFront.on("frames", this._onFrames);
|
|
},
|
|
|
|
/**
|
|
* Destruction function, called when the tool is closed.
|
|
*/
|
|
destroy: function() {
|
|
gFront.off("markers", this._onMarkers);
|
|
gFront.off("memory", this._onMemory);
|
|
gFront.off("frames", this._onFrames);
|
|
},
|
|
|
|
/**
|
|
* Gets the { stat, end } time interval for this recording.
|
|
* @return object
|
|
*/
|
|
getInterval: function() {
|
|
return { startTime: this._startTime, endTime: this._endTime };
|
|
},
|
|
|
|
/**
|
|
* Gets the accumulated markers in this recording.
|
|
* @return array
|
|
*/
|
|
getMarkers: function() {
|
|
return this._markers;
|
|
},
|
|
|
|
/**
|
|
* Gets the accumulated memory measurements in this recording.
|
|
* @return array
|
|
*/
|
|
getMemory: function() {
|
|
return this._memory;
|
|
},
|
|
|
|
/**
|
|
* Gets stack frame array reported by the actor. The marker "stack"
|
|
* and "endStack" properties are indices into this array. See
|
|
* actors/utils/stack.js for more details.
|
|
* @return array
|
|
*/
|
|
getFrames: function() {
|
|
return this._frames;
|
|
},
|
|
|
|
/**
|
|
* Updates the views to show or hide the memory recording data.
|
|
*/
|
|
updateMemoryRecording: Task.async(function*() {
|
|
if ($("#memory-checkbox").checked) {
|
|
yield TimelineView.showMemoryOverview();
|
|
} else {
|
|
yield TimelineView.hideMemoryOverview();
|
|
}
|
|
}),
|
|
|
|
/**
|
|
* Starts/stops the timeline recording and streaming.
|
|
*/
|
|
toggleRecording: Task.async(function*() {
|
|
let isRecording = yield gFront.isRecording();
|
|
if (isRecording == false) {
|
|
yield this._startRecording();
|
|
} else {
|
|
yield this._stopRecording();
|
|
}
|
|
}),
|
|
|
|
/**
|
|
* Starts the recording, updating the UI as needed.
|
|
*/
|
|
_startRecording: function*() {
|
|
TimelineView.handleRecordingStarted();
|
|
|
|
let withMemory = $("#memory-checkbox").checked;
|
|
let startTime = yield gFront.start({ withMemory });
|
|
|
|
// Times must come from the actor in order to be self-consistent.
|
|
// However, we also want to update the view with the elapsed time
|
|
// even when the actor is not generating data. To do this we get
|
|
// the local time and use it to compute a reasonable elapsed time.
|
|
// See _onRecordingTick.
|
|
this._localStartTime = performance.now();
|
|
this._startTime = startTime;
|
|
this._endTime = startTime;
|
|
this._markers = [];
|
|
this._memory = [];
|
|
this._frames = [];
|
|
this._updateId = setInterval(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
|
|
},
|
|
|
|
/**
|
|
* Stops the recording, updating the UI as needed.
|
|
*/
|
|
_stopRecording: function*() {
|
|
clearInterval(this._updateId);
|
|
|
|
// Sorting markers is only important when displayed in the waterfall.
|
|
this._markers = this._markers.sort((a,b) => (a.start > b.start));
|
|
|
|
TimelineView.handleRecordingUpdate();
|
|
TimelineView.handleRecordingEnded();
|
|
yield gFront.stop();
|
|
},
|
|
|
|
/**
|
|
* Used in tests. Stops the recording, discarding the accumulated markers and
|
|
* updating the UI as needed.
|
|
*/
|
|
_stopRecordingAndDiscardData: function*() {
|
|
// Clear the markers before calling async method _stopRecording to properly
|
|
// reset the selection if markers were already received. Bug 1092452.
|
|
this._markers.length = 0;
|
|
this._memory.length = 0;
|
|
|
|
yield this._stopRecording();
|
|
|
|
// Clear the markers after _stopRecording has finished. It's possible that
|
|
// server sent new markers before it received the request to stop sending
|
|
// them and client received them while we were waiting for _stopRecording
|
|
// to finish. Bug 1067287.
|
|
this._markers.length = 0;
|
|
this._memory.length = 0;
|
|
},
|
|
|
|
/**
|
|
* Callback handling the "markers" event on the timeline front.
|
|
*
|
|
* @param array markers
|
|
* A list of new markers collected since the last time this
|
|
* function was invoked.
|
|
* @param number endTime
|
|
* A time after the last marker in markers was collected.
|
|
*/
|
|
_onMarkers: function(markers, endTime) {
|
|
for (let marker of markers) {
|
|
marker.start -= this._startTime;
|
|
marker.end -= this._startTime;
|
|
}
|
|
Array.prototype.push.apply(this._markers, markers);
|
|
this._endTime = endTime;
|
|
},
|
|
|
|
/**
|
|
* Callback handling the "memory" event on the timeline front.
|
|
*
|
|
* @param number delta
|
|
* The number of milliseconds elapsed since epoch.
|
|
* @param object measurement
|
|
* A detailed breakdown of the current memory usage.
|
|
*/
|
|
_onMemory: function(delta, measurement) {
|
|
this._memory.push({
|
|
delta: delta - this._startTime,
|
|
value: measurement.total / 1024 / 1024
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Callback handling the "frames" event on the timeline front.
|
|
*
|
|
* @param number delta
|
|
* The number of milliseconds elapsed since epoch.
|
|
* @param object frames
|
|
* Newly generated frame objects.
|
|
*/
|
|
_onFrames: function(delta, frames) {
|
|
Array.prototype.push.apply(this._frames, frames);
|
|
},
|
|
|
|
/**
|
|
* Callback invoked at a fixed interval while recording.
|
|
* Updates the current time and the timeline overview.
|
|
*/
|
|
_onRecordingTick: function() {
|
|
// Compute an approximate ending time for the view. This is
|
|
// needed to ensure that the view updates even when new data is
|
|
// not being generated.
|
|
let fakeTime = this._startTime + (performance.now() - this._localStartTime);
|
|
if (fakeTime > this._endTime) {
|
|
this._endTime = fakeTime;
|
|
}
|
|
TimelineView.handleRecordingUpdate();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Functions handling the timeline frontend view.
|
|
*/
|
|
let TimelineView = {
|
|
/**
|
|
* Initialization function, called when the tool is started.
|
|
*/
|
|
initialize: Task.async(function*() {
|
|
let blueprint = this._getFilteredBluePrint();
|
|
this.markersOverview = new MarkersOverview($("#markers-overview"), blueprint);
|
|
this.waterfall = new Waterfall($("#timeline-waterfall"), $("#timeline-pane"), blueprint);
|
|
this.markerDetails = new MarkerDetails($("#timeline-waterfall-details"), $("#timeline-waterfall-container > splitter"));
|
|
|
|
this._onThemeChange = this._onThemeChange.bind(this);
|
|
this._onSelecting = this._onSelecting.bind(this);
|
|
this._onRefresh = this._onRefresh.bind(this);
|
|
|
|
gDevTools.on("pref-changed", this._onThemeChange);
|
|
this.markersOverview.on("selecting", this._onSelecting);
|
|
this.markersOverview.on("refresh", this._onRefresh);
|
|
this.markerDetails.on("resize", this._onRefresh);
|
|
|
|
this._onMarkerSelected = this._onMarkerSelected.bind(this);
|
|
this.waterfall.on("selected", this._onMarkerSelected);
|
|
this.waterfall.on("unselected", this._onMarkerSelected);
|
|
|
|
let theme = Services.prefs.getCharPref("devtools.theme");
|
|
this.markersOverview.setTheme(theme);
|
|
|
|
yield this.markersOverview.ready();
|
|
|
|
yield this.waterfall.recalculateBounds();
|
|
|
|
this._buildFilterPopup();
|
|
}),
|
|
|
|
/**
|
|
* Destruction function, called when the tool is closed.
|
|
*/
|
|
destroy: function() {
|
|
gDevTools.off("pref-changed", this._onThemeChange);
|
|
this.markerDetails.off("resize", this._onRefresh);
|
|
this.markerDetails.destroy();
|
|
this.waterfall.off("selected", this._onMarkerSelected);
|
|
this.waterfall.off("unselected", this._onMarkerSelected);
|
|
this.waterfall.destroy();
|
|
this.markersOverview.off("selecting", this._onSelecting);
|
|
this.markersOverview.off("refresh", this._onRefresh);
|
|
this.markersOverview.destroy();
|
|
|
|
// The memory overview graph is not always available.
|
|
if (this.memoryOverview) {
|
|
this.memoryOverview.destroy();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Shows the memory overview graph.
|
|
*/
|
|
showMemoryOverview: Task.async(function*() {
|
|
let theme = Services.prefs.getCharPref("devtools.theme");
|
|
|
|
this.memoryOverview = new MemoryOverview($("#memory-overview"));
|
|
this.memoryOverview.setTheme(theme);
|
|
yield this.memoryOverview.ready();
|
|
|
|
let memory = TimelineController.getMemory();
|
|
this.memoryOverview.setData(memory);
|
|
|
|
CanvasGraphUtils.linkAnimation(this.markersOverview, this.memoryOverview);
|
|
CanvasGraphUtils.linkSelection(this.markersOverview, this.memoryOverview);
|
|
}),
|
|
|
|
/**
|
|
* Hides the memory overview graph.
|
|
*/
|
|
hideMemoryOverview: function() {
|
|
if (!this.memoryOverview) {
|
|
return;
|
|
}
|
|
this.memoryOverview.destroy();
|
|
this.memoryOverview = null;
|
|
},
|
|
|
|
/**
|
|
* A marker has been selected in the waterfall.
|
|
*/
|
|
_onMarkerSelected: function(event, marker) {
|
|
if (event == "selected") {
|
|
this.markerDetails.render({
|
|
toolbox: gToolbox,
|
|
marker: marker,
|
|
frames: TimelineController.getFrames()
|
|
});
|
|
}
|
|
if (event == "unselected") {
|
|
this.markerDetails.empty();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Signals that a recording session has started and triggers the appropriate
|
|
* changes in the UI.
|
|
*/
|
|
handleRecordingStarted: function() {
|
|
$("#record-button").setAttribute("checked", "true");
|
|
$("#memory-checkbox").setAttribute("disabled", "true");
|
|
$("#timeline-pane").selectedPanel = $("#recording-notice");
|
|
|
|
this.markersOverview.clearView();
|
|
|
|
// The memory overview graph is not always available.
|
|
if (this.memoryOverview) {
|
|
this.memoryOverview.clearView();
|
|
}
|
|
|
|
this.waterfall.clearView();
|
|
|
|
window.emit(EVENTS.RECORDING_STARTED);
|
|
},
|
|
|
|
/**
|
|
* Signals that a recording session has ended and triggers the appropriate
|
|
* changes in the UI.
|
|
*/
|
|
handleRecordingEnded: function() {
|
|
$("#record-button").removeAttribute("checked");
|
|
$("#memory-checkbox").removeAttribute("disabled");
|
|
$("#timeline-pane").selectedPanel = $("#timeline-waterfall-container");
|
|
|
|
this.markersOverview.selectionEnabled = true;
|
|
|
|
// The memory overview graph is not always available.
|
|
if (this.memoryOverview) {
|
|
this.memoryOverview.selectionEnabled = true;
|
|
}
|
|
|
|
let interval = TimelineController.getInterval();
|
|
let markers = TimelineController.getMarkers();
|
|
let memory = TimelineController.getMemory();
|
|
|
|
if (markers.length) {
|
|
let start = markers[0].start * this.markersOverview.dataScaleX;
|
|
let end = start + this.markersOverview.width * OVERVIEW_INITIAL_SELECTION_RATIO;
|
|
this.markersOverview.setSelection({ start, end });
|
|
} else {
|
|
let startTime = interval.startTime;
|
|
let endTime = interval.endTime;
|
|
this.waterfall.setData({ markers, interval: { startTime, endTime } });
|
|
}
|
|
|
|
window.emit(EVENTS.RECORDING_ENDED);
|
|
},
|
|
|
|
/**
|
|
* Signals that a new set of markers was made available by the controller,
|
|
* or that the overview graph needs to be updated.
|
|
*/
|
|
handleRecordingUpdate: function() {
|
|
let interval = TimelineController.getInterval();
|
|
let markers = TimelineController.getMarkers();
|
|
let memory = TimelineController.getMemory();
|
|
|
|
let duration = interval.endTime - interval.startTime;
|
|
this.markersOverview.setData({ markers, duration });
|
|
|
|
// The memory overview graph is not always available.
|
|
if (this.memoryOverview) {
|
|
this.memoryOverview.setData(memory);
|
|
}
|
|
|
|
window.emit(EVENTS.OVERVIEW_UPDATED);
|
|
},
|
|
|
|
/**
|
|
* Callback handling the "selecting" event on the timeline overview.
|
|
*/
|
|
_onSelecting: function() {
|
|
if (!this.markersOverview.hasSelection() &&
|
|
!this.markersOverview.hasSelectionInProgress()) {
|
|
this.waterfall.clearView();
|
|
return;
|
|
}
|
|
this.waterfall.resetSelection();
|
|
this.updateWaterfall();
|
|
},
|
|
|
|
/**
|
|
* Rebuild the waterfall.
|
|
*/
|
|
updateWaterfall: function() {
|
|
let selection = this.markersOverview.getSelection();
|
|
let start = selection.start / this.markersOverview.dataScaleX;
|
|
let end = selection.end / this.markersOverview.dataScaleX;
|
|
|
|
let markers = TimelineController.getMarkers();
|
|
let interval = TimelineController.getInterval();
|
|
|
|
let startTime = Math.min(start, end);
|
|
let endTime = Math.max(start, end);
|
|
|
|
this.waterfall.setData({ markers, interval: { startTime, endTime } });
|
|
},
|
|
|
|
/**
|
|
* Callback handling the "refresh" event on the timeline overview.
|
|
*/
|
|
_onRefresh: function() {
|
|
this.waterfall.recalculateBounds();
|
|
this.updateWaterfall();
|
|
},
|
|
|
|
/**
|
|
* Rebuild a blueprint without hidden markers.
|
|
*/
|
|
_getFilteredBluePrint: function() {
|
|
let hiddenMarkers = Prefs.hiddenMarkers;
|
|
let filteredBlueprint = Cu.cloneInto(TIMELINE_BLUEPRINT, {});
|
|
let maybeRemovedGroups = new Set();
|
|
let removedGroups = new Set();
|
|
|
|
// 1. Remove hidden markers from the blueprint.
|
|
|
|
for (let hiddenMarkerName of hiddenMarkers) {
|
|
maybeRemovedGroups.add(filteredBlueprint[hiddenMarkerName].group);
|
|
delete filteredBlueprint[hiddenMarkerName];
|
|
}
|
|
|
|
// 2. Get a list of all the groups that will be removed.
|
|
|
|
for (let removedGroup of maybeRemovedGroups) {
|
|
let markerNames = Object.keys(filteredBlueprint);
|
|
let allGroupsRemoved = markerNames.every(e => filteredBlueprint[e].group != removedGroup);
|
|
if (allGroupsRemoved) {
|
|
removedGroups.add(removedGroup);
|
|
}
|
|
}
|
|
|
|
// 3. Offset groups.
|
|
|
|
for (let removedGroup of removedGroups) {
|
|
for (let [, markerDetails] of Iterator(filteredBlueprint)) {
|
|
if (markerDetails.group > removedGroup) {
|
|
markerDetails.group--;
|
|
}
|
|
}
|
|
}
|
|
|
|
return filteredBlueprint;
|
|
|
|
},
|
|
|
|
/**
|
|
* When the list of hidden markers changes, update waterfall
|
|
* and overview.
|
|
*/
|
|
_onHiddenMarkersChanged: function(e) {
|
|
let menuItems = $$("#timelineFilterPopup menuitem[marker-type]:not([checked])");
|
|
let hiddenMarkers = Array.map(menuItems, e => e.getAttribute("marker-type"));
|
|
|
|
Prefs.hiddenMarkers = hiddenMarkers;
|
|
let blueprint = this._getFilteredBluePrint();
|
|
|
|
this.waterfall.setBlueprint(blueprint);
|
|
this.updateWaterfall();
|
|
|
|
this.markersOverview.setBlueprint(blueprint);
|
|
this.markersOverview.refresh({ force: true });
|
|
},
|
|
|
|
/**
|
|
* Creates the filter popup.
|
|
*/
|
|
_buildFilterPopup: function() {
|
|
let popup = $("#timelineFilterPopup");
|
|
let button = $("#filter-button");
|
|
|
|
popup.addEventListener("popupshowing", () => button.setAttribute("open", "true"));
|
|
popup.addEventListener("popuphiding", () => button.removeAttribute("open"));
|
|
|
|
this._onHiddenMarkersChanged = this._onHiddenMarkersChanged.bind(this);
|
|
|
|
for (let [markerName, markerDetails] of Iterator(TIMELINE_BLUEPRINT)) {
|
|
let menuitem = document.createElement("menuitem");
|
|
menuitem.setAttribute("closemenu", "none");
|
|
menuitem.setAttribute("type", "checkbox");
|
|
menuitem.setAttribute("marker-type", markerName);
|
|
menuitem.setAttribute("label", markerDetails.label);
|
|
menuitem.setAttribute("flex", "1");
|
|
menuitem.setAttribute("align", "center");
|
|
|
|
menuitem.addEventListener("command", this._onHiddenMarkersChanged);
|
|
|
|
if (Prefs.hiddenMarkers.indexOf(markerName) == -1) {
|
|
menuitem.setAttribute("checked", "true");
|
|
}
|
|
|
|
// Style used by pseudo element ::before in timeline.css.in
|
|
let bulletStyle = `--bullet-bg: ${markerDetails.fill};`
|
|
bulletStyle += `--bullet-border: ${markerDetails.stroke}`;
|
|
menuitem.setAttribute("style", bulletStyle);
|
|
|
|
popup.appendChild(menuitem);
|
|
}
|
|
},
|
|
|
|
/*
|
|
* Called when the developer tools theme changes. Redraws
|
|
* the graphs with the new theme setting.
|
|
*/
|
|
_onThemeChange: function (_, theme) {
|
|
if (this.memoryOverview) {
|
|
this.memoryOverview.setTheme(theme.newValue);
|
|
this.memoryOverview.refresh({ force: true });
|
|
}
|
|
|
|
this.markersOverview.setTheme(theme.newValue);
|
|
this.markersOverview.refresh({ force: true });
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Convenient way of emitting events from the panel window.
|
|
*/
|
|
EventEmitter.decorate(this);
|
|
|
|
/**
|
|
* DOM query helpers.
|
|
*/
|
|
function $(selector, target = document) {
|
|
return target.querySelector(selector);
|
|
}
|
|
function $$(selector, target = document) {
|
|
return target.querySelectorAll(selector);
|
|
}
|