Bug 582644 - IME event remoting, patch for widget; r=dougt, blocking-fennec=2.0a1+
authorJim Chen <nchen@mozilla.com>
Tue, 17 Aug 2010 01:07:42 -0700
changeset 50730 d061f90eea9d59f98b18900f7a3a05e755aba5e8
parent 50727 007d994cac53d50efdfea24c03676996e7af9c0e
child 50731 2a11c34f4a68bea4c1344508817d1fe94e0343bc
push id15141
push userblassey@mozilla.com
push dateTue, 17 Aug 2010 16:43:57 +0000
treeherdermozilla-central@2dbb1278a15c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdougt
bugs582644
milestone2.0b4pre
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 582644 - IME event remoting, patch for widget; r=dougt, blocking-fennec=2.0a1+
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
widget/public/Makefile.in
widget/public/nsGUIEvent.h
widget/public/nsGUIEventIPC.h
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -43,21 +43,26 @@ include protocol PDocumentRenderer;
 include protocol PDocumentRendererShmem;
 include protocol PDocumentRendererNativeID;
 include protocol PGeolocationRequest;
 
 include "mozilla/TabTypes.h";
 include "TabMessageUtils.h";
 include "gfxMatrix.h";
 include "mozilla/net/NeckoMessageUtils.h";
+include "IPC/nsGUIEventIPC.h";
 
 using IPC::URI;
 using MagicWindowHandle;
 using RemoteDOMEvent;
 using gfxMatrix;
+using nsCompositionEvent;
+using nsTextEvent;
+using nsQueryContentEvent;
+using nsSelectionEvent;
 
 namespace mozilla {
 namespace dom {
 
 rpc protocol PBrowser
 {
     manager PContent;
 
@@ -100,16 +105,18 @@ parent:
                           bool sameURI) returns (bool retval);
 
 
     rpc CreateWindow() returns (PBrowser window);
 
     sync SyncMessage(nsString aMessage, nsString aJSON)
       returns (nsString[] retval);
 
+    QueryContentResult(nsQueryContentEvent event);
+
     PGeolocationRequest(URI uri);
 
     PContentDialog(PRUint32 aType, nsCString aName, nsCString aFeatures,
                    PRInt32[] aIntParams, nsString[] aStringParams);
 
     __delete__();
 
 child:
@@ -142,16 +149,24 @@ child:
      * @see nsIDOMWindowUtils sendKeyEvent.
      */
     KeyEvent(nsString aType,
              PRInt32 aKeyCode,
              PRInt32 aCharCode,
              PRInt32 aModifiers,
              bool aPreventDefault);
 
+    CompositionEvent(nsCompositionEvent event);
+
+    TextEvent(nsTextEvent event);
+
+    QueryContentEvent(nsQueryContentEvent event);
+
+    SelectionEvent(nsSelectionEvent event);
+
     /**
      * Activate event forwarding from client to parent.
      */
     ActivateFrameEvent(nsString aType, bool capture);
 
     LoadRemoteScript(nsString aURL);
 
     PDocumentRenderer(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h, nsString bgcolor, PRUint32 flags, bool flush);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -78,16 +78,18 @@
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsWeakReference.h"
 #include "nsISecureBrowserUI.h"
 #include "nsISSLStatusProvider.h"
 #include "nsSerializationHelper.h"
+#include "nsIFrame.h"
+#include "nsIView.h"
 
 #ifdef MOZ_WIDGET_QT
 #include <QX11EmbedWidget>
 #include <QGraphicsView>
 #include <QGraphicsWidget>
 #endif
 
 #ifdef MOZ_WIDGET_GTK2
@@ -715,25 +717,87 @@ TabChild::RecvKeyEvent(const nsString& a
   nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
   NS_ENSURE_TRUE(utils, true);
   PRBool ignored = PR_FALSE;
   utils->SendKeyEvent(aType, aKeyCode, aCharCode,
                       aModifiers, aPreventDefault, &ignored);
   return true;
 }
 
+bool
+TabChild::RecvCompositionEvent(const nsCompositionEvent& event)
+{
+  nsCompositionEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  return true;
+}
+
+bool
+TabChild::RecvTextEvent(const nsTextEvent& event)
+{
+  nsTextEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  IPC::ParamTraits<nsTextEvent>::Free(event);
+  return true;
+}
+
+bool
+TabChild::RecvQueryContentEvent(const nsQueryContentEvent& event)
+{
+  nsQueryContentEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  // Send result back even if query failed
+  SendQueryContentResult(localEvent);
+  return true;
+}
+
+bool
+TabChild::RecvSelectionEvent(const nsSelectionEvent& event)
+{
+  nsSelectionEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  return true;
+}
+
+bool
+TabChild::DispatchWidgetEvent(nsGUIEvent& event)
+{
+  nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
+  NS_ENSURE_TRUE(window, false);
+
+  nsIDocShell *docShell = window->GetDocShell();
+  NS_ENSURE_TRUE(docShell, false);
+
+  nsCOMPtr<nsIPresShell> presShell;
+  docShell->GetPresShell(getter_AddRefs(presShell));
+  NS_ENSURE_TRUE(presShell, false);
+
+  nsIFrame *frame = presShell->GetRootFrame();
+  NS_ENSURE_TRUE(frame, false);
+
+  nsIView *view = frame->GetView();
+  NS_ENSURE_TRUE(view, false);
+
+  nsCOMPtr<nsIWidget> widget = view->GetNearestWidget(nsnull);
+  NS_ENSURE_TRUE(widget, false);
+
+  nsEventStatus status;
+  event.widget = widget;
+  NS_ENSURE_SUCCESS(widget->DispatchEvent(&event, status), false);
+  return true;
+}
+
 mozilla::ipc::PDocumentRendererChild*
-TabChild::AllocPDocumentRenderer(
-        const PRInt32& x,
-        const PRInt32& y,
-        const PRInt32& w,
-        const PRInt32& h,
-        const nsString& bgcolor,
-        const PRUint32& flags,
-        const bool& flush)
+TabChild::AllocPDocumentRenderer(const PRInt32& x,
+                                 const PRInt32& y,
+                                 const PRInt32& w,
+                                 const PRInt32& h,
+                                 const nsString& bgcolor,
+                                 const PRUint32& flags,
+                                 const bool& flush)
 {
     return new mozilla::ipc::DocumentRendererChild();
 }
 
 bool
 TabChild::DeallocPDocumentRenderer(PDocumentRendererChild* actor)
 {
     delete actor;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -186,16 +186,20 @@ public:
                                 const PRInt32&  aClickCount,
                                 const PRInt32&  aModifiers,
                                 const bool&     aIgnoreRootScrollFrame);
     virtual bool RecvKeyEvent(const nsString& aType,
                               const PRInt32&  aKeyCode,
                               const PRInt32&  aCharCode,
                               const PRInt32&  aModifiers,
                               const bool&     aPreventDefault);
+    virtual bool RecvCompositionEvent(const nsCompositionEvent& event);
+    virtual bool RecvTextEvent(const nsTextEvent& event);
+    virtual bool RecvQueryContentEvent(const nsQueryContentEvent& event);
+    virtual bool RecvSelectionEvent(const nsSelectionEvent& event);
     virtual bool RecvActivateFrameEvent(const nsString& aType, const bool& capture);
     virtual bool RecvLoadRemoteScript(const nsString& aURL);
     virtual bool RecvAsyncMessage(const nsString& aMessage,
                                   const nsString& aJSON);
     virtual mozilla::ipc::PDocumentRendererChild* AllocPDocumentRenderer(
             const PRInt32& x,
             const PRInt32& y,
             const PRInt32& w,
@@ -280,16 +284,18 @@ public:
     JSContext* GetJSContext() { return mCx; }
 
     nsIPrincipal* GetPrincipal() { return mPrincipal; }
 
 protected:
     NS_OVERRIDE
     virtual bool RecvDestroy();
 
+    bool DispatchWidgetEvent(nsGUIEvent& event);
+
 private:
     void ActorDestroy(ActorDestroyReason why);
 
     bool InitTabChildGlobal();
 
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIXPConnectJSObjectHolder> mRootGlobal;
     JSContext* mCx;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -563,16 +563,22 @@ TabParent::RecvSyncMessage(const nsStrin
 bool
 TabParent::RecvAsyncMessage(const nsString& aMessage,
                             const nsString& aJSON)
 {
   return ReceiveMessage(aMessage, PR_FALSE, aJSON, nsnull);
 }
 
 bool
+TabParent::RecvQueryContentResult(const nsQueryContentEvent& event)
+{
+    return true;
+}
+
+bool
 TabParent::ReceiveMessage(const nsString& aMessage,
                           PRBool aSync,
                           const nsString& aJSON,
                           nsTArray<nsString>* aJSONRetVal)
 {
   nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   if (frameLoader && frameLoader->GetFrameMessageManager()) {
     nsFrameMessageManager* manager = frameLoader->GetFrameMessageManager();
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -127,16 +127,17 @@ public:
                                       bool* aAllowRefresh);
 
     virtual bool AnswerCreateWindow(PBrowserParent** retval);
     virtual bool RecvSyncMessage(const nsString& aMessage,
                                  const nsString& aJSON,
                                  nsTArray<nsString>* aJSONRetVal);
     virtual bool RecvAsyncMessage(const nsString& aMessage,
                                   const nsString& aJSON);
+    virtual bool RecvQueryContentResult(const nsQueryContentEvent& event);
     virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
                                                       const nsCString& aName,
                                                       const nsCString& aFeatures,
                                                       const nsTArray<int>& aIntParams,
                                                       const nsTArray<nsString>& aStringParams);
     virtual bool DeallocPContentDialog(PContentDialogParent* aDialog)
     {
       delete aDialog;
--- a/widget/public/Makefile.in
+++ b/widget/public/Makefile.in
@@ -41,16 +41,22 @@ srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= widget
 XPIDL_MODULE	= widget
 GRE_MODULE	= 1
 
+EXPORTS_NAMESPACES = IPC
+
+EXPORTS_IPC = \
+		nsGUIEventIPC.h \
+		$(NULL)
+
 EXPORTS		= \
 		nsIWidget.h \
 		nsGUIEvent.h \
 		nsEvent.h \
 		nsNativeWidget.h \
 		nsWidgetInitData.h \
 		nsWidgetsCID.h \
 		nsILookAndFeel.h \
--- a/widget/public/nsGUIEvent.h
+++ b/widget/public/nsGUIEvent.h
@@ -55,16 +55,25 @@
 #include "nsPIDOMEventTarget.h"
 #include "nsWeakPtr.h"
 #include "nsIWidget.h"
 #include "nsTArray.h"
 #include "nsTraceRefcnt.h"
 #include "nsITransferable.h"
 #include "nsIVariant.h"
 
+#ifdef MOZ_IPC
+namespace mozilla {
+namespace dom {
+  class PBrowserParent;
+  class PBrowserChild;
+}
+}
+#endif // MOZ_IPC
+
 #ifdef ACCESSIBILITY
 class nsAccessible;
 #endif
 class nsIRenderingContext;
 class nsIMenuItem;
 class nsIContent;
 class nsIURI;
 class nsHashKey;
@@ -504,16 +513,22 @@ protected:
       refPoint(0, 0),
       time(0),
       flags(isTrusted ? NS_EVENT_FLAG_TRUSTED : NS_EVENT_FLAG_NONE),
       userType(0)
   {
     MOZ_COUNT_CTOR(nsEvent);
   }
 
+#ifdef MOZ_IPC
+  nsEvent()
+  {
+  }
+#endif // MOZ_IPC
+
 public:
   nsEvent(PRBool isTrusted, PRUint32 msg)
     : eventStructType(NS_EVENT),
       message(msg),
       refPoint(0, 0),
       time(0),
       flags(isTrusted ? NS_EVENT_FLAG_TRUSTED : NS_EVENT_FLAG_NONE),
       userType(0)
@@ -555,16 +570,23 @@ class nsGUIEvent : public nsEvent
 {
 protected:
   nsGUIEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w, PRUint8 structType)
     : nsEvent(isTrusted, msg, structType),
       widget(w), pluginEvent(nsnull)
   {
   }
 
+#ifdef MOZ_IPC
+  nsGUIEvent()
+    : pluginEvent(nsnull)
+  {
+  }
+#endif // MOZ_IPC
+
 public:
   nsGUIEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
     : nsEvent(isTrusted, msg, NS_GUI_EVENT),
       widget(w), pluginEvent(nsnull)
   {
   }
 
   /// Originator of the event
@@ -719,16 +741,22 @@ class nsInputEvent : public nsGUIEvent
 protected:
   nsInputEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w,
                PRUint8 structType)
     : nsGUIEvent(isTrusted, msg, w, structType),
       isShift(PR_FALSE), isControl(PR_FALSE), isAlt(PR_FALSE), isMeta(PR_FALSE)
   {
   }
 
+#ifdef MOZ_IPC
+  nsInputEvent()
+  {
+  }
+#endif // MOZ_IPC
+
 public:
   nsInputEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
     : nsGUIEvent(isTrusted, msg, w, NS_INPUT_EVENT),
       isShift(PR_FALSE), isControl(PR_FALSE), isAlt(PR_FALSE), isMeta(PR_FALSE)
   {
   }
 
   /// PR_TRUE indicates the shift key is down
@@ -1015,16 +1043,26 @@ struct nsTextRange
 
   nsTextRangeStyle mRangeStyle;
 };
 
 typedef nsTextRange* nsTextRangeArray;
 
 class nsTextEvent : public nsInputEvent
 {
+#ifdef MOZ_IPC
+private:
+  friend class mozilla::dom::PBrowserParent;
+  friend class mozilla::dom::PBrowserChild;
+
+  nsTextEvent()
+  {
+  }
+#endif // MOZ_IPC
+
 public:
   nsTextEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
     : nsInputEvent(isTrusted, msg, w, NS_TEXT_EVENT),
       rangeCount(0), rangeArray(nsnull), isChar(PR_FALSE)
   {
   }
 
   nsString          theText;
@@ -1033,16 +1071,26 @@ public:
   // case there will be no range of type NS_TEXTRANGE_CARETPOSITION in the
   // array.
   nsTextRangeArray  rangeArray;
   PRBool            isChar;
 };
 
 class nsCompositionEvent : public nsInputEvent
 {
+#ifdef MOZ_IPC
+private:
+  friend class mozilla::dom::PBrowserParent;
+  friend class mozilla::dom::PBrowserChild;
+
+  nsCompositionEvent()
+  {
+  }
+#endif // MOZ_IPC
+
 public:
   nsCompositionEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
     : nsInputEvent(isTrusted, msg, w, NS_COMPOSITION_EVENT)
   {
   }
 };
 
 /* Mouse Scroll Events: Line Scrolling, Pixel Scrolling and Common Event Flows
@@ -1147,16 +1195,28 @@ public:
     panDirection(ePanNone),
     displayPanFeedback(PR_FALSE)
   {
   }
 };
 
 class nsQueryContentEvent : public nsGUIEvent
 {
+#ifdef MOZ_IPC
+private:
+  friend class mozilla::dom::PBrowserParent;
+  friend class mozilla::dom::PBrowserChild;
+
+  nsQueryContentEvent()
+  {
+    mReply.mContentsRoot = nsnull;
+    mReply.mFocusedWidget = nsnull;
+  }
+#endif // MOZ_IPC
+
 public:
   nsQueryContentEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget) :
     nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_QUERY_CONTENT_EVENT),
     mSucceeded(PR_FALSE)
   {
   }
 
   void InitForQueryTextContent(PRUint32 aOffset, PRUint32 aLength)
@@ -1214,16 +1274,26 @@ public:
   {
   }
 
   PRPackedBool fromRaise;
 };
 
 class nsSelectionEvent : public nsGUIEvent
 {
+#ifdef MOZ_IPC
+private:
+  friend class mozilla::dom::PBrowserParent;
+  friend class mozilla::dom::PBrowserChild;
+
+  nsSelectionEvent()
+  {
+  }
+#endif // MOZ_IPC
+
 public:
   nsSelectionEvent(PRBool aIsTrusted, PRUint32 aMsg, nsIWidget *aWidget) :
     nsGUIEvent(aIsTrusted, aMsg, aWidget, NS_SELECTION_EVENT),
     mExpandToClusterBoundary(PR_TRUE), mSucceeded(PR_FALSE)
   {
   }
 
   PRUint32 mOffset; // start offset of selection
new file mode 100644
--- /dev/null
+++ b/widget/public/nsGUIEventIPC.h
@@ -0,0 +1,284 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jim Chen <jchen@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsGUIEventIPC_h__
+#define nsGUIEventIPC_h__
+
+#include "IPC/IPCMessageUtils.h"
+#include "nsGUIEvent.h"
+
+namespace IPC
+{
+
+template<>
+struct ParamTraits<nsEvent>
+{
+  typedef nsEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.eventStructType);
+    WriteParam(aMsg, aParam.message);
+    WriteParam(aMsg, aParam.refPoint);
+    WriteParam(aMsg, aParam.time);
+    WriteParam(aMsg, aParam.flags);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->eventStructType) &&
+           ReadParam(aMsg, aIter, &aResult->message) &&
+           ReadParam(aMsg, aIter, &aResult->refPoint) &&
+           ReadParam(aMsg, aIter, &aResult->time) &&
+           ReadParam(aMsg, aIter, &aResult->flags);
+  }
+};
+
+template<>
+struct ParamTraits<nsGUIEvent>
+{
+  typedef nsGUIEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<nsEvent>(aParam));
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, static_cast<nsEvent*>(aResult));
+  }
+};
+
+template<>
+struct ParamTraits<nsInputEvent>
+{
+  typedef nsInputEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<nsGUIEvent>(aParam));
+    WriteParam(aMsg, aParam.isShift);
+    WriteParam(aMsg, aParam.isControl);
+    WriteParam(aMsg, aParam.isAlt);
+    WriteParam(aMsg, aParam.isMeta);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, static_cast<nsGUIEvent*>(aResult)) &&
+           ReadParam(aMsg, aIter, &aResult->isShift) &&
+           ReadParam(aMsg, aIter, &aResult->isControl) &&
+           ReadParam(aMsg, aIter, &aResult->isAlt) &&
+           ReadParam(aMsg, aIter, &aResult->isMeta);
+  }
+};
+
+template<>
+struct ParamTraits<nsTextRangeStyle>
+{
+  typedef nsTextRangeStyle paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mDefinedStyles);
+    WriteParam(aMsg, aParam.mLineStyle);
+    WriteParam(aMsg, aParam.mIsBoldLine);
+    WriteParam(aMsg, aParam.mForegroundColor);
+    WriteParam(aMsg, aParam.mBackgroundColor);
+    WriteParam(aMsg, aParam.mUnderlineColor);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mDefinedStyles) &&
+           ReadParam(aMsg, aIter, &aResult->mLineStyle) &&
+           ReadParam(aMsg, aIter, &aResult->mIsBoldLine) &&
+           ReadParam(aMsg, aIter, &aResult->mForegroundColor) &&
+           ReadParam(aMsg, aIter, &aResult->mBackgroundColor) &&
+           ReadParam(aMsg, aIter, &aResult->mUnderlineColor);
+  }
+};
+
+template<>
+struct ParamTraits<nsTextRange>
+{
+  typedef nsTextRange paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mStartOffset);
+    WriteParam(aMsg, aParam.mEndOffset);
+    WriteParam(aMsg, aParam.mRangeType);
+    WriteParam(aMsg, aParam.mRangeStyle);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->mStartOffset) &&
+           ReadParam(aMsg, aIter, &aResult->mEndOffset) &&
+           ReadParam(aMsg, aIter, &aResult->mRangeType) &&
+           ReadParam(aMsg, aIter, &aResult->mRangeStyle);
+  }
+};
+
+template<>
+struct ParamTraits<nsTextEvent>
+{
+  typedef nsTextEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<nsInputEvent>(aParam));
+    WriteParam(aMsg, aParam.theText);
+    WriteParam(aMsg, aParam.isChar);
+    WriteParam(aMsg, aParam.rangeCount);
+    for (PRUint32 index = 0; index < aParam.rangeCount; index++)
+      WriteParam(aMsg, aParam.rangeArray[index]);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    if (!ReadParam(aMsg, aIter, static_cast<nsInputEvent*>(aResult)) ||
+        !ReadParam(aMsg, aIter, &aResult->theText) ||
+        !ReadParam(aMsg, aIter, &aResult->isChar) ||
+        !ReadParam(aMsg, aIter, &aResult->rangeCount))
+      return false;
+
+    if (!aResult->rangeCount) {
+      aResult->rangeArray = nsnull;
+      return true;
+    }
+
+    aResult->rangeArray = new nsTextRange[aResult->rangeCount];
+    if (!aResult->rangeArray)
+      return false;
+
+    for (PRUint32 index = 0; index < aResult->rangeCount; index++)
+      if (!ReadParam(aMsg, aIter, &aResult->rangeArray[index])) {
+        Free(*aResult);
+        return false;
+      }
+    return true;
+  }
+
+  static void Free(const paramType& aResult)
+  {
+    if (aResult.rangeArray)
+      delete [] aResult.rangeArray;
+  }
+};
+
+template<>
+struct ParamTraits<nsCompositionEvent>
+{
+  typedef nsCompositionEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<nsInputEvent>(aParam));
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, static_cast<nsInputEvent*>(aResult));
+  }
+};
+
+template<>
+struct ParamTraits<nsQueryContentEvent>
+{
+  typedef nsQueryContentEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<nsGUIEvent>(aParam));
+    WriteParam(aMsg, aParam.mSucceeded);
+    WriteParam(aMsg, aParam.mInput.mOffset);
+    WriteParam(aMsg, aParam.mInput.mLength);
+    WriteParam(aMsg, aParam.mReply.mOffset);
+    WriteParam(aMsg, aParam.mReply.mString);
+    WriteParam(aMsg, aParam.mReply.mRect);
+    WriteParam(aMsg, aParam.mReply.mReversed);
+    WriteParam(aMsg, aParam.mReply.mHasSelection);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, static_cast<nsGUIEvent*>(aResult)) &&
+           ReadParam(aMsg, aIter, &aResult->mSucceeded) &&
+           ReadParam(aMsg, aIter, &aResult->mInput.mOffset) &&
+           ReadParam(aMsg, aIter, &aResult->mInput.mLength) &&
+           ReadParam(aMsg, aIter, &aResult->mReply.mOffset) &&
+           ReadParam(aMsg, aIter, &aResult->mReply.mString) &&
+           ReadParam(aMsg, aIter, &aResult->mReply.mRect) &&
+           ReadParam(aMsg, aIter, &aResult->mReply.mReversed) &&
+           ReadParam(aMsg, aIter, &aResult->mReply.mHasSelection);
+  }
+};
+
+template<>
+struct ParamTraits<nsSelectionEvent>
+{
+  typedef nsSelectionEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<nsGUIEvent>(aParam));
+    WriteParam(aMsg, aParam.mOffset);
+    WriteParam(aMsg, aParam.mLength);
+    WriteParam(aMsg, aParam.mReversed);
+    WriteParam(aMsg, aParam.mExpandToClusterBoundary);
+    WriteParam(aMsg, aParam.mSucceeded);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, static_cast<nsGUIEvent*>(aResult)) &&
+           ReadParam(aMsg, aIter, &aResult->mOffset) &&
+           ReadParam(aMsg, aIter, &aResult->mLength) &&
+           ReadParam(aMsg, aIter, &aResult->mReversed) &&
+           ReadParam(aMsg, aIter, &aResult->mExpandToClusterBoundary) &&
+           ReadParam(aMsg, aIter, &aResult->mSucceeded);
+  }
+};
+
+} // namespace IPC
+
+#endif // nsGUIEventIPC_h__
+