Bug 1137572 part.4 TextEventDispatcher::DispatchInputEvent() should decide if dispatches events with nsIWidget::DispatchInputEvent() with input transaction type r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 16 Mar 2016 13:47:48 +0900
changeset 288886 06d5532f051f5a0c6796443d0c1794700c6667b6
parent 288885 a8dbb4e58e546843c0b0710f8aa2b453f5cfcadc
child 288887 f31b1e7194143f36ab1e6f0355b9b1b1a11cec0a
push id73609
push usermasayuki@d-toybox.com
push dateWed, 16 Mar 2016 04:47:58 +0000
treeherdermozilla-inbound@eb7c36e2ef5d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1137572
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1137572 part.4 TextEventDispatcher::DispatchInputEvent() should decide if dispatches events with nsIWidget::DispatchInputEvent() with input transaction type r=smaug
dom/base/TextInputProcessor.cpp
dom/base/TextInputProcessor.h
widget/TextEventDispatcher.cpp
widget/TextEventDispatcher.h
--- a/dom/base/TextInputProcessor.cpp
+++ b/dom/base/TextInputProcessor.cpp
@@ -192,17 +192,18 @@ TextInputProcessor::BeginInputTransactio
     if (NS_WARN_IF(mDispatcher)) {
       // Forcibly initialize the members if we failed to end the input
       // transaction.
       UnlinkFromTextEventDispatcher();
     }
   }
 
   if (aForTests) {
-    rv = dispatcher->BeginTestInputTransaction(this);
+    bool isAPZAware = gfxPrefs::TestEventsAsyncEnabled();
+    rv = dispatcher->BeginTestInputTransaction(this, isAPZAware);
   } else {
     rv = dispatcher->BeginInputTransaction(this);
   }
 
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
@@ -774,33 +775,16 @@ TextInputProcessor::Keydown(nsIDOMKeyEve
   WidgetKeyboardEvent* originalKeyEvent =
     aDOMKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
   if (NS_WARN_IF(!originalKeyEvent)) {
     return NS_ERROR_INVALID_ARG;
   }
   return KeydownInternal(*originalKeyEvent, aKeyFlags, true, *aConsumedFlags);
 }
 
