Bug 1137557 - Part 0: TextEventDispatcher shouldn't forward keyboard events coming from TextInputProcessor to the parent process. r=smaug

This commit is contained in:
Masayuki Nakano 2015-08-04 05:52:00 -04:00
parent b775b4ff60
commit e2804df573
4 changed files with 97 additions and 18 deletions

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxPrefs.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEvents.h"
@ -772,6 +773,23 @@ TextInputProcessor::Keydown(nsIDOMKeyEvent* aDOMKeyEvent,
return KeydownInternal(*originalKeyEvent, aKeyFlags, true, *aDoDefault);
}
TextEventDispatcher::DispatchTo
TextInputProcessor::GetDispatchTo() const
{
// Support asynchronous tests.
if (mForTests) {
return gfxPrefs::TestEventsAsyncEnabled() ?
TextEventDispatcher::eDispatchToParentProcess :
TextEventDispatcher::eDispatchToCurrentProcess;
}
// Otherwise, TextInputProcessor supports only keyboard apps on B2G.
// Keyboard apps on B2G doesn't want to dispatch keyboard events to
// chrome process. Therefore, this should dispatch key events only in
// the current process.
return TextEventDispatcher::eDispatchToCurrentProcess;
}
nsresult
TextInputProcessor::KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aKeyFlags,
@ -816,14 +834,15 @@ TextInputProcessor::KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore :
nsEventStatus_eConsumeNoDefault;
if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status)) {
if (!mDispatcher->DispatchKeyboardEvent(NS_KEY_DOWN, keyEvent, status,
GetDispatchTo())) {
// If keydown event isn't dispatched, we don't need to dispatch keypress
// events.
return NS_OK;
}
if (aAllowToDispatchKeypress) {
mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status);
mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status, GetDispatchTo());
}
aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
@ -890,7 +909,8 @@ TextInputProcessor::KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore :
nsEventStatus_eConsumeNoDefault;
mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status);
mDispatcher->DispatchKeyboardEvent(NS_KEY_UP, keyEvent, status,
GetDispatchTo());
aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
return NS_OK;
}

View File

