diff --git a/b2g/chrome/content/devtools/hud.js b/b2g/chrome/content/devtools/hud.js
index 537ae66bf9a2..0d0bbb677832 100644
--- a/b2g/chrome/content/devtools/hud.js
+++ b/b2g/chrome/content/devtools/hud.js
@@ -765,9 +765,25 @@ let performanceEntriesWatcher = {
_fronts: new Map(),
_appLaunchName: null,
_appLaunchStartTime: null,
+ _supported: [
+ 'contentInteractive',
+ 'navigationInteractive',
+ 'navigationLoaded',
+ 'visuallyLoaded',
+ 'fullyLoaded',
+ 'mediaEnumerated',
+ 'scanEnd'
+ ],
init(client) {
this._client = client;
+ let setting = 'devtools.telemetry.supported_performance_marks';
+ let defaultValue = this._supported.join(',');
+
+ SettingsListener.observe(setting, defaultValue, supported => {
+ let value = supported || defaultValue;
+ this._supported = value.split(',');
+ });
},
trackTarget(target) {
@@ -783,38 +799,56 @@ let performanceEntriesWatcher = {
front.start();
front.on('entry', detail => {
- if (detail.type === 'mark') {
- let name = detail.name;
- let epoch = detail.epoch;
- let CHARS_UNTIL_APP_NAME = 7; // '@app://'
- // FIXME There is a potential race condition that can result
- // in some performance entries being disregarded. See bug 1189942.
- if (name.indexOf('appLaunch') != -1) {
- let appStartPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME;
- let length = (name.indexOf('.') - appStartPos);
- this._appLaunchName = name.substr(appStartPos, length);
- this._appLaunchStartTime = epoch;
- } else {
- let origin = detail.origin;
- origin = origin.substr(0, origin.indexOf('.'));
- if (this._appLaunchName === origin) {
- let time = epoch - this._appLaunchStartTime;
- let eventName = 'app-startup-time-' + name;
-
- // Events based on performance marks are for telemetry only, they are
- // not displayed in the HUD front end.
- target._logHistogram({name: eventName, value: time});
-
- memoryWatcher.front(target).residentUnique().then(value => {
- eventName = 'app-memory-' + name;
- target._logHistogram({name: eventName, value: value});
- }, err => {
- console.error(err);
- });
- }
- }
+ // Only process performance marks.
+ if (detail.type !== 'mark') {
+ return;
}
+
+ let name = detail.name;
+ let epoch = detail.epoch;
+
+ // FIXME There is a potential race condition that can result
+ // in some performance entries being disregarded. See bug 1189942.
+ //
+ // If this is an "app launch" mark, record the app that was
+ // launched and the epoch of when it was launched.
+ if (name.indexOf('appLaunch') !== -1) {
+ let CHARS_UNTIL_APP_NAME = 7; // '@app://'
+ let startPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME;
+ let endPos = name.indexOf('.');
+ this._appLaunchName = name.slice(startPos, endPos);
+ this._appLaunchStartTime = epoch;
+ return;
+ }
+
+ // Only process supported performance marks
+ if (this._supported.indexOf(name) === -1) {
+ return;
+ }
+
+ let origin = detail.origin;
+ origin = origin.slice(0, origin.indexOf('.'));
+
+ // Continue if the performance mark corresponds to the app
+ // for which we have recorded app launch information.
+ if (this._appLaunchName !== origin) {
+ return;
+ }
+
+ let time = epoch - this._appLaunchStartTime;
+ let eventName = 'app_startup_time_' + name;
+
+ // Events based on performance marks are for telemetry only, they are
+ // not displayed in the HUD front end.
+ target._logHistogram({name: eventName, value: time});
+
+ memoryWatcher.front(target).residentUnique().then(value => {
+ eventName = 'app_memory_' + name;
+ target._logHistogram({name: eventName, value: value});
+ }, err => {
+ console.error(err);
+ });
});
},
diff --git a/b2g/chrome/content/settings.js b/b2g/chrome/content/settings.js
index 30bc8d0e9c19..d176689363ea 100644
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -573,6 +573,10 @@ let settingsToObserve = {
'devtools.remote.wifi.visible': {
resetToPref: true
},
+ 'devtools.telemetry.supported_performance_marks': {
+ resetToPref: true
+ },
+
'dom.mozApps.use_reviewer_certs': false,
'dom.mozApps.signed_apps_installable_from': 'https://marketplace.firefox.com',
'dom.presentation.discovery.enabled': false,
diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml
index 42881aeb17ac..b63027262b52 100644
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml
index 3e10be06f1e0..aff5e63aece7 100644
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index c857ce32b61a..1c0759865d1d 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index a4b6e960edc2..685525075560 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index c96ad5a13778..b1db33d69668 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml
index 4c6cd155fa70..1fbc635cc2f5 100644
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index c857ce32b61a..1c0759865d1d 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,7 +19,7 @@
-
+
diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml
index 6001923311f9..51fd4f200673 100644
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index 26cf10b26ccb..364aa2b4507f 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
- "git_revision": "e6994410dcc88bfead0e44620a065220b7f12290",
+ "git_revision": "d2e5c49440bf8410ae747b15c0dd11c54053ef3e",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
- "revision": "0611acb452ed9c34d02ccdf24850677490b716d1",
+ "revision": "4b08f8a2624bc83d1f839f79b4969671417c42d6",
"repo_path": "integration/gaia-central"
}
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index 1ec80c8ba456..41edbe97e2e0 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml
index 927a6fee4561..21aed1744054 100644
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
diff --git a/browser/base/content/test/newtab/browser_newtab_block.js b/browser/base/content/test/newtab/browser_newtab_block.js
index de398321c588..1a958b794b30 100644
--- a/browser/base/content/test/newtab/browser_newtab_block.js
+++ b/browser/base/content/test/newtab/browser_newtab_block.js
@@ -13,6 +13,7 @@ gDirectorySource = "data:application/json," + JSON.stringify({
imageURI: "data:image/png;base64,helloWORLD3",
title: "title",
type: "affiliate",
+ adgroup_name: "test",
frecent_sites: ["example0.com"]
}]
});
diff --git a/browser/base/content/test/newtab/browser_newtab_bug1145428.js b/browser/base/content/test/newtab/browser_newtab_bug1145428.js
index ba15b6be513b..f0d1ac6177c0 100644
--- a/browser/base/content/test/newtab/browser_newtab_bug1145428.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug1145428.js
@@ -15,6 +15,7 @@ gDirectorySource = "data:application/json," + JSON.stringify({
enhancedImageURI: "data:image/png;base64,helloWORLD2",
title: "title",
type: "affiliate",
+ adgroup_name: "example",
frecent_sites: ["example0.com"],
}]
});
diff --git a/browser/base/content/test/newtab/browser_newtab_bug1178586.js b/browser/base/content/test/newtab/browser_newtab_bug1178586.js
index 32d887d4ca1d..dfc88942edbd 100644
--- a/browser/base/content/test/newtab/browser_newtab_bug1178586.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug1178586.js
@@ -13,6 +13,7 @@ gDirectorySource = "data:application/json," + JSON.stringify({
enhancedImageURI: "data:image/png;base64,helloWORLD2",
title: "title",
type: "affiliate",
+ adgroup_name: "example",
frecent_sites: ["example0.com"],
}]
});
diff --git a/browser/base/content/test/newtab/browser_newtab_enhanced.js b/browser/base/content/test/newtab/browser_newtab_enhanced.js
index 4225f173b512..661327ab62e2 100644
--- a/browser/base/content/test/newtab/browser_newtab_enhanced.js
+++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js
@@ -8,6 +8,7 @@ let suggestedLink = {
imageURI: "data:image/png;base64,helloWORLD3",
title: "title2",
type: "affiliate",
+ adgroup_name: "Technology",
frecent_sites: ["classroom.google.com", "codeacademy.org", "codecademy.com", "codeschool.com", "codeyear.com", "elearning.ut.ac.id", "how-to-build-websites.com", "htmlcodetutorial.com", "htmldog.com", "htmlplayground.com", "learn.jquery.com", "quackit.com", "roseindia.net", "teamtreehouse.com", "tizag.com", "tutorialspoint.com", "udacity.com", "w3schools.com", "webdevelopersnotes.com"]
};
@@ -139,7 +140,7 @@ function runTests() {
is(type, "affiliate", "suggested link is affiliate");
is(enhanced, "", "suggested link has no enhanced image");
is(title, "title2");
- ok(suggested.indexOf("Suggested for webdev education visitors") > -1, "Suggested for 'webdev education'");
+ ok(suggested.indexOf("Suggested for Technology visitors") > -1, "Suggested for 'Technology'");
// Enhanced history link shows up second
({type, enhanced, title, suggested} = getData(1));
@@ -152,8 +153,7 @@ function runTests() {
- // Test override category/adgroup name.
- suggestedLink.adgroup_name = "Technology";
+ // Test no override category/adgroup name.
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE,
"data:application/json," + JSON.stringify({"suggested": [suggestedLink]}));
yield watchLinksChangeOnce().then(TestRunner.next);
@@ -176,8 +176,8 @@ function runTests() {
ok(suggested.indexOf("Suggested for Technology enthusiasts who visit sites like classroom.google.com ") > -1, "Suggested for 'Technology' enthusiasts");
- // Test server provided explanation string without category override.
- delete suggestedLink.adgroup_name;
+ // Test server provided explanation string with category override.
+ suggestedLink.adgroup_name = "webdev education";
Services.prefs.setCharPref(PREF_NEWTAB_DIRECTORYSOURCE,
"data:application/json," + encodeURIComponent(JSON.stringify({"suggested": [suggestedLink]})));
yield watchLinksChangeOnce().then(TestRunner.next);
diff --git a/browser/components/extensions/ext-windows.js b/browser/components/extensions/ext-windows.js
index f83bc4b81949..9c878827622a 100644
--- a/browser/components/extensions/ext-windows.js
+++ b/browser/components/extensions/ext-windows.js
@@ -60,7 +60,7 @@ extensions.registerAPI((extension, context) => {
runSafe(context, callback, WindowManager.convert(extension, window, getInfo));
},
- getAll: function(getAll, callback) {
+ getAll: function(getInfo, callback) {
let e = Services.wm.getEnumerator("navigator:browser");
let windows = [];
while (e.hasMoreElements()) {
@@ -131,7 +131,10 @@ extensions.registerAPI((extension, context) => {
Services.focus.activeWindow = window;
}
// TODO: All the other properties...
- runSafe(context, callback, WindowManager.convert(extension, window));
+
+ if (callback) {
+ runSafe(context, callback, WindowManager.convert(extension, window));
+ }
},
remove: function(windowId, callback) {
diff --git a/browser/components/extensions/test/browser/browser.ini b/browser/components/extensions/test/browser/browser.ini
index 2ce3ab84db03..a64633ab2d18 100644
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -6,3 +6,4 @@ skip-if = os == 'android' || buildapp == 'b2g' || os == 'mac'
[browser_ext_tabs_executeScript.js]
[browser_ext_tabs_query.js]
[browser_ext_tabs_update.js]
+[browser_ext_windows_update.js]
diff --git a/browser/components/extensions/test/browser/browser_ext_windows_update.js b/browser/components/extensions/test/browser/browser_ext_windows_update.js
new file mode 100644
index 000000000000..eb70e2c33568
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_windows_update.js
@@ -0,0 +1,51 @@
+add_task(function* () {
+ function promiseWaitForFocus(aWindow) {
+ return new Promise(function(aResolve, aReject) {
+ waitForFocus(function() {
+ ok(Services.focus.activeWindow === aWindow, "correct window focused");
+ aResolve();
+ }, aWindow);
+ });
+ }
+
+ let window1 = window;
+ let window2 = yield BrowserTestUtils.openNewBrowserWindow();
+
+ Services.focus.activeWindow = window2;
+ yield promiseWaitForFocus(window2);
+
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ "permissions": ["windows"]
+ },
+
+ background: function() {
+ browser.windows.getAll(undefined, function(wins) {
+ browser.test.assertEq(wins.length, 2, "should have two windows");
+
+ // Sort the unfocused window to the lower index.
+ wins.sort(function(win1, win2) {
+ if (win1.focused === win2.focused) {
+ return 0;
+ }
+
+ return win1.focused ? 1 : -1;
+ });
+
+ browser.windows.update(wins[0].id, {focused: true}, function() {
+ browser.test.sendMessage("check");
+ });
+
+ });
+ },
+ });
+
+ yield extension.startup();
+ yield extension.awaitMessage("check");
+
+ yield promiseWaitForFocus(window1);
+
+ yield extension.unload();
+
+ yield BrowserTestUtils.closeWindow(window2);
+});
\ No newline at end of file
diff --git a/browser/devtools/canvasdebugger/snapshotslist.js b/browser/devtools/canvasdebugger/snapshotslist.js
index 799cae2fce01..9af772ddc5c7 100644
--- a/browser/devtools/canvasdebugger/snapshotslist.js
+++ b/browser/devtools/canvasdebugger/snapshotslist.js
@@ -420,7 +420,7 @@ let SnapshotsListView = Heritage.extend(WidgetMethods, {
// Prepare all the function calls for serialization.
yield DevToolsUtils.yieldingEach(functionCalls, (call, i) => {
- let { type, name, file, line, argsPreview, callerPreview } = call;
+ let { type, name, file, line, timestamp, argsPreview, callerPreview } = call;
return call.getDetails().then(({ stack }) => {
data.calls[i] = {
type: type,
@@ -428,6 +428,7 @@ let SnapshotsListView = Heritage.extend(WidgetMethods, {
file: file,
line: line,
stack: stack,
+ timestamp: timestamp,
argsPreview: argsPreview,
callerPreview: callerPreview
};
diff --git a/browser/devtools/canvasdebugger/test/browser.ini b/browser/devtools/canvasdebugger/test/browser.ini
index 6fdcb740dfcd..a806a06dee75 100644
--- a/browser/devtools/canvasdebugger/test/browser.ini
+++ b/browser/devtools/canvasdebugger/test/browser.ini
@@ -52,3 +52,5 @@ skip-if = e10s # bug 1102301 - leaks while running as a standalone directory in
[browser_canvas-frontend-stop-01.js]
[browser_canvas-frontend-stop-02.js]
[browser_canvas-frontend-stop-03.js]
+[browser_profiling-canvas.js]
+[browser_profiling-webgl.js]
diff --git a/browser/devtools/canvasdebugger/test/browser_profiling-canvas.js b/browser/devtools/canvasdebugger/test/browser_profiling-canvas.js
new file mode 100644
index 000000000000..4bf2647d24f8
--- /dev/null
+++ b/browser/devtools/canvasdebugger/test/browser_profiling-canvas.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if functions inside a single animation frame are recorded and stored
+ * for a canvas context profiling.
+ */
+
+function* ifTestingSupported() {
+ let currentTime = window.performance.now();
+ let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
+
+ let navigated = once(target, "navigate");
+
+ yield front.setup({ reload: true });
+ ok(true, "The front was setup up successfully.");
+
+ yield navigated;
+ ok(true, "Target automatically navigated when the front was set up.");
+
+ let snapshotActor = yield front.recordAnimationFrame();
+ ok(snapshotActor,
+ "A snapshot actor was sent after recording.");
+
+ let animationOverview = yield snapshotActor.getOverview();
+ ok(animationOverview,
+ "An animation overview could be retrieved after recording.");
+
+ let functionCalls = animationOverview.calls;
+ ok(functionCalls,
+ "An array of function call actors was sent after recording.");
+ is(functionCalls.length, 8,
+ "The number of function call actors is correct.");
+
+ info("Check the timestamps of function calls");
+
+ for ( let i = 0; i < functionCalls.length-1; i += 2 ) {
+ ok( functionCalls[i].timestamp > 0, "The timestamp of the called function is larger than 0." );
+ ok( functionCalls[i].timestamp < currentTime, "The timestamp has been minus the frame start time." );
+ ok( functionCalls[i+1].timestamp > functionCalls[i].timestamp, "The timestamp of the called function is correct." );
+ }
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/browser/devtools/canvasdebugger/test/browser_profiling-webgl.js b/browser/devtools/canvasdebugger/test/browser_profiling-webgl.js
new file mode 100644
index 000000000000..3339ff3899a5
--- /dev/null
+++ b/browser/devtools/canvasdebugger/test/browser_profiling-webgl.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if functions inside a single animation frame are recorded and stored
+ * for a canvas context profiling.
+ */
+
+function* ifTestingSupported() {
+ let currentTime = window.performance.now();
+ let { target, front } = yield initCanvasDebuggerBackend(WEBGL_ENUM_URL);
+
+ let navigated = once(target, "navigate");
+
+ yield front.setup({ reload: true });
+ ok(true, "The front was setup up successfully.");
+
+ yield navigated;
+ ok(true, "Target automatically navigated when the front was set up.");
+
+ let snapshotActor = yield front.recordAnimationFrame();
+ ok(snapshotActor,
+ "A snapshot actor was sent after recording.");
+
+ let animationOverview = yield snapshotActor.getOverview();
+ ok(animationOverview,
+ "An animation overview could be retrieved after recording.");
+
+ let functionCalls = animationOverview.calls;
+ ok(functionCalls,
+ "An array of function call actors was sent after recording.");
+ is(functionCalls.length, 3,
+ "The number of function call actors is correct.");
+
+ info("Check the timestamps of function calls");
+
+ for ( let i = 0; i < functionCalls.length-1; i += 2 ) {
+ ok( functionCalls[i].timestamp > 0, "The timestamp of the called function is larger than 0." );
+ ok( functionCalls[i].timestamp < currentTime, "The timestamp has been minus the frame start time." );
+ ok( functionCalls[i+1].timestamp > functionCalls[i].timestamp, "The timestamp of the called function is correct." );
+ }
+
+ yield removeTab(target.tab);
+ finish();
+}
diff --git a/browser/devtools/markupview/test/browser.ini b/browser/devtools/markupview/test/browser.ini
index f7a6327327bc..bca4e5bfb4fe 100644
--- a/browser/devtools/markupview/test/browser.ini
+++ b/browser/devtools/markupview/test/browser.ini
@@ -23,6 +23,7 @@ support-files =
doc_markup_toggle.html
doc_markup_tooltip.png
doc_markup_xul.xul
+ frame-script-utils.js
head.js
helper_attributes_test_runner.js
helper_events_test_runner.js
diff --git a/browser/devtools/markupview/test/browser_markupview_keybindings_04.js b/browser/devtools/markupview/test/browser_markupview_keybindings_04.js
index 17cb16e88232..282a5349558a 100644
--- a/browser/devtools/markupview/test/browser_markupview_keybindings_04.js
+++ b/browser/devtools/markupview/test/browser_markupview_keybindings_04.js
@@ -45,10 +45,28 @@ function assertNodeSelected(inspector, tagName) {
}
function* selectWithBrowserMenu(inspector) {
- yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
- type: "contextmenu",
- button: 2
- }, gBrowser.selectedBrowser);
+ // This test can't use BrowserTestUtils.synthesizeMouseAtCenter()
+ // method (see below) since it causes intermittent test failures.
+ // So, we are introducing a new "Test:MarkupView:SynthesizeMouse" event
+ // that is handled in the content scope. The main difference between
+ // this new event and BrowserTestUtils library is EventUtils library.
+ // While BrowserTestUtils is using:
+ // chrome://mochikit/content/tests/SimpleTest/EventUtils.js
+ // (see: AsyncUtilsContent.js)
+ // ... this test requires:
+ // chrome://marionette/content/EventUtils.js
+ // (see markupview/test/frame-script-utils.js)
+ // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1199180
+ yield executeInContent("Test:MarkupView:SynthesizeMouse", {
+ center: true,
+ selector: "div",
+ options: {type: "contextmenu", button: 2}
+ });
+
+ //yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
+ // type: "contextmenu",
+ // button: 2
+ //}, gBrowser.selectedBrowser);
// nsContextMenu also requires the popupNode to be set, but we can't set it to
// node under e10s as it's a CPOW, not a DOM node. But under e10s,
@@ -70,9 +88,18 @@ function* selectWithBrowserMenu(inspector) {
function* selectWithElementPicker(inspector) {
yield inspector.toolbox.highlighterUtils.startPicker();
- yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
- type: "mousemove",
- }, gBrowser.selectedBrowser);
+
+ yield executeInContent("Test:MarkupView:SynthesizeMouse", {
+ center: true,
+ selector: "div",
+ options: {type: "mousemove"}
+ });
+
+ // Read comment in selectWithBrowserMenu() method.
+ //yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
+ // type: "mousemove",
+ //}, gBrowser.selectedBrowser);
+
executeInContent("Test:SynthesizeKey", {
key: "VK_RETURN",
options: {}
diff --git a/browser/devtools/markupview/test/frame-script-utils.js b/browser/devtools/markupview/test/frame-script-utils.js
new file mode 100644
index 000000000000..5caa7aa33788
--- /dev/null
+++ b/browser/devtools/markupview/test/frame-script-utils.js
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci} = Components;
+const subScriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
+ .getService(Ci.mozIJSSubScriptLoader);
+let EventUtils = {};
+subScriptLoader.loadSubScript("chrome://marionette/content/EventUtils.js", EventUtils);
+
+/**
+ * Synthesize a mouse event on an element. This handler doesn't send a message
+ * back. Consumers should listen to specific events on the inspector/highlighter
+ * to know when the event got synthesized.
+ * @param {Object} msg The msg.data part expects the following properties:
+ * - {Number} x
+ * - {Number} y
+ * - {Boolean} center If set to true, x/y will be ignored and
+ * synthesizeMouseAtCenter will be used instead
+ * - {Object} options Other event options
+ * - {String} selector An optional selector that will be used to find the node to
+ * synthesize the event on, if msg.objects doesn't contain the CPOW.
+ * The msg.objects part should be the element.
+ * @param {Object} data Event detail properties:
+ */
+addMessageListener("Test:MarkupView:SynthesizeMouse", function(msg) {
+ let {x, y, center, options, selector} = msg.data;
+ let {node} = msg.objects;
+
+ if (!node && selector) {
+ node = content.document.querySelector(selector);
+ }
+
+ if (center) {
+ EventUtils.synthesizeMouseAtCenter(node, options, node.ownerDocument.defaultView);
+ } else {
+ EventUtils.synthesizeMouse(node, x, y, options, node.ownerDocument.defaultView);
+ }
+
+ // Most consumers won't need to listen to this message, unless they want to
+ // wait for the mouse event to be synthesized and don't have another event
+ // to listen to instead.
+ sendAsyncMessage("Test:MarkupView:SynthesizeMouse");
+});
diff --git a/browser/devtools/markupview/test/head.js b/browser/devtools/markupview/test/head.js
index c569901a77fe..edfa976df628 100644
--- a/browser/devtools/markupview/test/head.js
+++ b/browser/devtools/markupview/test/head.js
@@ -51,6 +51,7 @@ registerCleanupFunction(function*() {
const TEST_URL_ROOT = "http://mochi.test:8888/browser/browser/devtools/markupview/test/";
const CHROME_BASE = "chrome://mochitests/content/browser/browser/devtools/markupview/test/";
const COMMON_FRAME_SCRIPT_URL = "chrome://browser/content/devtools/frame-script-utils.js";
+const MARKUPVIEW_FRAME_SCRIPT_URL = CHROME_BASE + "frame-script-utils.js";
/**
* Add a new test tab in the browser and load the given url.
@@ -71,6 +72,7 @@ function addTab(url) {
info("Loading the helper frame script " + COMMON_FRAME_SCRIPT_URL);
linkedBrowser.messageManager.loadFrameScript(COMMON_FRAME_SCRIPT_URL, false);
+ linkedBrowser.messageManager.loadFrameScript(MARKUPVIEW_FRAME_SCRIPT_URL, false);
linkedBrowser.addEventListener("load", function onload() {
linkedBrowser.removeEventListener("load", onload, true);
diff --git a/browser/devtools/performance/modules/logic/frame-utils.js b/browser/devtools/performance/modules/logic/frame-utils.js
index d79fe5e0c930..ca9d1dde5d82 100644
--- a/browser/devtools/performance/modules/logic/frame-utils.js
+++ b/browser/devtools/performance/modules/logic/frame-utils.js
@@ -554,6 +554,30 @@ function getFrameInfo (node, options) {
}
exports.getFrameInfo = getFrameInfo;
+
+/**
+ * Takes an inverted ThreadNode and searches its youngest frames for
+ * a FrameNode with matching location.
+ *
+ * @param {ThreadNode} threadNode
+ * @param {string} location
+ * @return {?FrameNode}
+ */
+function findFrameByLocation (threadNode, location) {
+ if (!threadNode.inverted) {
+ throw new Error("FrameUtils.findFrameByLocation only supports leaf nodes in an inverted tree.");
+ }
+
+ let calls = threadNode.calls;
+ for (let i = 0; i < calls.length; i++) {
+ if (calls[i].location === location) {
+ return calls[i];
+ }
+ }
+ return null;
+}
+
+exports.findFrameByLocation = findFrameByLocation;
exports.computeIsContentAndCategory = computeIsContentAndCategory;
exports.parseLocation = parseLocation;
exports.getInflatedFrameCache = getInflatedFrameCache;
diff --git a/browser/devtools/performance/modules/logic/jit.js b/browser/devtools/performance/modules/logic/jit.js
index 1a8b28d9ffc2..19584020dada 100644
--- a/browser/devtools/performance/modules/logic/jit.js
+++ b/browser/devtools/performance/modules/logic/jit.js
@@ -269,23 +269,13 @@ const IMPLEMENTATION_NAMES = Object.keys(IMPLEMENTATION_MAP);
* @param {Array} sampleTimes
* An array of every sample time within the range we're counting.
* From a ThreadNode's `sampleTimes` property.
- * @param {number} op.startTime
- * The start time of the first sample.
- * @param {number} op.endTime
- * The end time of the last sample.
- * @param {number} op.resolution
- * The maximum amount of possible data points returned.
- * Also determines the size in milliseconds of each bucket
- * via `(endTime - startTime) / resolution`
+ * @param {number} bucketSize
+ * Size of each bucket in milliseconds.
+ * `duration / resolution = bucketSize` in OptimizationsGraph.
* @return {?Array