-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,
                                     bool aAllowToDispatchKeypress,
                                     uint32_t& aConsumedFlags)
 {
   aConsumedFlags = KEYEVENT_NOT_CONSUMED;
 
@@ -836,30 +820,28 @@ TextInputProcessor::KeydownInternal(cons
   RefPtr<TextEventDispatcher> kungfuDeathGrip(mDispatcher);
   rv = IsValidStateForComposition();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsEventStatus status = aConsumedFlags ? nsEventStatus_eConsumeNoDefault :
                                           nsEventStatus_eIgnore;
-  if (!mDispatcher->DispatchKeyboardEvent(eKeyDown, keyEvent, status,
-                                          GetDispatchTo())) {
+  if (!mDispatcher->DispatchKeyboardEvent(eKeyDown, keyEvent, status)) {
     // If keydown event isn't dispatched, we don't need to dispatch keypress
     // events.
     return NS_OK;
   }
 
   aConsumedFlags |=
     (status == nsEventStatus_eConsumeNoDefault) ? KEYDOWN_IS_CONSUMED :
                                                   KEYEVENT_NOT_CONSUMED;
 
   if (aAllowToDispatchKeypress &&
-      mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status, 
-                                               GetDispatchTo())) {
+      mDispatcher->MaybeDispatchKeypressEvents(keyEvent, status)) {
     aConsumedFlags |=
       (status == nsEventStatus_eConsumeNoDefault) ? KEYPRESS_IS_CONSUMED :
                                                     KEYEVENT_NOT_CONSUMED;
   }
 
   return NS_OK;
 }
 
@@ -918,17 +900,17 @@ TextInputProcessor::KeyupInternal(const 
   RefPtr<TextEventDispatcher> kungfuDeathGrip(mDispatcher);
   rv = IsValidStateForComposition();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsEventStatus status = aDoDefault ? nsEventStatus_eIgnore :
                                       nsEventStatus_eConsumeNoDefault;
-  mDispatcher->DispatchKeyboardEvent(eKeyUp, keyEvent, status, GetDispatchTo());
+  mDispatcher->DispatchKeyboardEvent(eKeyUp, keyEvent, status);
   aDoDefault = (status != nsEventStatus_eConsumeNoDefault);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TextInputProcessor::GetModifierState(const nsAString& aModifierKeyName,
                                      bool* aActive)
 {
--- a/dom/base/TextInputProcessor.h
+++ b/dom/base/TextInputProcessor.h
@@ -56,17 +56,16 @@ private:
              uint32_t aKeyFlags = 0);
   nsresult KeydownInternal(const WidgetKeyboardEvent& aKeyboardEvent,
                            uint32_t aKeyFlags,
                            bool aAllowToDispatchKeypress,
                            uint32_t& aConsumedFlags);
   nsresult KeyupInternal(const WidgetKeyboardEvent& aKeyboardEvent,
                          uint32_t aKeyFlags,
                          bool& aDoDefault);
-  TextEventDispatcher::DispatchTo GetDispatchTo() const;
   nsresult IsValidStateForComposition();
   void UnlinkFromTextEventDispatcher();
   nsresult PrepareKeyboardEventToDispatch(WidgetKeyboardEvent& aKeyboardEvent,
                                           uint32_t aKeyFlags);
   bool IsValidEventTypeForComposition(
          const WidgetKeyboardEvent& aKeyboardEvent) const;
   nsresult PrepareKeyboardEventForComposition(
              nsIDOMKeyEvent* aDOMKeyEvent,
--- a/widget/TextEventDispatcher.cpp
+++ b/widget/TextEventDispatcher.cpp
@@ -39,24 +39,28 @@ TextEventDispatcher::TextEventDispatcher
     sInitialized = true;
   }
 }
 
 nsresult
 TextEventDispatcher::BeginInputTransaction(
                        TextEventDispatcherListener* aListener)
 {
-  return BeginInputTransactionInternal(aListener, eOtherInputTransaction);
+  return BeginInputTransactionInternal(aListener,
+                                       eSameProcessSyncInputTransaction);
 }
 
 nsresult
 TextEventDispatcher::BeginTestInputTransaction(
-                       TextEventDispatcherListener* aListener)
+                       TextEventDispatcherListener* aListener,
+                       bool aIsAPZAware)
 {
-  return BeginInputTransactionInternal(aListener, eTestInputTransaction);
+  return BeginInputTransactionInternal(aListener,
+           aIsAPZAware ? eAsyncTestInputTransaction :
+                         eSameProcessSyncTestInputTransaction);
 }
 
 nsresult
 TextEventDispatcher::BeginNativeInputTransaction()
 {
   if (NS_WARN_IF(!mWidget)) {
     return NS_ERROR_FAILURE;
   }
@@ -145,18 +149,17 @@ TextEventDispatcher::GetState() const
   return NS_OK;
 }
 
 void
 TextEventDispatcher::InitEvent(WidgetGUIEvent& aEvent) const
 {
   aEvent.time = PR_IntervalNow();
   aEvent.refPoint = LayoutDeviceIntPoint(0, 0);
-  aEvent.mFlags.mIsSynthesizedForTests =
-    mInputTransactionType == eTestInputTransaction;
+  aEvent.mFlags.mIsSynthesizedForTests = IsForTests();
   if (aEvent.mClass != eCompositionEventClass) {
     return;
   }
   void* pseudoIMEContext = GetPseudoIMEContext();
   if (pseudoIMEContext) {
     aEvent.AsCompositionEvent()->mNativeIMEContext.
       InitWithRawNativeIMEContext(pseudoIMEContext);
   }
@@ -183,29 +186,28 @@ TextEventDispatcher::DispatchEvent(nsIWi
   nsresult rv = widget->DispatchEvent(&aEvent, aStatus);
   mDispatchingEvent--;
   return rv;
 }
 
 nsresult
 TextEventDispatcher::DispatchInputEvent(nsIWidget* aWidget,
                                         WidgetInputEvent& aEvent,
-                                        nsEventStatus& aStatus,
-                                        DispatchTo aDispatchTo)
+                                        nsEventStatus& aStatus)
 {
   RefPtr<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 (aDispatchTo == eDispatchToParentProcess) {
+  if (ShouldSendInputEventToAPZ()) {
     aStatus = widget->DispatchInputEvent(&aEvent);
   } else {
     rv = widget->DispatchEvent(&aEvent, aStatus);
   }
 
   mDispatchingEvent--;
   return rv;
 }
@@ -365,29 +367,26 @@ TextEventDispatcher::NotifyIME(const IME
     }
   }
 }
 
 bool
 TextEventDispatcher::DispatchKeyboardEvent(
                        EventMessage aMessage,
                        const WidgetKeyboardEvent& aKeyboardEvent,
-                       nsEventStatus& aStatus,
-                       DispatchTo aDispatchTo)
+                       nsEventStatus& aStatus)
 {
-  return DispatchKeyboardEventInternal(aMessage, aKeyboardEvent, aStatus,
-                                       aDispatchTo);
+  return DispatchKeyboardEventInternal(aMessage, aKeyboardEvent, aStatus);
 }
 
 bool
 TextEventDispatcher::DispatchKeyboardEventInternal(
                        EventMessage aMessage,
                        const WidgetKeyboardEvent& aKeyboardEvent,
                        nsEventStatus& aStatus,
-                       DispatchTo aDispatchTo,
                        uint32_t aIndexOfKeypress)
 {
   MOZ_ASSERT(aMessage == eKeyDown || aMessage == eKeyUp ||
              aMessage == eKeyPress, "Invalid aMessage value");
   nsresult rv = GetState();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
@@ -456,25 +455,24 @@ TextEventDispatcher::DispatchKeyboardEve
   // XXX Currently, we don't support to dispatch key event with native key
   //     event information.
   keyEvent.mNativeKeyEvent = nullptr;
   // XXX Currently, we don't support to dispatch key events with data for
   // plugins.
   keyEvent.mPluginEvent.Clear();
   // TODO: Manage mUniqueId here.
 
-  DispatchInputEvent(mWidget, keyEvent, aStatus, aDispatchTo);
+  DispatchInputEvent(mWidget, keyEvent, aStatus);
   return true;
 }
 
 bool
 TextEventDispatcher::MaybeDispatchKeypressEvents(
                        const WidgetKeyboardEvent& aKeyboardEvent,
-                       nsEventStatus& aStatus,
-                       DispatchTo aDispatchTo)
+                       nsEventStatus& aStatus)
 {
   // If the key event was consumed, keypress event shouldn't be fired.
   if (aStatus == nsEventStatus_eConsumeNoDefault) {
     return false;
   }
 
   // If the key isn't a printable key or just inputting one character or
   // no character, we should dispatch only one keypress.  Otherwise, i.e.,
@@ -484,17 +482,17 @@ TextEventDispatcher::MaybeDispatchKeypre
     aKeyboardEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ?
       1 : std::max(static_cast<nsAString::size_type>(1),
                    aKeyboardEvent.mKeyValue.Length());
   bool isDispatched = false;
   bool consumed = false;
   for (size_t i = 0; i < keypressCount; i++) {
     aStatus = nsEventStatus_eIgnore;
     if (!DispatchKeyboardEventInternal(eKeyPress, aKeyboardEvent,
-                                       aStatus, aDispatchTo, i)) {
+                                       aStatus, i)) {
       // The widget must have been gone.
       break;
     }
     isDispatched = true;
     if (!consumed) {
       consumed = (aStatus == nsEventStatus_eConsumeNoDefault);
     }
   }
