Merge m-c to b2g-inbound a=merge CLOSED TREE

This commit is contained in:
Wes Kocher 2015-02-06 14:56:32 -08:00
Родитель 2d220b0a24 37dc6c9583
Коммит 1b2b74bdb6
269 изменённых файлов: 5356 добавлений и 3986 удалений

Просмотреть файл

@ -319,7 +319,7 @@ pref("media.fragmented-mp4.gonk.enabled", true);
pref("media.video-queue.default-size", 3);
// optimize images' memory usage
pref("image.mem.decodeondraw", true);
pref("image.mem.decodeondraw", false);
pref("image.mem.allow_locking_in_content_processes", false); /* don't allow image locking */
// Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
// Almost everything that was factored into 'max_decoded_image_kb' is now stored

Просмотреть файл

@ -1438,6 +1438,7 @@ pref("devtools.profiler.ui.show-idle-blocks", true);
// The default Performance UI settings
pref("devtools.performance.ui.invert-call-tree", true);
pref("devtools.performance.ui.invert-flame-graph", false);
pref("devtools.performance.ui.flatten-tree-recursion", true);
pref("devtools.performance.ui.show-platform-data", false);
pref("devtools.performance.ui.show-idle-blocks", true);

Просмотреть файл

@ -0,0 +1,36 @@
# -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
# 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/.
function gEMEListener(msg /*{target: browser, data: data} */) {
let browser = msg.target;
let notificationId = "drmContentPlaying";
// Don't need to show if disabled, nor reshow if it's already there
if (!Services.prefs.getBoolPref("browser.eme.ui.enabled") ||
PopupNotifications.getNotification(notificationId, browser)) {
return;
}
let msgId = "emeNotifications.drmContentPlaying.message";
let brandName = document.getElementById("bundle_brand").getString("brandShortName");
let message = gNavigatorBundle.getFormattedString(msgId, [msg.data.drmProvider, brandName]);
let anchorId = "eme-notification-icon";
let mainAction = {
label: gNavigatorBundle.getString("emeNotifications.drmContentPlaying.button.label"),
accessKey: gNavigatorBundle.getString("emeNotifications.drmContentPlaying.button.accesskey"),
callback: function() { openPreferences("paneContent"); },
dismiss: true
};
let options = {
dismissed: true,
eventCallback: aTopic => aTopic == "swapping",
};
PopupNotifications.show(browser, notificationId, message, anchorId, mainAction, null, options);
};
window.messageManager.addMessageListener("EMEVideo:MetadataLoaded", gEMEListener);
window.addEventListener("unload", function() {
window.messageManager.removeMessageListener("EMEVideo:MetadataLoaded", gEMEListener);
}, false);

Просмотреть файл

