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 165278 eb278efeb18ad9046b1ecb52a5f70b329752d521
parent 165277 07560fe7043d6f595692c7b114a878ef19291445
child 165279 392019e712d7d19e1d4812767f573ca550219d05
push idunknown
push userunknown
push dateunknown
reviewerssmaug
bugs329127
milestone29.0a1
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.
   }