Bug 1377653 - part3: WidgetEvent::mFlags should have a bool flag if it's been posted to at least one remote process r?smaug draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 05 Jul 2017 18:59:44 +0900
changeset 604128 7d88774e3f019d66159cdf0eb8b77ba15ba1c7f1
parent 604127 ace5b1ea045dad943821a770454dea8131c8e69f
child 604129 d932cff2d71c9b730d7b5235843f7811d847f7bb
push id66965
push usermasayuki@d-toybox.com
push dateWed, 05 Jul 2017 10:02:44 +0000
reviewerssmaug
bugs1377653
milestone56.0a1
Bug 1377653 - part3: WidgetEvent::mFlags should have a bool flag if it's been posted to at least one remote process r?smaug Currently, it's not been managed yet that whether an event is posted to at least one remote process. So, for managing the state, BaseEventFlags should have a new bool flag and WidgetEvent and BaseEventFlags should have helper methods for it. Additionally, this fixes a bug of nsGUIEventIPC.h. In a lot of ParamTraits, static_cast<Foo> is used for using base class's ParamTraits. However, it causes creating temporary instance with copy constructor. Therefore, WidgetEvent::MarkAsPostedToRemoteProcess() call in ParamTraits<mozilla::WidgetEvent>::Write() didn't work as expected. MozReview-Commit-ID: DdafsbVfrya
dom/events/EventStateManager.cpp
dom/events/EventStateManager.h
dom/ipc/TabChild.cpp
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
widget/BasicEvents.h
widget/nsGUIEventIPC.h
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1220,40 +1220,45 @@ EventStateManager::HandleAccessKey(Widge
       nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
                                               HandleAccessKeyInRemoteChild, &accessKeyInfo);
     }
   }
 
   return false;
 }// end of HandleAccessKey
 
-bool
+void
 EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
                                              nsFrameLoader* aFrameLoader,
-                                             nsEventStatus *aStatus) {
+                                             nsEventStatus *aStatus)
+{
   TabParent* remote = TabParent::GetFrom(aFrameLoader);
   if (!remote) {
-    return false;
+    return;
   }
 
   switch (aEvent->mClass) {
   case eMouseEventClass: {
-    return remote->SendRealMouseEvent(*aEvent->AsMouseEvent());
+    remote->SendRealMouseEvent(*aEvent->AsMouseEvent());
+    return;
   }
   case eKeyboardEventClass: {
-    return remote->SendRealKeyEvent(*aEvent->AsKeyboardEvent());
+    remote->SendRealKeyEvent(*aEvent->AsKeyboardEvent());
+    return;
   }
   case eWheelEventClass: {
-    return remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
+    remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
+    return;
   }
   case eTouchEventClass: {
     // Let the child process synthesize a mouse event if needed, and
     // ensure we don't synthesize one in this process.
     *aStatus = nsEventStatus_eConsumeNoDefault;
-    return remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
+    remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
+    return;
   }
   case eDragEventClass: {
     if (remote->Manager()->IsContentParent()) {
       remote->Manager()->AsContentParent()->MaybeInvokeDragSession(remote);
     }
 
     nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
     uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
@@ -1263,24 +1268,23 @@ EventStateManager::DispatchCrossProcessE
       dragSession->GetDragAction(&action);
       nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
       dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
       if (initialDataTransfer) {
         initialDataTransfer->GetDropEffectInt(&dropEffect);
       }
     }
 
-    bool retval = remote->SendRealDragEvent(*aEvent->AsDragEvent(),
-                                            action, dropEffect);
-
-    return retval;
+    remote->SendRealDragEvent(*aEvent->AsDragEvent(), action, dropEffect);
+    return;
   }
   case ePluginEventClass: {
     *aStatus = nsEventStatus_eConsumeNoDefault;
-    return remote->SendPluginEvent(*aEvent->AsPluginEvent());
+    remote->SendPluginEvent(*aEvent->AsPluginEvent());
+    return;
   }
   default: {
     MOZ_CRASH("Attempt to send non-whitelisted event?");
   }
   }
 }
 
 bool
@@ -1292,16 +1296,19 @@ EventStateManager::IsRemoteTarget(nsICon
 bool
 EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
                                            nsEventStatus *aStatus) {
   if (*aStatus == nsEventStatus_eConsumeNoDefault ||
       !aEvent->CanBeSentToRemoteProcess()) {
     return false;
   }
 
+  MOZ_ASSERT(!aEvent->HasBeenPostedToRemoteProcess(),
+    "Why do we need to post same event to remote processes again?");
+
   // Collect the remote event targets we're going to forward this
   // event to.
   //
   // NB: the elements of |targets| must be unique, for correctness.
   AutoTArray<nsCOMPtr<nsIContent>, 1> targets;
   if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
     // If this event only has one target, and it's remote, add it to
     // the array.
@@ -1342,17 +1349,16 @@ EventStateManager::HandleCrossProcessEve
   }
 
   if (targets.Length() == 0) {
     return false;
   }
 
   // Look up the frame loader for all the remote targets we found, and
   // then dispatch the event to the remote content they represent.
-  bool dispatched = false;
   for (uint32_t i = 0; i < targets.Length(); ++i) {
     nsIContent* target = targets[i];
     nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(target);
     if (!loaderOwner) {
       continue;
     }
 
     RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
@@ -1361,19 +1367,19 @@ EventStateManager::HandleCrossProcessEve
     }
 
     uint32_t eventMode;
     frameLoader->GetEventMode(&eventMode);
     if (eventMode == nsIFrameLoader::EVENT_MODE_DONT_FORWARD_TO_CHILD) {
       continue;
     }
 
