зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
28bdd40776
|
@ -46,12 +46,7 @@ jobs:
|
||||||
run-on-projects:
|
run-on-projects:
|
||||||
- mozilla-central
|
- mozilla-central
|
||||||
- date
|
- date
|
||||||
when:
|
when: [] # never (hook only)
|
||||||
by-project:
|
|
||||||
# Match buildbot starts for now
|
|
||||||
date: [{hour: 15, minute: 0}]
|
|
||||||
mozilla-central: [{hour: 10, minute: 0}]
|
|
||||||
# No default
|
|
||||||
|
|
||||||
- name: nightly-android
|
- name: nightly-android
|
||||||
job:
|
job:
|
||||||
|
|
|
@ -911,7 +911,6 @@ var RefreshBlocker = {
|
||||||
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
||||||
.createInstance(Ci.nsIWebProgress);
|
.createInstance(Ci.nsIWebProgress);
|
||||||
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
|
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||||
this._filter.target = tabEventTarget;
|
|
||||||
|
|
||||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsIWebProgress);
|
.getInterface(Ci.nsIWebProgress);
|
||||||
|
|
|
@ -14,8 +14,6 @@ skip-if = !debug
|
||||||
[browser_tabopen_squeeze_reflows.js]
|
[browser_tabopen_squeeze_reflows.js]
|
||||||
[browser_tabswitch_reflows.js]
|
[browser_tabswitch_reflows.js]
|
||||||
[browser_toolbariconcolor_restyles.js]
|
[browser_toolbariconcolor_restyles.js]
|
||||||
[browser_urlbar_search_reflows.js]
|
|
||||||
skip-if = os == 'mac' && !debug # Disabled due to frequent failures. Bug 1384582
|
|
||||||
[browser_windowclose_reflows.js]
|
[browser_windowclose_reflows.js]
|
||||||
[browser_windowopen_reflows.js]
|
[browser_windowopen_reflows.js]
|
||||||
skip-if = os == 'linux' # Disabled due to frequent failures. Bug 1380465.
|
skip-if = os == 'linux' # Disabled due to frequent failures. Bug 1380465.
|
||||||
|
|
|
@ -10,15 +10,12 @@
|
||||||
* for tips on how to do that.
|
* for tips on how to do that.
|
||||||
*/
|
*/
|
||||||
const EXPECTED_APPMENU_OPEN_REFLOWS = [
|
const EXPECTED_APPMENU_OPEN_REFLOWS = [
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"openPopup@chrome://global/content/bindings/popup.xml",
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
"show/</<@chrome://browser/content/customizableui/panelUI.js",
|
"show/</<@chrome://browser/content/customizableui/panelUI.js",
|
||||||
],
|
],
|
||||||
},
|
|
||||||
|
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
|
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
|
||||||
"adjustArrowPosition@chrome://global/content/bindings/popup.xml",
|
"adjustArrowPosition@chrome://global/content/bindings/popup.xml",
|
||||||
"onxblpopupshowing@chrome://global/content/bindings/popup.xml",
|
"onxblpopupshowing@chrome://global/content/bindings/popup.xml",
|
||||||
|
@ -26,33 +23,55 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [
|
||||||
"show/</<@chrome://browser/content/customizableui/panelUI.js",
|
"show/</<@chrome://browser/content/customizableui/panelUI.js",
|
||||||
],
|
],
|
||||||
|
|
||||||
times: 2, // This number should only ever go down - never up.
|
[
|
||||||
},
|
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
|
||||||
|
"adjustArrowPosition@chrome://global/content/bindings/popup.xml",
|
||||||
|
"onxblpopupshowing@chrome://global/content/bindings/popup.xml",
|
||||||
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
|
"show/</<@chrome://browser/content/customizableui/panelUI.js",
|
||||||
|
],
|
||||||
|
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
|
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
|
||||||
"adjustArrowPosition@chrome://global/content/bindings/popup.xml",
|
"adjustArrowPosition@chrome://global/content/bindings/popup.xml",
|
||||||
"onxblpopuppositioned@chrome://global/content/bindings/popup.xml",
|
"onxblpopuppositioned@chrome://global/content/bindings/popup.xml",
|
||||||
],
|
],
|
||||||
},
|
|
||||||
|
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
|
"get_alignmentPosition@chrome://global/content/bindings/popup.xml",
|
||||||
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
||||||
"openPopup@chrome://global/content/bindings/popup.xml",
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
],
|
],
|
||||||
},
|
|
||||||
|
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
||||||
"openPopup@chrome://global/content/bindings/popup.xml",
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
],
|
],
|
||||||
|
|
||||||
times: 6, // This number should only ever go down - never up.
|
[
|
||||||
},
|
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
||||||
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
||||||
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
||||||
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
||||||
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"handleEvent@resource:///modules/PanelMultiView.jsm",
|
||||||
|
"openPopup@chrome://global/content/bindings/popup.xml",
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
const EXPECTED_APPMENU_SUBVIEW_REFLOWS = [
|
const EXPECTED_APPMENU_SUBVIEW_REFLOWS = [
|
||||||
|
@ -65,14 +84,15 @@ const EXPECTED_APPMENU_SUBVIEW_REFLOWS = [
|
||||||
* If we add more views where this is necessary, we may need to duplicate
|
* If we add more views where this is necessary, we may need to duplicate
|
||||||
* these expected reflows further.
|
* these expected reflows further.
|
||||||
*/
|
*/
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"descriptionHeightWorkaround@resource:///modules/PanelMultiView.jsm",
|
"descriptionHeightWorkaround@resource:///modules/PanelMultiView.jsm",
|
||||||
"onTransitionEnd@resource:///modules/PanelMultiView.jsm",
|
"onTransitionEnd@resource:///modules/PanelMultiView.jsm",
|
||||||
],
|
],
|
||||||
|
|
||||||
times: 2, // This number should only ever go down - never up.
|
[
|
||||||
},
|
"descriptionHeightWorkaround@resource:///modules/PanelMultiView.jsm",
|
||||||
|
"onTransitionEnd@resource:///modules/PanelMultiView.jsm",
|
||||||
|
],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Please don't add anything new!
|
* Please don't add anything new!
|
||||||
|
|
|
@ -15,11 +15,9 @@
|
||||||
const EXPECTED_REFLOWS = [
|
const EXPECTED_REFLOWS = [
|
||||||
// selection change notification may cause querying the focused editor content
|
// selection change notification may cause querying the focused editor content
|
||||||
// by IME and that will cause reflow.
|
// by IME and that will cause reflow.
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"select@chrome://global/content/bindings/textbox.xml",
|
"select@chrome://global/content/bindings/textbox.xml",
|
||||||
],
|
],
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -10,13 +10,11 @@
|
||||||
* for tips on how to do that.
|
* for tips on how to do that.
|
||||||
*/
|
*/
|
||||||
const EXPECTED_REFLOWS = [
|
const EXPECTED_REFLOWS = [
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"select@chrome://global/content/bindings/textbox.xml",
|
"select@chrome://global/content/bindings/textbox.xml",
|
||||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||||
"_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
|
"_adjustFocusAfterTabSwitch@chrome://browser/content/tabbrowser.xml",
|
||||||
],
|
],
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,264 +0,0 @@
|
||||||
"use strict";
|
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
|
|
||||||
"resource://testing-common/PlacesTestUtils.jsm");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WHOA THERE: We should never be adding new things to EXPECTED_REFLOWS. This
|
|
||||||
* is a whitelist that should slowly go away as we improve the performance of
|
|
||||||
* the front-end. Instead of adding more reflows to the whitelist, you should
|
|
||||||
* be modifying your code to avoid the reflow.
|
|
||||||
*
|
|
||||||
* See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
|
|
||||||
* for tips on how to do that.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* These reflows happen only the first time the awesomebar panel opens. */
|
|
||||||
const EXPECTED_REFLOWS_FIRST_OPEN = [
|
|
||||||
// Bug 1357054
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"_rebuild@chrome://browser/content/search/search.xml",
|
|
||||||
"set_popup@chrome://browser/content/search/search.xml",
|
|
||||||
"enableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"_enableOrDisableOneOffSearches@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"urlbar_XBL_Constructor/<@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openPopup@chrome://global/content/bindings/popup.xml",
|
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml"
|
|
||||||
],
|
|
||||||
times: 1, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"adjustSiteIconStart@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_siteIconStart@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"adjustSiteIconStart@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_reuseAcItem@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"invalidate@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
times: 9, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"onxblpopupshown@chrome://global/content/bindings/autocomplete.xml"
|
|
||||||
],
|
|
||||||
times: 5, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_siteIconStart@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
times: 6, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_invalidate/this._adjustHeightTimeout<@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
times: 3, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_reuseAcItem@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"invalidate@chrome://global/content/bindings/autocomplete.xml"
|
|
||||||
],
|
|
||||||
times: 390, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
times: 3, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
// Bug 1359989
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"openPopup@chrome://global/content/bindings/popup.xml",
|
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/* These reflows happen everytime the awesomebar panel opens. */
|
|
||||||
const EXPECTED_REFLOWS_SECOND_OPEN = [
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"onxblpopupshown@chrome://global/content/bindings/autocomplete.xml"
|
|
||||||
],
|
|
||||||
times: 3, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"adjustHeight@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_invalidate/this._adjustHeightTimeout<@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
times: 3, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"_handleOverflow@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"handleOverUnderflow@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_reuseAcItem@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_appendCurrentResult@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"_invalidate@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"invalidate@chrome://global/content/bindings/autocomplete.xml"
|
|
||||||
],
|
|
||||||
times: 444, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
// Bug 1384256
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
times: 3, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
// Bug 1359989
|
|
||||||
{
|
|
||||||
stack: [
|
|
||||||
"openPopup@chrome://global/content/bindings/popup.xml",
|
|
||||||
"_openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openAutocompletePopup@chrome://browser/content/urlbarBindings.xml",
|
|
||||||
"openPopup@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
"set_popupOpen@chrome://global/content/bindings/autocomplete.xml",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Promise that resolves once the AwesomeBar popup for a particular
|
|
||||||
* window has appeared after having done a search for its input text.
|
|
||||||
*
|
|
||||||
* @param win (browser window)
|
|
||||||
* The window to do the search in.
|
|
||||||
* @returns Promise
|
|
||||||
*/
|
|
||||||
async function promiseAutocompleteResultPopup(win) {
|
|
||||||
let URLBar = win.gURLBar;
|
|
||||||
URLBar.controller.startSearch(URLBar.value);
|
|
||||||
await BrowserTestUtils.waitForEvent(URLBar.popup, "popupshown");
|
|
||||||
await BrowserTestUtils.waitForCondition(() => {
|
|
||||||
return URLBar.controller.searchStatus >=
|
|
||||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH;
|
|
||||||
});
|
|
||||||
let matchCount = URLBar.popup._matchCount;
|
|
||||||
await BrowserTestUtils.waitForCondition(() => {
|
|
||||||
return URLBar.popup.richlistbox.childNodes.length == matchCount;
|
|
||||||
});
|
|
||||||
|
|
||||||
URLBar.controller.stopSearch();
|
|
||||||
// There are several setTimeout(fn, 0); calls inside autocomplete.xml
|
|
||||||
// that we need to wait for. Since those have higher priority than
|
|
||||||
// idle callbacks, we can be sure they will have run once this
|
|
||||||
// idle callback is called. The timeout seems to be required in
|
|
||||||
// automation - presumably because the machines can be pretty busy
|
|
||||||
// especially if it's GC'ing from previous tests.
|
|
||||||
await new Promise(resolve => win.requestIdleCallback(resolve, { timeout: 1000 }));
|
|
||||||
|
|
||||||
let hiddenPromise = BrowserTestUtils.waitForEvent(URLBar.popup, "popuphidden");
|
|
||||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
|
|
||||||
await hiddenPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SEARCH_TERM = "urlbar-reflows";
|
|
||||||
|
|
||||||
add_task(async function setup() {
|
|
||||||
const NUM_VISITS = 10;
|
|
||||||
let visits = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < NUM_VISITS; ++i) {
|
|
||||||
visits.push({
|
|
||||||
uri: `http://example.com/urlbar-reflows-${i}`,
|
|
||||||
title: `Reflow test for URL bar entry #${i}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await PlacesTestUtils.addVisits(visits);
|
|
||||||
|
|
||||||
registerCleanupFunction(async function() {
|
|
||||||
await PlacesTestUtils.clearHistory();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This test ensures that there are no unexpected
|
|
||||||
* uninterruptible reflows when typing into the URL bar
|
|
||||||
* with the default values in Places.
|
|
||||||
*/
|
|
||||||
add_task(async function() {
|
|
||||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
|
||||||
await ensureNoPreloadedBrowser(win);
|
|
||||||
|
|
||||||
let URLBar = win.gURLBar;
|
|
||||||
let popup = URLBar.popup;
|
|
||||||
|
|
||||||
URLBar.focus();
|
|
||||||
URLBar.value = SEARCH_TERM;
|
|
||||||
let testFn = async function(dirtyFrameFn) {
|
|
||||||
let oldInvalidate = popup.invalidate.bind(popup);
|
|
||||||
let oldResultsAdded = popup.onResultsAdded.bind(popup);
|
|
||||||
|
|
||||||
// We need to invalidate the frame tree outside of the normal
|
|
||||||
// mechanism since invalidations and result additions to the
|
|
||||||
// URL bar occur without firing JS events (which is how we
|
|
||||||
// normally know to dirty the frame tree).
|
|
||||||
popup.invalidate = (reason) => {
|
|
||||||
dirtyFrameFn();
|
|
||||||
oldInvalidate(reason);
|
|
||||||
};
|
|
||||||
|
|
||||||
popup.onResultsAdded = () => {
|
|
||||||
dirtyFrameFn();
|
|
||||||
oldResultsAdded();
|
|
||||||
};
|
|
||||||
|
|
||||||
await promiseAutocompleteResultPopup(win);
|
|
||||||
};
|
|
||||||
|
|
||||||
await withReflowObserver(testFn, EXPECTED_REFLOWS_FIRST_OPEN, win);
|
|
||||||
|
|
||||||
await withReflowObserver(testFn, EXPECTED_REFLOWS_SECOND_OPEN, win);
|
|
||||||
|
|
||||||
await BrowserTestUtils.closeWindow(win);
|
|
||||||
});
|
|
|
@ -13,94 +13,114 @@
|
||||||
* for tips on how to do that.
|
* for tips on how to do that.
|
||||||
*/
|
*/
|
||||||
const EXPECTED_REFLOWS = [
|
const EXPECTED_REFLOWS = [
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"select@chrome://global/content/bindings/textbox.xml",
|
"select@chrome://global/content/bindings/textbox.xml",
|
||||||
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||||
"_delayedStartup@chrome://browser/content/browser.js",
|
"_delayedStartup@chrome://browser/content/browser.js",
|
||||||
],
|
],
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Services.appinfo.OS == "Linux") {
|
if (Services.appinfo.OS == "Linux") {
|
||||||
if (gMultiProcessBrowser) {
|
if (gMultiProcessBrowser) {
|
||||||
EXPECTED_REFLOWS.push({
|
EXPECTED_REFLOWS.push(
|
||||||
stack: [
|
[
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
"EventListener.handleEvent*tabbrowser-tabs_XBL_Constructor@chrome://browser/content/tabbrowser.xml",
|
"EventListener.handleEvent*tabbrowser-tabs_XBL_Constructor@chrome://browser/content/tabbrowser.xml",
|
||||||
],
|
],
|
||||||
});
|
);
|
||||||
} else {
|
} else {
|
||||||
EXPECTED_REFLOWS.push({
|
EXPECTED_REFLOWS.push(
|
||||||
stack: [
|
[
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
"inferFromText@chrome://browser/content/browser.js",
|
"inferFromText@chrome://browser/content/browser.js",
|
||||||
"handleEvent@chrome://browser/content/browser.js",
|
"handleEvent@chrome://browser/content/browser.js",
|
||||||
],
|
],
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Services.appinfo.OS == "Darwin") {
|
if (Services.appinfo.OS == "Darwin") {
|
||||||
EXPECTED_REFLOWS.push({
|
EXPECTED_REFLOWS.push(
|
||||||
stack: [
|
[
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
"inferFromText@chrome://browser/content/browser.js",
|
"inferFromText@chrome://browser/content/browser.js",
|
||||||
"handleEvent@chrome://browser/content/browser.js",
|
"handleEvent@chrome://browser/content/browser.js",
|
||||||
],
|
],
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Services.appinfo.OS == "WINNT") {
|
if (Services.appinfo.OS == "WINNT") {
|
||||||
EXPECTED_REFLOWS.push(
|
EXPECTED_REFLOWS.push(
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
|
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
],
|
],
|
||||||
times: 2, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
[
|
||||||
stack: [
|
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
"inferFromText@chrome://browser/content/browser.js",
|
"inferFromText@chrome://browser/content/browser.js",
|
||||||
"handleEvent@chrome://browser/content/browser.js",
|
"handleEvent@chrome://browser/content/browser.js",
|
||||||
],
|
],
|
||||||
},
|
|
||||||
|
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
"EventListener.handleEvent*tabbrowser-tabs_XBL_Constructor@chrome://browser/content/tabbrowser.xml",
|
"EventListener.handleEvent*tabbrowser-tabs_XBL_Constructor@chrome://browser/content/tabbrowser.xml",
|
||||||
],
|
],
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
|
if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
|
||||||
EXPECTED_REFLOWS.push(
|
EXPECTED_REFLOWS.push(
|
||||||
{
|
[
|
||||||
stack: [
|
|
||||||
"rect@chrome://browser/content/browser-tabsintitlebar.js",
|
"rect@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
],
|
],
|
||||||
times: 4, // This number should only ever go down - never up.
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
[
|
||||||
stack: [
|
"rect@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"rect@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"rect@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
|
"verticalMargins@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
"_update@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
"updateAppearance@chrome://browser/content/browser-tabsintitlebar.js",
|
||||||
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
"handleEvent@chrome://browser/content/tabbrowser.xml",
|
||||||
],
|
],
|
||||||
times: 2, // This number should only ever go down - never up.
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,42 +2,59 @@
|
||||||
* Async utility function for ensuring that no unexpected uninterruptible
|
* Async utility function for ensuring that no unexpected uninterruptible
|
||||||
* reflows occur during some period of time in a window.
|
* reflows occur during some period of time in a window.
|
||||||
*
|
*
|
||||||
|
* The helper works by running a JS function before each event is
|
||||||
|
* dispatched that attempts to dirty the layout tree - the idea being
|
||||||
|
* that this puts us in the "worst case scenario" so that any JS
|
||||||
|
* that attempts to query for layout or style information will cause
|
||||||
|
* a reflow to fire. We also dirty the layout tree after each reflow
|
||||||
|
* occurs, for good measure.
|
||||||
|
*
|
||||||
|
* This sounds good in theory, but it's trickier in practice due to
|
||||||
|
* various optimizations in our Layout engine. The default function
|
||||||
|
* for dirtying the layout tree adds a margin to the first element
|
||||||
|
* child it finds in the window to a maximum of 3px, and then goes
|
||||||
|
* back to 0px again and loops.
|
||||||
|
*
|
||||||
|
* This is not sufficient for reflows that we expect to happen within
|
||||||
|
* scrollable frames, as Gecko is able to side-step reflowing the
|
||||||
|
* contents of a scrollable frame if outer frames are dirtied. Because
|
||||||
|
* of this, it's currently possible to override the default node to
|
||||||
|
* dirty with one more appropriate for the test.
|
||||||
|
*
|
||||||
|
* It is also theoretically possible for enough events to fire between
|
||||||
|
* reflows such that the before and after state of the layout tree is
|
||||||
|
* exactly the same, meaning that no reflow is required, which opens
|
||||||
|
* us up to missing expected reflows. This seems to be possible in
|
||||||
|
* theory, but hasn't yet shown up in practice - it's just something
|
||||||
|
* to be aware of.
|
||||||
|
*
|
||||||
|
* Bug 1363361 has been filed for a more reliable way of dirtying layout.
|
||||||
|
*
|
||||||
* @param testFn (async function)
|
* @param testFn (async function)
|
||||||
* The async function that will exercise the browser activity that is
|
* The async function that will exercise the browser activity that is
|
||||||
* being tested for reflows.
|
* being tested for reflows.
|
||||||
*
|
* @param expectedStacks (Array, optional)
|
||||||
* The testFn will be passed a single argument, which is a frame dirtying
|
* An Array of Arrays representing stacks.
|
||||||
* function that can be called if the test needs to trigger frame
|
|
||||||
* dirtying outside of the normal mechanism.
|
|
||||||
* @param expectedReflows (Array, optional)
|
|
||||||
* An Array of Objects representing reflows.
|
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* [
|
* [
|
||||||
* {
|
|
||||||
* // This reflow is caused by lorem ipsum
|
* // This reflow is caused by lorem ipsum
|
||||||
* stack: [
|
* [
|
||||||
* "select@chrome://global/content/bindings/textbox.xml",
|
* "select@chrome://global/content/bindings/textbox.xml",
|
||||||
* "focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
* "focusAndSelectUrlBar@chrome://browser/content/browser.js",
|
||||||
* "openLinkIn@chrome://browser/content/utilityOverlay.js",
|
* "openLinkIn@chrome://browser/content/utilityOverlay.js",
|
||||||
* "openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
* "openUILinkIn@chrome://browser/content/utilityOverlay.js",
|
||||||
* "BrowserOpenTab@chrome://browser/content/browser.js",
|
* "BrowserOpenTab@chrome://browser/content/browser.js",
|
||||||
* ],
|
* ],
|
||||||
* // We expect this particular reflow to happen 2 times
|
|
||||||
* times: 2,
|
|
||||||
* },
|
|
||||||
*
|
*
|
||||||
* {
|
* // This reflow is caused by lorem ipsum
|
||||||
* // This reflow is caused by lorem ipsum. We expect this reflow
|
* [
|
||||||
* // to only happen once, so we can omit the "times" property.
|
|
||||||
* stack: [
|
|
||||||
* "get_scrollPosition@chrome://global/content/bindings/scrollbox.xml",
|
* "get_scrollPosition@chrome://global/content/bindings/scrollbox.xml",
|
||||||
* "_fillTrailingGap@chrome://browser/content/tabbrowser.xml",
|
* "_fillTrailingGap@chrome://browser/content/tabbrowser.xml",
|
||||||
* "_handleNewTab@chrome://browser/content/tabbrowser.xml",
|
* "_handleNewTab@chrome://browser/content/tabbrowser.xml",
|
||||||
* "onxbltransitionend@chrome://browser/content/tabbrowser.xml",
|
* "onxbltransitionend@chrome://browser/content/tabbrowser.xml",
|
||||||
* ],
|
* ],
|
||||||
* }
|
|
||||||
*
|
*
|
||||||
* ]
|
* ]
|
||||||
*
|
*
|
||||||
|
@ -49,7 +66,7 @@
|
||||||
* @param window (browser window, optional)
|
* @param window (browser window, optional)
|
||||||
* The browser window to monitor. Defaults to the current window.
|
* The browser window to monitor. Defaults to the current window.
|
||||||
*/
|
*/
|
||||||
async function withReflowObserver(testFn, expectedReflows = [], win = window) {
|
async function withReflowObserver(testFn, expectedStacks = [], win = window) {
|
||||||
let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
let dwu = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsIDOMWindowUtils);
|
.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
let dirtyFrameFn = () => {
|
let dirtyFrameFn = () => {
|
||||||
|
@ -64,14 +81,9 @@ async function withReflowObserver(testFn, expectedReflows = [], win = window) {
|
||||||
let els = Cc["@mozilla.org/eventlistenerservice;1"]
|
let els = Cc["@mozilla.org/eventlistenerservice;1"]
|
||||||
.getService(Ci.nsIEventListenerService);
|
.getService(Ci.nsIEventListenerService);
|
||||||
|
|
||||||
// We're going to remove the reflows one by one as we see them so that
|
// We're going to remove the stacks one by one as we see them so that
|
||||||
// we can check for expected, unseen reflows, so let's clone the array.
|
// we can check for expected, unseen reflows, so let's clone the array.
|
||||||
// While we're at it, for reflows that omit the "times" property, default
|
expectedStacks = expectedStacks.slice(0);
|
||||||
// it to 1.
|
|
||||||
expectedReflows = expectedReflows.slice(0);
|
|
||||||
expectedReflows.forEach(r => {
|
|
||||||
r.times = r.times || 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
let observer = {
|
let observer = {
|
||||||
reflow(start, end) {
|
reflow(start, end) {
|
||||||
|
@ -92,14 +104,12 @@ async function withReflowObserver(testFn, expectedReflows = [], win = window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = expectedReflows.findIndex(reflow => path.startsWith(reflow.stack.join("|")));
|
let index = expectedStacks.findIndex(stack => path.startsWith(stack.join("|")));
|
||||||
|
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
Assert.ok(true, "expected uninterruptible reflow: '" +
|
Assert.ok(true, "expected uninterruptible reflow: '" +
|
||||||
JSON.stringify(pathWithLineNumbers, null, "\t") + "'");
|
JSON.stringify(pathWithLineNumbers, null, "\t") + "'");
|
||||||
if (--expectedReflows[index].times == 0) {
|
expectedStacks.splice(index, 1);
|
||||||
expectedReflows.splice(index, 1);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Assert.ok(false, "unexpected uninterruptible reflow \n" +
|
Assert.ok(false, "unexpected uninterruptible reflow \n" +
|
||||||
JSON.stringify(pathWithLineNumbers, null, "\t") + "\n");
|
JSON.stringify(pathWithLineNumbers, null, "\t") + "\n");
|
||||||
|
@ -125,16 +135,16 @@ async function withReflowObserver(testFn, expectedReflows = [], win = window) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dirtyFrameFn();
|
dirtyFrameFn();
|
||||||
await testFn(dirtyFrameFn);
|
await testFn();
|
||||||
} finally {
|
} finally {
|
||||||
for (let remainder of expectedReflows) {
|
for (let remainder of expectedStacks) {
|
||||||
Assert.ok(false,
|
Assert.ok(false,
|
||||||
`Unused expected reflow: ${JSON.stringify(remainder.stack, null, "\t")}\n` +
|
`Unused expected reflow: ${JSON.stringify(remainder, null, "\t")}.\n` +
|
||||||
`This reflow was supposed to be hit ${remainder.times} more time(s).\n` +
|
|
||||||
"This is probably a good thing - just remove it from the " +
|
"This is probably a good thing - just remove it from the " +
|
||||||
"expected list.");
|
"expected list.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
els.removeListenerForAllEvents(win, dirtyFrameFn, true);
|
els.removeListenerForAllEvents(win, dirtyFrameFn, true);
|
||||||
docShell.removeWeakReflowObserver(observer);
|
docShell.removeWeakReflowObserver(observer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,7 @@ add_task(async function() {
|
||||||
"Button (" + button.id + ") starts out with correct anchor");
|
"Button (" + button.id + ") starts out with correct anchor");
|
||||||
|
|
||||||
let navbar = document.getElementById("nav-bar").customizationTarget;
|
let navbar = document.getElementById("nav-bar").customizationTarget;
|
||||||
let onMouseUp = BrowserTestUtils.waitForEvent(navbar, "mouseup");
|
|
||||||
simulateItemDrag(button, navbar);
|
simulateItemDrag(button, navbar);
|
||||||
await onMouseUp;
|
|
||||||
is(CustomizableUI.getPlacementOfWidget(button.id).area, "nav-bar",
|
is(CustomizableUI.getPlacementOfWidget(button.id).area, "nav-bar",
|
||||||
"Button (" + button.id + ") ends up in nav-bar");
|
"Button (" + button.id + ") ends up in nav-bar");
|
||||||
|
|
||||||
|
@ -57,9 +55,7 @@ add_task(async function() {
|
||||||
"Button (" + button.id + ") has no anchor in toolbar");
|
"Button (" + button.id + ") has no anchor in toolbar");
|
||||||
|
|
||||||
let panel = document.getElementById("PanelUI-contents");
|
let panel = document.getElementById("PanelUI-contents");
|
||||||
let onMouseUp = BrowserTestUtils.waitForEvent(panel, "mouseup");
|
|
||||||
simulateItemDrag(button, panel);
|
simulateItemDrag(button, panel);
|
||||||
await onMouseUp;
|
|
||||||
is(CustomizableUI.getPlacementOfWidget(button.id).area, "PanelUI-contents",
|
is(CustomizableUI.getPlacementOfWidget(button.id).area, "PanelUI-contents",
|
||||||
"Button (" + button.id + ") ends up in panel");
|
"Button (" + button.id + ") ends up in panel");
|
||||||
is(button.getAttribute(kAnchorAttribute), "PanelUI-menu-button",
|
is(button.getAttribute(kAnchorAttribute), "PanelUI-menu-button",
|
||||||
|
|
|
@ -11,7 +11,6 @@ requestLongerTimeout(2);
|
||||||
// Test toggling the toolbox quickly and see if there is any race breaking it.
|
// Test toggling the toolbox quickly and see if there is any race breaking it.
|
||||||
|
|
||||||
const URL = "data:text/html;charset=utf-8,Toggling devtools quickly";
|
const URL = "data:text/html;charset=utf-8,Toggling devtools quickly";
|
||||||
const {gDevToolsBrowser} = require("devtools/client/framework/devtools-browser");
|
|
||||||
|
|
||||||
add_task(function* () {
|
add_task(function* () {
|
||||||
// Make sure this test starts with the selectedTool pref cleared. Previous
|
// Make sure this test starts with the selectedTool pref cleared. Previous
|
||||||
|
@ -81,10 +80,5 @@ add_task(function* () {
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
// When enabling the input event prioritization, we'll reserve some time to
|
EventUtils.synthesizeKey("VK_F12", {});
|
||||||
// process input events in each frame. In that case, the synthesized input
|
|
||||||
// events may delay the normal events. Replace synthesized key events by
|
|
||||||
// toggleToolboxCommand to prevent the synthesized input events jam the
|
|
||||||
// content process and cause the test timeout.
|
|
||||||
gDevToolsBrowser.toggleToolboxCommand(window.gBrowser);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ function* respondsToMoveEvents(helper, testActor) {
|
||||||
yield mouse.move(x, y);
|
yield mouse.move(x, y);
|
||||||
} else if (type === "keyboard") {
|
} else if (type === "keyboard") {
|
||||||
let options = shift ? {shiftKey: true} : {};
|
let options = shift ? {shiftKey: true} : {};
|
||||||
yield EventUtils.synthesizeAndWaitKey(key, options);
|
yield EventUtils.synthesizeKey(key, options);
|
||||||
}
|
}
|
||||||
yield checkPosition(expected, helper);
|
yield checkPosition(expected, helper);
|
||||||
}
|
}
|
||||||
|
@ -128,14 +128,14 @@ function* checkPosition({x, y}, {getElementAttribute}) {
|
||||||
function* respondsToReturnAndEscape({isElementHidden, show}) {
|
function* respondsToReturnAndEscape({isElementHidden, show}) {
|
||||||
info("Simulating return to select the color and hide the eyedropper");
|
info("Simulating return to select the color and hide the eyedropper");
|
||||||
|
|
||||||
yield EventUtils.synthesizeAndWaitKey("VK_RETURN", {});
|
yield EventUtils.synthesizeKey("VK_RETURN", {});
|
||||||
let hidden = yield isElementHidden("root");
|
let hidden = yield isElementHidden("root");
|
||||||
ok(hidden, "The eyedropper has been hidden");
|
ok(hidden, "The eyedropper has been hidden");
|
||||||
|
|
||||||
info("Showing the eyedropper again and simulating escape to hide it");
|
info("Showing the eyedropper again and simulating escape to hide it");
|
||||||
|
|
||||||
yield show("html");
|
yield show("html");
|
||||||
yield EventUtils.synthesizeAndWaitKey("VK_ESCAPE", {});
|
yield EventUtils.synthesizeKey("VK_ESCAPE", {});
|
||||||
hidden = yield isElementHidden("root");
|
hidden = yield isElementHidden("root");
|
||||||
ok(hidden, "The eyedropper has been hidden again");
|
ok(hidden, "The eyedropper has been hidden again");
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#ifndef TabGroup_h
|
#ifndef TabGroup_h
|
||||||
#define TabGroup_h
|
#define TabGroup_h
|
||||||
|
|
||||||
#include "nsHashKeys.h"
|
|
||||||
#include "nsISupportsImpl.h"
|
#include "nsISupportsImpl.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsTHashtable.h"
|
#include "nsTHashtable.h"
|
||||||
|
@ -44,7 +43,6 @@ class TabChild;
|
||||||
// window.opener. A DocGroup is a member of exactly one TabGroup.
|
// window.opener. A DocGroup is a member of exactly one TabGroup.
|
||||||
|
|
||||||
class DocGroup;
|
class DocGroup;
|
||||||
class TabChild;
|
|
||||||
|
|
||||||
class TabGroup final : public SchedulerGroup
|
class TabGroup final : public SchedulerGroup
|
||||||
{
|
{
|
||||||
|
|
|
@ -175,30 +175,6 @@ private:
|
||||||
nsSize mSize;
|
nsSize mSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class NativeInputRunnable final : public PrioritizableRunnable
|
|
||||||
{
|
|
||||||
explicit NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent);
|
|
||||||
~NativeInputRunnable() {}
|
|
||||||
public:
|
|
||||||
static already_AddRefed<nsIRunnable> Create(already_AddRefed<nsIRunnable>&& aEvent);
|
|
||||||
};
|
|
||||||
|
|
||||||
NativeInputRunnable::NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent)
|
|
||||||
: PrioritizableRunnable(Move(aEvent), nsIRunnablePriority::PRIORITY_INPUT)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ already_AddRefed<nsIRunnable>
|
|
||||||
NativeInputRunnable::Create(already_AddRefed<nsIRunnable>&& aEvent)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIRunnable> event(new NativeInputRunnable(Move(aEvent)));
|
|
||||||
return event.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // unnamed namespace
|
|
||||||
|
|
||||||
LinkedList<OldWindowSize> OldWindowSize::sList;
|
LinkedList<OldWindowSize> OldWindowSize::sList;
|
||||||
|
|
||||||
NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
|
NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils)
|
||||||
|
@ -1144,7 +1120,7 @@ nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout,
|
||||||
if (!widget)
|
if (!widget)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
NS_DispatchToMainThread(NativeInputRunnable::Create(
|
NS_DispatchToMainThread(
|
||||||
NewRunnableMethod<int32_t,
|
NewRunnableMethod<int32_t,
|
||||||
int32_t,
|
int32_t,
|
||||||
uint32_t,
|
uint32_t,
|
||||||
|
@ -1158,7 +1134,7 @@ nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout,
|
||||||
aModifiers,
|
aModifiers,
|
||||||
aCharacters,
|
aCharacters,
|
||||||
aUnmodifiedCharacters,
|
aUnmodifiedCharacters,
|
||||||
aObserver)));
|
aObserver));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1175,7 +1151,7 @@ nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX,
|
||||||
if (!widget)
|
if (!widget)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
NS_DispatchToMainThread(NativeInputRunnable::Create(
|
NS_DispatchToMainThread(
|
||||||
NewRunnableMethod<LayoutDeviceIntPoint, int32_t, int32_t, nsIObserver*>(
|
NewRunnableMethod<LayoutDeviceIntPoint, int32_t, int32_t, nsIObserver*>(
|
||||||
"nsIWidget::SynthesizeNativeMouseEvent",
|
"nsIWidget::SynthesizeNativeMouseEvent",
|
||||||
widget,
|
widget,
|
||||||
|
@ -1183,7 +1159,7 @@ nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX,
|
||||||
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
||||||
aNativeMessage,
|
aNativeMessage,
|
||||||
aModifierFlags,
|
aModifierFlags,
|
||||||
aObserver)));
|
aObserver));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,13 +1174,12 @@ nsDOMWindowUtils::SendNativeMouseMove(int32_t aScreenX,
|
||||||
if (!widget)
|
if (!widget)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
NS_DispatchToMainThread(NativeInputRunnable::Create(
|
NS_DispatchToMainThread(NewRunnableMethod<LayoutDeviceIntPoint, nsIObserver*>(
|
||||||
NewRunnableMethod<LayoutDeviceIntPoint, nsIObserver*>(
|
|
||||||
"nsIWidget::SynthesizeNativeMouseMove",
|
"nsIWidget::SynthesizeNativeMouseMove",
|
||||||
widget,
|
widget,
|
||||||
&nsIWidget::SynthesizeNativeMouseMove,
|
&nsIWidget::SynthesizeNativeMouseMove,
|
||||||
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
||||||
aObserver)));
|
aObserver));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,8 +1201,7 @@ nsDOMWindowUtils::SendNativeMouseScrollEvent(int32_t aScreenX,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DispatchToMainThread(NativeInputRunnable::Create(
|
NS_DispatchToMainThread(NewRunnableMethod<mozilla::LayoutDeviceIntPoint,
|
||||||
NewRunnableMethod<mozilla::LayoutDeviceIntPoint,
|
|
||||||
uint32_t,
|
uint32_t,
|
||||||
double,
|
double,
|
||||||
double,
|
double,
|
||||||
|
@ -1245,7 +1219,7 @@ nsDOMWindowUtils::SendNativeMouseScrollEvent(int32_t aScreenX,
|
||||||
aDeltaZ,
|
aDeltaZ,
|
||||||
aModifierFlags,
|
aModifierFlags,
|
||||||
aAdditionalFlags,
|
aAdditionalFlags,
|
||||||
aObserver)));
|
aObserver));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1267,7 +1241,7 @@ nsDOMWindowUtils::SendNativeTouchPoint(uint32_t aPointerId,
|
||||||
return NS_ERROR_INVALID_ARG;
|
return NS_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DispatchToMainThread(NativeInputRunnable::Create(
|
NS_DispatchToMainThread(
|
||||||
NewRunnableMethod<uint32_t,
|
NewRunnableMethod<uint32_t,
|
||||||
nsIWidget::TouchPointerState,
|
nsIWidget::TouchPointerState,
|
||||||
LayoutDeviceIntPoint,
|
LayoutDeviceIntPoint,
|
||||||
|
@ -1281,7 +1255,7 @@ nsDOMWindowUtils::SendNativeTouchPoint(uint32_t aPointerId,
|
||||||
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
||||||
aPressure,
|
aPressure,
|
||||||
aOrientation,
|
aOrientation,
|
||||||
aObserver)));
|
aObserver));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1296,14 +1270,14 @@ nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DispatchToMainThread(NativeInputRunnable::Create(
|
NS_DispatchToMainThread(
|
||||||
NewRunnableMethod<LayoutDeviceIntPoint, bool, nsIObserver*>(
|
NewRunnableMethod<LayoutDeviceIntPoint, bool, nsIObserver*>(
|
||||||
"nsIWidget::SynthesizeNativeTouchTap",
|
"nsIWidget::SynthesizeNativeTouchTap",
|
||||||
widget,
|
widget,
|
||||||
&nsIWidget::SynthesizeNativeTouchTap,
|
&nsIWidget::SynthesizeNativeTouchTap,
|
||||||
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
LayoutDeviceIntPoint(aScreenX, aScreenY),
|
||||||
aLongTap,
|
aLongTap,
|
||||||
aObserver)));
|
aObserver));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1325,11 +1299,11 @@ nsDOMWindowUtils::ClearNativeTouchSequence(nsIObserver* aObserver)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_DispatchToMainThread(NativeInputRunnable::Create(
|
NS_DispatchToMainThread(
|
||||||
NewRunnableMethod<nsIObserver*>("nsIWidget::ClearNativeTouchSequence",
|
NewRunnableMethod<nsIObserver*>("nsIWidget::ClearNativeTouchSequence",
|
||||||
widget,
|
widget,
|
||||||
&nsIWidget::ClearNativeTouchSequence,
|
&nsIWidget::ClearNativeTouchSequence,
|
||||||
aObserver)));
|
aObserver));
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -849,13 +849,6 @@ nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsFrameMessageManager::GetTabEventTarget(nsIEventTarget** aTarget)
|
|
||||||
{
|
|
||||||
*aTarget = nullptr;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
|
nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
|
||||||
nsAString& aAsciiBase64String)
|
nsAString& aAsciiBase64String)
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
interface mozIDOMWindowProxy;
|
interface mozIDOMWindowProxy;
|
||||||
interface nsIDocShell;
|
interface nsIDocShell;
|
||||||
interface nsIContent;
|
interface nsIContent;
|
||||||
interface nsIEventTarget;
|
|
||||||
interface nsIFrameLoader;
|
interface nsIFrameLoader;
|
||||||
interface nsIPrincipal;
|
interface nsIPrincipal;
|
||||||
|
|
||||||
|
@ -399,12 +398,6 @@ interface nsIContentFrameMessageManager : nsIMessageManagerGlobal
|
||||||
* The top level docshell or null.
|
* The top level docshell or null.
|
||||||
*/
|
*/
|
||||||
readonly attribute nsIDocShell docShell;
|
readonly attribute nsIDocShell docShell;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the SchedulerEventTarget corresponding to the TabGroup
|
|
||||||
* for this frame.
|
|
||||||
*/
|
|
||||||
readonly attribute nsIEventTarget tabEventTarget;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[uuid(b39a3324-b574-4f85-8cdb-274d04f807ef)]
|
[uuid(b39a3324-b574-4f85-8cdb-274d04f807ef)]
|
||||||
|
|
|
@ -199,14 +199,6 @@ nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsInProcessTabChildGlobal::GetTabEventTarget(nsIEventTarget** aTarget)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIEventTarget> target = GetMainThreadEventTarget();
|
|
||||||
target.forget(aTarget);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsInProcessTabChildGlobal::FireUnloadEvent()
|
nsInProcessTabChildGlobal::FireUnloadEvent()
|
||||||
{
|
{
|
||||||
|
|
|
@ -77,7 +77,6 @@ public:
|
||||||
}
|
}
|
||||||
NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
|
NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
|
||||||
NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
|
NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
|
||||||
NS_IMETHOD GetTabEventTarget(nsIEventTarget** aTarget) override;
|
|
||||||
|
|
||||||
NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
|
NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
|
||||||
|
|
||||||
|
|
|
@ -2867,7 +2867,6 @@ NodeAllowsClickThrough(nsINode* aNode)
|
||||||
|
|
||||||
void
|
void
|
||||||
EventStateManager::PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
|
EventStateManager::PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
|
||||||
nsIFrame* aTargetFrame,
|
|
||||||
nsEventStatus& aStatus)
|
nsEventStatus& aStatus)
|
||||||
{
|
{
|
||||||
if (aStatus == nsEventStatus_eConsumeNoDefault) {
|
if (aStatus == nsEventStatus_eConsumeNoDefault) {
|
||||||
|
@ -2875,24 +2874,6 @@ EventStateManager::PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
|
if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
|
||||||
if (aKeyboardEvent->IsWaitingReplyFromRemoteProcess()) {
|
|
||||||
RefPtr<TabParent> remote = aTargetFrame ?
|
|
||||||
TabParent::GetFrom(aTargetFrame->GetContent()) : nullptr;
|
|
||||||
if (remote && !remote->IsReadyToHandleInputEvents()) {
|
|
||||||
// We need to dispatch the event to the browser element again if we were
|
|
||||||
// waiting for the key reply but the event wasn't sent to the content
|
|
||||||
// process due to the remote browser wasn't ready.
|
|
||||||
WidgetKeyboardEvent keyEvent(*aKeyboardEvent);
|
|
||||||
aKeyboardEvent->MarkAsHandledInRemoteProcess();
|
|
||||||
EventDispatcher::Dispatch(remote->GetOwnerElement(), mPresContext,
|
|
||||||
&keyEvent);
|
|
||||||
if (keyEvent.DefaultPrevented()) {
|
|
||||||
aKeyboardEvent->PreventDefault(!keyEvent.DefaultPreventedByContent());
|
|
||||||
aStatus = nsEventStatus_eConsumeNoDefault;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// The widget expects a reply for every keyboard event. If the event wasn't
|
// The widget expects a reply for every keyboard event. If the event wasn't
|
||||||
// dispatched to a content process (non-e10s or no content process
|
// dispatched to a content process (non-e10s or no content process
|
||||||
// running), we need to short-circuit here. Otherwise, we need to wait for
|
// running), we need to short-circuit here. Otherwise, we need to wait for
|
||||||
|
@ -3544,7 +3525,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
|
||||||
case eKeyPress:
|
case eKeyPress:
|
||||||
{
|
{
|
||||||
WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
|
WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
|
||||||
PostHandleKeyboardEvent(keyEvent, mCurrentTarget, *aStatus);
|
PostHandleKeyboardEvent(keyEvent, *aStatus);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ public:
|
||||||
nsEventStatus* aStatus);
|
nsEventStatus* aStatus);
|
||||||
|
|
||||||
void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
|
void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
|
||||||
nsIFrame* aTargetFrame, nsEventStatus& aStatus);
|
nsEventStatus& aStatus);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DispatchLegacyMouseScrollEvents() dispatches eLegacyMouseLineOrPageScroll
|
* DispatchLegacyMouseScrollEvents() dispatches eLegacyMouseLineOrPageScroll
|
||||||
|
|
|
@ -1141,28 +1141,9 @@ function doTestZoom(aSettings, aCallback)
|
||||||
var scrollTop = gScrollableElement.scrollTop;
|
var scrollTop = gScrollableElement.scrollTop;
|
||||||
var scrollLeft = gScrollableElement.scrollLeft;
|
var scrollLeft = gScrollableElement.scrollLeft;
|
||||||
|
|
||||||
fullZoomChangePromise = new Promise(resolve => {
|
|
||||||
if (currentTest.expected & (kNegative | kPositive)) {
|
|
||||||
SpecialPowers.addChromeEventListener("FullZoomChange", function onFullZoomChange() {
|
|
||||||
if (SpecialPowers.getFullZoom(window) != 1) {
|
|
||||||
SpecialPowers.removeChromeEventListener("FullZoomChange", onFullZoomChange)
|
|
||||||
setTimeout(() => resolve(), 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
sendWheelAndWait(10, 10, event, function () {
|
sendWheelAndWait(10, 10, event, function () {
|
||||||
is(gScrollableElement.scrollTop, scrollTop, description + "scrolled vertical");
|
is(gScrollableElement.scrollTop, scrollTop, description + "scrolled vertical");
|
||||||
is(gScrollableElement.scrollLeft, scrollLeft, description + "scrolled horizontal");
|
is(gScrollableElement.scrollLeft, scrollLeft, description + "scrolled horizontal");
|
||||||
|
|
||||||
fullZoomChangePromise.then(() => {
|
|
||||||
// When input event prioritization is enabled, the wheel event may be
|
|
||||||
// dispatched to the content process before the message 'FullZoom' to
|
|
||||||
// zoom in/out. Waiting for the event 'FullZoomChange' and then check
|
|
||||||
// the result.
|
|
||||||
if (!(currentTest.expected & (kNegative | kPositive))) {
|
if (!(currentTest.expected & (kNegative | kPositive))) {
|
||||||
is(SpecialPowers.getFullZoom(window), 1.0, description + "zoomed");
|
is(SpecialPowers.getFullZoom(window), 1.0, description + "zoomed");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1177,17 +1158,12 @@ function doTestZoom(aSettings, aCallback)
|
||||||
description + "not zoomed out, got " + SpecialPowers.getFullZoom(window));
|
description + "not zoomed out, got " + SpecialPowers.getFullZoom(window));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (SpecialPowers.getFullZoom(window) != 1) {
|
|
||||||
// Only synthesizes key event to reset zoom when necessary to avoid
|
|
||||||
// triggering the next test before the key event is handled. In that
|
|
||||||
// case, the key event may break the next test.
|
|
||||||
synthesizeKey("0", { accelKey: true });
|
synthesizeKey("0", { accelKey: true });
|
||||||
}
|
|
||||||
onZoomReset(function () {
|
onZoomReset(function () {
|
||||||
hitEventLoop(doNextTest, 20);
|
hitEventLoop(doNextTest, 20);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
doNextTest();
|
doNextTest();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1261673
|
||||||
<title>Test for Bug 1261673</title>
|
<title>Test for Bug 1261673</title>
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||||
<script type="text/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
|
|
||||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -55,15 +54,21 @@ function runTests() {
|
||||||
(p["focus"]) ? input.focus() : input.blur();
|
(p["focus"]) ? input.focus() : input.blur();
|
||||||
expectChange = p["valueChanged"] == 0 ? expectChange : expectChange + 1;
|
expectChange = p["valueChanged"] == 0 ? expectChange : expectChange + 1;
|
||||||
result += parseInt(p["valueChanged"]);
|
result += parseInt(p["valueChanged"]);
|
||||||
sendWheelAndPaint(input, 1, 1, { deltaY: p["deltaY"], deltaMode: p["deltaMode"] }, () => {
|
synthesizeWheel(input, 1, 1, { deltaY: p["deltaY"], deltaMode: p["deltaMode"] });
|
||||||
|
window.postMessage("finished", "http://mochi.test:8888");
|
||||||
|
testIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("message", event => {
|
||||||
|
if (event.data == "finished") {
|
||||||
ok(input.value == result,
|
ok(input.value == result,
|
||||||
"Handle wheel in number input test-" + testIdx + " expect " + result +
|
"Handle wheel in number input test-" + testIdx + " expect " + result +
|
||||||
" get " + input.value);
|
" get " + input.value);
|
||||||
ok(numberChange == expectChange,
|
ok(numberChange == expectChange,
|
||||||
"UA should fire change event when input's value changed, expect " + expectChange + " get " + numberChange);
|
"UA should fire change event when input's value changed, expect " + expectChange + " get " + numberChange);
|
||||||
(++testIdx >= params.length) ? SimpleTest.finish() : runNext();
|
(testIdx >= params.length) ? SimpleTest.finish() : runNext();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
runNext();
|
runNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,24 +171,6 @@ ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
|
||||||
return nsIContentParent::DeallocPBrowserParent(aParent);
|
return nsIContentParent::DeallocPBrowserParent(aParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult
|
|
||||||
ContentBridgeParent::RecvPBrowserConstructor(PBrowserParent* actor,
|
|
||||||
const TabId& tabId,
|
|
||||||
const TabId& sameTabGroupAs,
|
|
||||||
const IPCTabContext& context,
|
|
||||||
const uint32_t& chromeFlags,
|
|
||||||
const ContentParentId& cpId,
|
|
||||||
const bool& isForBrowser)
|
|
||||||
{
|
|
||||||
return nsIContentParent::RecvPBrowserConstructor(actor,
|
|
||||||
tabId,
|
|
||||||
sameTabGroupAs,
|
|
||||||
context,
|
|
||||||
chromeFlags,
|
|
||||||
cpId,
|
|
||||||
isForBrowser);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ContentBridgeParent::NotifyTabDestroyed()
|
ContentBridgeParent::NotifyTabDestroyed()
|
||||||
{
|
{
|
||||||
|
|
|
@ -138,15 +138,6 @@ protected:
|
||||||
|
|
||||||
virtual bool DeallocPBrowserParent(PBrowserParent*) override;
|
virtual bool DeallocPBrowserParent(PBrowserParent*) override;
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult
|
|
||||||
RecvPBrowserConstructor(PBrowserParent* actor,
|
|
||||||
const TabId& tabId,
|
|
||||||
const TabId& sameTabGroupAs,
|
|
||||||
const IPCTabContext& context,
|
|
||||||
const uint32_t& chromeFlags,
|
|
||||||
const ContentParentId& cpId,
|
|
||||||
const bool& isForBrowser) override;
|
|
||||||
|
|
||||||
virtual PIPCBlobInputStreamParent*
|
virtual PIPCBlobInputStreamParent*
|
||||||
SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
|
SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
|
||||||
const nsID& aID,
|
const nsID& aID,
|
||||||
|
|
|
@ -1176,9 +1176,6 @@ ContentChild::InitXPCOM(const XPCOMInitData& aXPCOMInit,
|
||||||
GfxInfoBase::SetFeatureStatus(aXPCOMInit.gfxFeatureStatus());
|
GfxInfoBase::SetFeatureStatus(aXPCOMInit.gfxFeatureStatus());
|
||||||
|
|
||||||
DataStorage::SetCachedStorageEntries(aXPCOMInit.dataStorage());
|
DataStorage::SetCachedStorageEntries(aXPCOMInit.dataStorage());
|
||||||
|
|
||||||
// Enable input event prioritization.
|
|
||||||
nsThreadManager::get().EnableMainThreadEventPrioritization();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult
|
mozilla::ipc::IPCResult
|
||||||
|
|
|
@ -2878,24 +2878,6 @@ ContentParent::DeallocPBrowserParent(PBrowserParent* frame)
|
||||||
return nsIContentParent::DeallocPBrowserParent(frame);
|
return nsIContentParent::DeallocPBrowserParent(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult
|
|
||||||
ContentParent::RecvPBrowserConstructor(PBrowserParent* actor,
|
|
||||||
const TabId& tabId,
|
|
||||||
const TabId& sameTabGroupAs,
|
|
||||||
const IPCTabContext& context,
|
|
||||||
const uint32_t& chromeFlags,
|
|
||||||
const ContentParentId& cpId,
|
|
||||||
const bool& isForBrowser)
|
|
||||||
{
|
|
||||||
return nsIContentParent::RecvPBrowserConstructor(actor,
|
|
||||||
tabId,
|
|
||||||
sameTabGroupAs,
|
|
||||||
context,
|
|
||||||
chromeFlags,
|
|
||||||
cpId,
|
|
||||||
isForBrowser);
|
|
||||||
}
|
|
||||||
|
|
||||||
PIPCBlobInputStreamParent*
|
PIPCBlobInputStreamParent*
|
||||||
ContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
|
ContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
|
||||||
const uint64_t& aSize)
|
const uint64_t& aSize)
|
||||||
|
|
|
@ -845,15 +845,6 @@ private:
|
||||||
|
|
||||||
virtual bool DeallocPBrowserParent(PBrowserParent* frame) override;
|
virtual bool DeallocPBrowserParent(PBrowserParent* frame) override;
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult
|
|
||||||
RecvPBrowserConstructor(PBrowserParent* actor,
|
|
||||||
const TabId& tabId,
|
|
||||||
const TabId& sameTabGroupAs,
|
|
||||||
const IPCTabContext& context,
|
|
||||||
const uint32_t& chromeFlags,
|
|
||||||
const ContentParentId& cpId,
|
|
||||||
const bool& isForBrowser) override;
|
|
||||||
|
|
||||||
virtual PIPCBlobInputStreamParent*
|
virtual PIPCBlobInputStreamParent*
|
||||||
SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
|
SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
|
||||||
const nsID& aID,
|
const nsID& aID,
|
||||||
|
|
|
@ -542,12 +542,6 @@ parent:
|
||||||
*/
|
*/
|
||||||
async RemotePaintIsReady();
|
async RemotePaintIsReady();
|
||||||
|
|
||||||
/**
|
|
||||||
* Child informs the parent that the content is ready to handle input
|
|
||||||
* events. This is sent when the TabChild is created.
|
|
||||||
*/
|
|
||||||
async RemoteIsReadyToHandleInputEvents();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Child informs the parent that the layer tree is already available.
|
* Child informs the parent that the layer tree is already available.
|
||||||
*/
|
*/
|
||||||
|
@ -651,9 +645,7 @@ child:
|
||||||
* When two consecutive mouse move events would be added to the message queue,
|
* When two consecutive mouse move events would be added to the message queue,
|
||||||
* they are 'compressed' by dumping the oldest one.
|
* they are 'compressed' by dumping the oldest one.
|
||||||
*/
|
*/
|
||||||
prio(input) async RealMouseMoveEvent(WidgetMouseEvent event,
|
async RealMouseMoveEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId) compress;
|
||||||
ScrollableLayerGuid aGuid,
|
|
||||||
uint64_t aInputBlockId) compress;
|
|
||||||
/**
|
/**
|
||||||
* Mouse move events with |reason == eSynthesized| are sent via a separate
|
* Mouse move events with |reason == eSynthesized| are sent via a separate
|
||||||
* message because they do not generate DOM 'mousemove' events, and the
|
* message because they do not generate DOM 'mousemove' events, and the
|
||||||
|
@ -661,29 +653,21 @@ child:
|
||||||
* |reason == eReal| event being dropped in favour of an |eSynthesized|
|
* |reason == eReal| event being dropped in favour of an |eSynthesized|
|
||||||
* event, and thus a DOM 'mousemove' event to be lost.
|
* event, and thus a DOM 'mousemove' event to be lost.
|
||||||
*/
|
*/
|
||||||
prio(input) async SynthMouseMoveEvent(WidgetMouseEvent event,
|
async SynthMouseMoveEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||||
ScrollableLayerGuid aGuid,
|
async RealMouseButtonEvent(WidgetMouseEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||||
uint64_t aInputBlockId);
|
async RealKeyEvent(WidgetKeyboardEvent event);
|
||||||
prio(input) async RealMouseButtonEvent(WidgetMouseEvent event,
|
async MouseWheelEvent(WidgetWheelEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||||
ScrollableLayerGuid aGuid,
|
async RealTouchEvent(WidgetTouchEvent aEvent,
|
||||||
uint64_t aInputBlockId);
|
|
||||||
prio(input) async RealKeyEvent(WidgetKeyboardEvent event);
|
|
||||||
prio(input) async MouseWheelEvent(WidgetWheelEvent event,
|
|
||||||
ScrollableLayerGuid aGuid,
|
|
||||||
uint64_t aInputBlockId);
|
|
||||||
prio(input) async RealTouchEvent(WidgetTouchEvent aEvent,
|
|
||||||
ScrollableLayerGuid aGuid,
|
ScrollableLayerGuid aGuid,
|
||||||
uint64_t aInputBlockId,
|
uint64_t aInputBlockId,
|
||||||
nsEventStatus aApzResponse);
|
nsEventStatus aApzResponse);
|
||||||
prio(input) async HandleTap(TapType aType, LayoutDevicePoint point,
|
async HandleTap(TapType aType, LayoutDevicePoint point, Modifiers aModifiers,
|
||||||
Modifiers aModifiers, ScrollableLayerGuid aGuid,
|
ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
|
||||||
uint64_t aInputBlockId);
|
async RealTouchMoveEvent(WidgetTouchEvent aEvent,
|
||||||
prio(input) async RealTouchMoveEvent(WidgetTouchEvent aEvent,
|
|
||||||
ScrollableLayerGuid aGuid,
|
ScrollableLayerGuid aGuid,
|
||||||
uint64_t aInputBlockId,
|
uint64_t aInputBlockId,
|
||||||
nsEventStatus aApzResponse);
|
nsEventStatus aApzResponse);
|
||||||
prio(input) async RealDragEvent(WidgetDragEvent aEvent,
|
async RealDragEvent(WidgetDragEvent aEvent, uint32_t aDragAction, uint32_t aDropEffect);
|
||||||
uint32_t aDragAction, uint32_t aDropEffect);
|
|
||||||
async PluginEvent(WidgetPluginEvent aEvent);
|
async PluginEvent(WidgetPluginEvent aEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -90,7 +90,6 @@
|
||||||
#include "nsPIWindowRoot.h"
|
#include "nsPIWindowRoot.h"
|
||||||
#include "nsLayoutUtils.h"
|
#include "nsLayoutUtils.h"
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
#include "nsThreadManager.h"
|
|
||||||
#include "nsThreadUtils.h"
|
#include "nsThreadUtils.h"
|
||||||
#include "nsViewManager.h"
|
#include "nsViewManager.h"
|
||||||
#include "nsWeakReference.h"
|
#include "nsWeakReference.h"
|
||||||
|
@ -322,19 +321,7 @@ private:
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mTabChild);
|
MOZ_ASSERT(mTabChild);
|
||||||
// When enabling input event prioritization, we reserve limited time
|
|
||||||
// to process input events. We may handle the rest in the next frame
|
|
||||||
// when running out of time of the current frame. In that case, input
|
|
||||||
// events may be dispatched after ActorDestroy. Delay
|
|
||||||
// DelayedDeleteRunnable to avoid it to happen.
|
|
||||||
nsThread* thread = nsThreadManager::get().GetCurrentThread();
|
|
||||||
MOZ_ASSERT(thread);
|
|
||||||
bool eventPrioritizationEnabled = false;
|
|
||||||
thread->IsEventPrioritizationEnabled(&eventPrioritizationEnabled);
|
|
||||||
if (eventPrioritizationEnabled && thread->HasPendingInputEvents()) {
|
|
||||||
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(this));
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
// Check in case ActorDestroy was called after RecvDestroy message.
|
// Check in case ActorDestroy was called after RecvDestroy message.
|
||||||
if (mTabChild->IPCOpen()) {
|
if (mTabChild->IPCOpen()) {
|
||||||
Unused << PBrowserChild::Send__delete__(mTabChild);
|
Unused << PBrowserChild::Send__delete__(mTabChild);
|
||||||
|
@ -3520,14 +3507,6 @@ TabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
TabChildGlobal::GetTabEventTarget(nsIEventTarget** aTarget)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIEventTarget> target = EventTargetFor(TaskCategory::Other);
|
|
||||||
target.forget(aTarget);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIPrincipal*
|
nsIPrincipal*
|
||||||
TabChildGlobal::GetPrincipal()
|
TabChildGlobal::GetPrincipal()
|
||||||
{
|
{
|
||||||
|
|
|
@ -114,7 +114,6 @@ public:
|
||||||
}
|
}
|
||||||
NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
|
NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
|
||||||
NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
|
NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
|
||||||
NS_IMETHOD GetTabEventTarget(nsIEventTarget** aTarget) override;
|
|
||||||
|
|
||||||
nsresult AddEventListener(const nsAString& aType,
|
nsresult AddEventListener(const nsAString& aType,
|
||||||
nsIDOMEventListener* aListener,
|
nsIDOMEventListener* aListener,
|
||||||
|
|
|
@ -172,8 +172,6 @@ TabParent::TabParent(nsIContentParent* aManager,
|
||||||
, mPreserveLayers(false)
|
, mPreserveLayers(false)
|
||||||
, mHasPresented(false)
|
, mHasPresented(false)
|
||||||
, mHasBeforeUnload(false)
|
, mHasBeforeUnload(false)
|
||||||
, mIsReadyToHandleInputEvents(false)
|
|
||||||
, mIsMouseEnterIntoWidgetEventSuppressed(false)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aManager);
|
MOZ_ASSERT(aManager);
|
||||||
}
|
}
|
||||||
|
@ -1083,7 +1081,7 @@ TabParent::SendKeyEvent(const nsAString& aType,
|
||||||
int32_t aModifiers,
|
int32_t aModifiers,
|
||||||
bool aPreventDefault)
|
bool aPreventDefault)
|
||||||
{
|
{
|
||||||
if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
|
if (mIsDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode,
|
Unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode,
|
||||||
|
@ -1114,33 +1112,11 @@ TabParent::SendRealMouseEvent(WidgetMouseEvent& aEvent)
|
||||||
mTabSetsCursor = false;
|
mTabSetsCursor = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mIsReadyToHandleInputEvents) {
|
|
||||||
if (eMouseEnterIntoWidget == aEvent.mMessage) {
|
|
||||||
MOZ_ASSERT(!mIsMouseEnterIntoWidgetEventSuppressed);
|
|
||||||
mIsMouseEnterIntoWidgetEventSuppressed = true;
|
|
||||||
} else if (eMouseExitFromWidget == aEvent.mMessage) {
|
|
||||||
MOZ_ASSERT(mIsMouseEnterIntoWidgetEventSuppressed);
|
|
||||||
mIsMouseEnterIntoWidgetEventSuppressed = false;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollableLayerGuid guid;
|
ScrollableLayerGuid guid;
|
||||||
uint64_t blockId;
|
uint64_t blockId;
|
||||||
ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
|
ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
|
||||||
|
|
||||||
if (mIsMouseEnterIntoWidgetEventSuppressed) {
|
|
||||||
// In the case that the TabParent suppressed the eMouseEnterWidget event due
|
|
||||||
// to its corresponding TabChild wasn't ready to handle it, we have to
|
|
||||||
// resend it when the TabChild is ready.
|
|
||||||
mIsMouseEnterIntoWidgetEventSuppressed = false;
|
|
||||||
WidgetMouseEvent localEvent(aEvent);
|
|
||||||
localEvent.mMessage = eMouseEnterIntoWidget;
|
|
||||||
DebugOnly<bool> ret = SendRealMouseButtonEvent(localEvent, guid, blockId);
|
|
||||||
NS_WARNING_ASSERTION(ret, "SendRealMouseButtonEvent(eMouseEnterIntoWidget) failed");
|
|
||||||
MOZ_ASSERT(!ret || localEvent.HasBeenPostedToRemoteProcess());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eMouseMove == aEvent.mMessage) {
|
if (eMouseMove == aEvent.mMessage) {
|
||||||
if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
|
if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
|
||||||
DebugOnly<bool> ret = SendSynthMouseMoveEvent(aEvent, guid, blockId);
|
DebugOnly<bool> ret = SendSynthMouseMoveEvent(aEvent, guid, blockId);
|
||||||
|
@ -1175,7 +1151,7 @@ void
|
||||||
TabParent::SendRealDragEvent(WidgetDragEvent& aEvent, uint32_t aDragAction,
|
TabParent::SendRealDragEvent(WidgetDragEvent& aEvent, uint32_t aDragAction,
|
||||||
uint32_t aDropEffect)
|
uint32_t aDropEffect)
|
||||||
{
|
{
|
||||||
if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
|
if (mIsDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aEvent.mRefPoint += GetChildProcessOffset();
|
aEvent.mRefPoint += GetChildProcessOffset();
|
||||||
|
@ -1194,7 +1170,7 @@ TabParent::AdjustTapToChildWidget(const LayoutDevicePoint& aPoint)
|
||||||
void
|
void
|
||||||
TabParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent)
|
TabParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent)
|
||||||
{
|
{
|
||||||
if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
|
if (mIsDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1473,7 +1449,7 @@ TabParent::RecvClearNativeTouchSequence(const uint64_t& aObserverId)
|
||||||
void
|
void
|
||||||
TabParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent)
|
TabParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent)
|
||||||
{
|
{
|
||||||
if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
|
if (mIsDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aEvent.mRefPoint += GetChildProcessOffset();
|
aEvent.mRefPoint += GetChildProcessOffset();
|
||||||
|
@ -1494,7 +1470,7 @@ TabParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent)
|
||||||
void
|
void
|
||||||
TabParent::SendRealTouchEvent(WidgetTouchEvent& aEvent)
|
TabParent::SendRealTouchEvent(WidgetTouchEvent& aEvent)
|
||||||
{
|
{
|
||||||
if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
|
if (mIsDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1555,7 +1531,7 @@ TabParent::SendHandleTap(TapType aType,
|
||||||
const ScrollableLayerGuid& aGuid,
|
const ScrollableLayerGuid& aGuid,
|
||||||
uint64_t aInputBlockId)
|
uint64_t aInputBlockId)
|
||||||
{
|
{
|
||||||
if (mIsDestroyed || !mIsReadyToHandleInputEvents) {
|
if (mIsDestroyed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap) &&
|
if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap) &&
|
||||||
|
@ -2960,18 +2936,6 @@ TabParent::RecvRemotePaintIsReady()
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult
|
|
||||||
TabParent::RecvRemoteIsReadyToHandleInputEvents()
|
|
||||||
{
|
|
||||||
// When enabling input event prioritization, input events may preempt other
|
|
||||||
// normal priority IPC messages. To prevent the input events preempt
|
|
||||||
// PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
|
|
||||||
// notify the parent that TabChild is created and ready to handle input
|
|
||||||
// events.
|
|
||||||
SetReadyToHandleInputEvents();
|
|
||||||
return IPC_OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
mozilla::plugins::PPluginWidgetParent*
|
mozilla::plugins::PPluginWidgetParent*
|
||||||
TabParent::AllocPPluginWidgetParent()
|
TabParent::AllocPPluginWidgetParent()
|
||||||
{
|
{
|
||||||
|
|
|
@ -603,9 +603,6 @@ public:
|
||||||
void LiveResizeStarted() override;
|
void LiveResizeStarted() override;
|
||||||
void LiveResizeStopped() override;
|
void LiveResizeStopped() override;
|
||||||
|
|
||||||
void SetReadyToHandleInputEvents() { mIsReadyToHandleInputEvents = true; }
|
|
||||||
bool IsReadyToHandleInputEvents() { return mIsReadyToHandleInputEvents; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ReceiveMessage(const nsString& aMessage,
|
bool ReceiveMessage(const nsString& aMessage,
|
||||||
bool aSync,
|
bool aSync,
|
||||||
|
@ -631,8 +628,6 @@ protected:
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult RecvRemotePaintIsReady() override;
|
virtual mozilla::ipc::IPCResult RecvRemotePaintIsReady() override;
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult RecvRemoteIsReadyToHandleInputEvents() override;
|
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult RecvForcePaintNoOp(const uint64_t& aLayerObserverEpoch) override;
|
virtual mozilla::ipc::IPCResult RecvForcePaintNoOp(const uint64_t& aLayerObserverEpoch) override;
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult RecvSetDimensions(const uint32_t& aFlags,
|
virtual mozilla::ipc::IPCResult RecvSetDimensions(const uint32_t& aFlags,
|
||||||
|
@ -783,14 +778,6 @@ private:
|
||||||
// beforeunload event listener.
|
// beforeunload event listener.
|
||||||
bool mHasBeforeUnload;
|
bool mHasBeforeUnload;
|
||||||
|
|
||||||
// True when the remote browser is created and ready to handle input events.
|
|
||||||
bool mIsReadyToHandleInputEvents;
|
|
||||||
|
|
||||||
// True if we suppress the eMouseEnterIntoWidget event due to the TabChild was
|
|
||||||
// not ready to handle it. We will resend it when the next time we fire a
|
|
||||||
// mouse event and the TabChild is ready.
|
|
||||||
bool mIsMouseEnterIntoWidgetEventSuppressed;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static TabParent* GetTabParentFromLayersId(uint64_t aLayersId);
|
static TabParent* GetTabParentFromLayersId(uint64_t aLayersId);
|
||||||
};
|
};
|
||||||
|
|
|
@ -102,8 +102,7 @@ nsIContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
|
||||||
if (os) {
|
if (os) {
|
||||||
os->NotifyObservers(static_cast<nsITabChild*>(tabChild), "tab-child-created", nullptr);
|
os->NotifyObservers(static_cast<nsITabChild*>(tabChild), "tab-child-created", nullptr);
|
||||||
}
|
}
|
||||||
// Notify parent that we are ready to handle input events.
|
|
||||||
tabChild->SendRemoteIsReadyToHandleInputEvents();
|
|
||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,25 +206,6 @@ nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mozilla::ipc::IPCResult
|
|
||||||
nsIContentParent::RecvPBrowserConstructor(PBrowserParent* actor,
|
|
||||||
const TabId& tabId,
|
|
||||||
const TabId& sameTabGroupAs,
|
|
||||||
const IPCTabContext& context,
|
|
||||||
const uint32_t& chromeFlags,
|
|
||||||
const ContentParentId& cpId,
|
|
||||||
const bool& isForBrowser)
|
|
||||||
{
|
|
||||||
TabParent* parent = TabParent::GetFrom(actor);
|
|
||||||
// When enabling input event prioritization, input events may preempt other
|
|
||||||
// normal priority IPC messages. To prevent the input events preempt
|
|
||||||
// PBrowserConstructor, we use an IPC 'RemoteIsReadyToHandleInputEvents' to
|
|
||||||
// notify parent that TabChild is created. In this case, PBrowser is initiated
|
|
||||||
// from content so that we can set TabParent as ready to handle input events.
|
|
||||||
parent->SetReadyToHandleInputEvents();
|
|
||||||
return IPC_OK();
|
|
||||||
}
|
|
||||||
|
|
||||||
PIPCBlobInputStreamParent*
|
PIPCBlobInputStreamParent*
|
||||||
nsIContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
|
nsIContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
|
||||||
const uint64_t& aSize)
|
const uint64_t& aSize)
|
||||||
|
|
|
@ -117,15 +117,6 @@ protected: // IPDL methods
|
||||||
const bool& aIsForBrowser);
|
const bool& aIsForBrowser);
|
||||||
virtual bool DeallocPBrowserParent(PBrowserParent* frame);
|
virtual bool DeallocPBrowserParent(PBrowserParent* frame);
|
||||||
|
|
||||||
virtual mozilla::ipc::IPCResult
|
|
||||||
RecvPBrowserConstructor(PBrowserParent* actor,
|
|
||||||
const TabId& tabId,
|
|
||||||
const TabId& sameTabGroupAs,
|
|
||||||
const IPCTabContext& context,
|
|
||||||
const uint32_t& chromeFlags,
|
|
||||||
const ContentParentId& cpId,
|
|
||||||
const bool& isForBrowser);
|
|
||||||
|
|
||||||
virtual mozilla::ipc::PIPCBlobInputStreamParent*
|
virtual mozilla::ipc::PIPCBlobInputStreamParent*
|
||||||
AllocPIPCBlobInputStreamParent(const nsID& aID, const uint64_t& aSize);
|
AllocPIPCBlobInputStreamParent(const nsID& aID, const uint64_t& aSize);
|
||||||
|
|
||||||
|
|
|
@ -18,14 +18,14 @@ add_task(async function() {
|
||||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
|
||||||
let browser = tab.linkedBrowser;
|
let browser = tab.linkedBrowser;
|
||||||
|
|
||||||
await EventUtils.synthesizeAndWaitKey("d", { code: "KeyD", repeat: 3 });
|
EventUtils.synthesizeKey("d", { code: "KeyD", repeat: 3 });
|
||||||
|
|
||||||
await ContentTask.spawn(browser, null, async function() {
|
await ContentTask.spawn(browser, null, async function() {
|
||||||
is(content.document.body.getAttribute("data-down"), "2", "Correct number of events");
|
is(content.document.body.getAttribute("data-down"), "2", "Correct number of events");
|
||||||
is(content.document.body.getAttribute("data-press"), "2", "Correct number of events");
|
is(content.document.body.getAttribute("data-press"), "2", "Correct number of events");
|
||||||
});
|
});
|
||||||
|
|
||||||
await EventUtils.synthesizeAndWaitKey("p", { code: "KeyP", repeat: 3 });
|
EventUtils.synthesizeKey("p", { code: "KeyP", repeat: 3 });
|
||||||
|
|
||||||
await ContentTask.spawn(browser, null, async function() {
|
await ContentTask.spawn(browser, null, async function() {
|
||||||
is(content.document.body.getAttribute("data-down"), "4", "Correct number of events");
|
is(content.document.body.getAttribute("data-down"), "4", "Correct number of events");
|
||||||
|
|
|
@ -43,10 +43,11 @@ add_task(async function() {
|
||||||
// but in non-e10s it is handled by the browser UI code and hence won't
|
// but in non-e10s it is handled by the browser UI code and hence won't
|
||||||
// reach the web page. As a result, we need to observe the event in
|
// reach the web page. As a result, we need to observe the event in
|
||||||
// the content process only in e10s mode.
|
// the content process only in e10s mode.
|
||||||
if (gMultiProcessBrowser) {
|
var waitForKeypressContent = BrowserTestUtils.waitForContentEvent(aBrowser, "keypress");
|
||||||
return EventUtils.synthesizeAndWaitKey("x", {accelKey: true, shiftKey: true});
|
|
||||||
}
|
|
||||||
EventUtils.synthesizeKey("x", {accelKey: true, shiftKey: true});
|
EventUtils.synthesizeKey("x", {accelKey: true, shiftKey: true});
|
||||||
|
if (gMultiProcessBrowser) {
|
||||||
|
return waitForKeypressContent;
|
||||||
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,11 +93,6 @@ function waitFor(eventType, count) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RunAfterProcessedQueuedInputEvents(aCallback) {
|
|
||||||
let tm = SpecialPowers.Services.tm;
|
|
||||||
tm.dispatchToMainThread(aCallback, SpecialPowers.Ci.nsIRunnablePriority.PRIORITY_INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
function* test(testDriver) {
|
function* test(testDriver) {
|
||||||
// The main part of this test should run completely before the child process'
|
// The main part of this test should run completely before the child process'
|
||||||
// main-thread deals with the touch event, so check to make sure that happens.
|
// main-thread deals with the touch event, so check to make sure that happens.
|
||||||
|
@ -144,8 +139,8 @@ function* test(testDriver) {
|
||||||
// scrolling even though we know we haven't yet processed the DOM touch events
|
// scrolling even though we know we haven't yet processed the DOM touch events
|
||||||
// in the child process yet.
|
// in the child process yet.
|
||||||
//
|
//
|
||||||
// Note that the "async callback" we use here is SpecialPowers.tm.dispatchToMainThread
|
// Note that the "async callback" we use here is SpecialPowers.executeSoon,
|
||||||
// with priority = input, because nothing else does exactly what we want:
|
// because nothing else does exactly what we want:
|
||||||
// - setTimeout(..., 0) does not maintain ordering, because it respects the
|
// - setTimeout(..., 0) does not maintain ordering, because it respects the
|
||||||
// time delta provided (i.e. the callback can jump the queue to meet its
|
// time delta provided (i.e. the callback can jump the queue to meet its
|
||||||
// deadline).
|
// deadline).
|
||||||
|
@ -154,9 +149,6 @@ function* test(testDriver) {
|
||||||
// round-trip time.
|
// round-trip time.
|
||||||
// - SimpleTest.executeSoon has a codepath that delegates to setTimeout, so
|
// - SimpleTest.executeSoon has a codepath that delegates to setTimeout, so
|
||||||
// is less reliable if it ever decides to switch to that codepath.
|
// is less reliable if it ever decides to switch to that codepath.
|
||||||
// - SpecialPowers.executeSoon dispatches a task to main thread. However,
|
|
||||||
// normal runnables may be preempted by input events and be executed in an
|
|
||||||
// unexpected order.
|
|
||||||
|
|
||||||
// The other problem we need to deal with is the asynchronicity in the chrome
|
// The other problem we need to deal with is the asynchronicity in the chrome
|
||||||
// process. That is, we might request a snapshot before the chrome process has
|
// process. That is, we might request a snapshot before the chrome process has
|
||||||
|
@ -177,13 +169,13 @@ function* test(testDriver) {
|
||||||
// Set up the child process events and callbacks
|
// Set up the child process events and callbacks
|
||||||
var scroller = document.getElementById('scroller');
|
var scroller = document.getElementById('scroller');
|
||||||
synthesizeNativeTouch(scroller, 10, 110, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, 0);
|
synthesizeNativeTouch(scroller, 10, 110, SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, 0);
|
||||||
RunAfterProcessedQueuedInputEvents(testDriver);
|
SpecialPowers.executeSoon(testDriver);
|
||||||
for (var i = 1; i < 10; i++) {
|
for (var i = 1; i < 10; i++) {
|
||||||
synthesizeNativeTouch(scroller, 10, 110 - (i * 10), SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, 0);
|
synthesizeNativeTouch(scroller, 10, 110 - (i * 10), SpecialPowers.DOMWindowUtils.TOUCH_CONTACT, null, 0);
|
||||||
RunAfterProcessedQueuedInputEvents(testDriver);
|
SpecialPowers.executeSoon(testDriver);
|
||||||
}
|
}
|
||||||
synthesizeNativeTouch(scroller, 10, 10, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, null, 0);
|
synthesizeNativeTouch(scroller, 10, 10, SpecialPowers.DOMWindowUtils.TOUCH_REMOVE, null, 0);
|
||||||
RunAfterProcessedQueuedInputEvents(testDriver);
|
SpecialPowers.executeSoon(testDriver);
|
||||||
ok(true, "Finished setting up event queue");
|
ok(true, "Finished setting up event queue");
|
||||||
|
|
||||||
// Get our baseline snapshot
|
// Get our baseline snapshot
|
||||||
|
|
|
@ -67,7 +67,8 @@ Message::Message(int32_t routing_id,
|
||||||
header()->routing = routing_id;
|
header()->routing = routing_id;
|
||||||
header()->type = type;
|
header()->type = type;
|
||||||
header()->flags = nestedLevel;
|
header()->flags = nestedLevel;
|
||||||
set_priority(priority);
|
if (priority == HIGH_PRIORITY)
|
||||||
|
header()->flags |= PRIO_BIT;
|
||||||
if (compression == COMPRESSION_ENABLED)
|
if (compression == COMPRESSION_ENABLED)
|
||||||
header()->flags |= COMPRESS_BIT;
|
header()->flags |= COMPRESS_BIT;
|
||||||
else if (compression == COMPRESSION_ALL)
|
else if (compression == COMPRESSION_ALL)
|
||||||
|
|
|
@ -46,9 +46,8 @@ class Message : public Pickle {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PriorityValue {
|
enum PriorityValue {
|
||||||
NORMAL_PRIORITY = 0,
|
NORMAL_PRIORITY,
|
||||||
INPUT_PRIORITY = 1,
|
HIGH_PRIORITY,
|
||||||
HIGH_PRIORITY = 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MessageCompression {
|
enum MessageCompression {
|
||||||
|
@ -92,12 +91,17 @@ class Message : public Pickle {
|
||||||
}
|
}
|
||||||
|
|
||||||
PriorityValue priority() const {
|
PriorityValue priority() const {
|
||||||
return static_cast<PriorityValue>((header()->flags & PRIO_MASK) >> 2);
|
if (header()->flags & PRIO_BIT) {
|
||||||
|
return HIGH_PRIORITY;
|
||||||
|
}
|
||||||
|
return NORMAL_PRIORITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_priority(PriorityValue prio) {
|
void set_priority(PriorityValue prio) {
|
||||||
DCHECK(((prio << 2) & ~PRIO_MASK) == 0);
|
header()->flags &= ~PRIO_BIT;
|
||||||
header()->flags = (header()->flags & ~PRIO_MASK) | (prio << 2);
|
if (prio == HIGH_PRIORITY) {
|
||||||
|
header()->flags |= PRIO_BIT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_constructor() const {
|
bool is_constructor() const {
|
||||||
|
@ -311,16 +315,16 @@ class Message : public Pickle {
|
||||||
// flags
|
// flags
|
||||||
enum {
|
enum {
|
||||||
NESTED_MASK = 0x0003,
|
NESTED_MASK = 0x0003,
|
||||||
PRIO_MASK = 0x000C,
|
PRIO_BIT = 0x0004,
|
||||||
SYNC_BIT = 0x0010,
|
SYNC_BIT = 0x0008,
|
||||||
REPLY_BIT = 0x0020,
|
REPLY_BIT = 0x0010,
|
||||||
REPLY_ERROR_BIT = 0x0040,
|
REPLY_ERROR_BIT = 0x0020,
|
||||||
INTERRUPT_BIT = 0x0080,
|
INTERRUPT_BIT = 0x0040,
|
||||||
COMPRESS_BIT = 0x0100,
|
COMPRESS_BIT = 0x0080,
|
||||||
COMPRESSALL_BIT = 0x0200,
|
COMPRESSALL_BIT = 0x0100,
|
||||||
CONSTRUCTOR_BIT = 0x0400,
|
CONSTRUCTOR_BIT = 0x0200,
|
||||||
#ifdef MOZ_TASK_TRACER
|
#ifdef MOZ_TASK_TRACER
|
||||||
TASKTRACER_BIT = 0x0800,
|
TASKTRACER_BIT = 0x0400,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1976,20 +1976,8 @@ MessageChannel::MessageTask::Clear()
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
MessageChannel::MessageTask::GetPriority(uint32_t* aPriority)
|
MessageChannel::MessageTask::GetPriority(uint32_t* aPriority)
|
||||||
{
|
{
|
||||||
switch (mMessage.priority()) {
|
*aPriority = mMessage.priority() == Message::HIGH_PRIORITY ?
|
||||||
case Message::NORMAL_PRIORITY:
|
PRIORITY_HIGH : PRIORITY_NORMAL;
|
||||||
*aPriority = PRIORITY_NORMAL;
|
|
||||||
break;
|
|
||||||
case Message::INPUT_PRIORITY:
|
|
||||||
*aPriority = PRIORITY_INPUT;
|
|
||||||
break;
|
|
||||||
case Message::HIGH_PRIORITY:
|
|
||||||
*aPriority = PRIORITY_HIGH;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MOZ_ASSERT(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,7 @@ INSIDE_SYNC_NESTED = 2
|
||||||
INSIDE_CPOW_NESTED = 3
|
INSIDE_CPOW_NESTED = 3
|
||||||
|
|
||||||
NORMAL_PRIORITY = 1
|
NORMAL_PRIORITY = 1
|
||||||
INPUT_PRIORITY = 2
|
HIGH_PRIORITY = 2
|
||||||
HIGH_PRIORITY = 3
|
|
||||||
|
|
||||||
class Visitor:
|
class Visitor:
|
||||||
def defaultVisit(self, node):
|
def defaultVisit(self, node):
|
||||||
|
|
|
@ -1725,9 +1725,8 @@ def _generateMessageConstructor(clsname, msgid, segmentSize, nested, prio, prett
|
||||||
|
|
||||||
if prio == ipdl.ast.NORMAL_PRIORITY:
|
if prio == ipdl.ast.NORMAL_PRIORITY:
|
||||||
prioEnum = 'IPC::Message::NORMAL_PRIORITY'
|
prioEnum = 'IPC::Message::NORMAL_PRIORITY'
|
||||||
elif prio == ipdl.ast.INPUT_PRIORITY:
|
|
||||||
prioEnum = 'IPC::Message::INPUT_PRIORITY'
|
|
||||||
else:
|
else:
|
||||||
|
assert prio == ipdl.ast.HIGH_PRIORITY
|
||||||
prioEnum = 'IPC::Message::HIGH_PRIORITY'
|
prioEnum = 'IPC::Message::HIGH_PRIORITY'
|
||||||
|
|
||||||
func.addstmt(
|
func.addstmt(
|
||||||
|
|
|
@ -503,8 +503,7 @@ def p_Nested(p):
|
||||||
def p_Priority(p):
|
def p_Priority(p):
|
||||||
"""Priority : ID"""
|
"""Priority : ID"""
|
||||||
kinds = {'normal': 1,
|
kinds = {'normal': 1,
|
||||||
'input': 2,
|
'high': 2}
|
||||||
'high': 3}
|
|
||||||
if p[1] not in kinds:
|
if p[1] not in kinds:
|
||||||
_error(locFromTok(p, 1), "Expected normal or high for prio()")
|
_error(locFromTok(p, 1), "Expected normal or high for prio()")
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,11 @@ namespace _ipdltest {
|
||||||
|
|
||||||
sync protocol PTestPriority {
|
sync protocol PTestPriority {
|
||||||
parent:
|
parent:
|
||||||
prio(input) async PMsg1();
|
prio(high) async Msg1();
|
||||||
prio(input) sync PMsg2();
|
prio(high) sync Msg2();
|
||||||
prio(high) async PMsg3();
|
|
||||||
prio(high) sync PMsg4();
|
|
||||||
|
|
||||||
child:
|
child:
|
||||||
prio(input) async CMsg1();
|
prio(high) async Msg3();
|
||||||
prio(high) async CMsg2();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace _ipdltest
|
} // namespace _ipdltest
|
||||||
|
|
|
@ -255,13 +255,6 @@ public:
|
||||||
return idleEnd < aDefault ? idleEnd : aDefault;
|
return idleEnd < aDefault ? idleEnd : aDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<TimeStamp> GetNextTickHint()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
TimeStamp nextTick = MostRecentRefresh() + GetTimerRate();
|
|
||||||
return nextTick < TimeStamp::Now() ? Nothing() : Some(nextTick);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void StartTimer() = 0;
|
virtual void StartTimer() = 0;
|
||||||
virtual void StopTimer() = 0;
|
virtual void StopTimer() = 0;
|
||||||
|
@ -2409,17 +2402,6 @@ nsRefreshDriver::GetIdleDeadlineHint(TimeStamp aDefault)
|
||||||
return sRegularRateTimer->GetIdleDeadlineHint(aDefault);
|
return sRegularRateTimer->GetIdleDeadlineHint(aDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ Maybe<TimeStamp>
|
|
||||||
nsRefreshDriver::GetNextTickHint()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (!sRegularRateTimer) {
|
|
||||||
return Nothing();
|
|
||||||
}
|
|
||||||
return sRegularRateTimer->GetNextTickHint();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsRefreshDriver::Disconnect()
|
nsRefreshDriver::Disconnect()
|
||||||
{
|
{
|
||||||
|
|
|
@ -345,12 +345,6 @@ public:
|
||||||
*/
|
*/
|
||||||
static mozilla::TimeStamp GetIdleDeadlineHint(mozilla::TimeStamp aDefault);
|
static mozilla::TimeStamp GetIdleDeadlineHint(mozilla::TimeStamp aDefault);
|
||||||
|
|
||||||
/**
|
|
||||||
* It returns the expected timestamp of the next tick or nothing if the next
|
|
||||||
* tick is missed.
|
|
||||||
*/
|
|
||||||
static mozilla::Maybe<mozilla::TimeStamp> GetNextTickHint();
|
|
||||||
|
|
||||||
static void DispatchIdleRunnableAfterTick(nsIRunnable* aRunnable,
|
static void DispatchIdleRunnableAfterTick(nsIRunnable* aRunnable,
|
||||||
uint32_t aDelay);
|
uint32_t aDelay);
|
||||||
static void CancelIdleRunnable(nsIRunnable* aRunnable);
|
static void CancelIdleRunnable(nsIRunnable* aRunnable);
|
||||||
|
|
|
@ -3123,26 +3123,6 @@ pref("dom.idle_period.throttled_length", 10000);
|
||||||
// The amount of idle time (milliseconds) reserved for a long idle period
|
// The amount of idle time (milliseconds) reserved for a long idle period
|
||||||
pref("idle_queue.long_period", 50);
|
pref("idle_queue.long_period", 50);
|
||||||
|
|
||||||
// Control the event prioritization on content main thread
|
|
||||||
#ifdef NIGHTLY_BUILD
|
|
||||||
pref("prioritized_input_events.enabled", true);
|
|
||||||
#else
|
|
||||||
pref("prioritized_input_events.enabled", false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// The maximum and minimum time (milliseconds) we reserve for handling input
|
|
||||||
// events in each frame.
|
|
||||||
pref("prioritized_input_events.duration.max", 8);
|
|
||||||
pref("prioritized_input_events.duration.min", 1);
|
|
||||||
|
|
||||||
// The default amount of time (milliseconds) required for handling a input
|
|
||||||
// event.
|
|
||||||
pref("prioritized_input_events.default_duration_per_event", 1);
|
|
||||||
|
|
||||||
// The number of processed input events we use to predict the amount of time
|
|
||||||
// required to process the following input events.
|
|
||||||
pref("prioritized_input_events.count_for_prediction", 9);
|
|
||||||
|
|
||||||
// The minimum amount of time (milliseconds) required for an idle
|
// The minimum amount of time (milliseconds) required for an idle
|
||||||
// period to be scheduled on the main thread. N.B. that
|
// period to be scheduled on the main thread. N.B. that
|
||||||
// layout.idle_period.time_limit adds padding at the end of the idle
|
// layout.idle_period.time_limit adds padding at the end of the idle
|
||||||
|
|
|
@ -678,44 +678,6 @@ function synthesizeNativeMouseMove(aTarget, aOffsetX, aOffsetY, aCallback, aWind
|
||||||
utils.sendNativeMouseMove(x * scale, y * scale, null, observer);
|
utils.sendNativeMouseMove(x * scale, y * scale, null, observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a wrapper around synthesizeNativeMouseMove that waits for the mouse
|
|
||||||
* event to be dispatched to the target content.
|
|
||||||
*
|
|
||||||
* This API is supposed to be used in those test cases that synthesize some
|
|
||||||
* input events to chrome process and have some checks in content.
|
|
||||||
*/
|
|
||||||
function synthesizeAndWaitNativeMouseMove(aTarget, aOffsetX, aOffsetY,
|
|
||||||
aCallback, aWindow = window) {
|
|
||||||
let browser = gBrowser.selectedTab.linkedBrowser;
|
|
||||||
let mm = browser.messageManager;
|
|
||||||
let ContentTask =
|
|
||||||
_EU_Cu.import("resource://testing-common/ContentTask.jsm", null).ContentTask;
|
|
||||||
|
|
||||||
let eventRegisteredPromise = new Promise(resolve => {
|
|
||||||
mm.addMessageListener("Test:MouseMoveRegistered", function processed(message) {
|
|
||||||
mm.removeMessageListener("Test:MouseMoveRegistered", processed);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
let eventReceivedPromise = ContentTask.spawn(browser, [aOffsetX, aOffsetY],
|
|
||||||
([clientX, clientY]) => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
addEventListener("mousemove", function onMouseMoveEvent(e) {
|
|
||||||
if (e.clientX == clientX && e.clientY == clientY) {
|
|
||||||
removeEventListener("mousemove", onMouseMoveEvent);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sendAsyncMessage("Test:MouseMoveRegistered");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
eventRegisteredPromise.then(() => {
|
|
||||||
synthesizeNativeMouseMove(aTarget, aOffsetX, aOffsetY, null, aWindow);
|
|
||||||
});
|
|
||||||
return eventReceivedPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _computeKeyCodeFromChar(aChar)
|
function _computeKeyCodeFromChar(aChar)
|
||||||
{
|
{
|
||||||
if (aChar.length != 1) {
|
if (aChar.length != 1) {
|
||||||
|
@ -867,51 +829,6 @@ function synthesizeKey(aKey, aEvent, aWindow = window, aCallback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a wrapper around synthesizeKey that waits for the key event to be
|
|
||||||
* dispatched to the target content. It returns a promise which is resolved
|
|
||||||
* when the content receives the key event.
|
|
||||||
*
|
|
||||||
* This API is supposed to be used in those test cases that synthesize some
|
|
||||||
* input events to chrome process and have some checks in content.
|
|
||||||
*/
|
|
||||||
function synthesizeAndWaitKey(aKey, aEvent, aWindow = window,
|
|
||||||
checkBeforeSynthesize, checkAfterSynthesize)
|
|
||||||
{
|
|
||||||
let browser = gBrowser.selectedTab.linkedBrowser;
|
|
||||||
let mm = browser.messageManager;
|
|
||||||
let keyCode = _createKeyboardEventDictionary(aKey, aEvent, aWindow).dictionary.keyCode;
|
|
||||||
let ContentTask = _EU_Cu.import("resource://testing-common/ContentTask.jsm", null).ContentTask;
|
|
||||||
|
|
||||||
let keyRegisteredPromise = new Promise(resolve => {
|
|
||||||
mm.addMessageListener("Test:KeyRegistered", function processed(message) {
|
|
||||||
mm.removeMessageListener("Test:KeyRegistered", processed);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
let keyReceivedPromise = ContentTask.spawn(browser, keyCode, (keyCode) => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
addEventListener("keyup", function onKeyEvent(e) {
|
|
||||||
if (e.keyCode == keyCode) {
|
|
||||||
removeEventListener("keyup", onKeyEvent);
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sendAsyncMessage("Test:KeyRegistered");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
keyRegisteredPromise.then(() => {
|
|
||||||
if (checkBeforeSynthesize) {
|
|
||||||
checkBeforeSynthesize();
|
|
||||||
}
|
|
||||||
synthesizeKey(aKey, aEvent, aWindow);
|
|
||||||
if (checkAfterSynthesize) {
|
|
||||||
checkAfterSynthesize();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return keyReceivedPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _parseNativeModifiers(aModifiers, aWindow = window)
|
function _parseNativeModifiers(aModifiers, aWindow = window)
|
||||||
{
|
{
|
||||||
var navigator = _getNavigator(aWindow);
|
var navigator = _getNavigator(aWindow);
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include "nsITimer.h"
|
#include "nsITimer.h"
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsThreadUtils.h"
|
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
|
@ -18,8 +17,7 @@ using namespace mozilla;
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
nsBrowserStatusFilter::nsBrowserStatusFilter()
|
nsBrowserStatusFilter::nsBrowserStatusFilter()
|
||||||
: mTarget(GetMainThreadEventTarget())
|
: mCurProgress(0)
|
||||||
, mCurProgress(0)
|
|
||||||
, mMaxProgress(0)
|
, mMaxProgress(0)
|
||||||
, mStatusIsDirty(true)
|
, mStatusIsDirty(true)
|
||||||
, mCurrentPercentage(0)
|
, mCurrentPercentage(0)
|
||||||
|
@ -114,21 +112,6 @@ nsBrowserStatusFilter::GetLoadType(uint32_t *aLoadType)
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsBrowserStatusFilter::GetTarget(nsIEventTarget** aTarget)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIEventTarget> target = mTarget;
|
|
||||||
target.forget(aTarget);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsBrowserStatusFilter::SetTarget(nsIEventTarget* aTarget)
|
|
||||||
{
|
|
||||||
mTarget = aTarget;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// nsBrowserStatusFilter::nsIWebProgressListener
|
// nsBrowserStatusFilter::nsIWebProgressListener
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -379,7 +362,9 @@ nsBrowserStatusFilter::StartDelayTimer()
|
||||||
if (!mTimer)
|
if (!mTimer)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
mTimer->SetTarget(mTarget);
|
// Use the system group. The browser status filter is always used by chrome
|
||||||
|
// code.
|
||||||
|
mTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::Other));
|
||||||
return mTimer->InitWithNamedFuncCallback(
|
return mTimer->InitWithNamedFuncCallback(
|
||||||
TimeoutHandler, this, 160, nsITimer::TYPE_ONE_SHOT,
|
TimeoutHandler, this, 160, nsITimer::TYPE_ONE_SHOT,
|
||||||
"nsBrowserStatusFilter::TimeoutHandler");
|
"nsBrowserStatusFilter::TimeoutHandler");
|
||||||
|
|
|
@ -46,7 +46,6 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<nsIWebProgressListener> mListener;
|
nsCOMPtr<nsIWebProgressListener> mListener;
|
||||||
nsCOMPtr<nsIEventTarget> mTarget;
|
|
||||||
nsCOMPtr<nsITimer> mTimer;
|
nsCOMPtr<nsITimer> mTimer;
|
||||||
|
|
||||||
// delayed values
|
// delayed values
|
||||||
|
|
|
@ -34,7 +34,9 @@ async function do_test(test) {
|
||||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
|
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||||
|
|
||||||
info("Moving mouse out of the way.");
|
info("Moving mouse out of the way.");
|
||||||
await EventUtils.synthesizeAndWaitNativeMouseMove(tab.linkedBrowser, 300, 300);
|
await new Promise(resolve => {
|
||||||
|
EventUtils.synthesizeNativeMouseMove(tab.linkedBrowser, 300, 300, resolve);
|
||||||
|
});
|
||||||
|
|
||||||
info("creating input field");
|
info("creating input field");
|
||||||
await ContentTask.spawn(tab.linkedBrowser, test, async function(test) {
|
await ContentTask.spawn(tab.linkedBrowser, test, async function(test) {
|
||||||
|
@ -90,11 +92,15 @@ async function do_test(test) {
|
||||||
}, {once: true});
|
}, {once: true});
|
||||||
});
|
});
|
||||||
info("Initial mouse move");
|
info("Initial mouse move");
|
||||||
await EventUtils.synthesizeAndWaitNativeMouseMove(tab.linkedBrowser, 50, 5);
|
await new Promise(resolve => {
|
||||||
|
EventUtils.synthesizeNativeMouseMove(tab.linkedBrowser, 50, 5, resolve);
|
||||||
|
});
|
||||||
info("Waiting");
|
info("Waiting");
|
||||||
await new Promise(resolve => setTimeout(resolve, 400));
|
await new Promise(resolve => setTimeout(resolve, 400));
|
||||||
info("Second mouse move");
|
info("Second mouse move");
|
||||||
await EventUtils.synthesizeAndWaitNativeMouseMove(tab.linkedBrowser, 70, 5);
|
await new Promise(resolve => {
|
||||||
|
EventUtils.synthesizeNativeMouseMove(tab.linkedBrowser, 70, 5, resolve);
|
||||||
|
});
|
||||||
info("Waiting for tooltip to open");
|
info("Waiting for tooltip to open");
|
||||||
let tooltip = await awaitTooltipOpen;
|
let tooltip = await awaitTooltipOpen;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ var WebProgressListener = {
|
||||||
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
||||||
.createInstance(Ci.nsIWebProgress);
|
.createInstance(Ci.nsIWebProgress);
|
||||||
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
|
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||||
this._filter.target = tabEventTarget;
|
|
||||||
|
|
||||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsIWebProgress);
|
.getInterface(Ci.nsIWebProgress);
|
||||||
|
|
|
@ -175,11 +175,7 @@ add_task(async function() {
|
||||||
let findBar = gFindBar;
|
let findBar = gFindBar;
|
||||||
let initialValue = findBar._findField.value;
|
let initialValue = findBar._findField.value;
|
||||||
|
|
||||||
await EventUtils.synthesizeAndWaitKey("f", { accelKey: true }, window, null,
|
EventUtils.synthesizeKey("f", { accelKey: true }, window);
|
||||||
() => {
|
|
||||||
isnot(document.activeElement, findBar._findField.inputField,
|
|
||||||
"findbar is not yet focused");
|
|
||||||
});
|
|
||||||
|
|
||||||
let promises = [
|
let promises = [
|
||||||
BrowserTestUtils.sendChar("a", browser),
|
BrowserTestUtils.sendChar("a", browser),
|
||||||
|
@ -187,6 +183,8 @@ add_task(async function() {
|
||||||
BrowserTestUtils.sendChar("c", browser)
|
BrowserTestUtils.sendChar("c", browser)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
isnot(document.activeElement, findBar._findField.inputField,
|
||||||
|
"findbar is not yet focused");
|
||||||
is(findBar._findField.value, initialValue, "still has initial find query");
|
is(findBar._findField.value, initialValue, "still has initial find query");
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
|
@ -22,7 +22,6 @@ module.exports = {
|
||||||
removeWeakMessageListener: false,
|
removeWeakMessageListener: false,
|
||||||
sendAsyncMessage: false,
|
sendAsyncMessage: false,
|
||||||
sendSyncMessage: false,
|
sendSyncMessage: false,
|
||||||
sendRpcMessage: false,
|
sendRpcMessage: false
|
||||||
tabEventTarget: false
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nspr.h"
|
#include "nspr.h"
|
||||||
#include "mozilla/dom/TabGroup.h"
|
|
||||||
#include "mozilla/Logging.h"
|
#include "mozilla/Logging.h"
|
||||||
#include "mozilla/IntegerPrintfMacros.h"
|
#include "mozilla/IntegerPrintfMacros.h"
|
||||||
|
|
||||||
|
@ -981,27 +980,6 @@ nsDocLoader::GetLoadType(uint32_t *aLoadType)
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsDocLoader::GetTarget(nsIEventTarget** aTarget)
|
|
||||||
{
|
|
||||||
nsCOMPtr<mozIDOMWindowProxy> window;
|
|
||||||
nsresult rv = GetDOMWindow(getter_AddRefs(window));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> piwindow = nsPIDOMWindowOuter::From(window);
|
|
||||||
NS_ENSURE_STATE(piwindow);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIEventTarget> target = piwindow->TabGroup()->EventTargetFor(mozilla::TaskCategory::Other);
|
|
||||||
target.forget(aTarget);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsDocLoader::SetTarget(nsIEventTarget* aTarget)
|
|
||||||
{
|
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t nsDocLoader::GetMaxTotalProgress()
|
int64_t nsDocLoader::GetMaxTotalProgress()
|
||||||
{
|
{
|
||||||
int64_t newMaxTotal = 0;
|
int64_t newMaxTotal = 0;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "nsISupports.idl"
|
#include "nsISupports.idl"
|
||||||
|
|
||||||
interface mozIDOMWindowProxy;
|
interface mozIDOMWindowProxy;
|
||||||
interface nsIEventTarget;
|
|
||||||
interface nsIWebProgressListener;
|
interface nsIWebProgressListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -152,11 +151,4 @@ interface nsIWebProgress : nsISupports
|
||||||
* nsIDocShellLoadInfo.idl.
|
* nsIDocShellLoadInfo.idl.
|
||||||
*/
|
*/
|
||||||
readonly attribute unsigned long loadType;
|
readonly attribute unsigned long loadType;
|
||||||
|
|
||||||
/**
|
|
||||||
* Main thread event target to which progress updates should be
|
|
||||||
* dispatched. This typically will be a SchedulerEventTarget
|
|
||||||
* corresponding to the tab requesting updates.
|
|
||||||
*/
|
|
||||||
attribute nsIEventTarget target;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -100,16 +100,6 @@ function onEvent(aEvent)
|
||||||
setTimeout(gCallback, 0);
|
setTimeout(gCallback, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function observeKeyUpOnContent(aKeyCode, aCallback)
|
|
||||||
{
|
|
||||||
document.addEventListener("keyup", function keyUp(ev) {
|
|
||||||
if (ev.keyCode == aKeyCode) {
|
|
||||||
document.removeEventListener("keyup", keyUp);
|
|
||||||
SimpleTest.executeSoon(aCallback);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const kTests = [
|
const kTests = [
|
||||||
{ description: "InternalScrollPortEvent (overflow, vertical)",
|
{ description: "InternalScrollPortEvent (overflow, vertical)",
|
||||||
targetID: "scrollable-div", eventType: "overflow",
|
targetID: "scrollable-div", eventType: "overflow",
|
||||||
|
@ -160,8 +150,6 @@ const kTests = [
|
||||||
document.getElementById(this.targetID).focus();
|
document.getElementById(this.targetID).focus();
|
||||||
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_A : MAC_VK_ANSI_A,
|
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_A : MAC_VK_ANSI_A,
|
||||||
{}, "a", "a");
|
{}, "a", "a");
|
||||||
observeKeyUpOnContent(KeyboardEvent.DOM_VK_A, runNextTest);
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
canRun: function () {
|
canRun: function () {
|
||||||
return (kIsMac || kIsWin);
|
return (kIsMac || kIsWin);
|
||||||
|
@ -175,8 +163,6 @@ const kTests = [
|
||||||
document.getElementById(this.targetID).focus();
|
document.getElementById(this.targetID).focus();
|
||||||
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_A : MAC_VK_ANSI_A,
|
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_A : MAC_VK_ANSI_A,
|
||||||
{}, "a", "a");
|
{}, "a", "a");
|
||||||
observeKeyUpOnContent(KeyboardEvent.DOM_VK_A, runNextTest);
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
canRun: function () {
|
canRun: function () {
|
||||||
return (kIsMac || kIsWin);
|
return (kIsMac || kIsWin);
|
||||||
|
@ -190,8 +176,6 @@ const kTests = [
|
||||||
document.getElementById(this.targetID).focus();
|
document.getElementById(this.targetID).focus();
|
||||||
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_B : MAC_VK_ANSI_B,
|
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_B : MAC_VK_ANSI_B,
|
||||||
{ shiftKey: true }, "B", "B");
|
{ shiftKey: true }, "B", "B");
|
||||||
observeKeyUpOnContent(KeyboardEvent.DOM_VK_B, runNextTest);
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
canRun: function () {
|
canRun: function () {
|
||||||
return (kIsMac || kIsWin);
|
return (kIsMac || kIsWin);
|
||||||
|
@ -205,14 +189,6 @@ const kTests = [
|
||||||
document.getElementById(this.targetID).focus();
|
document.getElementById(this.targetID).focus();
|
||||||
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_C : MAC_VK_ANSI_C,
|
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_C : MAC_VK_ANSI_C,
|
||||||
{ accelKey: true }, kIsWin ? "\u0003" : "c", "c");
|
{ accelKey: true }, kIsWin ? "\u0003" : "c", "c");
|
||||||
|
|
||||||
// On Windows, synthesizeNativeKey will also fire keyup for accelKey
|
|
||||||
// (control key on Windows). We have to wait for it to prevent the key
|
|
||||||
// event break the next test case.
|
|
||||||
let waitKeyCode = _EU_isWin(window) ? KeyboardEvent.DOM_VK_CONTROL :
|
|
||||||
KeyboardEvent.DOM_VK_C;
|
|
||||||
observeKeyUpOnContent(waitKeyCode, runNextTest);
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
canRun: function () {
|
canRun: function () {
|
||||||
return (kIsMac || kIsWin);
|
return (kIsMac || kIsWin);
|
||||||
|
@ -349,8 +325,6 @@ const kTests = [
|
||||||
document.getElementById(this.targetID).focus();
|
document.getElementById(this.targetID).focus();
|
||||||
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_B : MAC_VK_ANSI_B,
|
synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, kIsWin ? WIN_VK_B : MAC_VK_ANSI_B,
|
||||||
{ shiftKey: true }, "B", "B");
|
{ shiftKey: true }, "B", "B");
|
||||||
observeKeyUpOnContent(KeyboardEvent.DOM_VK_B, runNextTest);
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
canRun: function () {
|
canRun: function () {
|
||||||
return (kIsMac || kIsWin);
|
return (kIsMac || kIsWin);
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#include "InputEventStatistics.h"
|
|
||||||
|
|
||||||
#include "nsRefreshDriver.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
TimeDuration
|
|
||||||
InputEventStatistics::TimeDurationCircularBuffer::GetMean()
|
|
||||||
{
|
|
||||||
return mTotal / (int64_t)mSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputEventStatistics::InputEventStatistics()
|
|
||||||
: mEnable(false)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(Preferences::IsServiceAvailable());
|
|
||||||
uint32_t inputDuration =
|
|
||||||
Preferences::GetUint("prioritized_input_events.default_duration_per_event",
|
|
||||||
sDefaultInputDuration);
|
|
||||||
|
|
||||||
TimeDuration defaultDuration = TimeDuration::FromMilliseconds(inputDuration);
|
|
||||||
|
|
||||||
uint32_t count =
|
|
||||||
Preferences::GetUint("prioritized_input_events.count_for_prediction",
|
|
||||||
sInputCountForPrediction);
|
|
||||||
|
|
||||||
mLastInputDurations =
|
|
||||||
MakeUnique<TimeDurationCircularBuffer>(count, defaultDuration);
|
|
||||||
|
|
||||||
uint32_t maxDuration =
|
|
||||||
Preferences::GetUint("prioritized_input_events.duration.max",
|
|
||||||
sMaxReservedTimeForHandlingInput);
|
|
||||||
|
|
||||||
uint32_t minDuration =
|
|
||||||
Preferences::GetUint("prioritized_input_events.duration.min",
|
|
||||||
sMinReservedTimeForHandlingInput);
|
|
||||||
|
|
||||||
mMaxInputDuration = TimeDuration::FromMilliseconds(maxDuration);
|
|
||||||
mMinInputDuration = TimeDuration::FromMilliseconds(minDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeStamp
|
|
||||||
InputEventStatistics::GetInputHandlingStartTime(uint32_t aInputCount)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mEnable);
|
|
||||||
Maybe<TimeStamp> nextTickHint = nsRefreshDriver::GetNextTickHint();
|
|
||||||
|
|
||||||
if (nextTickHint.isNothing()) {
|
|
||||||
// Return a past time to process input events immediately.
|
|
||||||
return TimeStamp::Now() - TimeDuration::FromMilliseconds(1);
|
|
||||||
}
|
|
||||||
TimeDuration inputCost = mLastInputDurations->GetMean() * aInputCount;
|
|
||||||
inputCost = inputCost > mMaxInputDuration
|
|
||||||
? mMaxInputDuration
|
|
||||||
: inputCost < mMinInputDuration
|
|
||||||
? mMinInputDuration
|
|
||||||
: inputCost;
|
|
||||||
|
|
||||||
return nextTickHint.value() - inputCost;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
|
@ -1,114 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
#if !defined(InputEventStatistics_h_)
|
|
||||||
#define InputEventStatistics_h_
|
|
||||||
|
|
||||||
#include "mozilla/Maybe.h"
|
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#include "mozilla/TimeStamp.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
|
|
||||||
class InputEventStatistics
|
|
||||||
{
|
|
||||||
// The default amount of time (milliseconds) required for handling a input
|
|
||||||
// event.
|
|
||||||
static const uint16_t sDefaultInputDuration = 1;
|
|
||||||
|
|
||||||
// The number of processed input events we use to predict the amount of time
|
|
||||||
// required to process the following input events.
|
|
||||||
static const uint16_t sInputCountForPrediction = 9;
|
|
||||||
|
|
||||||
// The default maximum and minimum time (milliseconds) we reserve for handling
|
|
||||||
// input events in each frame.
|
|
||||||
static const uint16_t sMaxReservedTimeForHandlingInput = 8;
|
|
||||||
static const uint16_t sMinReservedTimeForHandlingInput = 1;
|
|
||||||
|
|
||||||
class TimeDurationCircularBuffer
|
|
||||||
{
|
|
||||||
int16_t mSize;
|
|
||||||
int16_t mCurrentIndex;
|
|
||||||
nsTArray<TimeDuration> mBuffer;
|
|
||||||
TimeDuration mTotal;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TimeDurationCircularBuffer(uint32_t aSize, TimeDuration& aDefaultValue)
|
|
||||||
: mSize(aSize)
|
|
||||||
, mCurrentIndex(0)
|
|
||||||
{
|
|
||||||
mSize = mSize == 0 ? sInputCountForPrediction : mSize;
|
|
||||||
for (int16_t index = 0; index < mSize; ++index) {
|
|
||||||
mBuffer.AppendElement(aDefaultValue);
|
|
||||||
mTotal += aDefaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Insert(TimeDuration& aDuration)
|
|
||||||
{
|
|
||||||
mTotal += (aDuration - mBuffer[mCurrentIndex]);
|
|
||||||
mBuffer[mCurrentIndex++] = aDuration;
|
|
||||||
if (mCurrentIndex == mSize) {
|
|
||||||
mCurrentIndex = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeDuration GetMean();
|
|
||||||
};
|
|
||||||
|
|
||||||
UniquePtr<TimeDurationCircularBuffer> mLastInputDurations;
|
|
||||||
TimeDuration mMaxInputDuration;
|
|
||||||
TimeDuration mMinInputDuration;
|
|
||||||
bool mEnable;
|
|
||||||
|
|
||||||
InputEventStatistics();
|
|
||||||
~InputEventStatistics()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static InputEventStatistics& Get()
|
|
||||||
{
|
|
||||||
static InputEventStatistics sInstance;
|
|
||||||
return sInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateInputDuration(TimeDuration aDuration)
|
|
||||||
{
|
|
||||||
if (!mEnable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mLastInputDurations->Insert(aDuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeStamp GetInputHandlingStartTime(uint32_t aInputCount);
|
|
||||||
|
|
||||||
void SetEnable(bool aEnable)
|
|
||||||
{
|
|
||||||
mEnable = aEnable;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MOZ_RAII AutoTimeDurationHelper final
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AutoTimeDurationHelper()
|
|
||||||
{
|
|
||||||
mStartTime = TimeStamp::Now();
|
|
||||||
}
|
|
||||||
|
|
||||||
~AutoTimeDurationHelper()
|
|
||||||
{
|
|
||||||
InputEventStatistics::Get().UpdateInputDuration(TimeStamp::Now() - mStartTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
TimeStamp mStartTime;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // InputEventStatistics_h_
|
|
|
@ -513,18 +513,6 @@ LazyIdleThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent)
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
LazyIdleThread::EnableEventPrioritization()
|
|
||||||
{
|
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
LazyIdleThread::IsEventPrioritizationEnabled(bool* aResult)
|
|
||||||
{
|
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
LazyIdleThread::RegisterIdlePeriod(already_AddRefed<nsIIdlePeriod> aIdlePeriod)
|
LazyIdleThread::RegisterIdlePeriod(already_AddRefed<nsIIdlePeriod> aIdlePeriod)
|
||||||
{
|
{
|
||||||
|
|
|
@ -364,17 +364,8 @@ SchedulerGroup::Runnable::Run()
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
SchedulerGroup::Runnable::GetPriority(uint32_t* aPriority)
|
|
||||||
{
|
|
||||||
*aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
|
|
||||||
nsCOMPtr<nsIRunnablePriority> runnablePrio = do_QueryInterface(mRunnable);
|
|
||||||
return runnablePrio ? runnablePrio->GetPriority(aPriority) : NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS_INHERITED(SchedulerGroup::Runnable,
|
NS_IMPL_ISUPPORTS_INHERITED(SchedulerGroup::Runnable,
|
||||||
mozilla::Runnable,
|
mozilla::Runnable,
|
||||||
nsIRunnablePriority,
|
|
||||||
SchedulerGroup::Runnable)
|
SchedulerGroup::Runnable)
|
||||||
|
|
||||||
SchedulerGroup::AutoProcessEvent::AutoProcessEvent()
|
SchedulerGroup::AutoProcessEvent::AutoProcessEvent()
|
||||||
|
|
|
@ -81,7 +81,7 @@ public:
|
||||||
MOZ_ASSERT(IsSafeToRun());
|
MOZ_ASSERT(IsSafeToRun());
|
||||||
}
|
}
|
||||||
|
|
||||||
class Runnable final : public mozilla::Runnable, public nsIRunnablePriority
|
class Runnable final : public mozilla::Runnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
Runnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
||||||
|
@ -95,7 +95,6 @@ public:
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
NS_DECL_ISUPPORTS_INHERITED
|
||||||
NS_DECL_NSIRUNNABLE
|
NS_DECL_NSIRUNNABLE
|
||||||
NS_DECL_NSIRUNNABLEPRIORITY
|
|
||||||
|
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SCHEDULERGROUPRUNNABLE_IID);
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SCHEDULERGROUPRUNNABLE_IID);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/Monitor.h"
|
#include "mozilla/Monitor.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -111,8 +110,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
UniquePtrLessThan(mozilla::UniquePtr<Entry>& aLeft,
|
UniquePtrLessThan(UniquePtr<Entry>& aLeft, UniquePtr<Entry>& aRight)
|
||||||
mozilla::UniquePtr<Entry>& aRight)
|
|
||||||
{
|
{
|
||||||
// This is reversed because std::push_heap() sorts the "largest" to
|
// This is reversed because std::push_heap() sorts the "largest" to
|
||||||
// the front of the heap. We want that to be the earliest timer.
|
// the front of the heap. We want that to be the earliest timer.
|
||||||
|
@ -125,7 +123,7 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
nsTArray<mozilla::UniquePtr<Entry>> mTimers;
|
nsTArray<UniquePtr<Entry>> mTimers;
|
||||||
uint32_t mAllowedEarlyFiringMicroseconds;
|
uint32_t mAllowedEarlyFiringMicroseconds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ EXPORTS.mozilla += [
|
||||||
'DeadlockDetector.h',
|
'DeadlockDetector.h',
|
||||||
'HangAnnotations.h',
|
'HangAnnotations.h',
|
||||||
'HangMonitor.h',
|
'HangMonitor.h',
|
||||||
'InputEventStatistics.h',
|
|
||||||
'LazyIdleThread.h',
|
'LazyIdleThread.h',
|
||||||
'MainThreadIdlePeriod.h',
|
'MainThreadIdlePeriod.h',
|
||||||
'Monitor.h',
|
'Monitor.h',
|
||||||
|
@ -70,7 +69,6 @@ UNIFIED_SOURCES += [
|
||||||
'BlockingResourceBase.cpp',
|
'BlockingResourceBase.cpp',
|
||||||
'HangAnnotations.cpp',
|
'HangAnnotations.cpp',
|
||||||
'HangMonitor.cpp',
|
'HangMonitor.cpp',
|
||||||
'InputEventStatistics.cpp',
|
|
||||||
'LazyIdleThread.cpp',
|
'LazyIdleThread.cpp',
|
||||||
'MainThreadIdlePeriod.cpp',
|
'MainThreadIdlePeriod.cpp',
|
||||||
'nsEnvironment.cpp',
|
'nsEnvironment.cpp',
|
||||||
|
|
|
@ -18,11 +18,10 @@ interface nsIRunnable : nsISupports
|
||||||
void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, uuid(e75aa42a-80a9-11e6-afb5-e89d87348e2c)]
|
[uuid(e75aa42a-80a9-11e6-afb5-e89d87348e2c)]
|
||||||
interface nsIRunnablePriority : nsISupports
|
interface nsIRunnablePriority : nsISupports
|
||||||
{
|
{
|
||||||
const unsigned short PRIORITY_NORMAL = 0;
|
const unsigned short PRIORITY_NORMAL = 0;
|
||||||
const unsigned short PRIORITY_INPUT = 1;
|
const unsigned short PRIORITY_HIGH = 1;
|
||||||
const unsigned short PRIORITY_HIGH = 2;
|
|
||||||
readonly attribute unsigned long priority;
|
readonly attribute unsigned long priority;
|
||||||
};
|
};
|
||||||
|
|
|
@ -152,9 +152,6 @@ interface nsIThread : nsISerialEventTarget
|
||||||
*/
|
*/
|
||||||
[noscript] void idleDispatch(in alreadyAddRefed_nsIRunnable event);
|
[noscript] void idleDispatch(in alreadyAddRefed_nsIRunnable event);
|
||||||
|
|
||||||
[noscript] void enableEventPrioritization();
|
|
||||||
[noscript] bool isEventPrioritizationEnabled();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this attribute to dispatch runnables to the thread. Eventually, the
|
* Use this attribute to dispatch runnables to the thread. Eventually, the
|
||||||
* eventTarget attribute will be the only way to dispatch events to a
|
* eventTarget attribute will be the only way to dispatch events to a
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
[ptr] native PRThread(PRThread);
|
[ptr] native PRThread(PRThread);
|
||||||
|
|
||||||
interface nsIEventTarget;
|
|
||||||
interface nsIRunnable;
|
interface nsIRunnable;
|
||||||
interface nsIThread;
|
interface nsIThread;
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ interface nsIThreadManager : nsISupports
|
||||||
* .currentThread.dispatch(runnable, Ci.nsIEventTarget.DISPATCH_NORMAL);
|
* .currentThread.dispatch(runnable, Ci.nsIEventTarget.DISPATCH_NORMAL);
|
||||||
* C++ callers should instead use NS_DispatchToMainThread.
|
* C++ callers should instead use NS_DispatchToMainThread.
|
||||||
*/
|
*/
|
||||||
void dispatchToMainThread(in nsIRunnable event, [optional] in uint32_t priority);
|
void dispatchToMainThread(in nsIRunnable event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This queues a runnable to the main thread's idle queue.
|
* This queues a runnable to the main thread's idle queue.
|
||||||
|
@ -127,9 +126,4 @@ interface nsIThreadManager : nsISupports
|
||||||
* moving away from.
|
* moving away from.
|
||||||
*/
|
*/
|
||||||
void spinEventLoopUntilEmpty();
|
void spinEventLoopUntilEmpty();
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the SchedulerEventTarget for the SystemGroup.
|
|
||||||
*/
|
|
||||||
readonly attribute nsIEventTarget systemGroupEventTarget;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
#include "nsThreadSyncDispatch.h"
|
#include "nsThreadSyncDispatch.h"
|
||||||
#include "LeakRefPtr.h"
|
#include "LeakRefPtr.h"
|
||||||
#include "GeckoProfiler.h"
|
#include "GeckoProfiler.h"
|
||||||
#include "InputEventStatistics.h"
|
|
||||||
|
|
||||||
#ifdef MOZ_CRASHREPORTER
|
#ifdef MOZ_CRASHREPORTER
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
|
@ -816,156 +815,45 @@ nsThread::DispatchInternal(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags
|
||||||
return PutEvent(event.take(), aTarget);
|
return PutEvent(event.take(), aTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(nsThread::nsChainedEventQueue::EnablePrioritizationRunnable,
|
|
||||||
nsIRunnable)
|
|
||||||
|
|
||||||
void
|
|
||||||
nsThread::nsChainedEventQueue::EnablePrioritization(MutexAutoLock& aProofOfLock)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!mIsInputPrioritizationEnabled);
|
|
||||||
// When enabling event prioritization, there may be some pending events with
|
|
||||||
// different priorities in the normal queue. Create an event in the normal
|
|
||||||
// queue to consume all pending events in the time order to make sure we won't
|
|
||||||
// preempt a pending event (e.g. input) in the normal queue by another newly
|
|
||||||
// created event with the same priority.
|
|
||||||
mNormalQueue->PutEvent(new EnablePrioritizationRunnable(this), aProofOfLock);
|
|
||||||
mInputHandlingStartTime = TimeStamp();
|
|
||||||
mIsInputPrioritizationEnabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsThread::nsChainedEventQueue::
|
nsThread::nsChainedEventQueue::GetEvent(bool aMayWait, nsIRunnable** aEvent,
|
||||||
GetNormalOrInputOrHighPriorityEvent(bool aMayWait, nsIRunnable** aEvent,
|
|
||||||
unsigned short* aPriority,
|
unsigned short* aPriority,
|
||||||
MutexAutoLock& aProofOfLock)
|
mozilla::MutexAutoLock& aProofOfLock)
|
||||||
{
|
{
|
||||||
bool retVal = false;
|
bool retVal = false;
|
||||||
do {
|
do {
|
||||||
// Use mProcessHighPriorityQueueRunnable to prevent the high priority events
|
if (mProcessSecondaryQueueRunnable) {
|
||||||
// from consuming all cpu time and causing starvation.
|
MOZ_ASSERT(mSecondaryQueue->HasPendingEvent(aProofOfLock));
|
||||||
if (mProcessHighPriorityQueueRunnable) {
|
retVal = mSecondaryQueue->GetEvent(aMayWait, aEvent, aProofOfLock);
|
||||||
MOZ_ASSERT(mHighQueue->HasPendingEvent(aProofOfLock));
|
|
||||||
retVal = mHighQueue->GetEvent(false, aEvent, aProofOfLock);
|
|
||||||
MOZ_ASSERT(*aEvent);
|
MOZ_ASSERT(*aEvent);
|
||||||
SetPriorityIfNotNull(aPriority, nsIRunnablePriority::PRIORITY_HIGH);
|
if (aPriority) {
|
||||||
mInputHandlingStartTime = TimeStamp();
|
*aPriority = nsIRunnablePriority::PRIORITY_HIGH;
|
||||||
mProcessHighPriorityQueueRunnable = false;
|
}
|
||||||
|
mProcessSecondaryQueueRunnable = false;
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
mProcessHighPriorityQueueRunnable =
|
|
||||||
mHighQueue->HasPendingEvent(aProofOfLock);
|
|
||||||
|
|
||||||
uint32_t pendingInputCount = mInputQueue->Count(aProofOfLock);
|
|
||||||
if (pendingInputCount > 0) {
|
|
||||||
if (mInputHandlingStartTime.IsNull()) {
|
|
||||||
mInputHandlingStartTime =
|
|
||||||
InputEventStatistics::Get()
|
|
||||||
.GetInputHandlingStartTime(mInputQueue->Count(aProofOfLock));
|
|
||||||
}
|
|
||||||
if (TimeStamp::Now() > mInputHandlingStartTime) {
|
|
||||||
retVal = mInputQueue->GetEvent(false, aEvent, aProofOfLock);
|
|
||||||
MOZ_ASSERT(*aEvent);
|
|
||||||
SetPriorityIfNotNull(aPriority, nsIRunnablePriority::PRIORITY_INPUT);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't want to wait if there are some high priority events or input
|
// We don't want to wait if mSecondaryQueue has some events.
|
||||||
// events in the queues.
|
bool reallyMayWait =
|
||||||
bool reallyMayWait = aMayWait && !mProcessHighPriorityQueueRunnable &&
|
aMayWait && !mSecondaryQueue->HasPendingEvent(aProofOfLock);
|
||||||
pendingInputCount == 0;
|
retVal =
|
||||||
|
mNormalQueue->GetEvent(reallyMayWait, aEvent, aProofOfLock);
|
||||||
retVal = mNormalQueue->GetEvent(reallyMayWait, aEvent, aProofOfLock);
|
if (aPriority) {
|
||||||
if (*aEvent) {
|
*aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
|
||||||
// We got an event, return early.
|
|
||||||
SetPriorityIfNotNull(aPriority, nsIRunnablePriority::PRIORITY_NORMAL);
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
if (pendingInputCount > 0 && !mProcessHighPriorityQueueRunnable) {
|
|
||||||
// Handle input events if we have time for them.
|
|
||||||
MOZ_ASSERT(mInputQueue->HasPendingEvent(aProofOfLock));
|
|
||||||
retVal = mInputQueue->GetEvent(false, aEvent, aProofOfLock);
|
|
||||||
MOZ_ASSERT(*aEvent);
|
|
||||||
SetPriorityIfNotNull(aPriority, nsIRunnablePriority::PRIORITY_INPUT);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
} while (aMayWait || mProcessHighPriorityQueueRunnable);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
// Let's see if we should next time process an event from the secondary
|
||||||
nsThread::nsChainedEventQueue::
|
|
||||||
GetNormalOrHighPriorityEvent(bool aMayWait, nsIRunnable** aEvent,
|
|
||||||
unsigned short* aPriority,
|
|
||||||
MutexAutoLock& aProofOfLock)
|
|
||||||
{
|
|
||||||
bool retVal = false;
|
|
||||||
do {
|
|
||||||
// Use mProcessHighPriorityQueueRunnable to prevent the high priority events
|
|
||||||
// from consuming all cpu time and causing starvation.
|
|
||||||
if (mProcessHighPriorityQueueRunnable) {
|
|
||||||
MOZ_ASSERT(mHighQueue->HasPendingEvent(aProofOfLock));
|
|
||||||
retVal = mHighQueue->GetEvent(false, aEvent, aProofOfLock);
|
|
||||||
MOZ_ASSERT(*aEvent);
|
|
||||||
SetPriorityIfNotNull(aPriority, nsIRunnablePriority::PRIORITY_HIGH);
|
|
||||||
mProcessHighPriorityQueueRunnable = false;
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
mProcessHighPriorityQueueRunnable =
|
|
||||||
mHighQueue->HasPendingEvent(aProofOfLock);
|
|
||||||
|
|
||||||
// We don't want to wait if there are some events in the high priority
|
|
||||||
// queue.
|
// queue.
|
||||||
bool reallyMayWait = aMayWait && !mProcessHighPriorityQueueRunnable;
|
mProcessSecondaryQueueRunnable =
|
||||||
|
mSecondaryQueue->HasPendingEvent(aProofOfLock);
|
||||||
|
|
||||||
retVal = mNormalQueue->GetEvent(reallyMayWait, aEvent, aProofOfLock);
|
|
||||||
if (*aEvent) {
|
if (*aEvent) {
|
||||||
// We got an event, return early.
|
// We got an event, return early.
|
||||||
SetPriorityIfNotNull(aPriority, nsIRunnablePriority::PRIORITY_NORMAL);
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
} while (aMayWait || mProcessHighPriorityQueueRunnable);
|
} while(aMayWait || mProcessSecondaryQueueRunnable);
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
return retVal;
|
||||||
nsThread::nsChainedEventQueue::PutEvent(already_AddRefed<nsIRunnable> aEvent,
|
|
||||||
MutexAutoLock& aProofOfLock)
|
|
||||||
{
|
|
||||||
RefPtr<nsIRunnable> event(aEvent);
|
|
||||||
nsCOMPtr<nsIRunnablePriority> runnablePrio(do_QueryInterface(event));
|
|
||||||
uint32_t prio = nsIRunnablePriority::PRIORITY_NORMAL;
|
|
||||||
if (runnablePrio) {
|
|
||||||
runnablePrio->GetPriority(&prio);
|
|
||||||
}
|
|
||||||
switch (prio) {
|
|
||||||
case nsIRunnablePriority::PRIORITY_NORMAL:
|
|
||||||
mNormalQueue->PutEvent(event.forget(), aProofOfLock);
|
|
||||||
break;
|
|
||||||
case nsIRunnablePriority::PRIORITY_INPUT:
|
|
||||||
if (mIsInputPrioritizationEnabled) {
|
|
||||||
mInputQueue->PutEvent(event.forget(), aProofOfLock);
|
|
||||||
} else {
|
|
||||||
mNormalQueue->PutEvent(event.forget(), aProofOfLock);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case nsIRunnablePriority::PRIORITY_HIGH:
|
|
||||||
if (mIsInputPrioritizationEnabled) {
|
|
||||||
mHighQueue->PutEvent(event.forget(), aProofOfLock);
|
|
||||||
} else {
|
|
||||||
// During startup, ContentParent sends SetXPCOMProcessAttributes to
|
|
||||||
// initialize ContentChild and enable input event prioritization. After
|
|
||||||
// that, ContentParent sends PBrowserConstructor to create PBrowserChild.
|
|
||||||
// To prevent PBrowserConstructor preempt SetXPCOMProcessAttributes and
|
|
||||||
// cause problems, we have to put high priority events in mNormalQueue to
|
|
||||||
// keep the correct order of initialization.
|
|
||||||
mNormalQueue->PutEvent(event.forget(), aProofOfLock);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MOZ_ASSERT(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -1277,24 +1165,6 @@ nsThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsThread::EnableEventPrioritization()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
MutexAutoLock lock(mLock);
|
|
||||||
// Only support event prioritization for main event queue.
|
|
||||||
mEventsRoot.EnablePrioritization(lock);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsThread::IsEventPrioritizationEnabled(bool* aResult)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
*aResult = mEventsRoot.IsPrioritizationEnabled();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MOZ_CANARY
|
#ifdef MOZ_CANARY
|
||||||
void canary_alarm_handler(int signum);
|
void canary_alarm_handler(int signum);
|
||||||
|
|
||||||
|
@ -1572,10 +1442,7 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult)
|
||||||
sMainThreadRunnableName[length] = '\0';
|
sMainThreadRunnableName[length] = '\0';
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Maybe<AutoTimeDurationHelper> timeDurationHelper;
|
|
||||||
if (priority == nsIRunnablePriority::PRIORITY_INPUT) {
|
|
||||||
timeDurationHelper.emplace();
|
|
||||||
}
|
|
||||||
event->Run();
|
event->Run();
|
||||||
} else if (aMayWait) {
|
} else if (aMayWait) {
|
||||||
MOZ_ASSERT(ShuttingDown(),
|
MOZ_ASSERT(ShuttingDown(),
|
||||||
|
|
|
@ -97,16 +97,6 @@ public:
|
||||||
static const uint32_t kRunnableNameBufSize = 1000;
|
static const uint32_t kRunnableNameBufSize = 1000;
|
||||||
static mozilla::Array<char, kRunnableNameBufSize> sMainThreadRunnableName;
|
static mozilla::Array<char, kRunnableNameBufSize> sMainThreadRunnableName;
|
||||||
|
|
||||||
// Query whether there are some pending input events in the queue. This method
|
|
||||||
// is supposed to be called on main thread with input event prioritization
|
|
||||||
// enabled.
|
|
||||||
bool HasPendingInputEvents()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
mozilla::MutexAutoLock lock(mLock);
|
|
||||||
return mEventsRoot.HasPendingEventsInInputQueue(lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DoMainThreadSpecificProcessing(bool aReallyWait);
|
void DoMainThreadSpecificProcessing(bool aReallyWait);
|
||||||
|
|
||||||
|
@ -152,43 +142,27 @@ protected:
|
||||||
|
|
||||||
struct nsThreadShutdownContext* ShutdownInternal(bool aSync);
|
struct nsThreadShutdownContext* ShutdownInternal(bool aSync);
|
||||||
|
|
||||||
// Wrapper for nsEventQueue that supports chaining and prioritization.
|
// Wrapper for nsEventQueue that supports chaining.
|
||||||
class nsChainedEventQueue
|
class nsChainedEventQueue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit nsChainedEventQueue(mozilla::Mutex& aLock)
|
explicit nsChainedEventQueue(mozilla::Mutex& aLock)
|
||||||
: mNext(nullptr)
|
: mNext(nullptr)
|
||||||
, mEventsAvailable(aLock, "[nsChainedEventQueue.mEventsAvailable]")
|
, mEventsAvailable(aLock, "[nsChainedEventQueue.mEventsAvailable]")
|
||||||
, mIsInputPrioritizationEnabled(false)
|
, mProcessSecondaryQueueRunnable(false)
|
||||||
, mIsReadyToPrioritizeEvents(false)
|
|
||||||
, mProcessHighPriorityQueueRunnable(false)
|
|
||||||
{
|
{
|
||||||
mNormalQueue =
|
mNormalQueue =
|
||||||
mozilla::MakeUnique<nsEventQueue>(mEventsAvailable,
|
mozilla::MakeUnique<nsEventQueue>(mEventsAvailable,
|
||||||
nsEventQueue::eSharedCondVarQueue);
|
nsEventQueue::eSharedCondVarQueue);
|
||||||
// All queues need to use the same CondVar!
|
// Both queues need to use the same CondVar!
|
||||||
mInputQueue =
|
mSecondaryQueue =
|
||||||
mozilla::MakeUnique<nsEventQueue>(mEventsAvailable,
|
mozilla::MakeUnique<nsEventQueue>(mEventsAvailable,
|
||||||
nsEventQueue::eSharedCondVarQueue);
|
nsEventQueue::eSharedCondVarQueue);
|
||||||
mHighQueue =
|
|
||||||
mozilla::MakeUnique<nsEventQueue>(mEventsAvailable,
|
|
||||||
nsEventQueue::eSharedCondVarQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EnablePrioritization(mozilla::MutexAutoLock& aProofOfLock);
|
|
||||||
|
|
||||||
bool IsPrioritizationEnabled()
|
|
||||||
{
|
|
||||||
return mIsInputPrioritizationEnabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetEvent(bool aMayWait, nsIRunnable** aEvent,
|
bool GetEvent(bool aMayWait, nsIRunnable** aEvent,
|
||||||
unsigned short* aPriority,
|
unsigned short* aPriority,
|
||||||
mozilla::MutexAutoLock& aProofOfLock) {
|
mozilla::MutexAutoLock& aProofOfLock);
|
||||||
return mIsReadyToPrioritizeEvents
|
|
||||||
? GetNormalOrInputOrHighPriorityEvent(aMayWait, aEvent, aPriority, aProofOfLock)
|
|
||||||
: GetNormalOrHighPriorityEvent(aMayWait, aEvent, aPriority, aProofOfLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PutEvent(nsIRunnable* aEvent, mozilla::MutexAutoLock& aProofOfLock)
|
void PutEvent(nsIRunnable* aEvent, mozilla::MutexAutoLock& aProofOfLock)
|
||||||
{
|
{
|
||||||
|
@ -197,82 +171,43 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
void PutEvent(already_AddRefed<nsIRunnable> aEvent,
|
void PutEvent(already_AddRefed<nsIRunnable> aEvent,
|
||||||
mozilla::MutexAutoLock& aProofOfLock);
|
mozilla::MutexAutoLock& aProofOfLock)
|
||||||
|
{
|
||||||
|
RefPtr<nsIRunnable> event(aEvent);
|
||||||
|
nsCOMPtr<nsIRunnablePriority> runnablePrio =
|
||||||
|
do_QueryInterface(event);
|
||||||
|
uint32_t prio = nsIRunnablePriority::PRIORITY_NORMAL;
|
||||||
|
if (runnablePrio) {
|
||||||
|
runnablePrio->GetPriority(&prio);
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(prio == nsIRunnablePriority::PRIORITY_NORMAL ||
|
||||||
|
prio == nsIRunnablePriority::PRIORITY_HIGH);
|
||||||
|
if (prio == nsIRunnablePriority::PRIORITY_NORMAL) {
|
||||||
|
mNormalQueue->PutEvent(event.forget(), aProofOfLock);
|
||||||
|
} else {
|
||||||
|
mSecondaryQueue->PutEvent(event.forget(), aProofOfLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool HasPendingEvent(mozilla::MutexAutoLock& aProofOfLock)
|
bool HasPendingEvent(mozilla::MutexAutoLock& aProofOfLock)
|
||||||
{
|
{
|
||||||
return mNormalQueue->HasPendingEvent(aProofOfLock) ||
|
return mNormalQueue->HasPendingEvent(aProofOfLock) ||
|
||||||
mInputQueue->HasPendingEvent(aProofOfLock) ||
|
mSecondaryQueue->HasPendingEvent(aProofOfLock);
|
||||||
mHighQueue->HasPendingEvent(aProofOfLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasPendingEventsInInputQueue(mozilla::MutexAutoLock& aProofOfLock)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mIsInputPrioritizationEnabled);
|
|
||||||
return mInputQueue->HasPendingEvent(aProofOfLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsChainedEventQueue* mNext;
|
nsChainedEventQueue* mNext;
|
||||||
RefPtr<nsNestedEventTarget> mEventTarget;
|
RefPtr<nsNestedEventTarget> mEventTarget;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool GetNormalOrInputOrHighPriorityEvent(bool aMayWait,
|
|
||||||
nsIRunnable** aEvent,
|
|
||||||
unsigned short* aPriority,
|
|
||||||
mozilla::MutexAutoLock& aProofOfLock);
|
|
||||||
|
|
||||||
bool GetNormalOrHighPriorityEvent(bool aMayWait, nsIRunnable** aEvent,
|
|
||||||
unsigned short* aPriority,
|
|
||||||
mozilla::MutexAutoLock& aProofOfLock);
|
|
||||||
|
|
||||||
// This is used to flush pending events in nsChainedEventQueue::mNormalQueue
|
|
||||||
// before starting event prioritization.
|
|
||||||
class EnablePrioritizationRunnable final : public nsIRunnable
|
|
||||||
{
|
|
||||||
nsChainedEventQueue* mEventQueue;
|
|
||||||
|
|
||||||
public:
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
|
|
||||||
explicit EnablePrioritizationRunnable(nsChainedEventQueue* aQueue)
|
|
||||||
: mEventQueue(aQueue)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
|
||||||
{
|
|
||||||
mEventQueue->mIsReadyToPrioritizeEvents = true;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
~EnablePrioritizationRunnable()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void SetPriorityIfNotNull(unsigned short* aPriority, short aValue)
|
|
||||||
{
|
|
||||||
if (aPriority) {
|
|
||||||
*aPriority = aValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mozilla::CondVar mEventsAvailable;
|
mozilla::CondVar mEventsAvailable;
|
||||||
mozilla::TimeStamp mInputHandlingStartTime;
|
|
||||||
mozilla::UniquePtr<nsEventQueue> mNormalQueue;
|
mozilla::UniquePtr<nsEventQueue> mNormalQueue;
|
||||||
mozilla::UniquePtr<nsEventQueue> mInputQueue;
|
mozilla::UniquePtr<nsEventQueue> mSecondaryQueue;
|
||||||
mozilla::UniquePtr<nsEventQueue> mHighQueue;
|
|
||||||
bool mIsInputPrioritizationEnabled;
|
|
||||||
|
|
||||||
// When enabling input event prioritization, there may be some events in the
|
|
||||||
// queue. We have to process all of them before the new coming events to
|
|
||||||
// prevent the queued events are preempted by the newly ones with the same
|
|
||||||
// priority.
|
|
||||||
bool mIsReadyToPrioritizeEvents;
|
|
||||||
// Try to process one high priority runnable after each normal
|
// Try to process one high priority runnable after each normal
|
||||||
// priority runnable. This gives the processing model HTML spec has for
|
// priority runnable. This gives the processing model HTML spec has for
|
||||||
// 'Update the rendering' in the case only vsync messages are in the
|
// 'Update the rendering' in the case only vsync messages are in the
|
||||||
// secondary queue and prevents starving the normal queue.
|
// secondary queue and prevents starving the normal queue.
|
||||||
bool mProcessHighPriorityQueueRunnable;
|
bool mProcessSecondaryQueueRunnable;
|
||||||
};
|
};
|
||||||
|
|
||||||
class nsNestedEventTarget final : public nsIEventTarget
|
class nsNestedEventTarget final : public nsIEventTarget
|
||||||
|
|
|
@ -11,10 +11,7 @@
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "mozilla/AbstractThread.h"
|
#include "mozilla/AbstractThread.h"
|
||||||
#include "mozilla/InputEventStatistics.h"
|
|
||||||
#include "mozilla/SystemGroup.h"
|
|
||||||
#include "mozilla/ThreadLocal.h"
|
#include "mozilla/ThreadLocal.h"
|
||||||
#include "mozilla/Preferences.h"
|
|
||||||
#ifdef MOZ_CANARY
|
#ifdef MOZ_CANARY
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -330,7 +327,7 @@ NS_IMETHODIMP
|
||||||
nsThreadManager::GetCurrentThread(nsIThread** aResult)
|
nsThreadManager::GetCurrentThread(nsIThread** aResult)
|
||||||
{
|
{
|
||||||
// Keep this functioning during Shutdown
|
// Keep this functioning during Shutdown
|
||||||
if (!mMainThread) {
|
if (NS_WARN_IF(!mMainThread)) {
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
*aResult = GetCurrentThread();
|
*aResult = GetCurrentThread();
|
||||||
|
@ -379,14 +376,6 @@ nsThreadManager::SpinEventLoopUntilEmpty()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsThreadManager::GetSystemGroupEventTarget(nsIEventTarget** aTarget)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIEventTarget> target = SystemGroup::EventTargetFor(TaskCategory::Other);
|
|
||||||
target.forget(aTarget);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
nsThreadManager::GetHighestNumberOfThreads()
|
nsThreadManager::GetHighestNumberOfThreads()
|
||||||
{
|
{
|
||||||
|
@ -395,7 +384,7 @@ nsThreadManager::GetHighestNumberOfThreads()
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsThreadManager::DispatchToMainThread(nsIRunnable *aEvent, uint32_t aPriority)
|
nsThreadManager::DispatchToMainThread(nsIRunnable *aEvent)
|
||||||
{
|
{
|
||||||
// Note: C++ callers should instead use NS_DispatchToMainThread.
|
// Note: C++ callers should instead use NS_DispatchToMainThread.
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
@ -404,33 +393,10 @@ nsThreadManager::DispatchToMainThread(nsIRunnable *aEvent, uint32_t aPriority)
|
||||||
if (NS_WARN_IF(!mMainThread)) {
|
if (NS_WARN_IF(!mMainThread)) {
|
||||||
return NS_ERROR_NOT_INITIALIZED;
|
return NS_ERROR_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
if (aPriority != nsIRunnablePriority::PRIORITY_NORMAL) {
|
|
||||||
nsCOMPtr<nsIRunnable> event(aEvent);
|
|
||||||
return mMainThread->DispatchFromScript(
|
|
||||||
new PrioritizableRunnable(event.forget(), aPriority), 0);
|
|
||||||
}
|
|
||||||
return mMainThread->DispatchFromScript(aEvent, 0);
|
return mMainThread->DispatchFromScript(aEvent, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nsThreadManager::EnableMainThreadEventPrioritization()
|
|
||||||
{
|
|
||||||
static bool sIsInitialized = false;
|
|
||||||
if (sIsInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sIsInitialized = true;
|
|
||||||
MOZ_ASSERT(Preferences::IsServiceAvailable());
|
|
||||||
bool enable =
|
|
||||||
Preferences::GetBool("prioritized_input_events.enabled", false);
|
|
||||||
|
|
||||||
if (!enable) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
InputEventStatistics::Get().SetEnable(true);
|
|
||||||
mMainThread->EnableEventPrioritization();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsThreadManager::IdleDispatchToMainThread(nsIRunnable *aEvent, uint32_t aTimeout)
|
nsThreadManager::IdleDispatchToMainThread(nsIRunnable *aEvent, uint32_t aTimeout)
|
||||||
{
|
{
|
||||||
|
|
|
@ -53,7 +53,6 @@ public:
|
||||||
~nsThreadManager()
|
~nsThreadManager()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void EnableMainThreadEventPrioritization();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsThreadManager()
|
nsThreadManager()
|
||||||
|
|
|
@ -88,47 +88,6 @@ already_AddRefed<nsITimer> CreateTimer()
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS_INHERITED(PrioritizableRunnable, Runnable,
|
|
||||||
nsIRunnablePriority)
|
|
||||||
|
|
||||||
PrioritizableRunnable::PrioritizableRunnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
|
||||||
uint32_t aPriority)
|
|
||||||
// Real runnable name is managed by overridding the GetName function.
|
|
||||||
: Runnable("PrioritizableRunnable")
|
|
||||||
, mRunnable(Move(aRunnable))
|
|
||||||
, mPriority(aPriority)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
nsCOMPtr<nsIRunnablePriority> runnablePrio = do_QueryInterface(mRunnable);
|
|
||||||
MOZ_ASSERT(!runnablePrio);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
PrioritizableRunnable::GetName(nsACString& aName)
|
|
||||||
{
|
|
||||||
// Try to get a name from the underlying runnable.
|
|
||||||
nsCOMPtr<nsINamed> named = do_QueryInterface(mRunnable);
|
|
||||||
if (named) {
|
|
||||||
named->GetName(aName);
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
PrioritizableRunnable::Run()
|
|
||||||
{
|
|
||||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
|
||||||
return mRunnable->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
PrioritizableRunnable::GetPriority(uint32_t* aPriority)
|
|
||||||
{
|
|
||||||
*aPriority = mPriority;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // XPCOM_GLUE_AVOID_NSPR
|
#endif // XPCOM_GLUE_AVOID_NSPR
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -486,26 +486,6 @@ private:
|
||||||
IdleRunnable& operator=(const IdleRunnable&&) = delete;
|
IdleRunnable& operator=(const IdleRunnable&&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This class is designed to be a wrapper of a real runnable to support event
|
|
||||||
// prioritizable.
|
|
||||||
class PrioritizableRunnable : public Runnable, public nsIRunnablePriority
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PrioritizableRunnable(already_AddRefed<nsIRunnable>&& aRunnable,
|
|
||||||
uint32_t aPriority);
|
|
||||||
|
|
||||||
NS_IMETHOD GetName(nsACString& aName) override;
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS_INHERITED
|
|
||||||
NS_DECL_NSIRUNNABLE
|
|
||||||
NS_DECL_NSIRUNNABLEPRIORITY
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~PrioritizableRunnable() {};
|
|
||||||
nsCOMPtr<nsIRunnable> mRunnable;
|
|
||||||
uint32_t mPriority;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// An event that can be used to call a C++11 functions or function objects,
|
// An event that can be used to call a C++11 functions or function objects,
|
||||||
|
|
|
@ -132,7 +132,7 @@ public:
|
||||||
nsresult InitCommon(uint32_t aDelayMS, uint32_t aType,
|
nsresult InitCommon(uint32_t aDelayMS, uint32_t aType,
|
||||||
Callback&& newCallback);
|
Callback&& newCallback);
|
||||||
|
|
||||||
nsresult InitCommon(const mozilla::TimeDuration& aDelay, uint32_t aType,
|
nsresult InitCommon(const TimeDuration& aDelay, uint32_t aType,
|
||||||
Callback&& newCallback);
|
Callback&& newCallback);
|
||||||
|
|
||||||
Callback& GetCallback()
|
Callback& GetCallback()
|
||||||
|
@ -200,9 +200,9 @@ public:
|
||||||
// Updated only after this timer has been removed from the timer thread.
|
// Updated only after this timer has been removed from the timer thread.
|
||||||
int32_t mGeneration;
|
int32_t mGeneration;
|
||||||
|
|
||||||
mozilla::TimeDuration mDelay;
|
TimeDuration mDelay;
|
||||||
// Updated only after this timer has been removed from the timer thread.
|
// Updated only after this timer has been removed from the timer thread.
|
||||||
mozilla::TimeStamp mTimeout;
|
TimeStamp mTimeout;
|
||||||
|
|
||||||
#ifdef MOZ_TASK_TRACER
|
#ifdef MOZ_TASK_TRACER
|
||||||
mozilla::tasktracer::TracedTaskCommon mTracedTask;
|
mozilla::tasktracer::TracedTaskCommon mTracedTask;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче