Bug 329127 Create WidgetEvent::Duplicate() for nsDOMEvent::DuplicatePrivateData() r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Mon, 27 Jan 2014 15:10:44 +0900
changeset 181288 eb278efeb18ad9046b1ecb52a5f70b329752d521
parent 181287 07560fe7043d6f595692c7b114a878ef19291445
child 181289 392019e712d7d19e1d4812767f573ca550219d05
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs329127
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 329127 Create WidgetEvent::Duplicate() for nsDOMEvent::DuplicatePrivateData() r=smaug
dom/events/MutationEvent.h
dom/events/nsDOMEvent.cpp
widget/BasicEvents.h
widget/ContentEvents.h
widget/MiscEvents.h
widget/MouseEvents.h
widget/TextEvents.h
widget/TouchEvents.h
--- a/dom/events/MutationEvent.h
+++ b/dom/events/MutationEvent.h
@@ -20,16 +20,26 @@ public:
 
   InternalMutationEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_MUTATION_EVENT),
     mAttrChange(0)
   {
     mFlags.mCancelable = false;
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_MUTATION_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalMutationEvent* result = new InternalMutationEvent(false, message);
+    result->AssignMutationEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsCOMPtr<nsIDOMNode> mRelatedNode;
   nsCOMPtr<nsIAtom>    mAttrName;
   nsCOMPtr<nsIAtom>    mPrevAttrValue;
   nsCOMPtr<nsIAtom>    mNewAttrValue;
   unsigned short       mAttrChange;
 
   void AssignMutationEventData(const InternalMutationEvent& aEvent,
                                bool aCopyTargets)
--- a/dom/events/nsDOMEvent.cpp
+++ b/dom/events/nsDOMEvent.cpp
@@ -549,280 +549,22 @@ nsDOMEvent::InitEvent(const nsAString& a
   mEvent->target = nullptr;
   mEvent->originalTarget = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMEvent::DuplicatePrivateData()
 {
-  // FIXME! Simplify this method and make it somehow easily extendable,
-  //        Bug 329127
-  
   NS_ASSERTION(mEvent, "No WidgetEvent for nsDOMEvent duplication!");
   if (mEventIsInternal) {
     return NS_OK;
   }
 
-  WidgetEvent* newEvent = nullptr;
-  uint32_t msg = mEvent->message;
-
-  switch (mEvent->eventStructType) {
-    case NS_EVENT:
-    {
-      newEvent = new WidgetEvent(false, msg);
-      newEvent->AssignEventData(*mEvent, true);
-      break;
-    }
-    case NS_GUI_EVENT:
-    {
-      WidgetGUIEvent* oldGUIEvent = mEvent->AsGUIEvent();
-      // Not copying widget, it is a weak reference.
-      WidgetGUIEvent* guiEvent = new WidgetGUIEvent(false, msg, nullptr);
-      guiEvent->AssignGUIEventData(*oldGUIEvent, true);
-      newEvent = guiEvent;
-      break;
-    }
-    case NS_INPUT_EVENT:
-    {
-      WidgetInputEvent* oldInputEvent = mEvent->AsInputEvent();
-      WidgetInputEvent* inputEvent = new WidgetInputEvent(false, msg, nullptr);
-      inputEvent->AssignInputEventData(*oldInputEvent, true);
-      newEvent = inputEvent;
-      break;
-    }
-    case NS_KEY_EVENT:
-    {
-      WidgetKeyboardEvent* oldKeyEvent = mEvent->AsKeyboardEvent();
-      WidgetKeyboardEvent* keyEvent =
-        new WidgetKeyboardEvent(false, msg, nullptr);
-      keyEvent->AssignKeyEventData(*oldKeyEvent, true);
-      newEvent = keyEvent;
-      break;
-    }
-    case NS_MOUSE_EVENT:
-    {
-      WidgetMouseEvent* oldMouseEvent = mEvent->AsMouseEvent();
-      WidgetMouseEvent* mouseEvent =
-        new WidgetMouseEvent(false, msg, nullptr, oldMouseEvent->reason);
-      mouseEvent->AssignMouseEventData(*oldMouseEvent, true);
-      newEvent = mouseEvent;
-      break;
-    }
-    case NS_DRAG_EVENT:
-    {
-      WidgetDragEvent* oldDragEvent = mEvent->AsDragEvent();
-      WidgetDragEvent* dragEvent = new WidgetDragEvent(false, msg, nullptr);
-      dragEvent->AssignDragEventData(*oldDragEvent, true);
-      newEvent = dragEvent;
-      break;
-    }
-    case NS_CLIPBOARD_EVENT:
-    {
-      InternalClipboardEvent* oldClipboardEvent = mEvent->AsClipboardEvent();
-      InternalClipboardEvent* clipboardEvent =
-        new InternalClipboardEvent(false, msg);
-      clipboardEvent->AssignClipboardEventData(*oldClipboardEvent, true);
-      newEvent = clipboardEvent;
-      break;
-    }
-    case NS_SCRIPT_ERROR_EVENT:
-    {
-      InternalScriptErrorEvent* oldScriptErrorEvent =
-        mEvent->AsScriptErrorEvent();
-      InternalScriptErrorEvent* scriptErrorEvent =
-        new InternalScriptErrorEvent(false, msg);
-      scriptErrorEvent->AssignScriptErrorEventData(*oldScriptErrorEvent, true);
-      newEvent = scriptErrorEvent;
-      break;
-    }
-    case NS_TEXT_EVENT:
-    {
-      WidgetTextEvent* oldTextEvent = mEvent->AsTextEvent();
-      WidgetTextEvent* textEvent = new WidgetTextEvent(false, msg, nullptr);
-      textEvent->AssignTextEventData(*oldTextEvent, true);
-      newEvent = textEvent;
-      break;
-    }
-    case NS_COMPOSITION_EVENT:
-    {
-      WidgetCompositionEvent* compositionEvent =
-        new WidgetCompositionEvent(false, msg, nullptr);
-      WidgetCompositionEvent* oldCompositionEvent =
-        mEvent->AsCompositionEvent();
-      compositionEvent->AssignCompositionEventData(*oldCompositionEvent, true);
-      newEvent = compositionEvent;
-      break;
-    }
-    case NS_MOUSE_SCROLL_EVENT:
-    {
-      WidgetMouseScrollEvent* oldMouseScrollEvent =
-        mEvent->AsMouseScrollEvent();
-      WidgetMouseScrollEvent* mouseScrollEvent =
-        new WidgetMouseScrollEvent(false, msg, nullptr);
-      mouseScrollEvent->AssignMouseScrollEventData(*oldMouseScrollEvent, true);
-      newEvent = mouseScrollEvent;
-      break;
-    }
-    case NS_WHEEL_EVENT:
-    {
-      WidgetWheelEvent* oldWheelEvent = mEvent->AsWheelEvent();
-      WidgetWheelEvent* wheelEvent = new WidgetWheelEvent(false, msg, nullptr);
-      wheelEvent->AssignWheelEventData(*oldWheelEvent, true);
-      newEvent = wheelEvent;
-      break;
-    }
-    case NS_SCROLLPORT_EVENT:
-    {
-      InternalScrollPortEvent* oldScrollPortEvent = mEvent->AsScrollPortEvent();
-      InternalScrollPortEvent* scrollPortEvent =
-        new InternalScrollPortEvent(false, msg, nullptr);
-      scrollPortEvent->AssignScrollPortEventData(*oldScrollPortEvent, true);
-      newEvent = scrollPortEvent;
-      break;
-    }
-    case NS_SCROLLAREA_EVENT:
-    {
-      InternalScrollAreaEvent* oldScrollAreaEvent = mEvent->AsScrollAreaEvent();
-      InternalScrollAreaEvent* scrollAreaEvent = 
-        new InternalScrollAreaEvent(false, msg, nullptr);
-      scrollAreaEvent->AssignScrollAreaEventData(*oldScrollAreaEvent, true);
-      newEvent = scrollAreaEvent;
-      break;
-    }
-    case NS_MUTATION_EVENT:
-    {
-      InternalMutationEvent* mutationEvent =
-        new InternalMutationEvent(false, msg);
-      InternalMutationEvent* oldMutationEvent = mEvent->AsMutationEvent();
-      mutationEvent->AssignMutationEventData(*oldMutationEvent, true);
-      newEvent = mutationEvent;
-      break;
-    }
-    case NS_FORM_EVENT:
-    {
-      InternalFormEvent* oldFormEvent = mEvent->AsFormEvent();
-      InternalFormEvent* formEvent = new InternalFormEvent(false, msg);
-      formEvent->AssignFormEventData(*oldFormEvent, true);
-      newEvent = formEvent;
-      break;
-    }
-    case NS_FOCUS_EVENT:
-    {
-      InternalFocusEvent* newFocusEvent = new InternalFocusEvent(false, msg);
-      InternalFocusEvent* oldFocusEvent = mEvent->AsFocusEvent();
-      newFocusEvent->AssignFocusEventData(*oldFocusEvent, true);
-      newEvent = newFocusEvent;
-      break;
-    }
-    case NS_COMMAND_EVENT:
-    {
-      WidgetCommandEvent* oldCommandEvent = mEvent->AsCommandEvent();
-      WidgetCommandEvent* commandEvent =
-        new WidgetCommandEvent(false, mEvent->userType,
-                               oldCommandEvent->command, nullptr);
-      commandEvent->AssignCommandEventData(*oldCommandEvent, true);
-      newEvent = commandEvent;
-      break;
-    }
-    case NS_UI_EVENT:
-    {
-      InternalUIEvent* oldUIEvent = mEvent->AsUIEvent();
-      InternalUIEvent* uiEvent =
-        new InternalUIEvent(false, msg, oldUIEvent->detail);
-      uiEvent->AssignUIEventData(*oldUIEvent, true);
-      newEvent = uiEvent;
-      break;
-    }
-    case NS_SVGZOOM_EVENT:
-    {
-      WidgetGUIEvent* oldGUIEvent = mEvent->AsGUIEvent();
-      WidgetGUIEvent* guiEvent = new WidgetGUIEvent(false, msg, nullptr);
-      guiEvent->eventStructType = NS_SVGZOOM_EVENT;
-      guiEvent->AssignGUIEventData(*oldGUIEvent, true);
-      newEvent = guiEvent;
-      break;
-    }
-    case NS_SMIL_TIME_EVENT:
-    {
-      InternalUIEvent* oldUIEvent = mEvent->AsUIEvent();
-      InternalUIEvent* uiEvent = new InternalUIEvent(false, msg, 0);
-      uiEvent->eventStructType = NS_SMIL_TIME_EVENT;
-      uiEvent->AssignUIEventData(*oldUIEvent, true);
-      newEvent = uiEvent;
-      break;
-    }
-    case NS_SIMPLE_GESTURE_EVENT:
-    {
-      WidgetSimpleGestureEvent* oldSimpleGestureEvent =
-        mEvent->AsSimpleGestureEvent();
-      WidgetSimpleGestureEvent* simpleGestureEvent = 
-        new WidgetSimpleGestureEvent(false, msg, nullptr, 0, 0.0);
-      simpleGestureEvent->
-        AssignSimpleGestureEventData(*oldSimpleGestureEvent, true);
-      newEvent = simpleGestureEvent;
-      break;
-    }
-    case NS_TRANSITION_EVENT:
-    {
-      InternalTransitionEvent* oldTransitionEvent = mEvent->AsTransitionEvent();
-      InternalTransitionEvent* transitionEvent =
-         new InternalTransitionEvent(false, msg,
-                                     oldTransitionEvent->propertyName,
-                                     oldTransitionEvent->elapsedTime,
-                                     oldTransitionEvent->pseudoElement);
-      transitionEvent->AssignTransitionEventData(*oldTransitionEvent, true);
-      newEvent = transitionEvent;
-      break;
-    }
-    case NS_ANIMATION_EVENT:
-    {
-      InternalAnimationEvent* oldAnimationEvent = mEvent->AsAnimationEvent();
-      InternalAnimationEvent* animationEvent =
-        new InternalAnimationEvent(false, msg,
-                                   oldAnimationEvent->animationName,
-                                   oldAnimationEvent->elapsedTime,
-                                   oldAnimationEvent->pseudoElement);
-      animationEvent->AssignAnimationEventData(*oldAnimationEvent, true);
-      newEvent = animationEvent;
-      break;
-    }
-    case NS_TOUCH_EVENT:
-    {
-      WidgetTouchEvent* oldTouchEvent = mEvent->AsTouchEvent();
-      WidgetTouchEvent* touchEvent = new WidgetTouchEvent(false, oldTouchEvent);
-      touchEvent->AssignTouchEventData(*oldTouchEvent, true);
-      newEvent = touchEvent;
-      break;
-    }
-    case NS_POINTER_EVENT:
-    {
-      WidgetPointerEvent* oldPointerEvent = mEvent->AsPointerEvent();
-      WidgetPointerEvent* pointerEvent =
-        new WidgetPointerEvent(false, msg, nullptr,
-                               oldPointerEvent->pointerId,
-                               oldPointerEvent->width,
-                               oldPointerEvent->height,
-                               oldPointerEvent->tiltX,
-                               oldPointerEvent->tiltY,
-                               oldPointerEvent->isPrimary);
-      pointerEvent->buttons = oldPointerEvent->buttons;
-      newEvent = pointerEvent;
-      break;
-    }
-    default:
-    {
-      NS_WARNING("Unknown event type!!!");
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  newEvent->mFlags = mEvent->mFlags;
-
-  mEvent = newEvent;
+  mEvent = mEvent->Duplicate();
   mPresContext = nullptr;
   mEventIsInternal = true;
   mPrivateDataDuplicated = true;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -645,16 +645,26 @@ public:
   }
 
   WidgetEvent(const WidgetEvent& aOther)
   {
     MOZ_COUNT_CTOR(WidgetEvent);
     *this = aOther;
   }
 
+  virtual WidgetEvent* Duplicate() const
+  {
+    MOZ_ASSERT(eventStructType == NS_EVENT,
+               "Duplicate() must be overridden by sub class");
+    WidgetEvent* result = new WidgetEvent(false, message);
+    result->AssignEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // See event struct types
   nsEventStructType eventStructType;
   // See GUI MESSAGES,
   uint32_t message;
   // Relative to the widget of the event, or if there is no widget then it is
   // in screen coordinates. Not modified by layout code.
   LayoutDeviceIntPoint refPoint;
   // The previous refPoint, if known, used to calculate mouse movement deltas.
@@ -672,17 +682,21 @@ public:
 
   // Event targets, needed by DOM Events
   nsCOMPtr<dom::EventTarget> target;
   nsCOMPtr<dom::EventTarget> currentTarget;
   nsCOMPtr<dom::EventTarget> originalTarget;
 
   void AssignEventData(const WidgetEvent& aEvent, bool aCopyTargets)
   {
-    // eventStructType, message should be initialized with the constructor.
+    // eventStructType should be initialized with the constructor.
+    // However, NS_SVGZOOM_EVENT and NS_SMIL_TIME_EVENT are set after that.
+    // Therefore, we need to copy eventStructType here.
+    eventStructType = aEvent.eventStructType;
+    // message should be initialized with the constructor.
     refPoint = aEvent.refPoint;
     // lastRefPoint doesn't need to be copied.
     time = aEvent.time;
     // mFlags should be copied manually if it's necessary.
     userType = aEvent.userType;
     // typeString should be copied manually if it's necessary.
     target = aCopyTargets ? aEvent.target : nullptr;
     currentTarget = aCopyTargets ? aEvent.currentTarget : nullptr;
@@ -823,16 +837,28 @@ public:
   virtual WidgetGUIEvent* AsGUIEvent() MOZ_OVERRIDE { return this; }
 
   WidgetGUIEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetEvent(aIsTrusted, aMessage, NS_GUI_EVENT),
     widget(aWidget), pluginEvent(nullptr)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_GUI_EVENT ||
+                 eventStructType == NS_SVGZOOM_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetGUIEvent* result = new WidgetGUIEvent(false, message, nullptr);
+    result->AssignGUIEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   /// Originator of the event
   nsCOMPtr<nsIWidget> widget;
 
   /// Event for NPAPI plugin
   void* pluginEvent;
 
   void AssignGUIEventData(const WidgetGUIEvent& aEvent, bool aCopyTargets)
   {
@@ -912,16 +938,27 @@ public:
   virtual WidgetInputEvent* AsInputEvent() MOZ_OVERRIDE { return this; }
 
   WidgetInputEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_INPUT_EVENT),
     modifiers(0)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_INPUT_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetInputEvent* result = new WidgetInputEvent(false, message, nullptr);
+    result->AssignInputEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // true indicates the shift key is down
   bool IsShift() const
   {
     return ((modifiers & MODIFIER_SHIFT) != 0);
   }
   // true indicates the control key is down
   bool IsControl() const
   {
@@ -1028,16 +1065,27 @@ public:
   virtual InternalUIEvent* AsUIEvent() MOZ_OVERRIDE { return this; }
 
   InternalUIEvent(bool aIsTrusted, uint32_t aMessage, int32_t aDetail) :
     WidgetGUIEvent(aIsTrusted, aMessage, nullptr, NS_UI_EVENT),
     detail(aDetail)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_UI_EVENT ||
+                 eventStructType == NS_SMIL_TIME_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalUIEvent* result = new InternalUIEvent(false, message, detail);
+    result->AssignUIEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   int32_t detail;
 
   void AssignUIEventData(const InternalUIEvent& aEvent, bool aCopyTargets)
   {
     AssignGUIEventData(aEvent, aCopyTargets);
 
     // detail must have been initialized with the constructor.
   }
--- a/widget/ContentEvents.h
+++ b/widget/ContentEvents.h
@@ -32,16 +32,28 @@ public:
   }
 
   InternalScriptErrorEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_SCRIPT_ERROR_EVENT),
     lineNr(0), errorMsg(nullptr), fileName(nullptr)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_SCRIPT_ERROR_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalScriptErrorEvent* result =
+      new InternalScriptErrorEvent(false, message);
+    result->AssignScriptErrorEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
+
   int32_t           lineNr;
   const char16_t*  errorMsg;
   const char16_t*  fileName;
 
   // XXX Not tested by test_assign_event_data.html
   void AssignScriptErrorEventData(const InternalScriptErrorEvent& aEvent,
                                   bool aCopyTargets)
   {
@@ -77,16 +89,28 @@ public:
 
   InternalScrollPortEvent(bool aIsTrusted, uint32_t aMessage,
                           nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_SCROLLPORT_EVENT),
     orient(vertical)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_SCROLLPORT_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    InternalScrollPortEvent* result =
+      new InternalScrollPortEvent(false, message, nullptr);
+    result->AssignScrollPortEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   orientType orient;
 
   void AssignScrollPortEventData(const InternalScrollPortEvent& aEvent,
                                  bool aCopyTargets)
   {
     AssignGUIEventData(aEvent, aCopyTargets);
 
     orient = aEvent.orient;
@@ -106,16 +130,28 @@ public:
   }
 
   InternalScrollAreaEvent(bool aIsTrusted, uint32_t aMessage,
                           nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_SCROLLAREA_EVENT)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_SCROLLAREA_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    InternalScrollAreaEvent* result =
+      new InternalScrollAreaEvent(false, message, nullptr);
+    result->AssignScrollAreaEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsRect mArea;
 
   void AssignScrollAreaEventData(const InternalScrollAreaEvent& aEvent,
                                  bool aCopyTargets)
   {
     AssignGUIEventData(aEvent, aCopyTargets);
 
     mArea = aEvent.mArea;
@@ -135,16 +171,26 @@ public:
   virtual InternalFormEvent* AsFormEvent() MOZ_OVERRIDE { return this; }
 
   InternalFormEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_FORM_EVENT),
     originator(nullptr)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_FORM_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalFormEvent* result = new InternalFormEvent(false, message);
+    result->AssignFormEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsIContent *originator;
 
   void AssignFormEventData(const InternalFormEvent& aEvent, bool aCopyTargets)
   {
     AssignEventData(aEvent, aCopyTargets);
 
     // Don't copy originator due to a weak pointer.
   }
@@ -162,16 +208,26 @@ public:
     return this;
   }
 
   InternalClipboardEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_CLIPBOARD_EVENT)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_CLIPBOARD_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalClipboardEvent* result = new InternalClipboardEvent(false, message);
+    result->AssignClipboardEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsCOMPtr<nsIDOMDataTransfer> clipboardData;
 
   void AssignClipboardEventData(const InternalClipboardEvent& aEvent,
                                 bool aCopyTargets)
   {
     AssignEventData(aEvent, aCopyTargets);
 
     clipboardData = aEvent.clipboardData;
@@ -188,16 +244,26 @@ public:
   virtual InternalFocusEvent* AsFocusEvent() MOZ_OVERRIDE { return this; }
 
   InternalFocusEvent(bool aIsTrusted, uint32_t aMessage) :
     InternalUIEvent(aIsTrusted, aMessage, NS_FOCUS_EVENT, 0),
     fromRaise(false), isRefocus(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_FOCUS_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalFocusEvent* result = new InternalFocusEvent(false, message);
+    result->AssignFocusEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   /// The possible related target
   nsCOMPtr<dom::EventTarget> relatedTarget;
 
   bool fromRaise;
   bool isRefocus;
 
   void AssignFocusEventData(const InternalFocusEvent& aEvent, bool aCopyTargets)
   {
@@ -226,16 +292,28 @@ public:
                           const nsAString& aPseudoElement) :
     WidgetEvent(aIsTrusted, aMessage, NS_TRANSITION_EVENT),
     propertyName(aPropertyName), elapsedTime(aElapsedTime),
     pseudoElement(aPseudoElement)
   {
     mFlags.mCancelable = false;
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_TRANSITION_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalTransitionEvent* result =
+      new InternalTransitionEvent(false, message, propertyName,
+                                  elapsedTime, pseudoElement);
+    result->AssignTransitionEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsString propertyName;
   float elapsedTime;
   nsString pseudoElement;
 
   void AssignTransitionEventData(const InternalTransitionEvent& aEvent,
                                  bool aCopyTargets)
   {
     AssignEventData(aEvent, aCopyTargets);
@@ -262,16 +340,28 @@ public:
                          const nsAString& aPseudoElement) :
     WidgetEvent(aIsTrusted, aMessage, NS_ANIMATION_EVENT),
     animationName(aAnimationName), elapsedTime(aElapsedTime),
     pseudoElement(aPseudoElement)
   {
     mFlags.mCancelable = false;
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_ANIMATION_EVENT,
+               "Duplicate() must be overridden by sub class");
+    InternalAnimationEvent* result =
+      new InternalAnimationEvent(false, message, animationName,
+                                 elapsedTime, pseudoElement);
+    result->AssignAnimationEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsString animationName;
   float elapsedTime;
   nsString pseudoElement;
 
   void AssignAnimationEventData(const InternalAnimationEvent& aEvent,
                                 bool aCopyTargets)
   {
     AssignEventData(aEvent, aCopyTargets);
--- a/widget/MiscEvents.h
+++ b/widget/MiscEvents.h
@@ -30,16 +30,23 @@ public:
   WidgetContentCommandEvent(bool aIsTrusted, uint32_t aMessage,
                             nsIWidget* aWidget,
                             bool aOnlyEnabledCheck = false) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_CONTENT_COMMAND_EVENT),
     mOnlyEnabledCheck(aOnlyEnabledCheck), mSucceeded(false), mIsEnabled(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    // This event isn't an internal event of any DOM event.
+    MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
+    return nullptr;
+  }
+
   // NS_CONTENT_COMMAND_PASTE_TRANSFERABLE
   nsCOMPtr<nsITransferable> mTransferable; // [in]
 
   // NS_CONTENT_COMMAND_SCROLL
   // for mScroll.mUnit
   enum
   {
     eCmdScrollUnit_Line,
@@ -94,16 +101,28 @@ public:
                      nsIAtom* aCommand, nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, NS_USER_DEFINED_EVENT, aWidget,
                    NS_COMMAND_EVENT),
     command(aCommand)
   {
     userType = aEventType;
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_COMMAND_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetCommandEvent* result =
+      new WidgetCommandEvent(false, userType, command, nullptr);
+    result->AssignCommandEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsCOMPtr<nsIAtom> command;
 
   // XXX Not tested by test_assign_event_data.html
   void AssignCommandEventData(const WidgetCommandEvent& aEvent,
                               bool aCopyTargets)
   {
     AssignGUIEventData(aEvent, aCopyTargets);
 
@@ -123,16 +142,23 @@ public:
   virtual WidgetPluginEvent* AsPluginEvent() MOZ_OVERRIDE { return this; }
 
   WidgetPluginEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_PLUGIN_EVENT),
     retargetToFocusedDocument(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    // This event isn't an internal event of any DOM event.
+    MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
+    return nullptr;
+  }
+
   // If true, this event needs to be retargeted to focused document.
   // Otherwise, never retargeted. Defaults to false.
   bool retargetToFocusedDocument;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_MiscEvents_h__
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -57,16 +57,22 @@ protected:
     button(0), buttons(0), pressure(0),
     inputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE)
  {
  }
 
 public:
   virtual WidgetMouseEventBase* AsMouseEventBase() MOZ_OVERRIDE { return this; }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_CRASH("WidgetMouseEventBase must not be most-subclass");
+    return nullptr;
+  }
+
   /// The possible related target
   nsCOMPtr<nsISupports> relatedTarget;
 
   enum buttonType
   {
     eLeftButton   = 0,
     eMiddleButton = 1,
     eRightButton  = 2
@@ -203,16 +209,28 @@ public:
   {
     NS_WARN_IF_FALSE(message != NS_CONTEXTMENU ||
                      button ==
                        ((context == eNormal) ? eRightButton : eLeftButton),
                      "Wrong button set to NS_CONTEXTMENU event?");
   }
 #endif
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_MOUSE_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetMouseEvent* result =
+      new WidgetMouseEvent(false, message, nullptr, reason, context);
+    result->AssignMouseEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // Special return code for MOUSE_ACTIVATE to signal.
   // If the target accepts activation (1), or denies it (0).
   bool acceptActivation;
   // Whether the event should ignore scroll frame bounds during dispatch.
   bool ignoreRootScrollFrame;
 
   reasonType reason : 4;
   contextType context : 4;
@@ -253,16 +271,27 @@ public:
     userCancelled(false), mDefaultPreventedOnContent(false)
   {
     mFlags.mCancelable =
       (aMessage != NS_DRAGDROP_EXIT_SYNTH &&
        aMessage != NS_DRAGDROP_LEAVE_SYNTH &&
        aMessage != NS_DRAGDROP_END);
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_DRAG_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetDragEvent* result = new WidgetDragEvent(false, message, nullptr);
+    result->AssignDragEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // The dragging data.
   nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
 
   // If this is true, user has cancelled the drag operation.
   bool userCancelled;
   // If this is true, the drag event's preventDefault() is called on content.
   bool mDefaultPreventedOnContent;
 
@@ -301,16 +330,28 @@ public:
 
   WidgetMouseScrollEvent(bool aIsTrusted, uint32_t aMessage,
                          nsIWidget* aWidget) :
     WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, NS_MOUSE_SCROLL_EVENT),
     delta(0), isHorizontal(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_MOUSE_SCROLL_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetMouseScrollEvent* result =
+      new WidgetMouseScrollEvent(false, message, nullptr);
+    result->AssignMouseScrollEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // The delta value of mouse scroll event.
   // If the event message is NS_MOUSE_SCROLL, the value indicates scroll amount
   // in lines.  However, if the value is nsIDOMUIEvent::SCROLL_PAGE_UP or
   // nsIDOMUIEvent::SCROLL_PAGE_DOWN, the value inducates one page scroll.
   // If the event message is NS_MOUSE_PIXEL_SCROLL, the value indicates scroll
   // amount in pixels.
   int32_t delta;
 
@@ -351,16 +392,27 @@ public:
     deltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL),
     customizedByUserPrefs(false), isMomentum(false), isPixelOnlyDevice(false),
     lineOrPageDeltaX(0), lineOrPageDeltaY(0), scrollType(SCROLL_DEFAULT),
     overflowDeltaX(0.0), overflowDeltaY(0.0),
     mViewPortIsOverscrolled(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_WHEEL_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetWheelEvent* result = new WidgetWheelEvent(false, message, nullptr);
+    result->AssignWheelEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // NOTE: deltaX, deltaY and deltaZ may be customized by
   //       mousewheel.*.delta_multiplier_* prefs which are applied by
   //       nsEventStateManager.  So, after widget dispatches this event,
   //       these delta values may have different values than before.
   double deltaX;
   double deltaY;
   double deltaZ;
 
@@ -507,19 +559,45 @@ public:
     , width(aWidth)
     , height(aHeight)
     , tiltX(aTiltX)
     , tiltY(aTiltY)
     , isPrimary(aIsPrimary)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_POINTER_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetPointerEvent* result =
+      new WidgetPointerEvent(false, message, nullptr);
+    result->AssignPointerEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   uint32_t pointerId;
   uint32_t width;
   uint32_t height;
   uint32_t tiltX;
   uint32_t tiltY;
   bool isPrimary;
+
+  // XXX Not tested by test_assign_event_data.html
+  void AssignPointerEventData(const WidgetPointerEvent& aEvent,
+                              bool aCopyTargets)
+  {
+    AssignMouseEventData(aEvent, aCopyTargets);
+
+    pointerId = aEvent.pointerId;
+    width = aEvent.width;
+    height = aEvent.height;
+    tiltX = aEvent.tiltX;
+    tiltY = aEvent.tiltY;
+    isPrimary = aEvent.isPrimary;
+  }
 };
 
 } // namespace mozilla
 
 #endif // mozilla_MouseEvents_h__
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -84,16 +84,28 @@ public:
     location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD),
     isChar(false), mIsRepeat(false),
     mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified),
     mNativeKeyEvent(nullptr),
     mUniqueId(0)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_KEY_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetKeyboardEvent* result =
+      new WidgetKeyboardEvent(false, message, nullptr);
+    result->AssignKeyEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // A DOM keyCode value or 0.  If a keypress event whose charCode is 0, this
   // should be 0.
   uint32_t keyCode;
   // If the instance is a keypress event of a printable key, this is a UTF-16
   // value of the key.  Otherwise, 0.  This value must not be a control
   // character when some modifiers are active.  Then, this value should be an
   // unmodified value except Shift and AltGr.
   uint32_t charCode;
@@ -185,16 +197,27 @@ public:
     : WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_TEXT_EVENT)
     , mSeqno(kLatestSeqno)
     , rangeCount(0)
     , rangeArray(nullptr)
     , isChar(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_TEXT_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetTextEvent* result = new WidgetTextEvent(false, message, nullptr);
+    result->AssignTextEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // The composition string or the commit string.
   nsString theText;
   // Count of rangeArray.
   uint32_t rangeCount;
   // Pointer to the first item of the ranges (clauses).
   // Note that the range array may not specify a caret position; in that
   // case there will be no range of type NS_TEXTRANGE_CARETPOSITION in the
   // array.
@@ -245,16 +268,28 @@ public:
     , mSeqno(kLatestSeqno)
   {
     // XXX compositionstart is cancelable in draft of DOM3 Events.
     //     However, it doesn't make sense for us, we cannot cancel composition
     //     when we send compositionstart event.
     mFlags.mCancelable = false;
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_COMPOSITION_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetCompositionEvent* result =
+      new WidgetCompositionEvent(false, message, nullptr);
+    result->AssignCompositionEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // The composition string or the commit string.  If the instance is a
   // compositionstart event, this is initialized with selected text by
   // TextComposition automatically.
   nsString data;
 
   void AssignCompositionEventData(const WidgetCompositionEvent& aEvent,
                                   bool aCopyTargets)
   {
@@ -287,16 +322,23 @@ public:
 
   WidgetQueryContentEvent(bool aIsTrusted, uint32_t aMessage,
                           nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_QUERY_CONTENT_EVENT),
     mSucceeded(false), mWasAsync(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    // This event isn't an internal event of any DOM event.
+    MOZ_CRASH("WidgetQueryContentEvent doesn't support Duplicate()");
+    return nullptr;
+  }
+
   void InitForQueryTextContent(uint32_t aOffset, uint32_t aLength)
   {
     NS_ASSERTION(message == NS_QUERY_TEXT_CONTENT,
                  "wrong initializer is called");
     mInput.mOffset = aOffset;
     mInput.mLength = aLength;
   }
 
@@ -411,16 +453,23 @@ public:
     , mOffset(0)
     , mLength(0)
     , mReversed(false)
     , mExpandToClusterBoundary(true)
     , mSucceeded(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    // This event isn't an internal event of any DOM event.
+    MOZ_CRASH("WidgetSelectionEvent doesn't support Duplicate()");
+    return nullptr;
+  }
+
   // Start offset of selection
   uint32_t mOffset;
   // Length of selection
   uint32_t mLength;
   // Selection "anchor" should be in front
   bool mReversed;
   // Cluster-based or character-based
   bool mExpandToClusterBoundary;
--- a/widget/TouchEvents.h
+++ b/widget/TouchEvents.h
@@ -38,36 +38,33 @@ public:
 
   WidgetGestureNotifyEvent(bool aIsTrusted, uint32_t aMessage,
                            nsIWidget *aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_GESTURENOTIFY_EVENT),
     panDirection(ePanNone), displayPanFeedback(false)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    // This event isn't an internal event of any DOM event.
+    MOZ_CRASH("WidgetGestureNotifyEvent doesn't support Duplicate()");
+    return nullptr;
+  }
+
   enum ePanDirection
   {
     ePanNone,
     ePanVertical,
     ePanHorizontal,
     ePanBoth
   };
 
   ePanDirection panDirection;
   bool displayPanFeedback;
-
-  // XXX Not tested by test_assign_event_data.html
-  void AssignGestureNotifyEventData(const WidgetGestureNotifyEvent& aEvent,
-                                    bool aCopyTargets)
-  {
-    AssignGUIEventData(aEvent, aCopyTargets);
-
-    panDirection = aEvent.panDirection;
-    displayPanFeedback = aEvent.displayPanFeedback;
-  }
 };
 
 /******************************************************************************
  * mozilla::WidgetTouchEvent
  ******************************************************************************/
 
 class WidgetSimpleGestureEvent : public WidgetMouseEventBase
 {
@@ -90,16 +87,28 @@ public:
     WidgetMouseEventBase(aOther.mFlags.mIsTrusted,
                          aOther.message, aOther.widget,
                          NS_SIMPLE_GESTURE_EVENT),
     allowedDirections(aOther.allowedDirections), direction(aOther.direction),
     delta(aOther.delta), clickCount(0)
   {
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_SIMPLE_GESTURE_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // Not copying widget, it is a weak reference.
+    WidgetSimpleGestureEvent* result =
+      new WidgetSimpleGestureEvent(false, message, nullptr, direction, delta);
+    result->AssignSimpleGestureEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   // See nsIDOMSimpleGestureEvent for values
   uint32_t allowedDirections;
   // See nsIDOMSimpleGestureEvent for values
   uint32_t direction;
   // Delta for magnify and rotate events
   double delta;
   // The number of taps for tap events
   uint32_t clickCount;
@@ -135,17 +144,17 @@ public:
                      NS_TOUCH_EVENT)
   {
     modifiers = aOther.modifiers;
     time = aOther.time;
     touches.AppendElements(aOther.touches);
     MOZ_COUNT_CTOR(WidgetTouchEvent);
   }
 
-  WidgetTouchEvent(bool aIsTrusted, WidgetTouchEvent* aEvent) :
+  WidgetTouchEvent(bool aIsTrusted, const WidgetTouchEvent* aEvent) :
     WidgetInputEvent(aIsTrusted, aEvent->message, aEvent->widget,
                      NS_TOUCH_EVENT)
   {
     modifiers = aEvent->modifiers;
     time = aEvent->time;
     touches.AppendElements(aEvent->touches);
     MOZ_COUNT_CTOR(WidgetTouchEvent);
   }
@@ -156,16 +165,27 @@ public:
     MOZ_COUNT_CTOR(WidgetTouchEvent);
   }
 
   virtual ~WidgetTouchEvent()
   {
     MOZ_COUNT_DTOR(WidgetTouchEvent);
   }
 
+  virtual WidgetEvent* Duplicate() const MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(eventStructType == NS_TOUCH_EVENT,
+               "Duplicate() must be overridden by sub class");
+    // XXX Why does only WidgetTouchEvent copy the widget?
+    WidgetTouchEvent* result = new WidgetTouchEvent(false, this);
+    result->AssignTouchEventData(*this, true);
+    result->mFlags = mFlags;
+    return result;
+  }
+
   nsTArray<nsRefPtr<mozilla::dom::Touch>> touches;
 
   void AssignTouchEventData(const WidgetTouchEvent& aEvent, bool aCopyTargets)
   {
     AssignInputEventData(aEvent, aCopyTargets);
 
     // Currently, we don't need to copy touches.
   }