Bug 1330252, try to avoid flooding child process with repeated key events, r=masayuki

--HG--
extra : rebase_source : 53241a14eae10852024d68837d377b91a2f7fbec
This commit is contained in:
Olli Pettay 2017-01-16 11:29:37 +02:00
parent 0c21611303
commit cb443e8ff8
4 changed files with 114 additions and 0 deletions

View File

@ -383,6 +383,7 @@ TabChild::TabChild(nsIContentChild* aManager,
, mDidSetRealShowInfo(false)
, mDidLoadURLInit(false)
, mIsFreshProcess(false)
, mSkipKeyPress(false)
, mLayerObserverEpoch(0)
#if defined(XP_WIN) && defined(ACCESSIBILITY)
, mNativeWindowHandle(0)
@ -1778,10 +1779,52 @@ TabChild::RecvNativeSynthesisResponse(const uint64_t& aObserverId,
return IPC_OK();
}
// In case handling repeated keys takes much time, we skip firing new ones.
bool
TabChild::SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent)
{
if (mRepeatedKeyEventTime.IsNull() ||
!aEvent.mIsRepeat ||
(aEvent.mMessage != eKeyDown && aEvent.mMessage != eKeyPress)) {
mRepeatedKeyEventTime = TimeStamp();
mSkipKeyPress = false;
return false;
}
if ((aEvent.mMessage == eKeyDown &&
(mRepeatedKeyEventTime > aEvent.mTimeStamp)) ||
(mSkipKeyPress && (aEvent.mMessage == eKeyPress))) {
// If we skip a keydown event, also the following keypress events should be
// skipped.
mSkipKeyPress |= aEvent.mMessage == eKeyDown;
return true;
}
if (aEvent.mMessage == eKeyDown) {
// If keydown wasn't skipped, nor should the possible following keypress.
mRepeatedKeyEventTime = TimeStamp();
mSkipKeyPress = false;
}
return false;
}
void
TabChild::UpdateRepeatedKeyEventEndTime(const WidgetKeyboardEvent& aEvent)
{
if (aEvent.mIsRepeat &&
(aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyPress)) {
mRepeatedKeyEventTime = TimeStamp::Now();
}
}
mozilla::ipc::IPCResult
TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
const MaybeNativeKeyBinding& aBindings)
{
if (SkipRepeatedKeyEvent(event)) {
return IPC_OK();
}
AutoCacheNativeKeyCommands autoCache(mPuppetWidget);
if (event.mMessage == eKeyPress) {
@ -1804,6 +1847,10 @@ TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
localEvent.mWidget = mPuppetWidget;
nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
// Update the end time of the possible repeated event so that we can skip
// some incoming events in case event handling took long time.
UpdateRepeatedKeyEventEndTime(localEvent);
if (event.mMessage == eKeyDown) {
mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
}

View File

@ -747,6 +747,10 @@ private:
mUnscaledInnerSize = aSize;
}
bool SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent);
void UpdateRepeatedKeyEventEndTime(const WidgetKeyboardEvent& aEvent);
class DelayedDeleteRunnable;
TextureFactoryIdentifier mTextureFactoryIdentifier;
@ -795,6 +799,13 @@ private:
bool mDidLoadURLInit;
bool mIsFreshProcess;
bool mSkipKeyPress;
// Store the end time of the handling of the last repeated keydown/keypress
// event so that in case event handling takes time, some repeated events can
// be skipped to not flood child process.
mozilla::TimeStamp mRepeatedKeyEventTime;
AutoTArray<bool, NUMBER_OF_AUDIO_CHANNELS> mAudioChannelsActive;
RefPtr<layers::IAPZCTreeManager> mApzcTreeManager;

View File

@ -21,6 +21,8 @@ skip-if = !e10s
[browser_bug1004814.js]
[browser_bug1008941_dismissGeolocationHanger.js]
[browser_bug1238427.js]
[browser_bug1316330.js]
skip-if = !e10s
[browser_cancel_keydown_keypress_event.js]
support-files =
prevent_return_key.html

View File

@ -0,0 +1,54 @@
const URL =
"data:text/html,<script>" +
"window.focus();" +
"var down = 0; var press = 0;" +
"onkeydown = function(e) {" +
" document.body.setAttribute('data-down', ++down);" +
" if (e.keyCode == 'D') while (Date.now() - startTime < 500) {}" +
"};" +
"onkeypress = function(e) {" +
" document.body.setAttribute('data-press', ++press);" +
" if (e.charCode == 'P') while (Date.now() - startTime < 500) {}" +
"};" +
"</script>";
function createKeyEvent(type, id, repeated) {
var code = id.charCodeAt(0);
return new KeyboardEvent(type, { keyCode: code, charCode: code, bubbles: true, repeat: repeated });
}
add_task(function* () {
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, URL);
let browser = tab.linkedBrowser;
// Need to dispatch a DOM Event explicitly via PresShell to get KeyEvent with .repeat = true to
// be handled by EventStateManager, which then forwards the event to the child process.
var utils = EventUtils._getDOMWindowUtils(window);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "D", false), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "D", false), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "D", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "D", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "D", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "D", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keyup", "D", true), true);
yield ContentTask.spawn(browser, null, function* () {
is(content.document.body.getAttribute("data-down"), "2", "Correct number of events");
is(content.document.body.getAttribute("data-press"), "2", "Correct number of events");
});
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "P", false), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "P", false), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "P", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "P", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keydown", "P", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keypress", "P", true), true);
utils.dispatchDOMEventViaPresShell(browser, createKeyEvent("keyup", "P", true), true);
yield ContentTask.spawn(browser, null, function* () {
is(content.document.body.getAttribute("data-down"), "4", "Correct number of events");
is(content.document.body.getAttribute("data-press"), "4", "Correct number of events");
});
gBrowser.removeCurrentTab();
});