@ -214,6 +214,7 @@ let gInitialPages = [
#include browser-ctrlTab.js
#include browser-customization.js
#include browser-devedition.js
#include browser-eme.js
#include browser-feeds.js
#include browser-fullScreen.js
#include browser-fullZoom.js

Просмотреть файл

@ -822,6 +822,7 @@
<image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="translate-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="translated-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="eme-notification-icon" class="notification-anchor-icon" role="button"/>
</box>
<!-- Use onclick instead of normal popup= syntax since the popup
code fires onmousedown, and hence eats our favicon drag events.

Просмотреть файл

@ -8,6 +8,7 @@ let {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/ContentWebRTC.jsm");
Cu.import("resource:///modules/ContentObservers.jsm");
Cu.import("resource://gre/modules/InlineSpellChecker.jsm");
Cu.import("resource://gre/modules/InlineSpellCheckerContent.jsm");

Просмотреть файл

@ -19,7 +19,6 @@ DIRS += [
'sessionstore',
'shell',
'selfsupport',
'sidebar',
'tabview',
'uitour',
'translation',

Просмотреть файл

@ -11,6 +11,7 @@ support-files =
testEngine.xml
testEngine_dupe.xml
testEngine_mozsearch.xml
webapi.html
[browser_405664.js]
[browser_426329.js]
@ -43,3 +44,4 @@ skip-if = e10s || true # Bug ??????, Bug 1100301 - leaks windows until shutdown
[browser_searchbar_openpopup.js]
skip-if = os == "linux" || e10s # Linux has different focus behaviours and e10s seems to have timing issues.
[browser_searchbar_keyboard_navigation.js]
[browser_webapi.js]

Просмотреть файл

@ -0,0 +1,174 @@
let ROOT = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
function AddSearchProvider(...args) {
return gBrowser.addTab(ROOT + "webapi.html?AddSearchProvider:" + encodeURIComponent(JSON.stringify(args)));
}
function addSearchEngine(...args) {
return gBrowser.addTab(ROOT + "webapi.html?addSearchEngine:" + encodeURIComponent(JSON.stringify(args)));
}
function promiseDialogOpened() {
return new Promise((resolve, reject) => {
Services.wm.addListener({
onOpenWindow: function(xulWin) {
Services.wm.removeListener(this);
let win = xulWin.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
waitForFocus(() => {
if (win.location == "chrome://global/content/commonDialog.xul")
resolve(win)
else
reject();
}, win);
}
});
});
}
add_task(function* test_working_AddSearchProvider() {
gBrowser.selectedTab = AddSearchProvider(ROOT + "testEngine.xml");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
is(dialog.args.text, "Add \"Foo\" to the list of engines available in the search bar?\n\nFrom: example.com",
"Should have seen the right install message");
dialog.document.documentElement.cancelDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_HTTP_AddSearchProvider() {
gBrowser.selectedTab = AddSearchProvider(ROOT.replace("http:", "HTTP:") + "testEngine.xml");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
is(dialog.args.text, "Add \"Foo\" to the list of engines available in the search bar?\n\nFrom: example.com",
"Should have seen the right install message");
dialog.document.documentElement.cancelDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_relative_AddSearchProvider() {
gBrowser.selectedTab = AddSearchProvider("testEngine.xml");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
is(dialog.args.text, "Add \"Foo\" to the list of engines available in the search bar?\n\nFrom: example.com",
"Should have seen the right install message");
dialog.document.documentElement.cancelDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_invalid_AddSearchProvider() {
gBrowser.selectedTab = AddSearchProvider("z://foobar");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
is(dialog.args.text, "This search engine isn't supported by Nightly and can't be installed.",
"Should have seen the right error message")
dialog.document.documentElement.acceptDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_missing_AddSearchProvider() {
let url = ROOT + "foobar.xml";
gBrowser.selectedTab = AddSearchProvider(url);
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
is(dialog.args.text, "Nightly could not download the search plugin from:\n" + url,
"Should have seen the right error message")
dialog.document.documentElement.acceptDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_working_addSearchEngine_xml() {
gBrowser.selectedTab = addSearchEngine(ROOT + "testEngine.xml", "", "", "");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
is(dialog.args.text, "Add \"Foo\" to the list of engines available in the search bar?\n\nFrom: example.com",
"Should have seen the right install message");
dialog.document.documentElement.cancelDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_working_addSearchEngine_src() {
gBrowser.selectedTab = addSearchEngine(ROOT + "testEngine.src", "", "", "");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
is(dialog.args.text, "Add \"Test Sherlock\" to the list of engines available in the search bar?\n\nFrom: example.com",
"Should have seen the right install message");
dialog.document.documentElement.cancelDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_relative_addSearchEngine_xml() {
gBrowser.selectedTab = addSearchEngine("testEngine.xml", "", "", "");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
is(dialog.args.text, "Add \"Foo\" to the list of engines available in the search bar?\n\nFrom: example.com",
"Should have seen the right install message");
dialog.document.documentElement.cancelDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_relative_addSearchEngine_src() {
gBrowser.selectedTab = addSearchEngine("testEngine.src", "", "", "");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "confirmEx", "Should see the confirmation dialog.");
is(dialog.args.text, "Add \"Test Sherlock\" to the list of engines available in the search bar?\n\nFrom: example.com",
"Should have seen the right install message");
dialog.document.documentElement.cancelDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_invalid_addSearchEngine() {
gBrowser.selectedTab = addSearchEngine("z://foobar", "", "", "");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
is(dialog.args.text, "This search engine isn't supported by Nightly and can't be installed.",
"Should have seen the right error message")
dialog.document.documentElement.acceptDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_invalid_icon_addSearchEngine() {
gBrowser.selectedTab = addSearchEngine(ROOT + "testEngine.src", "z://foobar", "", "");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
is(dialog.args.text, "This search engine isn't supported by Nightly and can't be installed.",
"Should have seen the right error message")
dialog.document.documentElement.acceptDialog();
gBrowser.removeCurrentTab();
});
add_task(function* test_missing_addSearchEngine() {
let url = ROOT + "foobar.xml";
gBrowser.selectedTab = addSearchEngine(url, "", "", "");
let dialog = yield promiseDialogOpened();
is(dialog.args.promptType, "alert", "Should see the alert dialog.");
is(dialog.args.text, "Nightly could not download the search plugin from:\n" + url,
"Should have seen the right error message")
dialog.document.documentElement.acceptDialog();
gBrowser.removeCurrentTab();
});

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<script>
function installEngine() {
var query = window.location.search.substring(1).split(":");
var func = query[0];
var args = JSON.parse(decodeURIComponent(query[1]));
if (func == "AddSearchProvider")
window.external.AddSearchProvider(...args);
else if (func == "addSearchEngine")
window.sidebar.addSearchEngine(...args);
}
</script>
</head>
<body onload="installEngine()">
</body>
</html>

Просмотреть файл

@ -1,10 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# 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/.
EXTRA_COMPONENTS += [
'nsSidebar.js',
'nsSidebar.manifest',
]

Просмотреть файл

@ -1,127 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/* 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/. */
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const DEBUG = false; /* set to false to suppress debug messages */
const SIDEBAR_CONTRACTID = "@mozilla.org/sidebar;1";
const SIDEBAR_CID = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}");
// File extension for Sherlock search plugin description files
const SHERLOCK_FILE_EXT_REGEXP = /\.src$/i;
function nsSidebar()
{
}
nsSidebar.prototype.classID = SIDEBAR_CID;
nsSidebar.prototype.validateSearchEngine =
function (engineURL, iconURL)
{
try
{
// Make sure the URLs are HTTP, HTTPS, or FTP.
var isWeb = /^(https?|ftp):\/\//i;
if (!isWeb.test(engineURL))
throw "Unsupported search engine URL";
if (iconURL && !isWeb.test(iconURL))
throw "Unsupported search icon URL.";
}
catch(ex)
{
debug(ex);
Components.utils.reportError("Invalid argument passed to window.sidebar.addSearchEngine: " + ex);
var searchBundle = Services.strings.createBundle("chrome://global/locale/search/search.properties");
var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
var brandName = brandBundle.GetStringFromName("brandShortName");
var title = searchBundle.GetStringFromName("error_invalid_engine_title");
var msg = searchBundle.formatStringFromName("error_invalid_engine_msg",
[brandName], 1);
Services.ww.getNewPrompter(null).alert(title, msg);
return false;
}
return true;
}
// The suggestedTitle and suggestedCategory parameters are ignored, but remain
// for backward compatibility.
nsSidebar.prototype.addSearchEngine =
function (engineURL, iconURL, suggestedTitle, suggestedCategory)
{
debug("addSearchEngine(" + engineURL + ", " + iconURL + ", " +
suggestedCategory + ", " + suggestedTitle + ")");
if (!this.validateSearchEngine(engineURL, iconURL))
return;
// OpenSearch files will likely be far more common than Sherlock files, and
// have less consistent suffixes, so we assume that ".src" is a Sherlock
// (text) file, and anything else is OpenSearch (XML).
var dataType;
if (SHERLOCK_FILE_EXT_REGEXP.test(engineURL))
dataType = Components.interfaces.nsISearchEngine.DATA_TEXT;
else
dataType = Components.interfaces.nsISearchEngine.DATA_XML;
Services.search.addEngine(engineURL, dataType, iconURL, true);
}
// This function exists largely to implement window.external.AddSearchProvider(),
// to match other browsers' APIs. The capitalization, although nonstandard here,
// is therefore important.
nsSidebar.prototype.AddSearchProvider =
function (aDescriptionURL)
{
// Get the favicon URL for the current page, or our best guess at the current
// page since we don't have easy access to the active document. Most search
// engines will override this with an icon specified in the OpenSearch
// description anyway.
var win = Services.wm.getMostRecentWindow("navigator:browser");
var browser = win.gBrowser;
var iconURL = "";
// Use documentURIObject in the check for shouldLoadFavIcon so that we
// do the right thing with about:-style error pages. Bug 453442
if (browser.shouldLoadFavIcon(browser.selectedBrowser
.contentDocument
.documentURIObject))
iconURL = browser.getIcon();
if (!this.validateSearchEngine(aDescriptionURL, iconURL))
return;
const typeXML = Components.interfaces.nsISearchEngine.DATA_XML;
Services.search.addEngine(aDescriptionURL, typeXML, iconURL, true);
}
// This function exists to implement window.external.IsSearchProviderInstalled(),
// for compatibility with other browsers. It will return an integer value
// indicating whether the given engine is installed for the current user.
// However, it is currently stubbed out due to security/privacy concerns
// stemming from difficulties in determining what domain issued the request.
// See bug 340604 and
// http://msdn.microsoft.com/en-us/library/aa342526%28VS.85%29.aspx .
// XXX Implement this!
nsSidebar.prototype.IsSearchProviderInstalled =
function (aSearchURL)
{
return 0;
}
nsSidebar.prototype.QueryInterface = XPCOMUtils.generateQI([Components.interfaces.nsISupports]);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSidebar]);
/* static functions */
if (DEBUG)
debug = function (s) { dump("-*- sidebar component: " + s + "\n"); }
else
debug = function (s) {}

Просмотреть файл

@ -1,2 +0,0 @@
component {22117140-9c6e-11d3-aaf1-00805f8a4905} nsSidebar.js
contract @mozilla.org/sidebar;1 {22117140-9c6e-11d3-aaf1-00805f8a4905}

Просмотреть файл

@ -20,6 +20,12 @@ const RecordingModel = function (options={}) {
this._front = options.front;
this._performance = options.performance;
this._label = options.label || "";
this._configuration = {
withTicks: options.withTicks || false,
withMemory: options.withMemory || false,
withAllocations: options.withAllocations || false
};
};
RecordingModel.prototype = {
@ -29,6 +35,7 @@ RecordingModel.prototype = {
_profilerStartTime: 0,
_timelineStartTime: 0,
_memoryStartTime: 0,
_configuration: {},
// Serializable fields, necessary and sufficient for import and export.
_label: "",
@ -99,12 +106,9 @@ RecordingModel.prototype = {
/**
* Stops recording with the PerformanceFront.
*
* @param object options
* @see RecordingModel.prototype.startRecording
*/
stopRecording: Task.async(function *(options) {
let info = yield this._front.stopRecording(options);
stopRecording: Task.async(function *() {
let info = yield this._front.stopRecording(this.getConfiguration());
this._profile = info.profile;
this._duration = info.profilerEndTime - this._profilerStartTime;
this._recording = false;
@ -143,6 +147,15 @@ RecordingModel.prototype = {
}
},
/**
* Returns configuration object of specifying whether the recording
* was started withTicks, withMemory and withAllocations.
* @return object
*/
getConfiguration: function () {
return this._configuration;
},
/**
* Gets the accumulated markers in the current recording.
* @return array

Просмотреть файл

@ -58,11 +58,10 @@ const BRANCH_NAME = "devtools.performance.ui.";
// Events emitted by various objects in the panel.
const EVENTS = {
// Fired by the OptionsView when a preference changes.
PREF_CHANGED: "Preformance:PrefChanged",
PREF_CHANGED: "Performance:PrefChanged",
// Emitted by the PerformanceController or RecordingView
// when a recording model is selected
RECORDING_SELECTED: "Performance:RecordingSelected",
// Emitted by the PerformanceView when the state (display mode) changes.
UI_STATE_CHANGED: "Performance:UI:StateChanged",
// Emitted by the PerformanceView on clear button click
UI_CLEAR_RECORDINGS: "Performance:UI:ClearRecordings",
@ -82,6 +81,10 @@ const EVENTS = {
RECORDING_WILL_START: "Performance:RecordingWillStart",
RECORDING_WILL_STOP: "Performance:RecordingWillStop",
// Emitted by the PerformanceController or RecordingView
// when a recording model is selected
RECORDING_SELECTED: "Performance:RecordingSelected",
// When recordings have been cleared out
RECORDINGS_CLEARED: "Performance:RecordingsCleared",
@ -220,15 +223,15 @@ let PerformanceController = {
* when the front has started to record.
*/
startRecording: Task.async(function *() {
let recording = this._createRecording();
let withMemory = this.getPref("enable-memory");
let withTicks = this.getPref("enable-framerate");
let withAllocations = true;
let withAllocations = this.getPref("enable-memory");
let recording = this._createRecording({ withMemory, withTicks, withAllocations });
this.emit(EVENTS.RECORDING_WILL_START, recording);
yield recording.startRecording({ withTicks, withMemory, withAllocations });
this.emit(EVENTS.RECORDING_STARTED, recording, { withTicks, withMemory, withAllocations });
this.emit(EVENTS.RECORDING_STARTED, recording);
this.setCurrentRecording(recording);
}),
@ -241,9 +244,7 @@ let PerformanceController = {
let recording = this._getLatestRecording();
this.emit(EVENTS.RECORDING_WILL_STOP, recording);
yield recording.stopRecording({
withAllocations: true
});
yield recording.stopRecording();
this.emit(EVENTS.RECORDING_STOPPED, recording);
}),
@ -295,11 +296,18 @@ let PerformanceController = {
* Creates a new RecordingModel, fires events and stores it
* internally in the controller.
*
* @param object options
* @see PerformanceFront.prototype.startRecording
* @return RecordingModel
* The newly created recording model.
*/
_createRecording: function () {
let recording = new RecordingModel({ front: gFront, performance });
_createRecording: function (options={}) {
let { withMemory, withTicks, withAllocations } = options;
let front = gFront;
let recording = new RecordingModel(
{ front, performance, withMemory, withTicks, withAllocations });
this._recordings.push(recording);
return recording;
},

Просмотреть файл

@ -29,7 +29,7 @@ let PerformanceView = {
/**
* Sets up the view with event binding and main subviews.
*/
initialize: function () {
initialize: Task.async(function* () {
this._recordButton = $("#main-record-button");
this._importButton = $("#import-button");
this._clearButton = $("#clear-button");
@ -59,22 +59,23 @@ let PerformanceView = {
this.setState("empty");
return promise.all([
RecordingsView.initialize(),
OverviewView.initialize(),
ToolbarView.initialize(),
DetailsView.initialize()
]);
},
// Initialize the ToolbarView first, because other views may need access
// to the OptionsView via the controller, to read prefs.
yield ToolbarView.initialize();
yield RecordingsView.initialize();
yield OverviewView.initialize();
yield DetailsView.initialize();
}),
/**
* Unbinds events and destroys subviews.
*/
destroy: function () {
destroy: Task.async(function* () {
for (let button of $$(".record-button")) {
button.removeEventListener("click", this._onRecordButtonClick);
}
this._importButton.removeEventListener("click", this._onImportButtonClick);
this._clearButton.removeEventListener("click", this._onClearButtonClick);
PerformanceController.off(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
PerformanceController.off(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
@ -82,13 +83,11 @@ let PerformanceView = {
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
return promise.all([
RecordingsView.destroy(),
OverviewView.destroy(),
ToolbarView.destroy(),
DetailsView.destroy()
]);
},
yield ToolbarView.destroy();
yield RecordingsView.destroy();
yield OverviewView.destroy();
yield DetailsView.destroy();
}),
/**
* Sets the state of the profiler view. Possible options are "empty",
@ -104,6 +103,7 @@ let PerformanceView = {
}
this._state = state;
this.emit(EVENTS.UI_STATE_CHANGED, state);
},
/**

Просмотреть файл

@ -50,6 +50,11 @@
data-pref="invert-call-tree"
label="&profilerUI.invertTree;"
tooltiptext="&profilerUI.invertTree.tooltiptext;"/>
<menuitem id="option-invert-flame-graph"
type="checkbox"
data-pref="invert-flame-graph"
label="&profilerUI.invertFlameGraph;"
tooltiptext="&profilerUI.invertFlameGraph.tooltiptext;"/>
<menuitem id="option-flatten-tree-recursion"
type="checkbox"
data-pref="flatten-tree-recursion"

Просмотреть файл

@ -21,6 +21,7 @@ support-files =
[browser_perf-details-waterfall-render.js]
[browser_perf-details-01.js]
[browser_perf-details-02.js]
[browser_perf-details-03.js]
[browser_perf-front-basic-profiler-01.js]
[browser_perf-front-basic-timeline-01.js]
#[browser_perf-front-profiler-01.js] bug 1077464
@ -36,13 +37,16 @@ support-files =
[browser_perf-options-02.js]
[browser_perf-options-invert-call-tree-01.js]
[browser_perf-options-invert-call-tree-02.js]
[browser_perf-options-invert-flame-graph-01.js]
[browser_perf-options-invert-flame-graph-02.js]
[browser_perf-options-flatten-tree-recursion-01.js]
[browser_perf-options-flatten-tree-recursion-02.js]
[browser_perf-options-show-platform-data-01.js]
[browser_perf-options-show-platform-data-02.js]
[browser_perf-options-show-idle-blocks-01.js]
[browser_perf-options-show-idle-blocks-02.js]
[browser_perf-options-enable-memory.js]
[browser_perf-options-enable-memory-01.js]
[browser_perf-options-enable-memory-02.js]
[browser_perf-options-enable-framerate.js]
[browser_perf-overview-render-01.js]
[browser_perf-overview-render-02.js]
@ -53,6 +57,7 @@ support-files =
[browser_perf-overview-time-interval.js]
[browser_perf-shared-connection-02.js]
[browser_perf-shared-connection-03.js]
[browser_perf-states.js]
[browser_perf-ui-recording.js]
[browser_perf-recording-notices-01.js]
[browser_perf-recording-notices-02.js]

Просмотреть файл

@ -20,22 +20,19 @@ let TEST_DATA = {
sites: [0, 0, 1, 2, 3],
timestamps: [50, 100, 150, 200, 250],
frames: [
null,
{
null, {
source: "A",
line: 1,
column: 2,
functionDisplayName: "x",
parent: 0
},
{
}, {
source: "B",
line: 3,
column: 4,
functionDisplayName: "y",
parent: 1
},
{
}, {
source: "C",
line: 5,
column: 6,

Просмотреть файл

@ -8,7 +8,7 @@
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, PerformanceView, RecordingsView } = panel.panelWin;
let { EVENTS, PerformanceController, PerformanceView, RecordingsView, OverviewView } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);

Просмотреть файл

@ -14,7 +14,7 @@ function spawnTest () {
let selected = DetailsView.whenViewSelected(JsCallTreeView);
let notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-calltree");
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(JsCallTreeView),
@ -22,7 +22,7 @@ function spawnTest () {
selected = DetailsView.whenViewSelected(JsFlameGraphView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
DetailsView.selectView("js-flamegraph");
yield DetailsView.selectView("js-flamegraph");
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(JsFlameGraphView),
@ -30,7 +30,7 @@ function spawnTest () {
selected = DetailsView.whenViewSelected(WaterfallView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
DetailsView.selectView("waterfall");
yield DetailsView.selectView("waterfall");
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(WaterfallView),

Просмотреть файл

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let MEMORY_PREF = "devtools.performance.ui.enable-memory";
/**
* Tests that the details view hides the memory buttons when `enable-memory` is toggled,
* and that it switches to default panel if toggling while a memory panel is selected.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView } = panel.panelWin;
let { $, WaterfallView, MemoryCallTreeView, MemoryFlameGraphView } = panel.panelWin;
Services.prefs.setBoolPref(MEMORY_PREF, false);
ok(DetailsView.isViewSelected(WaterfallView),
"The waterfall view is selected by default in the details view.");
let flameBtn = $("toolbarbutton[data-view='memory-flamegraph']");
let callBtn = $("toolbarbutton[data-view='memory-calltree']");
is(flameBtn.hidden, true, "memory-flamegraph button hidden when enable-memory=false");
is(callBtn.hidden, true, "memory-calltree button hidden when enable-memory=false");
Services.prefs.setBoolPref(MEMORY_PREF, true);
is(flameBtn.hidden, false, "memory-flamegraph button shown when enable-memory=true");
is(callBtn.hidden, false, "memory-calltree button shown when enable-memory=true");
let selected = DetailsView.whenViewSelected(MemoryCallTreeView);
let notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
DetailsView.selectView("memory-calltree");
yield Promise.all([selected, notified]);
selected = DetailsView.whenViewSelected(WaterfallView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
Services.prefs.setBoolPref(MEMORY_PREF, false);
yield Promise.all([selected, notified]);
ok(DetailsView.isViewSelected(WaterfallView),
"The waterfall view is now selected when toggling off enable-memory when a memory panel is selected.");
Services.prefs.setBoolPref(MEMORY_PREF, true);
selected = DetailsView.whenViewSelected(MemoryFlameGraphView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
DetailsView.selectView("memory-flamegraph");
yield Promise.all([selected, notified]);
selected = DetailsView.whenViewSelected(WaterfallView);
notified = DetailsView.once(EVENTS.DETAILS_VIEW_SELECTED);
Services.prefs.setBoolPref(MEMORY_PREF, false);
yield Promise.all([selected, notified]);
yield teardown(panel);
finish();
}

Просмотреть файл

@ -8,7 +8,7 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-calltree");
ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
yield startRecording(panel);

Просмотреть файл

@ -8,7 +8,7 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
DetailsView.selectView("js-flamegraph");
yield DetailsView.selectView("js-flamegraph");
ok(DetailsView.isViewSelected(JsFlameGraphView), "The flamegraph is now selected.");
yield startRecording(panel);

Просмотреть файл

@ -8,7 +8,7 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
DetailsView.selectView("memory-calltree");
yield DetailsView.selectView("memory-calltree");
ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
yield startRecording(panel);

Просмотреть файл

@ -8,7 +8,7 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
DetailsView.selectView("memory-flamegraph");
yield DetailsView.selectView("memory-flamegraph");
ok(DetailsView.isViewSelected(MemoryFlameGraphView), "The flamegraph is now selected.");
yield startRecording(panel);

Просмотреть файл

@ -10,16 +10,36 @@ let WAIT_TIME = 1000;
function spawnTest () {
let { target, front } = yield initBackend(SIMPLE_URL);
let { profilerStartTime, timelineStartTime } = yield front.startRecording();
let startData = yield front.startRecording();
let { profilerStartTime, timelineStartTime, memoryStartTime } = startData;
ok("profilerStartTime" in startData,
"A `profilerStartTime` property is properly set in the recording data.");
ok("timelineStartTime" in startData,
"A `timelineStartTime` property is properly set in the recording data.");
ok("memoryStartTime" in startData,
"A `memoryStartTime` property is properly set in the recording data.");
ok(profilerStartTime !== undefined,
"A `profilerStartTime` property exists in the recording data.");
ok(timelineStartTime !== undefined,
"A `timelineStartTime` property exists in the recording data.");
is(memoryStartTime, 0,
"A `memoryStartTime` property exists in the recording data, but it's 0.");
yield busyWait(WAIT_TIME);
let { profile, profilerEndTime, timelineEndTime } = yield front.stopRecording();
let stopData = yield front.stopRecording();
let { profile, profilerEndTime, timelineEndTime, memoryEndTime } = stopData;
ok("profile" in stopData,
"A `profile` property is properly set in the recording data.");
ok("profilerEndTime" in stopData,
"A `profilerEndTime` property is properly set in the recording data.");
ok("timelineEndTime" in stopData,
"A `timelineEndTime` property is properly set in the recording data.");
ok("memoryEndTime" in stopData,
"A `memoryEndTime` property is properly set in the recording data.");
ok(profile,
"A `profile` property exists in the recording data.");
@ -27,6 +47,8 @@ function spawnTest () {
"A `profilerEndTime` property exists in the recording data.");
ok(timelineEndTime !== undefined,
"A `timelineEndTime` property exists in the recording data.");
is(memoryEndTime, 0,
"A `memoryEndTime` property exists in the recording data, but it's 0.");
yield removeTab(target.tab);
finish();

Просмотреть файл

@ -28,9 +28,7 @@ function spawnTest () {
front.on("ticks", handler);
yield front.startRecording({ withMemory: true, withTicks: true });
yield Promise.all(Object.keys(deferreds).map(type => deferreds[type].promise));
yield front.stopRecording();
is(counters.markers.length, 1, "one marker event fired.");

Просмотреть файл

@ -2,8 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the performance tool can jump to the debugger, when the source was already
* loaded in that tool.
* Tests if the performance tool can jump to the debugger, when the source was
* already loaded in that tool.
*/
function spawnTest() {

Просмотреть файл

@ -8,7 +8,7 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-calltree");
// Manually call the _onPrefChanged function so we can catch an error
try {

Просмотреть файл

@ -8,7 +8,7 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-calltree");
yield startRecording(panel);

Просмотреть файл

@ -1,8 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const FRAMERATE_PREF = "devtools.performance.ui.enable-framerate";
/**
* Tests that `enable-framerate` toggles the visibility of the fps graph,
* as well as enabling ticks data on the PerformanceFront.
@ -11,20 +9,14 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $ } = panel.panelWin;
let recordedWithTicks = null;
let onStart = (_, recording, { withMemory, withTicks }) => {
recordedWithTicks = withTicks;
};
PerformanceController.on(EVENTS.RECORDING_STARTED, onStart);
Services.prefs.setBoolPref(FRAMERATE_PREF, false);
ok($("#time-framerate").hidden, "fps graph is hidden when ticks disabled");
yield startRecording(panel);
yield stopRecording(panel);
ok(recordedWithTicks === false, "PerformanceFront started without ticks recording.");
is(PerformanceController.getCurrentRecording().getConfiguration().withTicks, false,
"PerformanceFront started without ticks recording.");
Services.prefs.setBoolPref(FRAMERATE_PREF, true);
ok(!$("#time-framerate").hidden, "fps graph is not hidden when ticks enabled");
@ -32,9 +24,9 @@ function spawnTest () {
yield startRecording(panel);
yield stopRecording(panel);
ok(recordedWithTicks === true, "PerformanceFront started with ticks recording.");
is(PerformanceController.getCurrentRecording().getConfiguration().withTicks, true,
"PerformanceFront started with ticks recording.");
PerformanceController.off(EVENTS.RECORDING_STARTED, onStart);
yield teardown(panel);
finish();
}

Просмотреть файл

@ -1,8 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const MEMORY_PREF = "devtools.performance.ui.enable-memory";
/**
* Tests that `enable-memory` toggles the visibility of the memory graph,
* as well as enabling memory data on the PerformanceFront.
@ -11,20 +9,16 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $ } = panel.panelWin;
let recordedWithMemory = null;
let onStart = (_, recording, { withMemory, withTicks }) => {
recordedWithMemory = withMemory;
};
PerformanceController.on(EVENTS.RECORDING_STARTED, onStart);
Services.prefs.setBoolPref(MEMORY_PREF, false);
ok($("#memory-overview").hidden, "memory graph is hidden when memory disabled");
yield startRecording(panel);
yield stopRecording(panel);
ok(recordedWithMemory === false, "PerformanceFront started without memory recording.");
is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, false,
"PerformanceFront started without memory recording.");
is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
"PerformanceFront started without allocations recording.");
Services.prefs.setBoolPref(MEMORY_PREF, true);
ok(!$("#memory-overview").hidden, "memory graph is not hidden when memory enabled");
@ -32,9 +26,11 @@ function spawnTest () {
yield startRecording(panel);
yield stopRecording(panel);
ok(recordedWithMemory === true, "PerformanceFront started with memory recording.");
is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, true,
"PerformanceFront started with memory recording.");
is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, true,
"PerformanceFront started with allocations recording.");
PerformanceController.off(EVENTS.RECORDING_STARTED, onStart);
yield teardown(panel);
finish();
}

Просмотреть файл

@ -0,0 +1,36 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that toggling `enable-memory` during a recording doesn't change that
* recording's state and does not break.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, $ } = panel.panelWin;
// Test starting without memory, and stopping with it.
Services.prefs.setBoolPref(MEMORY_PREF, false);
yield startRecording(panel);
Services.prefs.setBoolPref(MEMORY_PREF, true);
yield stopRecording(panel);
is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, false,
"The recording finished without tracking memory.");
is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, false,
"The recording finished without tracking allocations.");
// Test starting with memory, and stopping without it.
yield startRecording(panel);
Services.prefs.setBoolPref(MEMORY_PREF, false);
yield stopRecording(panel);
is(PerformanceController.getCurrentRecording().getConfiguration().withMemory, true,
"The recording finished with tracking memory.");
is(PerformanceController.getCurrentRecording().getConfiguration().withAllocations, true,
"The recording finished with tracking allocations.");
yield teardown(panel);
finish();
}

Просмотреть файл

@ -1,19 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const FLATTEN_PREF = "devtools.performance.ui.flatten-tree-recursion";
/**
* Tests that the js Flamegraphs gets rerendered when toggling `flatten-tree-recursion`
* Tests that the js flamegraphs get rerendered when toggling `flatten-tree-recursion`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
DetailsView.selectView("js-flamegraph");
let { EVENTS, PerformanceController, DetailsView, JsFlameGraphView } = panel.panelWin;
Services.prefs.setBoolPref(FLATTEN_PREF, true);
yield DetailsView.selectView("js-flamegraph");
yield startRecording(panel);
yield busyWait(100);
@ -21,18 +19,42 @@ function spawnTest () {
yield stopRecording(panel);
yield rendered;
let samples1 = PerformanceController.getCurrentRecording().getProfile().threads[0].samples;
let rendering1 = FlameGraphUtils._cache.get(samples1);
ok(samples1,
"The samples were retrieved from the controller.");
ok(rendering1,
"The rendering data was cached.");
rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(FLATTEN_PREF, false);
yield rendered;
ok(true, "JsFlameGraphView rerendered when toggling flatten-tree-recursion.");
let samples2 = PerformanceController.getCurrentRecording().getProfile().threads[0].samples;
let rendering2 = FlameGraphUtils._cache.get(samples2);
is(samples1, samples2,
"The same samples data should be retrieved from the controller (1).");
isnot(rendering1, rendering2,
"The rendering data should be different because other options were used (1).");
rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(FLATTEN_PREF, true);
yield rendered;
ok(true, "JsFlameGraphView rerendered when toggling back flatten-tree-recursion.");
let samples3 = PerformanceController.getCurrentRecording().getProfile().threads[0].samples;
let rendering3 = FlameGraphUtils._cache.get(samples3);
is(samples2, samples3,
"The same samples data should be retrieved from the controller (2).");
isnot(rendering2, rendering3,
"The rendering data should be different because other options were used (2).");
yield teardown(panel);
finish();
}

Просмотреть файл

@ -1,19 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const FLATTEN_PREF = "devtools.performance.ui.flatten-tree-recursion";
/**
* Tests that the memory Flamegraphs gets rerendered when toggling `flatten-tree-recursion`
* Tests that the memory flamegraphs get rerendered when toggling `flatten-tree-recursion`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
DetailsView.selectView("memory-flamegraph");
let { EVENTS, PerformanceController, DetailsView, MemoryFlameGraphView } = panel.panelWin;
// Enable memory to test
Services.prefs.setBoolPref(MEMORY_PREF, true);
Services.prefs.setBoolPref(FLATTEN_PREF, true);
yield DetailsView.selectView("memory-flamegraph");
yield startRecording(panel);
yield busyWait(100);
@ -21,18 +21,51 @@ function spawnTest () {
yield stopRecording(panel);
yield rendered;
let allocations1 = PerformanceController.getCurrentRecording().getAllocations();
let samples1 = RecordingUtils.getSamplesFromAllocations(allocations1);
let rendering1 = FlameGraphUtils._cache.get(samples1);
ok(allocations1,
"The allocations were retrieved from the controller.");
ok(samples1,
"The samples were retrieved from the utility funcs.");
ok(rendering1,
"The rendering data was cached.");
rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(FLATTEN_PREF, false);
yield rendered;
ok(true, "MemoryFlameGraphView rerendered when toggling flatten-tree-recursion.");
let allocations2 = PerformanceController.getCurrentRecording().getAllocations();
let samples2 = RecordingUtils.getSamplesFromAllocations(allocations2);
let rendering2 = FlameGraphUtils._cache.get(samples2);
is(allocations1, allocations2,
"The same allocations data should be retrieved from the controller (1).");
is(samples1, samples2,
"The same samples data should be retrieved from the utility funcs. (1).");
isnot(rendering1, rendering2,
"The rendering data should be different because other options were used (1).");
rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(FLATTEN_PREF, true);
yield rendered;
ok(true, "MemoryFlameGraphView rerendered when toggling back flatten-tree-recursion.");
let allocations3 = PerformanceController.getCurrentRecording().getAllocations();
let samples3 = RecordingUtils.getSamplesFromAllocations(allocations3);
let rendering3 = FlameGraphUtils._cache.get(samples3);
is(allocations2, allocations3,
"The same allocations data should be retrieved from the controller (2).");
is(samples2, samples3,
"The same samples data should be retrieved from the utility funcs. (2).");
isnot(rendering2, rendering3,
"The rendering data should be different because other options were used (2).");
yield teardown(panel);
finish();
}

Просмотреть файл

@ -1,11 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const INVERT_PREF = "devtools.performance.ui.invert-call-tree";
/**
* Tests that the js call tree view is re-rendered after the
* "invert-call-tree" pref is changed.
* Tests that the js call tree views get rerendered when toggling `invert-call-tree`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
@ -13,7 +10,7 @@ function spawnTest () {
Services.prefs.setBoolPref(INVERT_PREF, true);
DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-calltree");
ok(DetailsView.isViewSelected(JsCallTreeView), "The call tree is now selected.");
yield startRecording(panel);

Просмотреть файл

@ -1,19 +1,18 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const INVERT_PREF = "devtools.performance.ui.invert-call-tree";
/**
* Tests that the memory call tree view is re-rendered after the
* "invert-call-tree" pref is changed.
* Tests that the memory call tree views get rerendered when toggling `invert-call-tree`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryCallTreeView } = panel.panelWin;
// Enable memory to test
Services.prefs.setBoolPref(MEMORY_PREF, true);
Services.prefs.setBoolPref(INVERT_PREF, true);
DetailsView.selectView("memory-calltree");
yield DetailsView.selectView("memory-calltree");
ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
yield startRecording(panel);

Просмотреть файл

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const INVERT_PREF = "devtools.performance.ui.invert-flame-graph";
/**
* Tests that the js Flamegraphs gets rerendered when toggling `invert-flame-graph`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
yield DetailsView.selectView("js-flamegraph");
Services.prefs.setBoolPref(INVERT_PREF, true);
yield startRecording(panel);
yield busyWait(100);
let rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(INVERT_PREF, false);
yield rendered;
ok(true, "JsFlameGraphView rerendered when toggling invert-flame-graph.");
rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(INVERT_PREF, true);
yield rendered;
ok(true, "JsFlameGraphView rerendered when toggling back invert-flame-graph.");
yield teardown(panel);
finish();
}

Просмотреть файл

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const INVERT_PREF = "devtools.performance.ui.invert-flame-graph";
/**
* Tests that the memory Flamegraphs gets rerendered when toggling `invert-flame-graph`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
yield DetailsView.selectView("memory-flamegraph");
Services.prefs.setBoolPref(INVERT_PREF, true);
yield startRecording(panel);
yield busyWait(100);
let rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
yield stopRecording(panel);
yield rendered;
rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(INVERT_PREF, false);
yield rendered;
ok(true, "MemoryFlameGraphView rerendered when toggling invert-flame-graph.");
rendered = once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED);
Services.prefs.setBoolPref(INVERT_PREF, true);
yield rendered;
ok(true, "MemoryFlameGraphView rerendered when toggling back invert-flame-graph.");
yield teardown(panel);
finish();
}

Просмотреть файл

@ -1,19 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const IDLE_PREF = "devtools.performance.ui.show-idle-blocks";
/**
* Tests that the js Flamegraphs gets rerendered when toggling `show-idle-blocks`
* Tests that the js flamegraphs get rerendered when toggling `show-idle-blocks`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
DetailsView.selectView("js-flamegraph");
Services.prefs.setBoolPref(IDLE_PREF, true);
yield DetailsView.selectView("js-flamegraph");
yield startRecording(panel);
yield busyWait(100);

Просмотреть файл

@ -1,19 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const IDLE_PREF = "devtools.performance.ui.show-idle-blocks";
/**
* Tests that the memory Flamegraphs gets rerendered when toggling `show-idle-blocks`
* Tests that the memory flamegraphs get rerendered when toggling `show-idle-blocks`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, MemoryFlameGraphView } = panel.panelWin;
DetailsView.selectView("memory-flamegraph");
// Enable memory to test
Services.prefs.setBoolPref(MEMORY_PREF, true);
Services.prefs.setBoolPref(IDLE_PREF, true);
yield DetailsView.selectView("memory-flamegraph");
yield startRecording(panel);
yield busyWait(100);

Просмотреть файл

@ -1,19 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
/**
* Tests that the JsCallTree get rerendered when toggling `show-platform-data`
* Tests that the js call tree views get rerendered when toggling `show-platform-data`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView, JsCallTreeView } = panel.panelWin;
DetailsView.selectView("js-calltree");
let { EVENTS, DetailsView, JsCallTreeView } = panel.panelWin;
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
yield DetailsView.selectView("js-calltree");
yield startRecording(panel);
yield busyWait(100);

Просмотреть файл

@ -1,17 +1,16 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
/**
* Tests that the JsFlamegraphs get rerendered when toggling `show-platform-data`
* Tests that the js flamegraphs get rerendered when toggling `show-platform-data`
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, DetailsView, JsFlameGraphView } = panel.panelWin;
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
DetailsView.selectView("js-flamegraph");
yield DetailsView.selectView("js-flamegraph");
yield startRecording(panel);
yield busyWait(100);

Просмотреть файл

@ -8,6 +8,9 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
// Enable memory to test all the overview graphs.
Services.prefs.setBoolPref(MEMORY_PREF, true);
yield startRecording(panel);
yield Promise.all([

Просмотреть файл

@ -9,8 +9,18 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
// Enable memory to test all the overview graphs.
Services.prefs.setBoolPref(MEMORY_PREF, true);
yield startRecording(panel);
yield Promise.all([
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
]);
ok("selectionEnabled" in OverviewView.framerateGraph,
"The selection should not be enabled for the framerate overview (1).");
is(OverviewView.framerateGraph.selectionEnabled, false,

Просмотреть файл

@ -8,8 +8,8 @@ function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, OverviewView } = panel.panelWin;
Services.prefs.setBoolPref("devtools.performance.ui.enable-memory", true);
Services.prefs.setBoolPref("devtools.performance.ui.enable-framerate", true);
// Enable memory to test all the overview graphs.
Services.prefs.setBoolPref(MEMORY_PREF, true);
yield startRecording(panel);
@ -24,9 +24,6 @@ function spawnTest () {
yield stopRecording(panel);
// Wait for the overview graph to be rerendered *after* recording.
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
ok(OverviewView.markersOverview.width > 0,
"The overview's framerate graph has a width.");
ok(OverviewView.markersOverview.dataScaleX > 0,

Просмотреть файл

@ -11,14 +11,14 @@ function spawnTest () {
yield startRecording(panel);
// Wait for the overview graph to be rendered while recording.
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
yield Promise.all([
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED)
]);
yield stopRecording(panel);
// Wait for the overview graph to be rerendered *after* recording.
yield once(OverviewView, EVENTS.OVERVIEW_RENDERED);
let graph = OverviewView.markersOverview;
let MAX = graph.width;

Просмотреть файл

@ -7,12 +7,30 @@
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
let framerateGraph = OverviewView.framerateGraph;
let markersOverview = OverviewView.markersOverview;
let memoryOverview = OverviewView.memoryOverview;
// Enable memory to test all the overview graphs.
Services.prefs.setBoolPref(MEMORY_PREF, true);
yield startRecording(panel);
yield Promise.all([
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
]);
let markersOverview = OverviewView.markersOverview;
let memoryOverview = OverviewView.memoryOverview;
let framerateGraph = OverviewView.framerateGraph;
ok(markersOverview,
"The markers graph should have been created now.");
ok(memoryOverview,
"The memory graph should have been created now.");
ok(framerateGraph,
"The framerate graph should have been created now.");
ok(!framerateGraph.selectionEnabled,
"Selection shouldn't be enabled when the first recording started (1).");
ok(!markersOverview.selectionEnabled,
@ -31,6 +49,13 @@ function spawnTest () {
yield startRecording(panel);
yield Promise.all([
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
]);
ok(!framerateGraph.selectionEnabled,
"Selection shouldn't be enabled when the second recording started (1).");
ok(!markersOverview.selectionEnabled,

Просмотреть файл

@ -7,15 +7,26 @@
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, OverviewView } = panel.panelWin;
// Enable memory to test all the overview graphs.
Services.prefs.setBoolPref(MEMORY_PREF, true);
yield startRecording(panel);
yield Promise.all([
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.MEMORY_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
]);
yield stopRecording(panel);
let framerateGraph = OverviewView.framerateGraph;
let markersOverview = OverviewView.markersOverview;
let memoryOverview = OverviewView.memoryOverview;
let MAX = framerateGraph.width;
yield startRecording(panel);
yield stopRecording(panel);
// Perform a selection inside the framerate graph.
let selected = once(OverviewView, EVENTS.OVERVIEW_RANGE_SELECTED);

Просмотреть файл

@ -24,11 +24,14 @@ function spawnTest () {
}
yield startRecording(panel);
busyWait(100);
let rendered = once(OverviewView, EVENTS.OVERVIEW_RENDERED);
yield Promise.all([
once(OverviewView, EVENTS.FRAMERATE_GRAPH_RENDERED),
once(OverviewView, EVENTS.MARKERS_GRAPH_RENDERED),
once(OverviewView, EVENTS.OVERVIEW_RENDERED)
]);
yield stopRecording(panel);
yield rendered;
// Get/set the time interval and wait for the event propagation.

Просмотреть файл

@ -27,12 +27,12 @@ function spawnTest () {
ok(true, "Waterfall rerenders when a range in the overview graph is selected.");
rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-calltree");
yield rendered;
ok(true, "Call tree rerenders after its corresponding pane is shown.");
rendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
DetailsView.selectView("js-flamegraph");
yield DetailsView.selectView("js-flamegraph");
yield rendered;
ok(true, "Flamegraph rerenders after its corresponding pane is shown.");
@ -42,12 +42,12 @@ function spawnTest () {
ok(true, "Flamegraph rerenders when a range in the overview graph is removed.");
rendered = once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED);
DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-calltree");
yield rendered;
ok(true, "Call tree rerenders after its corresponding pane is shown.");
rendered = once(WaterfallView, EVENTS.WATERFALL_RENDERED);
DetailsView.selectView("waterfall");
yield DetailsView.selectView("waterfall");
yield rendered;
ok(true, "Waterfall rerenders after its corresponding pane is shown.");

Просмотреть файл

@ -8,10 +8,23 @@
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, PerformanceController, DetailsSubview, RecordingsView } = panel.panelWin;
let { $, EVENTS, PerformanceController, DetailsView, DetailsSubview, RecordingsView } = panel.panelWin;
// Enable memory to test the memory-calltree and memory-flamegraph.
Services.prefs.setBoolPref(MEMORY_PREF, true);
// Need to allow widgets to be updated while hidden, otherwise we can't use
// `waitForWidgetsRendered`.
DetailsSubview.canUpdateWhileHidden = true;
// Cycle through all the views to initialize them, otherwise we can't use
// `waitForWidgetsRendered`. The waterfall is shown by default, but all the
// other views are created lazily, so won't emit any events.
yield DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-flamegraph");
yield DetailsView.selectView("memory-calltree");
yield DetailsView.selectView("memory-flamegraph");
yield startRecording(panel);
yield stopRecording(panel);

Просмотреть файл

@ -0,0 +1,95 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that view states and lazy component intialization works.
*/
function spawnTest () {
let { panel } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceView, OverviewView, DetailsView } = panel.panelWin;
is(PerformanceView.getState(), "empty",
"The intial state of the performance panel view is correct.");
ok(!("markersOverview" in OverviewView),
"The markers graph should not have been created yet.");
ok(!("memoryOverview" in OverviewView),
"The memory graph should not have been created yet.");
ok(!("framerateGraph" in OverviewView),
"The framerate graph should not have been created yet.");
ok(DetailsView.components["waterfall"].initialized,
"The waterfall detail view should have been created by default.");
ok(!DetailsView.components["js-calltree"].initialized,
"The js-calltree detail view should not have been created yet.");
ok(!DetailsView.components["js-flamegraph"].initialized,
"The js-flamegraph detail view should not have been created yet.");
ok(!DetailsView.components["memory-calltree"].initialized,
"The memory-calltree detail view should not have been created yet.");
ok(!DetailsView.components["memory-flamegraph"].initialized,
"The memory-flamegraph detail view should not have been created yet.");
Services.prefs.setBoolPref(MEMORY_PREF, true);
ok(!("markersOverview" in OverviewView),
"The markers graph should still not have been created yet.");
ok(!("memoryOverview" in OverviewView),
"The memory graph should still not have been created yet.");
ok(!("framerateGraph" in OverviewView),
"The framerate graph should still not have been created yet.");
let stateChanged = once(PerformanceView, EVENTS.UI_STATE_CHANGED);
yield startRecording(panel);
yield stateChanged;
is(PerformanceView.getState(), "recording",
"The current state of the performance panel view is 'recording'.");
ok(OverviewView.memoryOverview,
"The memory graph should have been created now.");
ok(OverviewView.framerateGraph,
"The framerate graph should have been created now.");
stateChanged = once(PerformanceView, EVENTS.UI_STATE_CHANGED);
yield stopRecording(panel);
yield stateChanged;
is(PerformanceView.getState(), "recorded",
"The current state of the performance panel view is 'recorded'.");
ok(!DetailsView.components["js-calltree"].initialized,
"The js-calltree detail view should still not have been created yet.");
ok(!DetailsView.components["js-flamegraph"].initialized,
"The js-flamegraph detail view should still not have been created yet.");
ok(!DetailsView.components["memory-calltree"].initialized,
"The memory-calltree detail view should still not have been created yet.");
ok(!DetailsView.components["memory-flamegraph"].initialized,
"The memory-flamegraph detail view should still not have been created yet.");
yield DetailsView.selectView("js-calltree");
is(PerformanceView.getState(), "recorded",
"The current state of the performance panel view is still 'recorded'.");
ok(DetailsView.components["js-calltree"].initialized,
"The js-calltree detail view should still have been created now.");
ok(!DetailsView.components["js-flamegraph"].initialized,
"The js-flamegraph detail view should still not have been created yet.");
ok(!DetailsView.components["memory-calltree"].initialized,
"The memory-calltree detail view should still not have been created yet.");
ok(!DetailsView.components["memory-flamegraph"].initialized,
"The memory-flamegraph detail view should still not have been created yet.");
yield DetailsView.selectView("memory-calltree");
is(PerformanceView.getState(), "recorded",
"The current state of the performance panel view is still 'recorded'.");
ok(DetailsView.components["js-calltree"].initialized,
"The js-calltree detail view should still register as being created.");
ok(!DetailsView.components["js-flamegraph"].initialized,
"The js-flamegraph detail view should still not have been created yet.");
ok(DetailsView.components["memory-calltree"].initialized,
"The memory-calltree detail view should still have been created now.");
ok(!DetailsView.components["memory-flamegraph"].initialized,
"The memory-flamegraph detail view should still not have been created yet.");
yield teardown(panel);
finish();
}

Просмотреть файл

@ -7,8 +7,21 @@
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, DetailsSubview } = panel.panelWin;
let { EVENTS, PerformanceController, DetailsView, DetailsSubview } = panel.panelWin;
// Enable memory to test the memory-calltree and memory-flamegraph.
Services.prefs.setBoolPref(MEMORY_PREF, true);
// Cycle through all the views to initialize them, otherwise we can't use
// `waitForWidgetsRendered`. The waterfall is shown by default, but all the
// other views are created lazily, so won't emit any events.
yield DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-flamegraph");
yield DetailsView.selectView("memory-calltree");
yield DetailsView.selectView("memory-flamegraph");
// Need to allow widgets to be updated while hidden, otherwise we can't use
// `waitForWidgetsRendered`.
DetailsSubview.canUpdateWhileHidden = true;
yield startRecording(panel);

Просмотреть файл

@ -8,8 +8,21 @@
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
let { EVENTS, PerformanceController, DetailsSubview } = panel.panelWin;
let { EVENTS, PerformanceController, DetailsView, DetailsSubview } = panel.panelWin;
// Enable memory to test the memory-calltree and memory-flamegraph.
Services.prefs.setBoolPref(MEMORY_PREF, true);
// Cycle through all the views to initialize them, otherwise we can't use
// `waitForWidgetsRendered`. The waterfall is shown by default, but all the
// other views are created lazily, so won't emit any events.
yield DetailsView.selectView("js-calltree");
yield DetailsView.selectView("js-flamegraph");
yield DetailsView.selectView("memory-calltree");
yield DetailsView.selectView("memory-flamegraph");
// Need to allow widgets to be updated while hidden, otherwise we can't use
// `waitForWidgetsRendered`.
DetailsSubview.canUpdateWhileHidden = true;
yield startRecording(panel);

Просмотреть файл

@ -22,6 +22,13 @@ const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-u
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/performance/test/";
const SIMPLE_URL = EXAMPLE_URL + "doc_simple-test.html";
const FRAMERATE_PREF = "devtools.performance.ui.enable-framerate";
const MEMORY_PREF = "devtools.performance.ui.enable-memory";
const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
const IDLE_PREF = "devtools.performance.ui.show-idle-blocks";
const INVERT_PREF = "devtools.performance.ui.invert-call-tree";
const FLATTEN_PREF = "devtools.performance.ui.flatten-tree-recursion";
// All tests are asynchronous.
waitForExplicitFinish();
@ -248,12 +255,10 @@ function* startRecording(panel) {
ok(!button.hasAttribute("checked"),
"The record button should not be checked yet.");
ok(!button.hasAttribute("locked"),
"The record button should not be locked yet.");
click(win, button);
yield clicked;
ok(button.hasAttribute("checked"),
@ -262,7 +267,16 @@ function* startRecording(panel) {
"The record button should be locked.");
yield willStart;
let stateChanged = once(win.PerformanceView, win.EVENTS.UI_STATE_CHANGED);
yield hasStarted;
let overviewRendered = once(win.OverviewView, win.EVENTS.OVERVIEW_RENDERED);
yield stateChanged;
yield overviewRendered;
is(win.PerformanceView.getState(), "recording",
"The current state is 'recording'.");
ok(button.hasAttribute("checked"),
"The record button should still be checked.");
@ -283,7 +297,6 @@ function* stopRecording(panel) {
"The record button should not be locked yet.");
click(win, button);
yield clicked;
ok(!button.hasAttribute("checked"),
@ -292,7 +305,16 @@ function* stopRecording(panel) {
"The record button should be locked.");
yield willStop;
let stateChanged = once(win.PerformanceView, win.EVENTS.UI_STATE_CHANGED);
yield hasStopped;
let overviewRendered = once(win.OverviewView, win.EVENTS.OVERVIEW_RENDERED);
yield stateChanged;
yield overviewRendered;
is(win.PerformanceView.getState(), "recorded",
"The current state is 'recorded'.");
ok(!button.hasAttribute("checked"),
"The record button should not be checked.");
@ -306,7 +328,9 @@ function waitForWidgetsRendered(panel) {
OverviewView,
WaterfallView,
JsCallTreeView,
JsFlameGraphView
JsFlameGraphView,
MemoryCallTreeView,
MemoryFlameGraphView,
} = panel.panelWin;
return Promise.all([
@ -316,7 +340,9 @@ function waitForWidgetsRendered(panel) {
once(OverviewView, EVENTS.OVERVIEW_RENDERED),
once(WaterfallView, EVENTS.WATERFALL_RENDERED),
once(JsCallTreeView, EVENTS.JS_CALL_TREE_RENDERED),
once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED)
once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED),
once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED),
once(MemoryFlameGraphView, EVENTS.MEMORY_FLAMEGRAPH_RENDERED),
]);
}

Просмотреть файл

@ -102,11 +102,10 @@ let DetailsSubview = {
/**
* Fired when a preference in `devtools.performance.ui.` is changed.
*/
_onPrefChanged: function (_, prefName, value) {
_onPrefChanged: function (_, prefName) {
// All detail views require a recording to be complete, so do not
// attempt to render if recording is in progress or does not exist.
let recording = PerformanceController.getCurrentRecording();
if (!recording || recording.isRecording()) {
return;
}
@ -115,6 +114,10 @@ let DetailsSubview = {
return;
}
if (this._onRerenderPrefChanged) {
this._onRerenderPrefChanged();
}
if (DetailsView.isViewSelected(this) || this.canUpdateWhileHidden) {
this.render(OverviewView.getTimeInterval());
} else {

Просмотреть файл

@ -8,7 +8,10 @@
*/
let JsCallTreeView = Heritage.extend(DetailsSubview, {
rerenderPrefs: ["invert-call-tree", "show-platform-data"],
rerenderPrefs: [
"invert-call-tree",
"show-platform-data"
],
rangeChangeDebounceTime: 50, // ms

Просмотреть файл

@ -9,7 +9,12 @@
*/
let JsFlameGraphView = Heritage.extend(DetailsSubview, {
rerenderPrefs: ["flatten-tree-recursion", "show-platform-data", "show-idle-blocks"],
rerenderPrefs: [
"invert-flame-graph",
"flatten-tree-recursion",
"show-platform-data",
"show-idle-blocks"
],
/**
* Sets up the view with event binding.
@ -48,6 +53,7 @@ let JsFlameGraphView = Heritage.extend(DetailsSubview, {
let samples = profile.threads[0].samples;
let data = FlameGraphUtils.createFlameGraphDataFromSamples(samples, {
invertStack: PerformanceController.getPref("invert-flame-graph"),
flattenRecursion: PerformanceController.getPref("flatten-tree-recursion"),
filterFrames: !PerformanceController.getPref("show-platform-data") && FrameNode.isContent,
showIdleBlocks: PerformanceController.getPref("show-idle-blocks") && L10N.getStr("table.idle")
@ -73,5 +79,15 @@ let JsFlameGraphView = Heritage.extend(DetailsSubview, {
_onRangeChangeInGraph: function () {
let interval = this.graph.getViewRange();
OverviewView.setTimeInterval(interval, { stopPropagation: true });
},
/**
* Called whenever a pref is changed and this view needs to be rerendered.
*/
_onRerenderPrefChanged: function() {
let recording = PerformanceController.getCurrentRecording();
let profile = recording.getProfile();
let samples = profile.threads[0].samples;
FlameGraphUtils.removeFromCache(samples);
}
});

Просмотреть файл

@ -8,7 +8,9 @@
*/
let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
rerenderPrefs: ["invert-call-tree", "show-platform-data"],
rerenderPrefs: [
"invert-call-tree"
],
rangeChangeDebounceTime: 100, // ms
@ -60,11 +62,10 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
*/
_prepareCallTree: function (allocations, { startTime, endTime }, options) {
let samples = RecordingUtils.getSamplesFromAllocations(allocations);
let contentOnly = !PerformanceController.getPref("show-platform-data");
let invertTree = PerformanceController.getPref("invert-call-tree");
let threadNode = new ThreadNode(samples,
{ startTime, endTime, contentOnly, invertTree });
{ startTime, endTime, invertTree });
// If we have an empty profile (no samples), then don't invert the tree, as
// it would hide the root node and a completely blank call tree space can be
@ -101,5 +102,4 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
// Memory allocation samples don't contain cateogry labels.
root.toggleCategories(false);
}
});

Просмотреть файл

@ -9,7 +9,11 @@
*/
let MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
rerenderPrefs: ["flatten-tree-recursion", "show-idle-blocks"],
rerenderPrefs: [
"invert-flame-graph",
"flatten-tree-recursion",
"show-idle-blocks"
],
/**
* Sets up the view with event binding.
@ -48,6 +52,7 @@ let MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
let samples = RecordingUtils.getSamplesFromAllocations(allocations);
let data = FlameGraphUtils.createFlameGraphDataFromSamples(samples, {
invertStack: PerformanceController.getPref("invert-flame-graph"),
flattenRecursion: PerformanceController.getPref("flatten-tree-recursion"),
showIdleBlocks: PerformanceController.getPref("show-idle-blocks") && L10N.getStr("table.idle")
});
@ -72,5 +77,15 @@ let MemoryFlameGraphView = Heritage.extend(DetailsSubview, {
_onRangeChangeInGraph: function () {
let interval = this.graph.getViewRange();
OverviewView.setTimeInterval(interval, { stopPropagation: true });
},
/**
* Called whenever a pref is changed and this view needs to be rerendered.
*/
_onRerenderPrefChanged: function() {
let recording = PerformanceController.getCurrentRecording();
let allocations = recording.getAllocations();
let samples = RecordingUtils.getSamplesFromAllocations(allocations);
FlameGraphUtils.removeFromCache(samples);
}
});

Просмотреть файл

@ -7,6 +7,7 @@
* Waterfall view containing the timeline markers, controlled by DetailsView.
*/
let WaterfallView = Heritage.extend(DetailsSubview, {
rangeChangeDebounceTime: 10, // ms
/**
@ -18,12 +19,9 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
this.waterfall = new Waterfall($("#waterfall-breakdown"), $("#details-pane"), TIMELINE_BLUEPRINT);
this.details = new MarkerDetails($("#waterfall-details"), $("#waterfall-view > splitter"));
this._onRecordingStarted = this._onRecordingStarted.bind(this);
this._onMarkerSelected = this._onMarkerSelected.bind(this);
this._onResize = this._onResize.bind(this);
PerformanceController.on(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
this.waterfall.on("selected", this._onMarkerSelected);
this.waterfall.on("unselected", this._onMarkerSelected);
this.details.on("resize", this._onResize);
@ -37,8 +35,6 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
destroy: function () {
DetailsSubview.destroy.call(this);
PerformanceController.off(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
this.waterfall.off("selected", this._onMarkerSelected);
this.waterfall.off("unselected", this._onMarkerSelected);
this.details.off("resize", this._onResize);
@ -59,13 +55,6 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
this.emit(EVENTS.WATERFALL_RENDERED);
},
/**
* Called when recording starts.
*/
_onRecordingStarted: function () {
this.waterfall.clearView();
},
/**
* Called when a marker is selected in the waterfall view,
* updating the markers detail view.

Просмотреть файл

@ -17,8 +17,8 @@ let DetailsView = {
"waterfall": { id: "waterfall-view", view: WaterfallView },
"js-calltree": { id: "js-calltree-view", view: JsCallTreeView },
"js-flamegraph": { id: "js-flamegraph-view", view: JsFlameGraphView },
"memory-calltree": { id: "memory-calltree-view", view: MemoryCallTreeView },
"memory-flamegraph": { id: "memory-flamegraph-view", view: MemoryFlameGraphView }
"memory-calltree": { id: "memory-calltree-view", view: MemoryCallTreeView, pref: "enable-memory" },
"memory-flamegraph": { id: "memory-flamegraph-view", view: MemoryFlameGraphView, pref: "enable-memory" }
},
/**
@ -29,16 +29,16 @@ let DetailsView = {
this.toolbar = $("#performance-toolbar-controls-detail-views");
this._onViewToggle = this._onViewToggle.bind(this);
this.setAvailableViews = this.setAvailableViews.bind(this);
for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
button.addEventListener("command", this._onViewToggle);
}
for (let [_, { view }] of Iterator(this.components)) {
yield view.initialize();
}
yield this.selectView(DEFAULT_DETAILS_SUBVIEW);
this.setAvailableViews();
this.selectView(DEFAULT_DETAILS_SUBVIEW);
PerformanceController.on(EVENTS.PREF_CHANGED, this.setAvailableViews);
}),
/**
@ -49,11 +49,34 @@ let DetailsView = {
button.removeEventListener("command", this._onViewToggle);
}
for (let [_, { view }] of Iterator(this.components)) {
yield view.destroy();
for (let [_, component] of Iterator(this.components)) {
component.initialized && (yield component.view.destroy());
}
PerformanceController.off(EVENTS.PREF_CHANGED, this.setAvailableViews);
}),
/**
* Sets the possible views based off of prefs by hiding/showing the
* buttons that select them and going to default view if currently selected.
* Called when a preference changes in `devtools.performance.ui.`.
*/
setAvailableViews: function () {
for (let [name, { view, pref }] of Iterator(this.components)) {
if (!pref) {
continue;
}
let value = PerformanceController.getPref(pref);
$(`toolbarbutton[data-view=${name}]`).hidden = !value;
// If the view is currently selected and not enabled, go back to the
// default view.
if (!value && this.isViewSelected(view)) {
this.selectView(DEFAULT_DETAILS_SUBVIEW);
}
}
},
/**
* Select one of the DetailView's subviews to be rendered,
* hiding the others.
@ -61,8 +84,11 @@ let DetailsView = {
* @param String viewName
* Name of the view to be shown.
*/
selectView: function (viewName) {
this.el.selectedPanel = $("#" + this.components[viewName].id);
selectView: Task.async(function *(viewName) {
let component = this.components[viewName];
this.el.selectedPanel = $("#" + component.id);
yield this._whenViewInitialized(component);
for (let button of $$("toolbarbutton[data-view]", this.toolbar)) {
if (button.getAttribute("data-view") === viewName) {
@ -73,7 +99,7 @@ let DetailsView = {
}
this.emit(EVENTS.DETAILS_VIEW_SELECTED, viewName);
},
}),
/**
* Checks if the provided view is currently selected.
@ -109,6 +135,30 @@ let DetailsView = {
return this.whenViewSelected(viewObject);
}),
/**
* Initializes a subview if it wasn't already set up, and makes sure
* it's populated with recording data if there is some available.
*
* @param object component
* A component descriptor from DetailsView.components
*/
_whenViewInitialized: Task.async(function *(component) {
if (component.initialized) {
return;
}
component.initialized = true;
yield component.view.initialize();
// If this view is initialized *after* a recording is shown, it won't display
// any data. Make sure it's populated by setting `shouldUpdateWhenShown`.
// All detail views require a recording to be complete, so do not
// attempt to render if recording is in progress or does not exist.
let recording = PerformanceController.getCurrentRecording();
if (recording && !recording.isRecording()) {
component.view.shouldUpdateWhenShown = true;
}
}),
/**
* Called when a view button is clicked.
*/

Просмотреть файл

@ -25,7 +25,7 @@ let OverviewView = {
/**
* Sets up the view with event binding.
*/
initialize: Task.async(function *() {
initialize: function () {
this._onRecordingWillStart = this._onRecordingWillStart.bind(this);
this._onRecordingStarted = this._onRecordingStarted.bind(this);
this._onRecordingWillStop = this._onRecordingWillStop.bind(this);
@ -35,39 +35,25 @@ let OverviewView = {
this._onGraphSelecting = this._onGraphSelecting.bind(this);
this._onPrefChanged = this._onPrefChanged.bind(this);
yield this._showMarkersGraph();
yield this._showMemoryGraph();
yield this._showFramerateGraph();
this.markersOverview.on("selecting", this._onGraphSelecting);
PerformanceController.on(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
// Toggle the initial state of memory and framerate graph based off of
// the prefs.
// Toggle the initial visibility of memory and framerate graph containers
// based off of prefs.
$("#memory-overview").hidden = !PerformanceController.getPref("enable-memory");
$("#time-framerate").hidden = !PerformanceController.getPref("enable-framerate");
PerformanceController.on(EVENTS.PREF_CHANGED, this._onPrefChanged);
PerformanceController.on(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
PerformanceController.on(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.on(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
// Populate this overview with some dummy initial data.
this.markersOverview.setData({ duration: 1000, markers: [] });
this.memoryOverview.setData([]);
this.framerateGraph.setData([]);
}),
},
/**
* Unbinds events.
*/
destroy: function () {
this.markersOverview.off("selecting", this._onGraphSelecting);
PerformanceController.off(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
PerformanceController.off(EVENTS.PREF_CHANGED, this._onPrefChanged);
PerformanceController.off(EVENTS.RECORDING_WILL_START, this._onRecordingWillStart);
PerformanceController.off(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.off(EVENTS.RECORDING_WILL_STOP, this._onRecordingWillStop);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
@ -111,43 +97,64 @@ let OverviewView = {
},
/**
* Sets up the framerate graph.
* Sets up the markers overivew graph, if needed.
*
* @return object
* A promise resolved to `true` when the graph was initialized.
*/
_showFramerateGraph: Task.async(function *() {
this.framerateGraph = new LineGraphWidget($("#time-framerate"), {
metric: L10N.getStr("graphs.fps")
});
this.framerateGraph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
yield this.framerateGraph.ready();
}),
/**
* Sets up the markers overivew graph.
*/
_showMarkersGraph: Task.async(function *() {
_markersGraphAvailable: Task.async(function *() {
if (this.markersOverview) {
yield this.markersOverview.ready();
return true;
}
this.markersOverview = new MarkersOverview($("#markers-overview"), TIMELINE_BLUEPRINT);
this.markersOverview.headerHeight = MARKERS_GRAPH_HEADER_HEIGHT;
this.markersOverview.rowHeight = MARKERS_GRAPH_ROW_HEIGHT;
this.markersOverview.groupPadding = MARKERS_GROUP_VERTICAL_PADDING;
this.markersOverview.on("selecting", this._onGraphSelecting);
yield this.markersOverview.ready();
return true;
}),
/**
* Sets up the memory overview graph.
* Sets up the memory overview graph, if allowed and needed.
*
* @return object
* A promise resolved to `true` if the graph was initialized and is
* ready to use, `false` if the graph is disabled.
*/
_showMemoryGraph: Task.async(function *() {
_memoryGraphAvailable: Task.async(function *() {
if (!PerformanceController.getPref("enable-memory")) {
return false;
}
if (this.memoryOverview) {
yield this.memoryOverview.ready();
return true;
}
this.memoryOverview = new MemoryOverview($("#memory-overview"));
this.memoryOverview.fixedHeight = MEMORY_GRAPH_HEIGHT;
yield this.memoryOverview.ready();
CanvasGraphUtils.linkAnimation(this.markersOverview, this.memoryOverview);
CanvasGraphUtils.linkSelection(this.markersOverview, this.memoryOverview);
return true;
}),
/**
* Sets up the framerate graph.
* Sets up the framerate graph, if allowed and needed.
*
* @return object
* A promise resolved to `true` if the graph was initialized and is
* ready to use, `false` if the graph is disabled.
*/
_showFramerateGraph: Task.async(function *() {
_framerateGraphAvailable: Task.async(function *() {
if (!PerformanceController.getPref("enable-framerate")) {
return false;
}
if (this.framerateGraph) {
yield this.framerateGraph.ready();
return true;
}
let metric = L10N.getStr("graphs.fps");
this.framerateGraph = new LineGraphWidget($("#time-framerate"), { metric });
this.framerateGraph.fixedHeight = FRAMERATE_GRAPH_HEIGHT;
@ -155,6 +162,7 @@ let OverviewView = {
CanvasGraphUtils.linkAnimation(this.markersOverview, this.framerateGraph);
CanvasGraphUtils.linkSelection(this.markersOverview, this.framerateGraph);
return true;
}),
/**
@ -171,16 +179,16 @@ let OverviewView = {
let timestamps = recording.getTicks();
// Empty or older recordings might yield no markers, memory or timestamps.
if (markers) {
if (markers && (yield this._markersGraphAvailable())) {
this.markersOverview.setData({ markers, duration });
this.emit(EVENTS.MARKERS_GRAPH_RENDERED);
}
if (memory) {
if (memory && (yield this._memoryGraphAvailable())) {
this.memoryOverview.dataDuration = duration;
this.memoryOverview.setData(memory);
this.emit(EVENTS.MEMORY_GRAPH_RENDERED);
}
if (timestamps) {
if (timestamps && (yield this._framerateGraphAvailable())) {
this.framerateGraph.dataDuration = duration;
yield this.framerateGraph.setDataFromTimestamps(timestamps, resolution);
this.emit(EVENTS.FRAMERATE_GRAPH_RENDERED);
@ -200,13 +208,23 @@ let OverviewView = {
this._prepareNextTick();
}),
/**
* Called to refresh the timer to keep firing _onRecordingTick.
*/
_prepareNextTick: function () {
// Check here to see if there's still a _timeoutId, incase
// `stop` was called before the _prepareNextTick call was executed.
if (this._timeoutId) {
this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
}
},
/**
* Fired when the graph selection has changed. Called by
* mouseup and scroll events.
*/
_onGraphSelecting: function () {
let recording = PerformanceController.getCurrentRecording();
if (recording == null || this._stopSelectionChangeEventPropagation) {
if (this._stopSelectionChangeEventPropagation) {
return;
}
// If the range is smaller than a pixel (which can happen when performing
@ -219,24 +237,13 @@ let OverviewView = {
}
},
/**
* Called to refresh the timer to keep firing _onRecordingTick.
*/
_prepareNextTick: function () {
// Check here to see if there's still a _timeoutId, incase
// `stop` was called before the _prepareNextTick call was executed.
if (this._timeoutId) {
this._timeoutId = setTimeout(this._onRecordingTick, OVERVIEW_UPDATE_INTERVAL);
}
},
/**
* Called when recording will start.
*/
_onRecordingWillStart: function (_, recording) {
this._checkSelection(recording);
this.framerateGraph.dropSelection();
},
_onRecordingWillStart: Task.async(function* (_, recording) {
yield this._checkSelection(recording);
this.markersOverview.dropSelection();
}),
/**
* Called when recording actually starts.
@ -256,40 +263,50 @@ let OverviewView = {
/**
* Called when recording actually stops.
*/
_onRecordingStopped: function (_, recording) {
this._checkSelection(recording);
_onRecordingStopped: Task.async(function* (_, recording) {
this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
},
yield this._checkSelection(recording);
}),
/**
* Called when a new recording is selected.
*/
_onRecordingSelected: function (_, recording) {
_onRecordingSelected: Task.async(function* (_, recording) {
if (!recording) {
return;
}
this.markersOverview.dropSelection();
this._checkSelection(recording);
// If timeout exists, we have something recording, so
// this will still tick away at rendering. Otherwise, force a render.
if (!this._timeoutId) {
this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
yield this.render(FRAMERATE_GRAPH_HIGH_RES_INTERVAL);
}
},
yield this._checkSelection(recording);
this.markersOverview.dropSelection();
}),
_checkSelection: function (recording) {
/**
* Makes sure the selection is enabled or disabled in all the graphs,
* based on whether a recording currently exists and is not in progress.
*/
_checkSelection: Task.async(function* (recording) {
let selectionEnabled = !recording.isRecording();
this.markersOverview.selectionEnabled = selectionEnabled;
this.memoryOverview.selectionEnabled = selectionEnabled;
this.framerateGraph.selectionEnabled = selectionEnabled;
},
if (yield this._markersGraphAvailable()) {
this.markersOverview.selectionEnabled = selectionEnabled;
}
if (yield this._memoryGraphAvailable()) {
this.memoryOverview.selectionEnabled = selectionEnabled;
}
if (yield this._framerateGraphAvailable()) {
this.framerateGraph.selectionEnabled = selectionEnabled;
}
}),
/**
* Called whenever a preference in `devtools.performance.ui.` changes. Used
* to toggle the visibility of memory and framerate graphs.
*/
_onPrefChanged: function (_, prefName, value) {
_onPrefChanged: function (_, prefName) {
if (prefName === "enable-memory") {
$("#memory-overview").hidden = !PerformanceController.getPref("enable-memory");
}

Просмотреть файл

@ -143,10 +143,10 @@ function FlameGraph(parent, sharpness) {
this._onResize = this._onResize.bind(this);
this.refresh = this.refresh.bind(this);
container.addEventListener("mousemove", this._onMouseMove);
container.addEventListener("mousedown", this._onMouseDown);
container.addEventListener("mouseup", this._onMouseUp);
container.addEventListener("MozMousePixelScroll", this._onMouseWheel);
this._window.addEventListener("mousemove", this._onMouseMove);
this._window.addEventListener("mousedown", this._onMouseDown);
this._window.addEventListener("mouseup", this._onMouseUp);
this._window.addEventListener("MozMousePixelScroll", this._onMouseWheel);
let ownerWindow = this._parent.ownerDocument.defaultView;
ownerWindow.addEventListener("resize", this._onResize);
@ -181,11 +181,10 @@ FlameGraph.prototype = {
* Destroys this graph.
*/
destroy: function() {
let container = this._container;
container.removeEventListener("mousemove", this._onMouseMove);
container.removeEventListener("mousedown", this._onMouseDown);
container.removeEventListener("mouseup", this._onMouseUp);
container.removeEventListener("MozMousePixelScroll", this._onMouseWheel);
this._window.removeEventListener("mousemove", this._onMouseMove);
this._window.removeEventListener("mousedown", this._onMouseDown);
this._window.removeEventListener("mouseup", this._onMouseUp);
this._window.removeEventListener("MozMousePixelScroll", this._onMouseWheel);
let ownerWindow = this._parent.ownerDocument.defaultView;
ownerWindow.removeEventListener("resize", this._onResize);
@ -870,6 +869,8 @@ let FlameGraphUtils = {
* A list of { time, frames: [{ location }] } objects.
* @param object options [optional]
* Additional options supported by this operation:
* - invertStack: specifies if the frames array in every sample
* should be reversed
* - flattenRecursion: specifies if identical consecutive frames
* should be omitted from the output
* - filterFrames: predicate used for filtering all frames, passing
@ -917,6 +918,11 @@ let FlameGraphUtils = {
frames = frames.filter(options.filterFrames);
}
// Invert the stack if preferred, reversing the frames array in place.
if (options.invertStack) {
frames.reverse();
}
// If no frames are available, add a pseudo "idle" block in between.
if (options.showIdleBlocks && frames.length == 0) {
frames = [{ location: options.showIdleBlocks || "" }];

Просмотреть файл

@ -191,11 +191,11 @@ this.AbstractCanvasGraph = function(parent, name, sharpness) {
this._onResize = this._onResize.bind(this);
this.refresh = this.refresh.bind(this);
container.addEventListener("mousemove", this._onMouseMove);
container.addEventListener("mousedown", this._onMouseDown);
container.addEventListener("mouseup", this._onMouseUp);
container.addEventListener("MozMousePixelScroll", this._onMouseWheel);
container.addEventListener("mouseout", this._onMouseOut);
this._window.addEventListener("mousemove", this._onMouseMove);
this._window.addEventListener("mousedown", this._onMouseDown);
this._window.addEventListener("mouseup", this._onMouseUp);
this._window.addEventListener("MozMousePixelScroll", this._onMouseWheel);
this._window.addEventListener("mouseout", this._onMouseOut);
let ownerWindow = this._parent.ownerDocument.defaultView;
ownerWindow.addEventListener("resize", this._onResize);
@ -230,12 +230,11 @@ AbstractCanvasGraph.prototype = {
* Destroys this graph.
*/
destroy: function() {
let container = this._container;
container.removeEventListener("mousemove", this._onMouseMove);
container.removeEventListener("mousedown", this._onMouseDown);
container.removeEventListener("mouseup", this._onMouseUp);
container.removeEventListener("MozMousePixelScroll", this._onMouseWheel);
container.removeEventListener("mouseout", this._onMouseOut);
this._window.removeEventListener("mousemove", this._onMouseMove);
this._window.removeEventListener("mousedown", this._onMouseDown);
this._window.removeEventListener("mouseup", this._onMouseUp);
this._window.removeEventListener("MozMousePixelScroll", this._onMouseWheel);
this._window.removeEventListener("mouseout", this._onMouseOut);
let ownerWindow = this._parent.ownerDocument.defaultView;
ownerWindow.removeEventListener("resize", this._onResize);

Просмотреть файл

@ -24,3 +24,5 @@ webide.jar:
content/devicepreferences.xhtml (devicepreferences.xhtml)
content/devicesettings.js (devicesettings.js)
content/devicesettings.xhtml (devicesettings.xhtml)
content/wifi-auth.js (wifi-auth.js)
content/wifi-auth.xhtml (wifi-auth.xhtml)

Просмотреть файл

@ -0,0 +1,44 @@
/* 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 Cu = Components.utils;
const { Services } = Cu.import("resource://gre/modules/Services.jsm");
const { require } =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
const QR = require("devtools/toolkit/qrcode/index");
window.addEventListener("load", function onLoad() {
window.removeEventListener("load", onLoad);
document.getElementById("close").onclick = () => window.close();
document.getElementById("no-scanner").onclick = showToken;
document.getElementById("yes-scanner").onclick = hideToken;
buildUI();
});
function buildUI() {
let { oob } = window.arguments[0];
createQR(oob);
createToken(oob);
}
function createQR(oob) {
let oobData = JSON.stringify(oob);
let imgData = QR.encodeToDataURI(oobData, "L" /* low quality */);
document.querySelector("#qr-code img").src = imgData.src;
}
function createToken(oob) {
let token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k;
document.querySelector("#token pre").textContent = token;
}
function showToken() {
document.querySelector("body").setAttribute("token", "true");
}
function hideToken() {
document.querySelector("body").removeAttribute("token");
}

Просмотреть файл

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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/. -->
<!DOCTYPE html [
<!ENTITY % webideDTD SYSTEM "chrome://browser/locale/devtools/webide.dtd" >
%webideDTD;
]>
<html id="devtools:wifi-auth" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf8"/>
<link rel="stylesheet" href="chrome://webide/skin/deck.css" type="text/css"/>
<link rel="stylesheet" href="chrome://webide/skin/wifi-auth.css" type="text/css"/>
<script type="application/javascript;version=1.8" src="chrome://webide/content/wifi-auth.js"></script>
</head>
<body>
<div id="controls">
<a id="close">&deck_close;</a>
</div>
<h3 id="header">&wifi_auth_header;</h3>
<div id="scan-request">&wifi_auth_scan_request;</div>
<div id="qr-code">
<div id="qr-code-wrapper">
<img/>
</div>
<a id="no-scanner" class="toggle-scanner">&wifi_auth_no_scanner;</a>
</div>
<div id="token">
<div>&wifi_auth_token_request;</div>
<pre id="token-value"/>
<a id="yes-scanner" class="toggle-scanner">&wifi_auth_yes_scanner;</a>
</div>
</body>
</html>

Просмотреть файл

@ -365,7 +365,10 @@ let AppManager = exports.AppManager = {
try {
// Reset the connection's state to defaults
this.connection.resetOptions();
deferred.resolve(this.selectedRuntime.connect(this.connection));
// Only watch for errors here. Final resolution occurs above, once
// we've reached the CONNECTED state.
this.selectedRuntime.connect(this.connection)
.then(null, e => deferred.reject(e));
} catch(e) {
deferred.reject(e);
}

Просмотреть файл

@ -2,7 +2,7 @@
* 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/. */
const {Cu} = require("chrome");
const {Cu, Ci} = require("chrome");
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
@ -11,6 +11,10 @@ const {DebuggerServer} = require("resource://gre/modules/devtools/dbg-server.jsm
const discovery = require("devtools/toolkit/discovery/discovery");
const EventEmitter = require("devtools/toolkit/event-emitter");
const promise = require("promise");
loader.lazyRequireGetter(this, "AuthenticationResult",
"devtools/toolkit/security/auth", true);
loader.lazyRequireGetter(this, "DevToolsUtils",
"devtools/toolkit/DevToolsUtils");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
@ -448,7 +452,7 @@ WiFiRuntime.prototype = {
return promise.reject(new Error("Can't find device: " + this.name));
}
connection.advertisement = service;
// TODO: Customize client authentication UX
connection.authenticator.sendOOB = this.sendOOB;
connection.connect();
return promise.resolve();
},
@ -458,6 +462,81 @@ WiFiRuntime.prototype = {
get name() {
return this.deviceName;
},
/**
* During OOB_CERT authentication, a notification dialog like this is used to
* to display a token which the user must transfer through some mechanism to the
* server to authenticate the devices.
*
* This implementation presents the token as text for the user to transfer
* manually. For a mobile device, you should override this implementation with
* something more convenient, such as displaying a QR code.
*
* This method receives an object containing:
* @param host string
* The host name or IP address of the debugger server.
* @param port number
* The port number of the debugger server.
* @param cert object (optional)
* The server's cert details.
* @param authResult AuthenticationResult
* Authentication result sent from the server.
* @param oob object (optional)
* The token data to be transferred during OOB_CERT step 8:
* * sha256: hash(ClientCert)
* * k : K(random 128-bit number)
* @return object containing:
* * close: Function to hide the notification
*/
sendOOB(session) {
const WINDOW_ID = "devtools:wifi-auth";
let { authResult } = session;
// Only show in the PENDING state
if (authResult != AuthenticationResult.PENDING) {
throw new Error("Expected PENDING result, got " + authResult);
}
// Listen for the window our prompt opens, so we can close it programatically
let promptWindow;
let windowListener = {
onOpenWindow(xulWindow) {
let win = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
win.addEventListener("load", function listener() {
win.removeEventListener("load", listener, false);
if (win.document.documentElement.getAttribute("id") != WINDOW_ID) {
return;
}
// Found the window
promptWindow = win;
Services.wm.removeListener(windowListener);
}, false);
},
onCloseWindow() {},
onWindowTitleChange() {}
};
Services.wm.addListener(windowListener);
// |openDialog| is typically a blocking API, so |executeSoon| to get around this
DevToolsUtils.executeSoon(() => {
let win = Services.wm.getMostRecentWindow("devtools:webide");
let width = win.outerWidth * 0.8;
let height = win.outerHeight * 0.5;
win.openDialog("chrome://webide/content/wifi-auth.xhtml",
WINDOW_ID,
"modal=yes,width=" + width + ",height=" + height, session);
});
return {
close() {
if (!promptWindow) {
return;
}
promptWindow.close();
promptWindow = null;
}
};
}
};
// For testing use only

Просмотреть файл

@ -16,3 +16,4 @@ webide.jar:
skin/permissionstable.css (permissionstable.css)
skin/monitor.css (monitor.css)
skin/config-view.css (config-view.css)
skin/wifi-auth.css (wifi-auth.css)

Просмотреть файл

@ -0,0 +1,60 @@
/* 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, body {
background: white;
}
body {
display: flex;
flex-direction: column;
height: 90%;
}
div {
margin-bottom: 1em;
}
#qr-code {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
#qr-code-wrapper {
flex: 1;
width: 100%;
margin: 2em 0;
text-align: center;
}
#qr-code img {
height: 100%;
}
.toggle-scanner {
color: #4C9ED9;
font-size: small;
cursor: pointer;
border-bottom: 1px dotted;
}
#token {
display: none;
}
body[token] > #token {
display: flex;
flex-direction: column;
}
body[token] > #qr-code {
display: none;
}
#token pre,
#token a {
align-self: center;
}

Просмотреть файл

@ -400,6 +400,7 @@
@RESPATH@/components/toolkitsearch.manifest
@RESPATH@/components/nsSearchService.js
@RESPATH@/components/nsSearchSuggestions.js
@RESPATH@/components/nsSidebar.js
@RESPATH@/components/passwordmgr.manifest
@RESPATH@/components/nsLoginInfo.js
@RESPATH@/components/nsLoginManager.js
@ -419,8 +420,6 @@
@RESPATH@/components/nsHelperAppDlg.js
@RESPATH@/components/NetworkGeolocationProvider.manifest
@RESPATH@/components/NetworkGeolocationProvider.js
@RESPATH@/browser/components/nsSidebar.manifest
@RESPATH@/browser/components/nsSidebar.js
@RESPATH@/components/extensions.manifest
@RESPATH@/components/addonManager.js
@RESPATH@/components/amContentHandler.js

Просмотреть файл

@ -591,6 +591,11 @@ getUserMedia.sharingMenuMicrophoneWindow = %S (microphone and window)
# origin for the sharing menu if no readable origin could be deduced from the URL.
getUserMedia.sharingMenuUnknownHost = Unknown origin
# LOCALIZATION NOTE(emeNotifications.drmContentPlaying.message): %1$S is the vendor name of the DRM that's in use, %2$S is brandShortName.
emeNotifications.drmContentPlaying.message = Some audio or video on this site uses %1$S DRM software, which may limit what %2$S can let you do with it.
emeNotifications.drmContentPlaying.button.label = Configure…
emeNotifications.drmContentPlaying.button.accesskey = C
# LOCALIZATION NOTE - %S is brandShortName
slowStartup.message = %S seems slow… to… start.
slowStartup.helpButton.label = Learn How to Speed It Up

Просмотреть файл

@ -81,6 +81,11 @@
<!ENTITY profilerUI.invertTree "Invert Call Tree">
<!ENTITY profilerUI.invertTree.tooltiptext "Inverting the call tree displays the profiled call paths starting from the youngest frames and expanding out to the older frames.">
<!-- LOCALIZATION NOTE (profilerUI.invertFlameGraph): This is the label shown next to
- a checkbox that inverts and un-inverts the profiler's flame graph. -->
<!ENTITY profilerUI.invertFlameGraph "Invert Flame Chart">
<!ENTITY profilerUI.invertFlameGraph.tooltiptext "Inverting the flame chart displays the profiled call paths starting from the youngest frames and expanding out to the older frames.">
<!-- LOCALIZATION NOTE (profilerUI.showPlatformData): This is the
- label for the checkbox that toggles whether or not Gecko platform data
- is displayed in the profiler. -->

Просмотреть файл

@ -173,3 +173,21 @@
<!-- Monitor -->
<!ENTITY monitor_title "Monitor">
<!ENTITY monitor_help "Help">
<!-- WiFi Authentication -->
<!-- LOCALIZATION NOTE (wifi_auth_header): The header displayed on the dialog
that instructs the user to transfer an authentication token to the
server. -->
<!ENTITY wifi_auth_header "Client Identification">
<!-- LOCALIZATION NOTE (wifi_auth_scan_request): Instructions requesting the
user to transfer authentication info by scanning a QR code. -->
<!ENTITY wifi_auth_scan_request "The endpoint you are connecting to needs more information to authenticate this connection. Please scan the QR code below via the prompt on your other device.">
<!-- LOCALIZATION NOTE (wifi_auth_no_scanner): Link text to assist users with
devices that can't scan a QR code. -->
<!ENTITY wifi_auth_no_scanner "No QR scanner prompt?">
<!-- LOCALIZATION NOTE (wifi_auth_yes_scanner): Link text to assist users with
devices that can scan a QR code. -->
<!ENTITY wifi_auth_yes_scanner "Have a QR scanner prompt?">
<!-- LOCALIZATION NOTE (wifi_auth_token_request): Instructions requesting the
user to transfer authentication info by transferring a token. -->
<!ENTITY wifi_auth_token_request "If your other device asks for a token instead of scanning a QR code, please copy the value below to the other device:">

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
/**
* This module is for small observers that we want to register once per content
* process, usually in order to forward content-based observer service notifications
* to the chrome process through message passing. Using a JSM avoids having them
* in content.js and thereby registering N observers for N open tabs, which is bad
* for perf.
*/
"use strict";
this.EXPORTED_SYMBOLS = [];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
let gEMEUIObserver = function(subject, topic, data) {
let win = subject.ownerDocument.defaultView.top;
let mm = getMessageManagerForWindow(win);
if (mm) {
mm.sendAsyncMessage("EMEVideo:MetadataLoaded", {
// bug 1129370 covers making this the actual DRM provider inferred from
// either |subject| or |data| here.
drmProvider: "Adobe"
});
}
};
function getMessageManagerForWindow(aContentWindow) {
let ir = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDocShell)
.sameTypeRootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor);
try {
// If e10s is disabled, this throws NS_NOINTERFACE for closed tabs.
return ir.getInterface(Ci.nsIContentFrameMessageManager);
} catch(e if e.result == Cr.NS_NOINTERFACE) {
return null;
}
}
Services.obs.addObserver(gEMEUIObserver, "media-eme-metadataloaded", false);

Просмотреть файл

@ -278,6 +278,17 @@ let ProcessHangMonitor = {
return;
}
// On e10s this counts slow-script/hanged-plugin notice only once.
// This code is not reached on non-e10s.
if (report.hangType == report.SLOW_SCRIPT) {
// On non-e10s, SLOW_SCRIPT_NOTICE_COUNT is probed at nsGlobalWindow.cpp
Services.telemetry.getHistogramById("SLOW_SCRIPT_NOTICE_COUNT").add();
} else if (report.hangType == report.PLUGIN_HANG) {
// On non-e10s we have sufficient plugin telemetry probes,
// so PLUGIN_HANG_NOTICE_COUNT is only probed on e10s.
Services.telemetry.getHistogramById("PLUGIN_HANG_NOTICE_COUNT").add();
}
// Otherwise create a new timer and display the report.
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.initWithCallback(this, HANG_EXPIRATION_TIME, timer.TYPE_ONE_SHOT);

Просмотреть файл

@ -16,6 +16,7 @@ EXTRA_JS_MODULES += [
'Chat.jsm',
'ContentClick.jsm',
'ContentLinkHandler.jsm',
'ContentObservers.jsm',
'ContentSearch.jsm',
'ContentWebRTC.jsm',
'CustomizationTabPreloader.jsm',

Просмотреть файл

@ -2185,6 +2185,17 @@ chatbox {
border-top-right-radius: 2.5px;
}
/* EME notifications */
.popup-notification-icon[popupid="drmContentPlaying"],
#eme-notification-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}
#eme-notification-icon:hover:active {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
}
/* Customization mode */
%include ../shared/customizableui/customizeMode.inc.css

Просмотреть файл

@ -30,6 +30,7 @@ browser.jar:
skin/classic/browser/content-contextmenu.svg
skin/classic/browser/dots.png (../shared/dots.png)
skin/classic/browser/dots@2x.png (../shared/dots@2x.png)
skin/classic/browser/drm-icon.svg (../shared/drm-icon.svg)
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png

Просмотреть файл

@ -4612,6 +4612,17 @@ window > chatbox {
border-bottom-right-radius: @toolbarbuttonCornerRadius@;
}
/* EME notifications */
.popup-notification-icon[popupid="drmContentPlaying"],
#eme-notification-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}
#eme-notification-icon:hover:active {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
}
/* Customization mode */
%include ../shared/customizableui/customizeMode.inc.css

Просмотреть файл

@ -30,6 +30,7 @@ browser.jar:
skin/classic/browser/content-contextmenu.svg
skin/classic/browser/dots.png (../shared/dots.png)
skin/classic/browser/dots@2x.png (../shared/dots@2x.png)
skin/classic/browser/drm-icon.svg (../shared/drm-icon.svg)
* skin/classic/browser/engineManager.css (engineManager.css)
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png

Просмотреть файл

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<style>
#chains > use > path {
fill: url(#baseGradient);
}
#chains-pressed > use > path {
fill: url(#pressedGradient);
}
g:not(:target) {
display: none;
}
</style>
<defs>
<linearGradient id="baseGradient" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="16" y2="0">
<stop offset="0" style="stop-color:#808080"/>
<stop offset="1" style="stop-color:#999999"/>
</linearGradient>
<linearGradient id="pressedGradient" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="16" y2="0">
<stop offset="0" style="stop-color:#4D4D4D"/>
<stop offset="1" style="stop-color:#808080"/>
</linearGradient>
<path id="path1" d="M7.058,9.72c-0.245,0.245-0.62,0.27-0.834,0.056C6.01,9.562,6.035,9.186,6.28,8.942l0.218-0.218
c-0.245-0.245-0.645-0.245-0.89,0L4.496,9.836c-0.245,0.245-0.245,0.645,0,0.89l0.779,0.779c0.245,0.245,0.645,0.245,0.89,0
l1.112-1.112c0.245-0.245,0.245-0.645,0-0.89L7.058,9.72z"/>
<path id="path2" d="M10.726,4.496c-0.245-0.245-0.645-0.245-0.89,0L8.723,5.608c-0.245,0.245-0.245,0.645,0,0.89
L8.95,6.272c0.245-0.245,0.62-0.27,0.834-0.056s0.189,0.59-0.056,0.834L9.502,7.277c0.245,0.245,0.645,0.245,0.89,0l1.112-1.112
c0.245-0.245,0.245-0.645,0-0.89L10.726,4.496z"/>
<path id="path3" d="M8,0C3.582,0,0,3.582,0,8s3.582,8,8,8s8-3.582,8-8S12.418,0,8,0z M12.527,6.81l-1.489,1.489
c-0.631,0.631-1.663,0.631-2.293,0L8.612,8.167L8.167,8.612l0.133,0.133c0.631,0.631,0.631,1.663,0,2.293L6.81,12.527
c-0.631,0.631-1.663,0.631-2.293,0l-1.044-1.044c-0.631-0.631-0.631-1.663,0-2.293l1.489-1.489c0.631-0.631,1.663-0.631,2.293,0
l0.133,0.133l0.445-0.445L7.701,7.255c-0.631-0.631-0.631-1.663,0-2.293L9.19,3.473c0.631-0.631,1.663-0.631,2.293,0l1.044,1.044
C13.158,5.148,13.158,6.18,12.527,6.81z"/>
</defs>
<g id="chains">
<use xlink:href="#path1"/>
<use xlink:href="#path2"/>
<use xlink:href="#path3"/>
</g>
<g id="chains-pressed">
<use xlink:href="#path1"/>
<use xlink:href="#path2"/>
<use xlink:href="#path3"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 2.3 KiB

Просмотреть файл

@ -153,15 +153,19 @@ treecol {
white-space: nowrap;
}
#startupTable > tr > .content-cell {
display: flex;
#startupTable > tr > .content-cell > menulist,
#startupTable > tr > .content-cell > textbox {
width: calc(100% - 8px);
margin-left: 4px;
margin-right: 4px;
}
#startupTable > tr > .homepage-buttons {
display: flex;
flex-wrap: wrap;
}
#startupTable > tr > td > .content-cell-item {
#startupTable > tr > .homepage-buttons > .content-cell-item {
flex-grow: 1;
}

Просмотреть файл

@ -2807,6 +2807,17 @@ chatbox {
border-top-right-radius: 2.5px;
}
/* EME notifications */
.popup-notification-icon[popupid="drmContentPlaying"],
#eme-notification-icon {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains");
}
#eme-notification-icon:hover:active {
list-style-image: url("chrome://browser/skin/drm-icon.svg#chains-pressed");
}
/* Customization mode */
%include ../shared/customizableui/customizeMode.inc.css

Просмотреть файл

@ -32,6 +32,7 @@ browser.jar:
skin/classic/browser/content-contextmenu.svg
skin/classic/browser/dots.png (../shared/dots.png)
skin/classic/browser/dots@2x.png (../shared/dots@2x.png)
skin/classic/browser/drm-icon.svg (../shared/drm-icon.svg)
* skin/classic/browser/engineManager.css
skin/classic/browser/fullscreen-darknoise.png
skin/classic/browser/Geolocation-16.png
@ -494,6 +495,7 @@ browser.jar:
* skin/classic/aero/browser/content-contextmenu.svg
skin/classic/aero/browser/dots.png (../shared/dots.png)
skin/classic/aero/browser/dots@2x.png (../shared/dots@2x.png)
skin/classic/aero/browser/drm-icon.svg (../shared/drm-icon.svg)
* skin/classic/aero/browser/engineManager.css
skin/classic/aero/browser/fullscreen-darknoise.png
skin/classic/aero/browser/Geolocation-16.png

Просмотреть файл

@ -46,7 +46,7 @@ leak:mozilla::TransportLayerDtls::Setup
###
# Bug 981195 - Small leak in the parser. m4
leak:TypeCompartment::fixObjectGroup
leak:ObjectGroup::fixPlainObjectGroup
# Bug 982111 - WebM is leaking. m1
leak:nestegg_read_packet

Просмотреть файл

@ -3078,8 +3078,14 @@ nsGlobalWindow::PreHandleEvent(EventChainPreVisitor& aVisitor)
gEntropyCollector->RandomUpdate((void*)&(aVisitor.mEvent->time),
sizeof(uint32_t));
}
} else if (msg == NS_RESIZE_EVENT) {
mIsHandlingResizeEvent = true;
} else if (msg == NS_RESIZE_EVENT && aVisitor.mEvent->mFlags.mIsTrusted) {
// QIing to window so that we can keep the old behavior also in case
// a child window is handling resize.
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(aVisitor.mEvent->originalTarget);
if (window) {
mIsHandlingResizeEvent = true;
}
} else if (msg == NS_MOUSE_BUTTON_DOWN &&
aVisitor.mEvent->mFlags.mIsTrusted) {
gMouseDown = true;
@ -7259,7 +7265,7 @@ nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll,
NS_IMETHODIMP
nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
{
ScrollBy(aXScrollDif, aYScrollDif);
ScrollBy(double(aXScrollDif), double(aYScrollDif));
return NS_OK;
}
@ -11018,6 +11024,10 @@ nsGlobalWindow::ShowSlowScriptDialog()
return ContinueSlowScriptAndKeepNotifying;
}
// Reached only on non-e10s - once per slow script dialog.
// On e10s - we probe once at ProcessHangsMonitor.jsm
Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT, 1);
// Get the nsIPrompt interface from the docshell
nsCOMPtr<nsIDocShell> ds = GetDocShell();
NS_ENSURE_TRUE(ds, KillSlowScript);

Просмотреть файл

@ -37,7 +37,7 @@ interface nsIFrame;
* interface to mirror this interface when changing it.
*/
[scriptable, builtinclass, uuid(ce098f6c-baca-4178-a9aa-266e8bfe509b)]
[scriptable, builtinclass, uuid(5794d12b-3195-4526-a814-a2181f6c71fe)]
interface nsIImageLoadingContent : imgINotificationObserver
{
/**
@ -170,9 +170,17 @@ interface nsIImageLoadingContent : imgINotificationObserver
/**
* A visible count is stored, if it is non-zero then this image is considered
* visible. These methods increment, decrement, or return the visible coount.
* visible. These methods increment, decrement, or return the visible count.
*
* @param aNonvisibleAction What to do if the image's visibility count is now
* zero. If ON_NONVISIBLE_NO_ACTION, nothing will be
* done. If ON_NONVISIBLE_REQUEST_DISCARD, the image
* will be asked to discard its surfaces if possible.
*/
[noscript, notxpcom] void IncrementVisibleCount();
[noscript, notxpcom] void DecrementVisibleCount();
[noscript, notxpcom] void DecrementVisibleCount(in uint32_t aNonvisibleAction);
[noscript, notxpcom] uint32_t GetVisibleCount();
const long ON_NONVISIBLE_NO_ACTION = 0;
const long ON_NONVISIBLE_REQUEST_DISCARD = 1;
};

Просмотреть файл

@ -105,8 +105,8 @@ nsImageLoadingContent::DestroyImageLoadingContent()
{
// Cancel our requests so they won't hold stale refs to us
// NB: Don't ask to discard the images here.
ClearCurrentRequest(NS_BINDING_ABORTED, 0);
ClearPendingRequest(NS_BINDING_ABORTED, 0);
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION);
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_NO_ACTION);
}
nsImageLoadingContent::~nsImageLoadingContent()
@ -554,7 +554,7 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame)
if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
// We assume all images in popups are visible, so this decrement balances
// out the increment in FrameCreated above.
DecrementVisibleCount();
DecrementVisibleCount(ON_NONVISIBLE_NO_ACTION);
}
}
@ -777,14 +777,14 @@ nsImageLoadingContent::IncrementVisibleCount()
}
void
nsImageLoadingContent::DecrementVisibleCount()
nsImageLoadingContent::DecrementVisibleCount(uint32_t aNonvisibleAction)
{
NS_ASSERTION(mVisibleCount > 0, "visible count should be positive here");
mVisibleCount--;
if (mVisibleCount == 0) {
UntrackImage(mCurrentRequest);
UntrackImage(mPendingRequest);
UntrackImage(mCurrentRequest, aNonvisibleAction);
UntrackImage(mPendingRequest, aNonvisibleAction);
}
}
@ -1096,8 +1096,8 @@ void
nsImageLoadingContent::CancelImageRequests(bool aNotify)
{
AutoStateChanger changer(this, aNotify);
ClearPendingRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
ClearCurrentRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
}
nsresult
@ -1109,8 +1109,8 @@ nsImageLoadingContent::UseAsPrimaryRequest(imgRequestProxy* aRequest,
AutoStateChanger changer(this, aNotify);
// Get rid if our existing images
ClearPendingRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
ClearCurrentRequest(NS_BINDING_ABORTED, REQUEST_DISCARD);
ClearPendingRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
ClearCurrentRequest(NS_BINDING_ABORTED, ON_NONVISIBLE_REQUEST_DISCARD);
// Clone the request we were given.
nsRefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
@ -1227,7 +1227,7 @@ nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision)
// reason "image source changed". However, apparently there's some abuse
// over in nsImageFrame where the displaying of the "broken" icon for the
// next image depends on the cancel reason of the previous image. ugh.
ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, REQUEST_DISCARD);
ClearPendingRequest(NS_ERROR_IMAGE_BLOCKED, ON_NONVISIBLE_REQUEST_DISCARD);
// For the blocked case, we only want to cancel the existing current request
// if size is not available. bz says the web depends on this behavior.
@ -1235,7 +1235,7 @@ nsImageLoadingContent::SetBlockedRequest(nsIURI* aURI, int16_t aContentDecision)
mImageBlockingStatus = aContentDecision;
uint32_t keepFlags = mCurrentRequestFlags & REQUEST_IS_IMAGESET;
ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, REQUEST_DISCARD);
ClearCurrentRequest(NS_ERROR_IMAGE_BLOCKED, ON_NONVISIBLE_REQUEST_DISCARD);
// We still want to remember what URI we were and if it was an imageset,
// despite not having an actual request. These are both cleared as part of
@ -1253,7 +1253,8 @@ nsImageLoadingContent::PrepareCurrentRequest(ImageLoadType aImageLoadType)
mImageBlockingStatus = nsIContentPolicy::ACCEPT;
// Get rid of anything that was there previously.
ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED, REQUEST_DISCARD);
ClearCurrentRequest(NS_ERROR_IMAGE_SRC_CHANGED,
ON_NONVISIBLE_REQUEST_DISCARD);
if (mNewRequestsWillNeedAnimationReset) {
mCurrentRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
@ -1271,7 +1272,8 @@ nsRefPtr<imgRequestProxy>&
nsImageLoadingContent::PreparePendingRequest(ImageLoadType aImageLoadType)
{
// Get rid of anything that was there previously.
ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED, REQUEST_DISCARD);
ClearPendingRequest(NS_ERROR_IMAGE_SRC_CHANGED,
ON_NONVISIBLE_REQUEST_DISCARD);
if (mNewRequestsWillNeedAnimationReset) {
mPendingRequestFlags |= REQUEST_NEEDS_ANIMATION_RESET;
@ -1336,7 +1338,7 @@ nsImageLoadingContent::MakePendingRequestCurrent()
void
nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
uint32_t aFlags)
uint32_t aNonvisibleAction)
{
if (!mCurrentRequest) {
// Even if we didn't have a current request, we might have been keeping
@ -1354,7 +1356,7 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
&mCurrentRequestRegistered);
// Clean up the request.
UntrackImage(mCurrentRequest, aFlags);
UntrackImage(mCurrentRequest, aNonvisibleAction);
mCurrentRequest->CancelAndForgetObserver(aReason);
mCurrentRequest = nullptr;
mCurrentRequestFlags = 0;
@ -1362,7 +1364,7 @@ nsImageLoadingContent::ClearCurrentRequest(nsresult aReason,
void
nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
uint32_t aFlags)
uint32_t aNonvisibleAction)
{
if (!mPendingRequest)
return;
@ -1372,7 +1374,7 @@ nsImageLoadingContent::ClearPendingRequest(nsresult aReason,
nsLayoutUtils::DeregisterImageRequest(GetFramePresContext(), mPendingRequest,
&mPendingRequestRegistered);
UntrackImage(mPendingRequest, aFlags);
UntrackImage(mPendingRequest, aNonvisibleAction);
mPendingRequest->CancelAndForgetObserver(aReason);
mPendingRequest = nullptr;
mPendingRequestFlags = 0;
@ -1472,7 +1474,9 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage)
}
void
nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0 */)
nsImageLoadingContent::UntrackImage(imgIRequest* aImage,
uint32_t aNonvisibleAction
/* = ON_NONVISIBLE_NO_ACTION */)
{
if (!aImage)
return;
@ -1489,9 +1493,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0
if (doc && (mCurrentRequestFlags & REQUEST_IS_TRACKED)) {
mCurrentRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mCurrentRequest,
(aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0);
}
else if (aFlags & REQUEST_DISCARD) {
(aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD)
? nsIDocument::REQUEST_DISCARD
: 0);
} else if (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) {
// If we're not in the document we may still need to be discarded.
aImage->RequestDiscard();
}
@ -1500,9 +1505,10 @@ nsImageLoadingContent::UntrackImage(imgIRequest* aImage, uint32_t aFlags /* = 0
if (doc && (mPendingRequestFlags & REQUEST_IS_TRACKED)) {
mPendingRequestFlags &= ~REQUEST_IS_TRACKED;
doc->RemoveImage(mPendingRequest,
(aFlags & REQUEST_DISCARD) ? nsIDocument::REQUEST_DISCARD : 0);
}
else if (aFlags & REQUEST_DISCARD) {
(aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD)
? nsIDocument::REQUEST_DISCARD
: 0);
} else if (aNonvisibleAction == ON_NONVISIBLE_REQUEST_DISCARD) {
// If we're not in the document we may still need to be discarded.
aImage->RequestDiscard();
}

Просмотреть файл

@ -316,9 +316,12 @@ protected:
/**
* Cancels and nulls-out the "current" and "pending" requests if they exist.
*
* @param aNonvisibleAction An action to take if the image is no longer
* visible as a result; see |UntrackImage|.
*/
void ClearCurrentRequest(nsresult aReason, uint32_t aFlags);
void ClearPendingRequest(nsresult aReason, uint32_t aFlags);
void ClearCurrentRequest(nsresult aReason, uint32_t aNonvisibleAction);
void ClearPendingRequest(nsresult aReason, uint32_t aNonvisibleAction);
/**
* Retrieve a pointer to the 'registered with the refresh driver' flag for
@ -347,14 +350,14 @@ protected:
*
* No-op if aImage is null.
*
* REQUEST_DISCARD passed to UntrackImage means we request the discard of the
* decoded data of the image.
* @param aNonvisibleAction What to do if the image's visibility count is now
* zero. If ON_NONVISIBLE_NO_ACTION, nothing will be
* done. If ON_NONVISIBLE_REQUEST_DISCARD, the image
* will be asked to discard its surfaces if possible.
*/
void TrackImage(imgIRequest* aImage);
enum {
REQUEST_DISCARD = 0x1
};
void UntrackImage(imgIRequest* aImage, uint32_t aFlags = 0);
void UntrackImage(imgIRequest* aImage,
uint32_t aNonvisibleAction = ON_NONVISIBLE_NO_ACTION);
/* MEMBERS */
nsRefPtr<imgRequestProxy> mCurrentRequest;

Просмотреть файл

@ -772,4 +772,6 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
[test_window_define_nonconfigurable.html]
skip-if = true # bug 1107443 - code for newly-added test was disabled
[test_root_iframe.html]
[test_performance_user_timing.html]
[test_performance_user_timing.html]
[test_bug1126851.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g'

Просмотреть файл

@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1126851
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1126851</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1126851 **/
SimpleTest.waitForExplicitFinish();
function runTest() {
win = window.open("about:blank", "");
win.onload = function() {
win.onunload = function() {
ok(true, "got unload");
win.close();
SimpleTest.finish();
}
win.onresize = function() {
win.location.reload();
}
win.document.dispatchEvent(new win.Event("resize", { bubbles: true }));
}
}
</script>
</head>
<body onload="runTest()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1126851">Mozilla Bug 1126851</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -195,13 +195,13 @@ private:
ErrorResult& mRv;
};
class PostMessageRunnable MOZ_FINAL : public nsICancelableRunnable
class BCPostMessageRunnable MOZ_FINAL : public nsICancelableRunnable
{
public:
NS_DECL_ISUPPORTS
PostMessageRunnable(BroadcastChannelChild* aActor,
BroadcastChannelMessage* aData)
BCPostMessageRunnable(BroadcastChannelChild* aActor,
BroadcastChannelMessage* aData)
: mActor(aActor)
, mData(aData)
{
@ -249,13 +249,13 @@ public:
}
private:
~PostMessageRunnable() {}
~BCPostMessageRunnable() {}
nsRefPtr<BroadcastChannelChild> mActor;
nsRefPtr<BroadcastChannelMessage> mData;
};
NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable)
NS_IMPL_ISUPPORTS(BCPostMessageRunnable, nsICancelableRunnable, nsIRunnable)
class CloseRunnable MOZ_FINAL : public nsICancelableRunnable
{
@ -559,8 +559,8 @@ void
BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData)
{
if (mActor) {
nsRefPtr<PostMessageRunnable> runnable =
new PostMessageRunnable(mActor, aData);
nsRefPtr<BCPostMessageRunnable> runnable =
new BCPostMessageRunnable(mActor, aData);
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
NS_WARNING("Failed to dispatch to the current thread!");

Просмотреть файл

@ -8,7 +8,7 @@ EXPORTS.mozilla.dom += [
'BroadcastChannel.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'BroadcastChannel.cpp',
'BroadcastChannelChild.cpp',
'BroadcastChannelParent.cpp',

Просмотреть файл

@ -109,7 +109,10 @@ function test3(e) {
numPendingChildTests++;
onTryAgain();
waitForPendingTests(function() { test4(); });
waitForPendingTests(function() {
mm.removeMessageListener('test-try-again', onTryAgain);
test4();
});
}
function test4() {
@ -240,7 +243,10 @@ function test6f() {
numPendingChildTests++;
onTryAgain();
waitForPendingTests(test6g);
waitForPendingTests(function() {
mm.removeMessageListener('test-try-again', onTryAgain);
test6g();
});
}
function test6g() {
@ -269,7 +275,10 @@ function test6g() {
numPendingChildTests++;
onTryAgain();
waitForPendingTests(test6h);
waitForPendingTests(function() {
mm.removeMessageListener('test-try-again', onTryAgain);
test6h();
});
}
function test6h() {

Просмотреть файл

@ -505,7 +505,7 @@ IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
static already_AddRefed<GLContext>
CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
bool requireCompatProfile, WebGLContext* webgl)
WebGLContext* webgl)
{
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
@ -515,7 +515,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
return nullptr;
}
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless(requireCompatProfile);
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during native OpenGL init.");
return nullptr;
@ -530,7 +530,7 @@ CreateHeadlessNativeGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
// Eventually, we want to be able to pick ANGLE-EGL or native EGL.
static already_AddRefed<GLContext>
CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
bool requireCompatProfile, WebGLContext* webgl)
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
@ -543,7 +543,7 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
return nullptr;
}
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile);
gl = gl::GLContextProviderEGL::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during ANGLE OpenGL init.");
return nullptr;
@ -555,13 +555,13 @@ CreateHeadlessANGLE(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
}
static already_AddRefed<GLContext>
CreateHeadlessEGL(bool forceEnabled, bool requireCompatProfile,
CreateHeadlessEGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
#ifdef ANDROID
gl = gl::GLContextProviderEGL::CreateHeadless(requireCompatProfile);
gl = gl::GLContextProviderEGL::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during EGL OpenGL init.");
return nullptr;
@ -583,22 +583,16 @@ CreateHeadlessGL(bool forceEnabled, const nsCOMPtr<nsIGfxInfo>& gfxInfo,
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"))
disableANGLE = true;
bool requireCompatProfile = webgl->IsWebGL2() ? false : true;
nsRefPtr<GLContext> gl;
if (preferEGL)
gl = CreateHeadlessEGL(forceEnabled, requireCompatProfile, webgl);
gl = CreateHeadlessEGL(forceEnabled, gfxInfo, webgl);
if (!gl && !disableANGLE) {
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, requireCompatProfile,
webgl);
}
if (!gl && !disableANGLE)
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, webgl);
if (!gl) {
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo,
requireCompatProfile, webgl);
}
if (!gl)
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, webgl);
return gl.forget();
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше