Bug 1377653 - part2: Add helper methods to WidgetEvent and BaseEventFlags to manage propagation state between parent process and remote process r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 05 Jul 2017 13:58:41 +0900
changeset 604127 ace5b1ea045dad943821a770454dea8131c8e69f
parent 604126 bcd9175704756f33e671747458ee1a5a21f31354
child 604128 7d88774e3f019d66159cdf0eb8b77ba15ba1c7f1
push id66965
push usermasayuki@d-toybox.com
push dateWed, 05 Jul 2017 10:02:44 +0000
reviewerssmaug
bugs1377653
milestone56.0a1
Bug 1377653 - part2: Add helper methods to WidgetEvent and BaseEventFlags to manage propagation state between parent process and remote process r?smaug Currently, we have 2 bool flags (and optional 2 bool flags with related purpose) for managing propagation state between parent process and remote process. However, it's really complicated. Actually, setting these flags and referring the flags is usually follow explanation. So, for making simpler, WidgetEvent and BaseEventFlags should have some utility methods for making them as self documented code. This patch moves WidgetKeyboardEvent::mIsReserved to BaseEventFlags::mIsReservedByChrome. That allows us to manage the cross process event propagation state in same place. MozReview-Commit-ID: IXEDQJ4GpAZ
dom/events/EventStateManager.cpp
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
dom/xbl/nsXBLWindowKeyHandler.cpp
widget/BasicEvents.h
widget/TextEvents.h
widget/WidgetEventImpl.cpp
widget/nsGUIEventIPC.h
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -685,34 +685,35 @@ EventStateManager::PreHandleEvent(nsPres
     }
     break;
   }
   case eMouseEnterIntoWidget:
     // In some cases on e10s eMouseEnterIntoWidget
     // event was sent twice into child process of content.
     // (From specific widget code (sending is not permanent) and
     // from ESM::DispatchMouseOrPointerEvent (sending is permanent)).
-    // Flag mNoCrossProcessBoundaryForwarding helps to
-    // suppress sending accidental event from widget code.
+    // IsCrossProcessForwardingStopped() helps to suppress sending accidental
+    // event from widget code.
     aEvent->StopCrossProcessForwarding();
     break;
   case eMouseExitFromWidget:
     // If this is a remote frame, we receive eMouseExitFromWidget from the
     // parent the mouse exits our content. Since the parent may update the
     // cursor while the mouse is outside our frame, and since PuppetWidget
     // caches the current cursor internally, re-entering our content (say from
     // over a window edge) wont update the cursor if the cached value and the
     // current cursor match. So when the mouse exits a remote frame, clear the
     // cached widget cursor so a proper update will occur when the mouse
     // re-enters.
     if (XRE_IsContentProcess()) {
       ClearCachedWidgetCursor(mCurrentTarget);
     }
 
-    // Flag helps to suppress double event sending into process of content.
+    // IsCrossProcessForwardingStopped() helps to suppress double event sending
+    // into process of content.
     // For more information see comment above, at eMouseEnterIntoWidget case.
     aEvent->StopCrossProcessForwarding();
 
     // If the event is not a top-level window exit, then it's not
     // really an exit --- we may have traversed widget boundaries but
     // we're still in our toplevel window.
     if (mouseEvent->mExitFrom != WidgetMouseEvent::eTopLevel) {
       // Treat it as a synthetic move so we don't generate spurious
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1914,17 +1914,17 @@ TabChild::RecvRealKeyEvent(const WidgetK
 
   if (localEvent.mFlags.mIsSuppressedOrDelayed) {
     localEvent.PreventDefault();
   }
 
   // If a response is desired from the content process, resend the key event.
   // If mAccessKeyForwardedToChild is set, then don't resend the key event yet
   // as RecvHandleAccessKey will do this.
-  if (localEvent.mFlags.mWantReplyFromContentProcess) {
+  if (localEvent.WantReplyFromContentProcess()) {
     SendReplyKeyEvent(localEvent);
   }
 
   if (localEvent.mAccessKeyForwardedToChild) {
     SendAccessKeyNotHandled(localEvent);
   }
 
   return IPC_OK();
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1954,18 +1954,17 @@ TabParent::GetChildProcessOffset()
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mFrameElement, IPC_OK());
 
   WidgetKeyboardEvent localEvent(aEvent);
-  // Mark the event as not to be dispatched to remote process again.
-  localEvent.StopCrossProcessForwarding();
+  localEvent.MarkAsHandledInRemoteProcess();
 
   // Here we convert the WidgetEvent that we received to an nsIDOMEvent
   // to be able to dispatch it to the <browser> element as the target element.
   nsIDocument* doc = mFrameElement->OwnerDoc();
   nsIPresShell* presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, IPC_OK());
   nsPresContext* presContext = presShell->GetPresContext();
   NS_ENSURE_TRUE(presContext, IPC_OK());
@@ -1988,16 +1987,17 @@ TabParent::RecvReplyKeyEvent(const Widge
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvAccessKeyNotHandled(const WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mFrameElement, IPC_OK());
 
   WidgetKeyboardEvent localEvent(aEvent);
+  localEvent.MarkAsHandledInRemoteProcess();
   localEvent.mMessage = eAccessKeyNotFound;
   localEvent.mAccessKeyForwardedToChild = false;
 
   // Here we convert the WidgetEvent that we received to an nsIDOMEvent
   // to be able to dispatch it to the <browser> element as the target element.
   nsIDocument* doc = mFrameElement->OwnerDoc();
   nsIPresShell* presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, IPC_OK());
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -479,17 +479,17 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDO
     return NS_OK;
   }
 
   WidgetKeyboardEvent* widgetKeyboardEvent =
     aEvent->WidgetEventPtr()->AsKeyboardEvent();
   if (widgetKeyboardEvent->IsKeyEventOnPlugin()) {
     // key events on plugin shouldn't execute shortcut key handlers which are
     // not reserved.
-    if (!widgetKeyboardEvent->mIsReserved) {
+    if (!widgetKeyboardEvent->IsReservedByChrome()) {
       return NS_OK;
     }
 
     // If the event is untrusted event or was already consumed, do nothing.
     if (!widgetKeyboardEvent->IsTrusted() ||
         widgetKeyboardEvent->DefaultPrevented()) {
       return NS_OK;
     }
@@ -511,70 +511,57 @@ nsXBLWindowKeyHandler::HandleEvent(nsIDO
 
 void
 nsXBLWindowKeyHandler::HandleEventOnCaptureInDefaultEventGroup(
                          nsIDOMKeyEvent* aEvent)
 {
   WidgetKeyboardEvent* widgetKeyboardEvent =
     aEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
 
-  if (widgetKeyboardEvent->mIsReserved) {
-    MOZ_RELEASE_ASSERT(
-      widgetKeyboardEvent->mFlags.mOnlySystemGroupDispatchInContent);
-    MOZ_RELEASE_ASSERT(
-      widgetKeyboardEvent->mFlags.mNoCrossProcessBoundaryForwarding);
+  if (widgetKeyboardEvent->IsReservedByChrome()) {
     return;
   }
 
   bool isReserved = false;
   if (HasHandlerForEvent(aEvent, &isReserved) && isReserved) {
-    widgetKeyboardEvent->mIsReserved = true;
-    // For reserved commands (such as Open New Tab), we don't to wait for
-    // the content to answer (so mWantReplyFromContentProcess remains false),
-    // neither to give a chance for content to override its behavior.
-    widgetKeyboardEvent->StopCrossProcessForwarding();
-    // If the key combination is reserved by chrome, we shouldn't expose the
-    // keyboard event to web contents because such keyboard events shouldn't be
-    // cancelable.  So, it's not good behavior to fire keyboard events but
-    // to ignore the defaultPrevented attribute value in chrome.
-    widgetKeyboardEvent->mFlags.mOnlySystemGroupDispatchInContent = true;
+    widgetKeyboardEvent->MarkAsReservedByChrome();
   }
 }
 
 void
 nsXBLWindowKeyHandler::HandleEventOnCaptureInSystemEventGroup(
                          nsIDOMKeyEvent* aEvent)
 {
   WidgetKeyboardEvent* widgetEvent =
     aEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
 
-  if (widgetEvent->mFlags.mNoCrossProcessBoundaryForwarding ||
+  if (widgetEvent->IsCrossProcessForwardingStopped() ||
       widgetEvent->mFlags.mOnlySystemGroupDispatchInContent) {
     return;
   }
 
   nsCOMPtr<mozilla::dom::Element> originalTarget =
     do_QueryInterface(aEvent->AsEvent()->WidgetEventPtr()->mOriginalTarget);
   if (!EventStateManager::IsRemoteTarget(originalTarget)) {
     return;
   }
 
   if (!HasHandlerForEvent(aEvent)) {
     return;
   }
 
-  // Inform the child process that this is a event that we want a reply
-  // from.
-  widgetEvent->mFlags.mWantReplyFromContentProcess = true;
-  // If this event hadn't been marked as mNoCrossProcessBoundaryForwarding
+  // If this event wasn't marked as IsCrossProcessForwardingStopped,
   // yet, it means it wasn't processed by content. We'll not call any
-  // of the handlers at this moment, and will wait for the event to be
-  // redispatched with mNoCrossProcessBoundaryForwarding = 1 to process it.
-  // XXX Why not StopImmediatePropagation()?
-  aEvent->AsEvent()->StopPropagation();
+  // of the handlers at this moment, and will wait the reply event.
+  // So, stop immediate propagation in this event first, then, mark it as
+  // waiting reply from remote process.  Finally, when this process receives
+  // a reply from the remote process, it should be dispatched into this
+  // DOM tree again.
+  widgetEvent->StopImmediatePropagation();
+  widgetEvent->MarkAsWaitingReplyFromRemoteProcess();
 }
 
 bool
 nsXBLWindowKeyHandler::IsHTMLEditableFieldFocused()
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (!fm)
     return false;
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -13,16 +13,20 @@
 #include "mozilla/TimeStamp.h"
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
 #include "nsISupportsImpl.h"
 #include "nsIWidget.h"
 #include "nsString.h"
 #include "Units.h"
 
+#ifdef DEBUG
+#include "nsXULAppAPI.h"
+#endif // #ifdef DEBUG
+
 namespace IPC {
 template<typename T>
 struct ParamTraits;
 } // namespace IPC
 
 namespace mozilla {
 
 /******************************************************************************
@@ -88,42 +92,37 @@ public:
   // automated tests or something hacky approach of an add-on.
   bool    mIsSynthesizedForTests : 1;
   // If mExceptionWasRaised is true, one of the event handlers has raised an
   // exception.
   bool    mExceptionWasRaised : 1;
   // If mRetargetToNonNativeAnonymous is true and the target is in a non-native
   // native anonymous subtree, the event target is set to mOriginalTarget.
   bool    mRetargetToNonNativeAnonymous : 1;
-  // If mNoCrossProcessBoundaryForwarding is true, the event is not allowed to
-  // cross process boundary.
-  bool    mNoCrossProcessBoundaryForwarding : 1;
   // If mNoContentDispatch is true, the event is never dispatched to the
   // event handlers which are added to the contents, onfoo attributes and
   // properties.  Note that this flag is ignored when
   // EventChainPreVisitor::mForceContentDispatch is set true.  For exapmle,
   // window and document object sets it true.  Therefore, web applications
   // can handle the event if they add event listeners to the window or the
   // document.
   // XXX This is an ancient and broken feature, don't use this for new bug
   //     as far as possible.
   bool    mNoContentDispatch : 1;
   // If mOnlyChromeDispatch is true, the event is dispatched to only chrome.
   bool    mOnlyChromeDispatch : 1;
+  // Indicates if the key combination is reserved by chrome.  This is set by
+  // MarkAsReservedByChrome().
+  bool mIsReservedByChrome : 1;
   // If mOnlySystemGroupDispatchInContent is true, event listeners added to
   // the default group for non-chrome EventTarget won't be called.
   // Be aware, if this is true, EventDispatcher needs to check if each event
   // listener is added to chrome node, so, don't set this to true for the
   // events which are fired a lot of times like eMouseMove.
   bool    mOnlySystemGroupDispatchInContent : 1;
-  // If mWantReplyFromContentProcess is true, the event will be redispatched
-  // in the parent process after the content process has handled it. Useful
-  // for when the parent process need the know first how the event was used
-  // by content before handling it itself.
-  bool mWantReplyFromContentProcess : 1;
   // The event's action will be handled by APZ. The main thread should not
   // perform its associated action. This is currently only relevant for
   // wheel and touch events.
   bool mHandledByAPZ : 1;
   // True if the event is currently being handled by an event listener that
   // was registered as a passive listener.
   bool mInPassiveListener: 1;
   // If mComposed is true, the event fired by nodes in shadow DOM can cross the
@@ -138,16 +137,29 @@ public:
   // was suppressed or delayed in contents side.
   // It is also set to true for the events (in a DelayedInputEvent), which will
   // be dispatched afterwards.
   bool mIsSuppressedOrDelayed : 1;
   // Certain mouse events can be marked as positionless to return 0 from
   // coordinate related getters.
   bool mIsPositionless : 1;
 
+  // Flags managing state of propagation between processes.
+  // Note the the following flags shouldn't be referred directly.  Use utility
+  // methods instead.
+
+  // If mNoRemoteProcessDispatch is true, the event is not allowed to be sent
+  // to remote process.
+  bool mNoRemoteProcessDispatch : 1;
+  // If mWantReplyFromContentProcess is true, the event will be redispatched
+  // in the parent process after the content process has handled it. Useful
+  // for when the parent process need the know first how the event was used
+  // by content before handling it itself.
+  bool mWantReplyFromContentProcess : 1;
+
   // If the event is being handled in target phase, returns true.
   inline bool InTargetPhase() const
   {
     return (mInBubblingPhase && mInCapturePhase);
   }
 
   /**
    * Helper methods for methods of DOM Event.
@@ -156,20 +168,16 @@ public:
   {
     mPropagationStopped = true;
   }
   inline void StopImmediatePropagation()
   {
     StopPropagation();
     mImmediatePropagationStopped = true;
   }
-  inline void StopCrossProcessForwarding()
-  {
-    mNoCrossProcessBoundaryForwarding = true;
-  }
   inline void PreventDefault(bool aCalledByDefaultHandler = true)
   {
     if (!mCancelable) {
       return;
     }
     mDefaultPrevented = true;
     // Note that even if preventDefault() has already been called by chrome,
     // a call of preventDefault() by content needs to overwrite
@@ -202,16 +210,107 @@ public:
   {
     return mIsTrusted;
   }
   inline bool PropagationStopped() const
   {
     return mPropagationStopped;
   }
 
+  // Helper methods to access flags managing state of propagation between
+  // processes.
+
+  /**
+   * Prevent to be dispatched to remote process.
+   */
+  inline void StopCrossProcessForwarding()
+  {
+    mNoRemoteProcessDispatch = true;
+    mWantReplyFromContentProcess = false;
+  }
+  /**
+   * Return true if the event shouldn't be dispatched to remote process.
+   */
+  inline bool IsCrossProcessForwardingStopped() const
+  {
+    return mNoRemoteProcessDispatch;
+  }
+  /**
+   * Mark the event as waiting reply from remote process.
+   */
+  inline void MarkAsWaitingReplyFromRemoteProcess()
+  {
+    // When this is called, it means that event handlers in this process need
+    // a reply from content in a remote process.  So, callers should stop
+    // propagation in this process first.
+    NS_ASSERTION(PropagationStopped(),
+                 "Why didn't you stop propagation in this process?");
+    mNoRemoteProcessDispatch = false;
+    mWantReplyFromContentProcess = true;
+  }
+  /**
+   * Return true if the event handler should wait reply event.  I.e., if this
+   * returns true, any event handler should do nothing with the event.
+   */
+  inline bool IsWaitingReplyFromRemoteProcess() const
+  {
+    return !mNoRemoteProcessDispatch && mWantReplyFromContentProcess;
+  }
+  /**
+   * Mark the event as already handled in the remote process.  This should be
+   * called when initializing reply events.
+   */
+  inline void MarkAsHandledInRemoteProcess()
+  {
+    mNoRemoteProcessDispatch = true;
+    mWantReplyFromContentProcess = true;
+  }
+  /**
+   * Return true if the event has already been handled in the remote process.
+   */
+  inline bool IsHandledInRemoteProcess() const
+  {
+    return mNoRemoteProcessDispatch && mWantReplyFromContentProcess;
+  }
+  /**
+   * Return true if the event should be sent back to its parent process.
+   */
+  inline bool WantReplyFromContentProcess() const
+  {
+    MOZ_ASSERT(!XRE_IsParentProcess());
+    return IsWaitingReplyFromRemoteProcess();
+  }
+  /**
+   * Mark the event is reserved by chrome.  I.e., shouldn't be dispatched to
+   * content because it shouldn't be cancelable.
+   */
+  inline void MarkAsReservedByChrome()
+  {
+    mIsReservedByChrome = true;
+    // For reserved commands (such as Open New Tab), we don't need to wait for
+    // the content to answer, neither to give a chance for content to override
+    // its behavior.
+    StopCrossProcessForwarding();
+    // If the event is reserved by chrome, we shouldn't expose the event to
+    // web contents because such events shouldn't be cancelable.  So, it's not
+    // good behavior to fire such events but to ignore the defaultPrevented
+    // attribute value in chrome.
+    mOnlySystemGroupDispatchInContent = true;
+  }
+  /**
+   * Return true if the event is reserved by chrome.
+   */
+  inline bool IsReservedByChrome() const
+  {
+    MOZ_ASSERT(!mIsReservedByChrome ||
+               (IsCrossProcessForwardingStopped() &&
+                mOnlySystemGroupDispatchInContent));
+    return mIsReservedByChrome;
+  }
+
   inline void Clear()
   {
     SetRawFlags(0);
   }
   // Get if either the instance's bit or the aOther's bit is true, the
   // instance's bit becomes true.  In other words, this works like:
   // eventFlags |= aOther;
   inline void Union(const BaseEventFlags& aOther)
@@ -450,17 +549,16 @@ public:
     mOriginalTarget = aCopyTargets ? aEvent.mOriginalTarget : nullptr;
   }
 
   /**
    * Helper methods for methods of DOM Event.
    */
   void StopPropagation() { mFlags.StopPropagation(); }
   void StopImmediatePropagation() { mFlags.StopImmediatePropagation(); }
-  void StopCrossProcessForwarding() { mFlags.StopCrossProcessForwarding(); }
   void PreventDefault(bool aCalledByDefaultHandler = true)
   {
     // Legacy mouse events shouldn't be prevented on ePointerDown by default
     // handlers.
     MOZ_RELEASE_ASSERT(!aCalledByDefaultHandler || mMessage != ePointerDown);
     mFlags.PreventDefault(aCalledByDefaultHandler);
   }
   void PreventDefaultBeforeDispatch() { mFlags.PreventDefaultBeforeDispatch(); }
@@ -468,16 +566,86 @@ public:
   bool DefaultPreventedByContent() const
   {
     return mFlags.DefaultPreventedByContent();
   }
   bool IsTrusted() const { return mFlags.IsTrusted(); }
   bool PropagationStopped() const { return mFlags.PropagationStopped(); }
 
   /**
+   * Prevent to be dispatched to remote process.
+   */
+  inline void StopCrossProcessForwarding()
+  {
+    mFlags.StopCrossProcessForwarding();
+  }
+  /**
+   * Return true if the event shouldn't be dispatched to remote process.
+   */
+  inline bool IsCrossProcessForwardingStopped() const
+  {
+    return mFlags.IsCrossProcessForwardingStopped();
+  }
+  /**
+   * Mark the event as waiting reply from remote process.
+   * Note that this also stops immediate propagation in current process.
+   */
+  inline void MarkAsWaitingReplyFromRemoteProcess()
+  {
+    mFlags.MarkAsWaitingReplyFromRemoteProcess();
+  }
+  /**
+   * Return true if the event handler should wait reply event.  I.e., if this
+   * returns true, any event handler should do nothing with the event.
+   */
+  inline bool IsWaitingReplyFromRemoteProcess() const
+  {
+    return mFlags.IsWaitingReplyFromRemoteProcess();
+  }
+  /**
+   * Mark the event as already handled in the remote process.  This should be
+   * called when initializing reply events.
+   */
+  inline void MarkAsHandledInRemoteProcess()
+  {
+    mFlags.MarkAsHandledInRemoteProcess();
+  }
+  /**
+   * Return true if the event has already been handled in the remote process.
+   * I.e., if this returns true, the event is a reply event.
+   */
+  inline bool IsHandledInRemoteProcess() const
+  {
+    return mFlags.IsHandledInRemoteProcess();
+  }
+  /**
+   * Return true if the event should be sent back to its parent process.
+   * So, usual event handlers shouldn't call this.
+   */
+  inline bool WantReplyFromContentProcess() const
+  {
+    return mFlags.WantReplyFromContentProcess();
+  }
+  /**
+   * Mark the event is reserved by chrome.  I.e., shouldn't be dispatched to
+   * content because it shouldn't be cancelable.
+   */
+  inline void MarkAsReservedByChrome()
+  {
+    mFlags.MarkAsReservedByChrome();
+  }
+  /**
+   * Return true if the event is reserved by chrome.
+   */
+  inline bool IsReservedByChrome() const
+  {
+    return mFlags.IsReservedByChrome();
+  }
+
+  /**
    * Utils for checking event types
    */
 
   /**
    * As*Event() returns the pointer of the instance only when the instance is
    * the class or one of its derived class.
    */
 #define NS_ROOT_EVENT_CLASS(aPrefix, aName)
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -149,17 +149,16 @@ protected:
 #ifdef XP_MACOSX
     , mNativeModifierFlags(0)
     , mNativeKeyCode(0)
 #endif // #ifdef XP_MACOSX
     , mKeyNameIndex(KEY_NAME_INDEX_Unidentified)
     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
     , mIsRepeat(false)
     , mIsComposing(false)
-    , mIsReserved(false)
     , mIsSynthesizedByTIP(false)
     , mEditCommandsForSingleLineEditorInitialized(false)
     , mEditCommandsForMultiLineEditorInitialized(false)
     , mEditCommandsForRichTextEditorInitialized(false)
   {
   }
 
 public:
@@ -179,25 +178,26 @@ public:
 #ifdef XP_MACOSX
     , mNativeModifierFlags(0)
     , mNativeKeyCode(0)
 #endif // #ifdef XP_MACOSX
     , mKeyNameIndex(KEY_NAME_INDEX_Unidentified)
     , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN)
     , mIsRepeat(false)
     , mIsComposing(false)
-    , mIsReserved(false)
     , mIsSynthesizedByTIP(false)
     , mEditCommandsForSingleLineEditorInitialized(false)
     , mEditCommandsForMultiLineEditorInitialized(false)
     , mEditCommandsForRichTextEditorInitialized(false)
   {
     // If this is a keyboard event on a plugin, it shouldn't fired on content.
-    mFlags.mOnlySystemGroupDispatchInContent =
-      mFlags.mNoCrossProcessBoundaryForwarding = IsKeyEventOnPlugin();
+    if (IsKeyEventOnPlugin()) {
+      mFlags.mOnlySystemGroupDispatchInContent = true;
+      StopCrossProcessForwarding();
+    }
   }
 
   static bool IsKeyDownOrKeyDownOnPlugin(EventMessage aMessage)
   {
     return aMessage == eKeyDown || aMessage == eKeyDownOnPlugin;
   }
   bool IsKeyDownOrKeyDownOnPlugin() const
   {
@@ -291,19 +291,16 @@ public:
 
   // Indicates whether the event is generated by auto repeat or not.
   // if this is keyup event, always false.
   bool mIsRepeat;
   // Indicates whether the event is generated during IME (or deadkey)
   // composition.  This is initialized by EventStateManager.  So, key event
   // dispatchers don't need to initialize this.
   bool mIsComposing;
-  // Indicates if the key combination is reserved by chrome.  This is set by
-  // nsXBLWindowKeyHandler at capturing phase of the default event group.
-  bool mIsReserved;
   // Indicates whether the event is synthesized from Text Input Processor
   // or an actual event from nsAppShell.
   bool mIsSynthesizedByTIP;
 
   /**
    * Retrieves all edit commands from mWidget.  This shouldn't be called when
    * the instance is an untrusted event, doesn't have widget or in non-chrome
    * process.
@@ -479,17 +476,16 @@ public:
 
     mKeyCode = aEvent.mKeyCode;
     mCharCode = aEvent.mCharCode;
     mPseudoCharCode = aEvent.mPseudoCharCode;
     mLocation = aEvent.mLocation;
     mAlternativeCharCodes = aEvent.mAlternativeCharCodes;
     mIsRepeat = aEvent.mIsRepeat;
     mIsComposing = aEvent.mIsComposing;
-    mIsReserved = aEvent.mIsReserved;
     mAccessKeyForwardedToChild = aEvent.mAccessKeyForwardedToChild;
     mKeyNameIndex = aEvent.mKeyNameIndex;
     mCodeNameIndex = aEvent.mCodeNameIndex;
     mKeyValue = aEvent.mKeyValue;
     mCodeValue = aEvent.mCodeValue;
     // Don't copy mNativeKeyEvent because it may be referred after its instance
     // is destroyed.
     mNativeKeyEvent = nullptr;
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -314,17 +314,17 @@ WidgetEvent::HasPluginActivationEventMes
  * Specific event checking methods.
  ******************************************************************************/
 
 bool
 WidgetEvent::CanBeSentToRemoteProcess() const
 {
   // If this event is explicitly marked as shouldn't be sent to remote process,
   // just return false.
-  if (mFlags.mNoCrossProcessBoundaryForwarding) {
+  if (IsCrossProcessForwardingStopped()) {
     return false;
   }
 
   if (mClass == eKeyboardEventClass ||
       mClass == eWheelEventClass) {
     return true;
   }
 
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -436,17 +436,16 @@ struct ParamTraits<mozilla::WidgetKeyboa
                static_cast<mozilla::CodeNameIndexType>(aParam.mCodeNameIndex));
     WriteParam(aMsg, aParam.mKeyValue);
     WriteParam(aMsg, aParam.mCodeValue);
     WriteParam(aMsg, aParam.mKeyCode);
     WriteParam(aMsg, aParam.mCharCode);
     WriteParam(aMsg, aParam.mPseudoCharCode);
     WriteParam(aMsg, aParam.mAlternativeCharCodes);
     WriteParam(aMsg, aParam.mIsRepeat);
-    WriteParam(aMsg, aParam.mIsReserved);
     WriteParam(aMsg, aParam.mAccessKeyForwardedToChild);
     WriteParam(aMsg, aParam.mLocation);
     WriteParam(aMsg, aParam.mUniqueId);
     WriteParam(aMsg, aParam.mIsSynthesizedByTIP);
 #ifdef XP_MACOSX
     WriteParam(aMsg, aParam.mNativeKeyCode);
     WriteParam(aMsg, aParam.mNativeModifierFlags);
     WriteParam(aMsg, aParam.mNativeCharacters);
@@ -475,17 +474,16 @@ struct ParamTraits<mozilla::WidgetKeyboa
         ReadParam(aMsg, aIter, &codeNameIndex) &&
         ReadParam(aMsg, aIter, &aResult->mKeyValue) &&
         ReadParam(aMsg, aIter, &aResult->mCodeValue) &&
         ReadParam(aMsg, aIter, &aResult->mKeyCode) &&
         ReadParam(aMsg, aIter, &aResult->mCharCode) &&
         ReadParam(aMsg, aIter, &aResult->mPseudoCharCode) &&
         ReadParam(aMsg, aIter, &aResult->mAlternativeCharCodes) &&
         ReadParam(aMsg, aIter, &aResult->mIsRepeat) &&
-        ReadParam(aMsg, aIter, &aResult->mIsReserved) &&
         ReadParam(aMsg, aIter, &aResult->mAccessKeyForwardedToChild) &&
         ReadParam(aMsg, aIter, &aResult->mLocation) &&
         ReadParam(aMsg, aIter, &aResult->mUniqueId) &&
         ReadParam(aMsg, aIter, &aResult->mIsSynthesizedByTIP) &&
 #ifdef XP_MACOSX
         ReadParam(aMsg, aIter, &aResult->mNativeKeyCode) &&
         ReadParam(aMsg, aIter, &aResult->mNativeModifierFlags) &&
         ReadParam(aMsg, aIter, &aResult->mNativeCharacters) &&