--- a/widget/TextEventDispatcher.h
+++ b/widget/TextEventDispatcher.h
@@ -51,17 +51,18 @@ public:
    *
    * @param aListener       Specify the listener to listen notifications and
    *                        requests.  This must not be null.
    *                        NOTE: aListener is stored as weak reference in
    *                              TextEventDispatcher.  See mListener
    *                              definition below.
    */
   nsresult BeginInputTransaction(TextEventDispatcherListener* aListener);
-  nsresult BeginTestInputTransaction(TextEventDispatcherListener* aListener);
+  nsresult BeginTestInputTransaction(TextEventDispatcherListener* aListener,
+                                     bool aIsAPZAware);
   nsresult BeginNativeInputTransaction();
 
   /**
    * EndInputTransaction() should be called when the listener stops using
    * the TextEventDispatcher.
    *
    * @param aListener       The listener using the TextEventDispatcher instance.
    */
@@ -191,76 +192,51 @@ public:
     mPendingComposition.Clear();
   }
 
   /**
    * @see nsIWidget::NotifyIME()
    */
   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.
    *
    * @param aMessage        Must be eKeyDown or eKeyUp.
    *                        Use MaybeDispatchKeypressEvents() for dispatching
    *                        eKeyPress.
    * @param aKeyboardEvent  A keyboard event.
    * @param aStatus         If dispatching event should be marked as consumed,
    *                        set nsEventStatus_eConsumeNoDefault.  Otherwise,
    *                        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(EventMessage aMessage,
                              const WidgetKeyboardEvent& aKeyboardEvent,
-                             nsEventStatus& aStatus,
-                             DispatchTo aDispatchTo = eDispatchToParentProcess);
+                             nsEventStatus& aStatus);
 
   /**
    * MaybeDispatchKeypressEvents() maybe dispatches a keypress event which is
    * generated from aKeydownEvent.
    *
    * @param aKeyboardEvent  A keyboard event.
    * @param aStatus         Sets the result when the caller dispatches
    *                        aKeyboardEvent.  Note that if the value is
    *                        nsEventStatus_eConsumeNoDefault, this does NOT
    *                        dispatch keypress events.
    *                        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,
-                                   DispatchTo aDispatchTo =
-                                     eDispatchToParentProcess);
+                                   nsEventStatus& aStatus);
 
 private:
   // mWidget is owner of the instance.  When this is created, this is set.
   // And when mWidget is released, this is cleared by OnDestroyWidget().
   // Note that mWidget may be destroyed already (i.e., mWidget->Destroyed() may
   // return true).
   nsIWidget* mWidget;
   // mListener is a weak reference to TextEventDispatcherListener.  That might
@@ -295,26 +271,66 @@ private:
 
   // While dispatching an event, this is incremented.
   uint16_t mDispatchingEvent;
 
   enum InputTransactionType : uint8_t
   {
     // No input transaction has been started.
     eNoInputTransaction,
-    // Input transaction for native IME or keyboard event handler.
+    // Input transaction for native IME or keyboard event handler.  Note that
+    // keyboard events may be dispatched via parent process if there is.
     eNativeInputTransaction,
-    // Input transaction for automated tests.
-    eTestInputTransaction,
-    // Input transaction for Others (must be IME on B2G).
-    eOtherInputTransaction
+    // Input transaction for automated tests which are APZ-aware.  Note that
+    // keyboard events may be dispatched via parent process if there is.
+    eAsyncTestInputTransaction,
+    // Input transaction for automated tests which assume events are fired
+    // synchronously.  I.e., keyboard events are always dispatched in the
+    // current process.
+    eSameProcessSyncTestInputTransaction,
+    // Input transaction for Others (must be IME on B2G).  Events are fired
+    // synchronously because TextInputProcessor which is the only user of
+    // this input transaction type 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.
+    eSameProcessSyncInputTransaction
   };
 
   InputTransactionType mInputTransactionType;
 
+  bool IsForTests() const
+  {
+    return mInputTransactionType == eAsyncTestInputTransaction ||
+           mInputTransactionType == eSameProcessSyncTestInputTransaction;
+  }
+
+  // ShouldSendInputEventToAPZ() returns true when WidgetInputEvent should
+  // be dispatched via its parent process (if there is) for APZ.  Otherwise,
+  // when the input transaction is for IME of B2G or automated tests which
+  // isn't APZ-aware, WidgetInputEvent should be dispatched form current
+  // process directly.
+  bool ShouldSendInputEventToAPZ() const
+  {
+    switch (mInputTransactionType) {
+      case eNativeInputTransaction:
+      case eAsyncTestInputTransaction:
+        return true;
+      case eSameProcessSyncTestInputTransaction:
+      case eSameProcessSyncInputTransaction:
+        return false;
+      case eNoInputTransaction:
+        NS_WARNING("Why does the caller need to dispatch an event when "
+                   "there is no input transaction?");
+        return true;
+      default:
+        MOZ_CRASH("Define the behavior of new InputTransactionType");
+    }
+  }
+
   // See IsComposing().
   bool mIsComposing;
 
   // If this is true, keydown and keyup events are dispatched even when there
   // is a composition.
   static bool sDispatchKeyEventsDuringComposition;
 
   nsresult BeginInputTransactionInternal(
@@ -332,23 +348,20 @@ private:
    * DispatchEvent() dispatches aEvent on aWidget.
    */
   nsresult DispatchEvent(nsIWidget* aWidget,
                          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);