-    dispatched |= DispatchCrossProcessEvent(aEvent, frameLoader, aStatus);
-  }
-  return dispatched;
+    DispatchCrossProcessEvent(aEvent, frameLoader, aStatus);
+  }
+  return aEvent->HasBeenPostedToRemoteProcess();
 }
 
 //
 // CreateClickHoldTimer
 //
 // Fire off a timer for determining if the user wants click-hold. This timer
 // is a one-shot that will be cancelled when the user moves enough to fire
 // a drag.
@@ -2818,24 +2824,23 @@ NodeAllowsClickThrough(nsINode* aNode)
     aNode = nsContentUtils::GetCrossDocParentNode(aNode);
   }
   return true;
 }
 #endif
 
 void
 EventStateManager::PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
-                                           nsEventStatus& aStatus,
-                                           bool dispatchedToContentProcess)
+                                           nsEventStatus& aStatus)
 {
   if (aStatus == nsEventStatus_eConsumeNoDefault) {
     return;
   }
 
-  if (!dispatchedToContentProcess) {
+  if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
     // 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
     // running), we need to short-circuit here. Otherwise, we need to wait for
     // the content process to handle the event.
     aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
     if (aKeyboardEvent->DefaultPrevented()) {
       aStatus = nsEventStatus_eConsumeNoDefault;
       return;
@@ -2850,18 +2855,19 @@ EventStateManager::PostHandleKeyboardEve
       // This is to prevent keyboard scrolling while alt modifier in use.
       if (!aKeyboardEvent->IsAlt()) {
         aStatus = nsEventStatus_eConsumeNoDefault;
 
         // Handling the tab event after it was sent to content is bad,
         // because to the FocusManager the remote-browser looks like one
         // element, so we would just move the focus to the next element
         // in chrome, instead of handling it in content.
-        if (dispatchedToContentProcess)
+        if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
           break;
+        }
 
         EnsureDocument(mPresContext);
         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
         if (fm && mDocument) {
           // Shift focus forward or back depending on shift key
           bool isDocMove =
             aKeyboardEvent->IsControl() || aKeyboardEvent->mKeyCode == NS_VK_F6;
           uint32_t dir = aKeyboardEvent->IsShift() ?
@@ -2902,17 +2908,17 @@ EventStateManager::PostHandleEvent(nsPre
                                    nsEventStatus* aStatus)
 {
   NS_ENSURE_ARG(aPresContext);
   NS_ENSURE_ARG_POINTER(aStatus);
 
   mCurrentTarget = aTargetFrame;
   mCurrentTargetContent = nullptr;
 
-  bool dispatchedToContentProcess = HandleCrossProcessEvent(aEvent, aStatus);
+  HandleCrossProcessEvent(aEvent, aStatus);
   // NOTE: the above call may have destroyed aTargetFrame, please use
   // mCurrentTarget henceforth.  This is to avoid using it accidentally:
   aTargetFrame = nullptr;
 
   // Most of the events we handle below require a frame.
   // Add special cases here.
   if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
       aEvent->mMessage != eMouseDown) {
@@ -2934,17 +2940,18 @@ EventStateManager::PostHandleEvent(nsPre
         nsIPresShell::SetCapturingContent(nullptr, 0);
         break;
       }
 
       // For remote content, capture the event in the parent process at the
       // <xul:browser remote> element. This will ensure that subsequent mousemove/mouseup
       // events will continue to be dispatched to this element and therefore forwarded
       // to the child.
-      if (dispatchedToContentProcess && !nsIPresShell::GetCapturingContent()) {
+      if (aEvent->HasBeenPostedToRemoteProcess() &&
+          !nsIPresShell::GetCapturingContent()) {
         nsIContent* content = mCurrentTarget ? mCurrentTarget->GetContent() : nullptr;
         nsIPresShell::SetCapturingContent(content, 0);
       }
 
       nsCOMPtr<nsIContent> activeContent;
       // When content calls PreventDefault on pointerdown, we also call
       // PreventDefault on the subsequent mouse events to suppress default
       // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
@@ -3439,17 +3446,17 @@ EventStateManager::PostHandleEvent(nsPre
         }
       } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
         // No one called preventDefault(), so handle drop only in chrome.
         dragSession->SetOnlyChromeDrop(true);
       }
       if (ContentChild* child = ContentChild::GetSingleton()) {
         child->SendUpdateDropEffect(action, dropEffect);
       }
-      if (dispatchedToContentProcess) {
+      if (aEvent->HasBeenPostedToRemoteProcess()) {
         dragSession->SetCanDrop(true);
       } else if (initialDataTransfer) {
         // Now set the drop effect in the initial dataTransfer. This ensures
         // that we can get the desired drop effect in the drop event. For events
         // dispatched to content, the content process will take care of setting
         // this.
         initialDataTransfer->SetDropEffectInt(dropEffect);
       }
@@ -3475,17 +3482,17 @@ EventStateManager::PostHandleEvent(nsPre
     break;
 
   case eKeyUp:
     break;
 
   case eKeyPress:
     {
       WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
-      PostHandleKeyboardEvent(keyEvent, *aStatus, dispatchedToContentProcess);
+      PostHandleKeyboardEvent(keyEvent, *aStatus);
     }
     break;
 
   case eMouseEnterIntoWidget:
     if (mCurrentTarget) {
       nsCOMPtr<nsIContent> targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
       SetContentState(targetContent, NS_EVENT_STATE_HOVER);
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -104,18 +104,17 @@ public:
    * DOM and frame processing.
    */
   nsresult PostHandleEvent(nsPresContext* aPresContext,
                            WidgetEvent* aEvent,
                            nsIFrame* aTargetFrame,
                            nsEventStatus* aStatus);
 
   void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
-                               nsEventStatus& aStatus,
-                               bool dispatchedToContentProcess);
+                               nsEventStatus& aStatus);
 
   /**
    * DispatchLegacyMouseScrollEvents() dispatches eLegacyMouseLineOrPageScroll
    * event and eLegacyMousePixelScroll event for compatibility with old Gecko.
    */
   void DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
                                        WidgetWheelEvent* aEvent,
                                        nsEventStatus* aStatus);
@@ -890,19 +889,32 @@ protected:
   void FillInEventFromGestureDown(WidgetMouseEvent* aEvent);
 
   nsresult DoContentCommandEvent(WidgetContentCommandEvent* aEvent);
   nsresult DoContentCommandScrollEvent(WidgetContentCommandEvent* aEvent);
 
   dom::TabParent *GetCrossProcessTarget();
   bool IsTargetCrossProcess(WidgetGUIEvent* aEvent);
 
-  bool DispatchCrossProcessEvent(WidgetEvent* aEvent,
+  /**
+   * DispatchCrossProcessEvent() try to post aEvent to target remote process.
+   * If you need to check if the event is posted to a remote process, you
+   * can use aEvent->HasBeenPostedToRemoteProcess().
+   */
+  void DispatchCrossProcessEvent(WidgetEvent* aEvent,
                                  nsFrameLoader* aRemote,
                                  nsEventStatus *aStatus);
+  /**
+   * HandleCrossProcessEvent() may post aEvent to target remote processes.
+   * When it succeeded to post the event to at least one remote process,
+   * returns true.  Otherwise, including the case not tried to dispatch to
+   * post the event, returns false.
+   * If you need to check if the event is posted to at least one remote
+   * process, you can use aEvent->HasBeenPostedToRemoteProcess().
+   */
   bool HandleCrossProcessEvent(WidgetEvent* aEvent,
                                nsEventStatus* aStatus);
 
   void ReleaseCurrentIMEContentObserver();
 
   void HandleQueryContentEvent(WidgetQueryContentEvent* aEvent);
 
 private:
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1827,17 +1827,20 @@ TabChild::RequestEditCommands(nsIWidget:
     case nsIWidget::NativeKeyBindingsForSingleLineEditor:
     case nsIWidget::NativeKeyBindingsForMultiLineEditor:
     case nsIWidget::NativeKeyBindingsForRichTextEditor:
       break;
     default:
       MOZ_ASSERT_UNREACHABLE("Invalid native key bindings type");
   }
 
-  SendRequestNativeKeyBindings(aType, aEvent, &aCommands);
+  // Don't send aEvent to the parent process directly because it'll be marked
+  // as posted to remote process.
+  WidgetKeyboardEvent localEvent(aEvent);
+  SendRequestNativeKeyBindings(aType, localEvent, &aCommands);
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvNativeSynthesisResponse(const uint64_t& aObserverId,
                                       const nsCString& aResponse)
 {
   mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId,
                                                              aResponse.get());
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -813,17 +813,21 @@ TabParent::ThemeChanged()
 }
 
 void
 TabParent::HandleAccessKey(const WidgetKeyboardEvent& aEvent,
                            nsTArray<uint32_t>& aCharCodes,
                            const int32_t& aModifierMask)
 {
   if (!mIsDestroyed) {
-    Unused << SendHandleAccessKey(aEvent, aCharCodes, aModifierMask);
+    // Note that we don't need to mark aEvent is posted to a remote process
+    // because the event may be dispatched to it as normal keyboard event.
+    // Therefore, we should use local copy to send it.
+    WidgetKeyboardEvent localEvent(aEvent);
+    Unused << SendHandleAccessKey(localEvent, aCharCodes, aModifierMask);
   }
 }
 
 void
 TabParent::Activate()
 {
   if (!mIsDestroyed) {
     Unused << Manager()->SendActivate(this);
@@ -1078,21 +1082,21 @@ TabParent::SendKeyEvent(const nsAString&
 {
   if (mIsDestroyed) {
     return;
   }
   Unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode,
                                          aModifiers, aPreventDefault);
 }
 
-bool
+void
 TabParent::SendRealMouseEvent(WidgetMouseEvent& aEvent)
 {
   if (mIsDestroyed) {
-    return false;
+    return;
   }
   aEvent.mRefPoint += GetChildProcessOffset();
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     // When we mouseenter the tab, the tab's cursor should
     // become the current cursor.  When we mouseexit, we stop.
     if (eMouseEnterIntoWidget == aEvent.mMessage) {
@@ -1109,66 +1113,79 @@ TabParent::SendRealMouseEvent(WidgetMous
   }
 
   ScrollableLayerGuid guid;
   uint64_t blockId;
   ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
 
   if (eMouseMove == aEvent.mMessage) {
     if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
-      return SendSynthMouseMoveEvent(aEvent, guid, blockId);
-    } else {
-      return SendRealMouseMoveEvent(aEvent, guid, blockId);
+      DebugOnly<bool> ret = SendSynthMouseMoveEvent(aEvent, guid, blockId);
+      NS_WARNING_ASSERTION(ret, "SendSynthMouseMoveEvent() failed");
+      MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+      return;
     }
+    DebugOnly<bool> ret = SendRealMouseMoveEvent(aEvent, guid, blockId);
+    NS_WARNING_ASSERTION(ret, "SendRealMouseMoveEvent() failed");
+    MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+    return;
   }
 
-  return SendRealMouseButtonEvent(aEvent, guid, blockId);
+  DebugOnly<bool> ret = SendRealMouseButtonEvent(aEvent, guid, blockId);
+  NS_WARNING_ASSERTION(ret, "SendRealMouseButtonEvent() failed");
+  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
 }
 
 LayoutDeviceToCSSScale
 TabParent::GetLayoutDeviceToCSSScale()
 {
   nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
   nsIDocument* doc = (content ? content->OwnerDoc() : nullptr);
   nsIPresShell* shell = (doc ? doc->GetShell() : nullptr);
   nsPresContext* ctx = (shell ? shell->GetPresContext() : nullptr);
   return LayoutDeviceToCSSScale(ctx
     ? (float)ctx->AppUnitsPerDevPixel() / nsPresContext::AppUnitsPerCSSPixel()
     : 0.0f);
 }
 
-bool
+void
 TabParent::SendRealDragEvent(WidgetDragEvent& aEvent, uint32_t aDragAction,
                              uint32_t aDropEffect)
 {
   if (mIsDestroyed) {
-    return false;
+    return;
   }
   aEvent.mRefPoint += GetChildProcessOffset();
-  return PBrowserParent::SendRealDragEvent(aEvent, aDragAction, aDropEffect);
+  DebugOnly<bool> ret =
+    PBrowserParent::SendRealDragEvent(aEvent, aDragAction, aDropEffect);
+  NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealDragEvent() failed");
+  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
 }
 
 LayoutDevicePoint
 TabParent::AdjustTapToChildWidget(const LayoutDevicePoint& aPoint)
 {
   return aPoint + LayoutDevicePoint(GetChildProcessOffset());
 }
 
-bool
+void
 TabParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent)
 {
   if (mIsDestroyed) {
-    return false;
+    return;
   }
 
   ScrollableLayerGuid guid;
   uint64_t blockId;
   ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
   aEvent.mRefPoint += GetChildProcessOffset();
-  return PBrowserParent::SendMouseWheelEvent(aEvent, guid, blockId);
+  DebugOnly<bool> ret =
+    PBrowserParent::SendMouseWheelEvent(aEvent, guid, blockId);
+  NS_WARNING_ASSERTION(ret, "PBrowserParent::SendMouseWheelEvent() failed");
+  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return IPC_OK();
@@ -1423,40 +1440,42 @@ TabParent::RecvClearNativeTouchSequence(
   AutoSynthesizedEventResponder responder(this, aObserverId, "cleartouch");
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->ClearNativeTouchSequence(responder.GetObserver());
   }
   return IPC_OK();
 }
 
-bool
+void
 TabParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent)
 {
   if (mIsDestroyed) {
-    return false;
+    return;
   }
   aEvent.mRefPoint += GetChildProcessOffset();
 
   if (aEvent.mMessage == eKeyPress) {
     // XXX Should we do this only when input context indicates an editor having
     //     focus and the key event won't cause inputting text?
     aEvent.InitAllEditCommands();
   } else {
     aEvent.PreventNativeKeyBindings();
   }
 
-  return PBrowserParent::SendRealKeyEvent(aEvent);
+  DebugOnly<bool> ret = PBrowserParent::SendRealKeyEvent(aEvent);
+  NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealKeyEvent() failed");
+  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
 }
 
-bool
+void
 TabParent::SendRealTouchEvent(WidgetTouchEvent& aEvent)
 {
   if (mIsDestroyed) {
-    return false;
+    return;
   }
 
   // PresShell::HandleEventInternal adds touches on touch end/cancel.  This
   // confuses remote content and the panning and zooming logic into thinking
   // that the added touches are part of the touchend/cancel, when actually
   // they're not.
   if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchCancel) {
     for (int i = aEvent.mTouches.Length() - 1; i >= 0; i--) {
@@ -1467,27 +1486,46 @@ TabParent::SendRealTouchEvent(WidgetTouc
   }
 
   ScrollableLayerGuid guid;
   uint64_t blockId;
   nsEventStatus apzResponse;
   ApzAwareEventRoutingToChild(&guid, &blockId, &apzResponse);
 
   if (mIsDestroyed) {
-    return false;
+    return;
   }
 
   LayoutDeviceIntPoint offset = GetChildProcessOffset();
   for (uint32_t i = 0; i < aEvent.mTouches.Length(); i++) {
     aEvent.mTouches[i]->mRefPoint += offset;
   }
 
-  return (aEvent.mMessage == eTouchMove) ?
-    PBrowserParent::SendRealTouchMoveEvent(aEvent, guid, blockId, apzResponse) :
+  if (aEvent.mMessage == eTouchMove) {
+    DebugOnly<bool> ret =
+      PBrowserParent::SendRealTouchMoveEvent(aEvent, guid, blockId,
+                                             apzResponse);
+    NS_WARNING_ASSERTION(ret,
+                         "PBrowserParent::SendRealTouchMoveEvent() failed");
+    MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+    return;
+  }
+
+  DebugOnly<bool> ret =
     PBrowserParent::SendRealTouchEvent(aEvent, guid, blockId, apzResponse);
+  NS_WARNING_ASSERTION(ret, "PBrowserParent::SendRealTouchEvent() failed");
+  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
+}
+
+void
+TabParent::SendPluginEvent(WidgetPluginEvent& aEvent)
+{
+  DebugOnly<bool> ret = PBrowserParent::SendPluginEvent(aEvent);
+  NS_WARNING_ASSERTION(ret, "PBrowserParent::SendPluginEvent() failed");
+  MOZ_ASSERT(!ret || aEvent.HasBeenPostedToRemoteProcess());
 }
 
 bool
 TabParent::SendHandleTap(TapType aType,
                          const LayoutDevicePoint& aPoint,
                          Modifiers aModifiers,
                          const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId)
@@ -2047,33 +2085,38 @@ TabParent::SendCompositionEvent(WidgetCo
 {
   if (mIsDestroyed) {
     return false;
   }
 
   if (!mContentCache.OnCompositionEvent(aEvent)) {
     return true;
   }
-  return PBrowserParent::SendCompositionEvent(aEvent);
+  if (NS_WARN_IF(!PBrowserParent::SendCompositionEvent(aEvent))) {
+    return false;
+  }
+  MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
+  return true;
 }
 
 bool
 TabParent::SendSelectionEvent(WidgetSelectionEvent& aEvent)
 {
   if (mIsDestroyed) {
     return false;
   }
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
   mContentCache.OnSelectionEvent(aEvent);
   if (NS_WARN_IF(!PBrowserParent::SendSelectionEvent(aEvent))) {
     return false;
   }
+  MOZ_ASSERT(aEvent.HasBeenPostedToRemoteProcess());
   aEvent.mSucceeded = true;
   return true;
 }
 
 bool
 TabParent::SendPasteTransferable(const IPCDataTransfer& aDataTransfer,
                                  const bool& aIsPrivateData,
                                  const IPC::Principal& aRequestingPrincipal)
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -433,27 +433,45 @@ public:
   void SendMouseEvent(const nsAString& aType, float aX, float aY,
                       int32_t aButton, int32_t aClickCount,
                       int32_t aModifiers, bool aIgnoreRootScrollFrame);
 
   void SendKeyEvent(const nsAString& aType, int32_t aKeyCode,
                     int32_t aCharCode, int32_t aModifiers,
                     bool aPreventDefault);
 
-  bool SendRealMouseEvent(mozilla::WidgetMouseEvent& aEvent);
+  /**
+   * The following Send*Event() marks aEvent as posted to remote process if
+   * it succeeded.  So, you can check the result with
+   * aEvent.HasBeenPostedToRemoteProcess().
+   */
+  void SendRealMouseEvent(WidgetMouseEvent& aEvent);
 
-  bool SendRealDragEvent(mozilla::WidgetDragEvent& aEvent,
+  void SendRealDragEvent(WidgetDragEvent& aEvent,
                          uint32_t aDragAction,
                          uint32_t aDropEffect);
 
-  bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& aEvent);
+  void SendMouseWheelEvent(WidgetWheelEvent& aEvent);
+
+  void SendRealKeyEvent(WidgetKeyboardEvent& aEvent);
+
+  void SendRealTouchEvent(WidgetTouchEvent& aEvent);
+
+  void SendPluginEvent(WidgetPluginEvent& aEvent);
 
-  bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& aEvent);
+  /**
+   * Different from above Send*Event(), these methods return true if the
+   * event has been posted to the remote process or failed to do that but
+   * shouldn't be handled by following event listeners.
+   * If you need to check if it's actually posted to the remote process,
+   * you can refer aEvent.HasBeenPostedToRemoteProcess().
+   */
+  bool SendCompositionEvent(mozilla::WidgetCompositionEvent& aEvent);
 
-  bool SendRealTouchEvent(WidgetTouchEvent& aEvent);
+  bool SendSelectionEvent(mozilla::WidgetSelectionEvent& aEvent);
 
   bool SendHandleTap(TapType aType,
                      const LayoutDevicePoint& aPoint,
                      Modifiers aModifiers,
                      const ScrollableLayerGuid& aGuid,
                      uint64_t aInputBlockId);
 
   virtual PDocumentRendererParent*
@@ -491,20 +509,16 @@ public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAUTHPROMPTPROVIDER
   NS_DECL_NSISECUREBROWSERUI
   NS_DECL_NSIWEBBROWSERPERSISTABLE
 
   bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
 
-  bool SendCompositionEvent(mozilla::WidgetCompositionEvent& aEvent);
-
-  bool SendSelectionEvent(mozilla::WidgetSelectionEvent& aEvent);
-
   bool SendPasteTransferable(const IPCDataTransfer& aDataTransfer,
                              const bool& aIsPrivateData,
                              const IPC::Principal& aRequestingPrincipal);
 
   static TabParent* GetFrom(nsFrameLoader* aFrameLoader);
 
   static TabParent* GetFrom(nsIFrameLoader* aFrameLoader);
 
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -149,16 +149,20 @@ public:
   // 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 mPostedToRemoteProcess is true, the event has been posted to the
+  // remote process (but it's not handled yet if it's not a duplicated event
+  // instance).
+  bool mPostedToRemoteProcess : 1;
 
   // If the event is being handled in target phase, returns true.
   inline bool InTargetPhase() const
   {
     return (mInBubblingPhase && mInCapturePhase);
   }
 
   /**
@@ -218,31 +222,33 @@ public:
   // Helper methods to access flags managing state of propagation between
   // processes.
 
   /**
    * Prevent to be dispatched to remote process.
    */
   inline void StopCrossProcessForwarding()
   {
+    MOZ_ASSERT(!mPostedToRemoteProcess);
     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()
   {
+    MOZ_ASSERT(!mPostedToRemoteProcess);
     // 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;
   }
@@ -257,16 +263,17 @@ public:
   /**
    * 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;
+    mPostedToRemoteProcess = false;
   }
   /**
    * Return true if the event has already been handled in the remote process.
    */
   inline bool IsHandledInRemoteProcess() const
   {
     return mNoRemoteProcessDispatch && mWantReplyFromContentProcess;
   }
@@ -274,21 +281,51 @@ public:
    * 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 has already posted to a remote process.
+   */
+  inline void MarkAsPostedToRemoteProcess()
+  {
+    MOZ_ASSERT(!IsCrossProcessForwardingStopped());
+    mPostedToRemoteProcess = true;
+  }
+  /**
+   * Reset the cross process dispatching state.  This should be used when a
+   * process receives the event because the state is in the sender.
+   */
+  inline void ResetCrossProcessDispatchingState()
+  {
+    MOZ_ASSERT(!IsCrossProcessForwardingStopped());
+    mPostedToRemoteProcess = false;
+  }
+  /**
+   * Return true if the event has been posted to a remote process.
+   * Note that MarkAsPostedToRemoteProcess() is called by
+   * ParamTraits<mozilla::WidgetEvent>.  Therefore, it *might* be possible
+   * that posting the event failed even if this returns true.  But that must
+   * really rare.  If that'd be problem for you, you should unmark this in
+   * TabParent or somewhere.
+   */
+  inline bool HasBeenPostedToRemoteProcess() const
+  {
+    return mPostedToRemoteProcess;
+  }
+  /**
    * Mark the event is reserved by chrome.  I.e., shouldn't be dispatched to
    * content because it shouldn't be cancelable.
    */
   inline void MarkAsReservedByChrome()
   {
+    MOZ_ASSERT(!mPostedToRemoteProcess);
     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
@@ -620,16 +657,38 @@ public:
    * 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 has already posted to a remote process.
+   */
+  inline void MarkAsPostedToRemoteProcess()
+  {
+    mFlags.MarkAsPostedToRemoteProcess();
+  }
+  /**
+   * Reset the cross process dispatching state.  This should be used when a
+   * process receives the event because the state is in the sender.
+   */
+  inline void ResetCrossProcessDispatchingState()
+  {
+    mFlags.ResetCrossProcessDispatchingState();
+  }
+  /**
+   * Return true if the event has been posted to a remote process.
+   */
+  inline bool HasBeenPostedToRemoteProcess() const
+  {
+    return mFlags.HasBeenPostedToRemoteProcess();
+  }
+  /**
    * 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();
   }
   /**
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -56,16 +56,19 @@ struct ParamTraits<mozilla::BaseEventFla
 
 template<>
 struct ParamTraits<mozilla::WidgetEvent>
 {
   typedef mozilla::WidgetEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
+    // Mark the event as posted to another process.
+    const_cast<mozilla::WidgetEvent&>(aParam).MarkAsPostedToRemoteProcess();
+
     WriteParam(aMsg,
       static_cast<mozilla::EventClassIDType>(aParam.mClass));
     WriteParam(aMsg, aParam.mMessage);
     WriteParam(aMsg, aParam.mRefPoint);
     WriteParam(aMsg, aParam.mFocusSequenceNumber);
     WriteParam(aMsg, aParam.mTime);
     WriteParam(aMsg, aParam.mTimeStamp);
     WriteParam(aMsg, aParam.mFlags);
@@ -77,16 +80,21 @@ struct ParamTraits<mozilla::WidgetEvent>
     bool ret = ReadParam(aMsg, aIter, &eventClassID) &&
                ReadParam(aMsg, aIter, &aResult->mMessage) &&
                ReadParam(aMsg, aIter, &aResult->mRefPoint) &&
                ReadParam(aMsg, aIter, &aResult->mFocusSequenceNumber) &&
                ReadParam(aMsg, aIter, &aResult->mTime) &&
                ReadParam(aMsg, aIter, &aResult->mTimeStamp) &&
                ReadParam(aMsg, aIter, &aResult->mFlags);
     aResult->mClass = static_cast<mozilla::EventClassID>(eventClassID);
+    if (ret) {
+      // Reset cross process dispatching state here because the event has not
+      // been dispatched to different process from current process.
+      aResult->ResetCrossProcessDispatchingState();
+    }
     return ret;
   }
 };
 
 template<>
 struct ParamTraits<mozilla::NativeEventData>
 {
   typedef mozilla::NativeEventData paramType;
@@ -104,17 +112,17 @@ struct ParamTraits<mozilla::NativeEventD
 
 template<>
 struct ParamTraits<mozilla::WidgetGUIEvent>
 {
   typedef mozilla::WidgetGUIEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetEvent&>(aParam));
     WriteParam(aMsg, aParam.mPluginEvent);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, static_cast<mozilla::WidgetEvent*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->mPluginEvent);
   }
@@ -122,17 +130,17 @@ struct ParamTraits<mozilla::WidgetGUIEve
 
 template<>
 struct ParamTraits<mozilla::WidgetInputEvent>
 {
   typedef mozilla::WidgetInputEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetGUIEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetGUIEvent&>(aParam));
     WriteParam(aMsg, aParam.mModifiers);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter,
                      static_cast<mozilla::WidgetGUIEvent*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->mModifiers);
@@ -141,17 +149,17 @@ struct ParamTraits<mozilla::WidgetInputE
 
 template<>
 struct ParamTraits<mozilla::WidgetMouseEventBase>
 {
   typedef mozilla::WidgetMouseEventBase paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetInputEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetInputEvent&>(aParam));
     WriteParam(aMsg, aParam.button);
     WriteParam(aMsg, aParam.buttons);
     WriteParam(aMsg, aParam.pressure);
     WriteParam(aMsg, aParam.hitCluster);
     WriteParam(aMsg, aParam.inputSource);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
@@ -168,17 +176,17 @@ struct ParamTraits<mozilla::WidgetMouseE
 
 template<>
 struct ParamTraits<mozilla::WidgetWheelEvent>
 {
   typedef mozilla::WidgetWheelEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetMouseEventBase>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetMouseEventBase&>(aParam));
     WriteParam(aMsg, aParam.mDeltaX);
     WriteParam(aMsg, aParam.mDeltaY);
     WriteParam(aMsg, aParam.mDeltaZ);
     WriteParam(aMsg, aParam.mDeltaMode);
     WriteParam(aMsg, aParam.mCustomizedByUserPrefs);
     WriteParam(aMsg, aParam.mMayHaveMomentum);
     WriteParam(aMsg, aParam.mIsMomentum);
     WriteParam(aMsg, aParam.mIsNoLineOrPageDelta);
@@ -250,17 +258,17 @@ struct ParamTraits<mozilla::WidgetPointe
 
 template<>
 struct ParamTraits<mozilla::WidgetMouseEvent>
 {
   typedef mozilla::WidgetMouseEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetMouseEventBase>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetMouseEventBase&>(aParam));
     WriteParam(aMsg, static_cast<mozilla::WidgetPointerHelper>(aParam));
     WriteParam(aMsg, aParam.mIgnoreRootScrollFrame);
     WriteParam(aMsg, static_cast<paramType::ReasonType>(aParam.mReason));
     WriteParam(aMsg, static_cast<paramType::ContextMenuTriggerType>(
                        aParam.mContextMenuTrigger));
     WriteParam(aMsg, static_cast<paramType::ExitFromType>(aParam.mExitFrom));
     WriteParam(aMsg, aParam.mClickCount);
   }
@@ -291,17 +299,17 @@ struct ParamTraits<mozilla::WidgetMouseE
 
 template<>
 struct ParamTraits<mozilla::WidgetDragEvent>
 {
   typedef mozilla::WidgetDragEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetMouseEvent&>(aParam));
     WriteParam(aMsg, aParam.mUserCancelled);
     WriteParam(aMsg, aParam.mDefaultPreventedOnContent);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool rv =
       ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEvent*>(aResult)) &&
@@ -313,17 +321,17 @@ struct ParamTraits<mozilla::WidgetDragEv
 
 template<>
 struct ParamTraits<mozilla::WidgetPointerEvent>
 {
   typedef mozilla::WidgetPointerEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetMouseEvent&>(aParam));
     WriteParam(aMsg, aParam.mWidth);
     WriteParam(aMsg, aParam.mHeight);
     WriteParam(aMsg, aParam.mIsPrimary);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool rv =
@@ -424,17 +432,17 @@ struct ParamTraits<mozilla::ShortcutKeyC
 
 template<>
 struct ParamTraits<mozilla::WidgetKeyboardEvent>
 {
   typedef mozilla::WidgetKeyboardEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetInputEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetInputEvent&>(aParam));
     WriteParam(aMsg,
                static_cast<mozilla::KeyNameIndexType>(aParam.mKeyNameIndex));
     WriteParam(aMsg,
                static_cast<mozilla::CodeNameIndexType>(aParam.mCodeNameIndex));
     WriteParam(aMsg, aParam.mKeyValue);
     WriteParam(aMsg, aParam.mCodeValue);
     WriteParam(aMsg, aParam.mKeyCode);
     WriteParam(aMsg, aParam.mCharCode);
@@ -595,17 +603,17 @@ struct ParamTraits<mozilla::TextRangeArr
 
 template<>
 struct ParamTraits<mozilla::WidgetCompositionEvent>
 {
   typedef mozilla::WidgetCompositionEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetGUIEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetGUIEvent&>(aParam));
     WriteParam(aMsg, aParam.mData);
     WriteParam(aMsg, aParam.mNativeIMEContext);
     bool hasRanges = !!aParam.mRanges;
     WriteParam(aMsg, hasRanges);
     if (hasRanges) {
       WriteParam(aMsg, *aParam.mRanges.get());
     }
   }
@@ -679,17 +687,17 @@ struct ParamTraits<mozilla::WidgetQueryC
 
 template<>
 struct ParamTraits<mozilla::WidgetQueryContentEvent>
 {
   typedef mozilla::WidgetQueryContentEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetGUIEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetGUIEvent&>(aParam));
     WriteParam(aMsg, aParam.mSucceeded);
     WriteParam(aMsg, aParam.mUseNativeLineBreak);
     WriteParam(aMsg, aParam.mWithFontRanges);
     WriteParam(aMsg, aParam.mInput);
     WriteParam(aMsg, aParam.mReply.mOffset);
     WriteParam(aMsg, aParam.mReply.mTentativeCaretOffset);
     WriteParam(aMsg, aParam.mReply.mString);
     WriteParam(aMsg, aParam.mReply.mRect);
@@ -720,17 +728,17 @@ struct ParamTraits<mozilla::WidgetQueryC
 
 template<>
 struct ParamTraits<mozilla::WidgetSelectionEvent>
 {
   typedef mozilla::WidgetSelectionEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetGUIEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetGUIEvent&>(aParam));
     WriteParam(aMsg, aParam.mOffset);
     WriteParam(aMsg, aParam.mLength);
     WriteParam(aMsg, aParam.mReversed);
     WriteParam(aMsg, aParam.mExpandToClusterBoundary);
     WriteParam(aMsg, aParam.mSucceeded);
     WriteParam(aMsg, aParam.mUseNativeLineBreak);
   }
 
@@ -953,17 +961,17 @@ struct ParamTraits<mozilla::widget::IMEN
 
 template<>
 struct ParamTraits<mozilla::WidgetPluginEvent>
 {
   typedef mozilla::WidgetPluginEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::WidgetGUIEvent>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::WidgetGUIEvent&>(aParam));
     WriteParam(aMsg, aParam.mRetargetToFocusedDocument);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter,
                      static_cast<mozilla::WidgetGUIEvent*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->mRetargetToFocusedDocument);
@@ -1122,17 +1130,17 @@ struct ParamTraits<mozilla::MultiTouchIn
 
 template<>
 struct ParamTraits<mozilla::MultiTouchInput>
 {
   typedef mozilla::MultiTouchInput paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::InputData>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mTouches);
     WriteParam(aMsg, aParam.mHandledByAPZ);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, static_cast<mozilla::InputData*>(aResult)) &&
@@ -1160,17 +1168,17 @@ struct ParamTraits<mozilla::MouseInput::
 
 template<>
 struct ParamTraits<mozilla::MouseInput>
 {
   typedef mozilla::MouseInput paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::InputData>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mButtonType);
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mInputSource);
     WriteParam(aMsg, aParam.mButtons);
     WriteParam(aMsg, aParam.mOrigin);
     WriteParam(aMsg, aParam.mLocalOrigin);
     WriteParam(aMsg, aParam.mHandledByAPZ);
   }
@@ -1198,17 +1206,17 @@ struct ParamTraits<mozilla::PanGestureIn
 
 template<>
 struct ParamTraits<mozilla::PanGestureInput>
 {
   typedef mozilla::PanGestureInput paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::InputData>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mPanStartPoint);
     WriteParam(aMsg, aParam.mPanDisplacement);
     WriteParam(aMsg, aParam.mLocalPanStartPoint);
     WriteParam(aMsg, aParam.mLocalPanDisplacement);
     WriteParam(aMsg, aParam.mLineOrPageDeltaX);
     WriteParam(aMsg, aParam.mLineOrPageDeltaY);
     WriteParam(aMsg, aParam.mUserDeltaMultiplierX);
@@ -1246,17 +1254,17 @@ struct ParamTraits<mozilla::PinchGesture
 
 template<>
 struct ParamTraits<mozilla::PinchGestureInput>
 {
   typedef mozilla::PinchGestureInput paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::InputData>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mFocusPoint);
     WriteParam(aMsg, aParam.mLocalFocusPoint);
     WriteParam(aMsg, aParam.mCurrentSpan);
     WriteParam(aMsg, aParam.mPreviousSpan);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
@@ -1280,17 +1288,17 @@ struct ParamTraits<mozilla::TapGestureIn
 
 template<>
 struct ParamTraits<mozilla::TapGestureInput>
 {
   typedef mozilla::TapGestureInput paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::InputData>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mPoint);
     WriteParam(aMsg, aParam.mLocalPoint);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, static_cast<mozilla::InputData*>(aResult)) &&
@@ -1318,17 +1326,17 @@ struct ParamTraits<mozilla::ScrollWheelI
 
 template<>
 struct ParamTraits<mozilla::ScrollWheelInput>
 {
   typedef mozilla::ScrollWheelInput paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::InputData>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mDeltaType);
     WriteParam(aMsg, aParam.mScrollMode);
     WriteParam(aMsg, aParam.mOrigin);
     WriteParam(aMsg, aParam.mHandledByAPZ);
     WriteParam(aMsg, aParam.mDeltaX);
     WriteParam(aMsg, aParam.mDeltaY);
     WriteParam(aMsg, aParam.mLocalOrigin);
     WriteParam(aMsg, aParam.mLineOrPageDeltaX);
@@ -1372,17 +1380,17 @@ struct ParamTraits<mozilla::KeyboardInpu
 
 template<>
 struct ParamTraits<mozilla::KeyboardInput>
 {
   typedef mozilla::KeyboardInput paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    WriteParam(aMsg, static_cast<mozilla::InputData>(aParam));
+    WriteParam(aMsg, static_cast<const mozilla::InputData&>(aParam));
     WriteParam(aMsg, aParam.mType);
     WriteParam(aMsg, aParam.mKeyCode);
     WriteParam(aMsg, aParam.mCharCode);
     WriteParam(aMsg, aParam.mShortcutCandidates);
     WriteParam(aMsg, aParam.mHandledByAPZ);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)