@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/TextEventDispatcher.h"
#include "mozilla/TextEventDispatcherListener.h"
#include "nsAutoPtr.h"
#include "nsITextInputProcessor.h"
@ -17,10 +18,6 @@
namespace mozilla {
namespace widget{
class TextEventDispatcher;
} // namespace widget
class TextInputProcessor final : public nsITextInputProcessor
, public widget::TextEventDispatcherListener
{
@ -64,6 +61,7 @@ private:
nsresult KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent,
uint32_t aKeyFlags,
bool& aDoDefault);
TextEventDispatcher::DispatchTo GetDispatchTo() const;
nsresult IsValidStateForComposition();
void UnlinkFromTextEventDispatcher();
nsresult PrepareKeyboardEventToDispatch(WidgetKeyboardEvent& aKeyboardEvent,

View File

@ -140,16 +140,34 @@ nsresult
TextEventDispatcher::DispatchEvent(nsIWidget* aWidget,
WidgetGUIEvent& aEvent,
nsEventStatus& aStatus)
{
MOZ_ASSERT(!aEvent.AsInputEvent(), "Use DispatchInputEvent()");
nsRefPtr<TextEventDispatcher> kungFuDeathGrip(this);
nsCOMPtr<nsIWidget> widget(aWidget);
mDispatchingEvent++;
nsresult rv = widget->DispatchEvent(&aEvent, aStatus);
mDispatchingEvent--;
return rv;
}
nsresult
TextEventDispatcher::DispatchInputEvent(nsIWidget* aWidget,
WidgetInputEvent& aEvent,
nsEventStatus& aStatus,
DispatchTo aDispatchTo)
{
nsRefPtr<TextEventDispatcher> kungFuDeathGrip(this);
nsCOMPtr<nsIWidget> widget(aWidget);
mDispatchingEvent++;
// If the event is dispatched via nsIWidget::DispatchInputEvent(), it
// sends the event to the parent process first since APZ needs to handle it
// first. However, some callers (e.g., keyboard apps on B2G and tests
// expecting synchronous dispatch) don't want this to do that.
nsresult rv = NS_OK;
if (aEvent.AsInputEvent() &&
(!aEvent.mFlags.mIsSynthesizedForTests || gfxPrefs::TestEventsAsyncEnabled()))
{
aStatus = widget->DispatchInputEvent(aEvent.AsInputEvent());
if (aDispatchTo == eDispatchToParentProcess) {
aStatus = widget->DispatchInputEvent(&aEvent);
} else {
rv = widget->DispatchEvent(&aEvent, aStatus);
}
@ -286,9 +304,11 @@ bool
TextEventDispatcher::DispatchKeyboardEvent(
uint32_t aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus)
nsEventStatus& aStatus,
DispatchTo aDispatchTo)
{
return DispatchKeyboardEventInternal(aMessage, aKeyboardEvent, aStatus);
return DispatchKeyboardEventInternal(aMessage, aKeyboardEvent, aStatus,
aDispatchTo);
}
bool
@ -296,6 +316,7 @@ TextEventDispatcher::DispatchKeyboardEventInternal(
uint32_t aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
DispatchTo aDispatchTo,
uint32_t aIndexOfKeypress)
{
MOZ_ASSERT(aMessage == NS_KEY_DOWN || aMessage == NS_KEY_UP ||
@ -374,14 +395,15 @@ TextEventDispatcher::DispatchKeyboardEventInternal(
keyEvent.mPluginEvent.Clear();
// TODO: Manage mUniqueId here.
DispatchEvent(mWidget, keyEvent, aStatus);
DispatchInputEvent(mWidget, keyEvent, aStatus, aDispatchTo);
return true;
}
bool
TextEventDispatcher::MaybeDispatchKeypressEvents(
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus)
nsEventStatus& aStatus,
DispatchTo aDispatchTo)
{
// If the key event was consumed, keypress event shouldn't be fired.
if (aStatus == nsEventStatus_eConsumeNoDefault) {
@ -401,7 +423,7 @@ TextEventDispatcher::MaybeDispatchKeypressEvents(
for (size_t i = 0; i < keypressCount; i++) {
aStatus = nsEventStatus_eIgnore;
if (!DispatchKeyboardEventInternal(NS_KEY_PRESS, aKeyboardEvent,
aStatus, i)) {
aStatus, aDispatchTo, i)) {
// The widget must have been gone.
break;
}

View File

@ -180,6 +180,26 @@ public:
*/
nsresult NotifyIME(const IMENotification& aIMENotification);
/**
* DispatchTo indicates whether the event may be dispatched to its parent
* process first (if there is) or not. If the event is dispatched to the
* parent process, APZ will handle it first. Otherwise, the event won't be
* handled by APZ if it's in a child process.
*/
enum DispatchTo
{
// The event may be dispatched to its parent process if there is a parent.
// In such case, the event will be handled asynchronously. Additionally,
// the event may be sent to its child process if a child process (including
// the dispatching process) has focus.
eDispatchToParentProcess = 0,
// The event must be dispatched in the current process. But of course,
// the event may be sent to a child process when it has focus. If there is
// no child process, the event may be handled synchronously.
eDispatchToCurrentProcess = 1
};
/**
* DispatchKeyboardEvent() maybe dispatches aKeyboardEvent.
*
@ -192,11 +212,13 @@ public:
* set nsEventStatus_eIgnore. After dispatching
* a event and it's consumed this returns
* nsEventStatus_eConsumeNoDefault.
* @param aDispatchTo See comments of DispatchTo.
* @return true if an event is dispatched. Otherwise, false.
*/
bool DispatchKeyboardEvent(uint32_t aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus);
nsEventStatus& aStatus,
DispatchTo aDispatchTo = eDispatchToParentProcess);
/**
* MaybeDispatchKeypressEvents() maybe dispatches a keypress event which is
@ -210,11 +232,14 @@ public:
* When this method dispatches one or more keypress
* events and one of them is consumed, this returns
* nsEventStatus_eConsumeNoDefault.
* @param aDispatchTo See comments of DispatchTo.
* @return true if one or more events are dispatched.
* Otherwise, false.
*/
bool MaybeDispatchKeypressEvents(const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus);
nsEventStatus& aStatus,
DispatchTo aDispatchTo =
eDispatchToParentProcess);
private:
// mWidget is owner of the instance. When this is created, this is set.
@ -273,6 +298,7 @@ private:
*/
void InitEvent(WidgetGUIEvent& aEvent) const;
/**
* DispatchEvent() dispatches aEvent on aWidget.
*/
@ -280,6 +306,16 @@ private:
WidgetGUIEvent& aEvent,
nsEventStatus& aStatus);
/**
* DispatchInputEvent() dispatches aEvent on aWidget.
*
* @param aDispatchTo See comments of DispatchTo.
*/
nsresult DispatchInputEvent(nsIWidget* aWidget,
WidgetInputEvent& aEvent,
nsEventStatus& aStatus,
DispatchTo aDispatchTo);
/**
* StartCompositionAutomaticallyIfNecessary() starts composition if it hasn't
* been started it yet.
@ -308,6 +344,7 @@ private:
* set nsEventStatus_eIgnore. After dispatching
* a event and it's consumed this returns
* nsEventStatus_eConsumeNoDefault.
* @param aDispatchTo See comments of DispatchTo.
* @param aIndexOfKeypress This must be 0 if aMessage isn't NS_KEY_PRESS or
* aKeyboard.mKeyNameIndex isn't
* KEY_NAME_INDEX_USE_STRING. Otherwise, i.e.,
@ -320,6 +357,8 @@ private:
bool DispatchKeyboardEventInternal(uint32_t aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
DispatchTo aDispatchTo =
eDispatchToParentProcess,
uint32_t aIndexOfKeypress = 0);
};