+                              nsEventStatus& aStatus);
 
   /**
    * StartCompositionAutomaticallyIfNecessary() starts composition if it hasn't
    * been started it yet.
    *
    * @param aStatus         If it succeeded to start composition normally, this
    *                        returns nsEventStatus_eIgnore.  Otherwise, e.g.,
    *                        the composition is canceled during dispatching
@@ -368,30 +381,27 @@ private:
    * @param aKeyboardEvent  A keyboard event.  If aMessage is eKeyPress and
    *                        the event is for second or later character, its
    *                        mKeyValue should be empty string.
    * @param aStatus         If dispatching event should be marked as consumed,
    *                        set nsEventStatus_eConsumeNoDefault.  Otherwise,
    *                        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 eKeyPress or
    *                            aKeyboard.mKeyNameIndex isn't
    *                            KEY_NAME_INDEX_USE_STRING.  Otherwise, i.e.,
    *                            when an eKeyPress event causes inputting
    *                            text, this must be between 0 and
    *                            mKeyValue.Length() - 1 since keypress events
    *                            sending only one character per event.
    * @return                true if an event is dispatched.  Otherwise, false.
    */
   bool DispatchKeyboardEventInternal(EventMessage aMessage,
                                      const WidgetKeyboardEvent& aKeyboardEvent,
                                      nsEventStatus& aStatus,
-                                     DispatchTo aDispatchTo =
-                                       eDispatchToParentProcess,
                                      uint32_t aIndexOfKeypress = 0);
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // #ifndef mozilla_widget_textcompositionsynthesizer_h_