Bug 920425 part.2 Implement mozilla::WidgetEvent::As*Event() methods r=roc
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 18 Oct 2013 15:10:20 +0900
changeset 151298 f20b704a6727d82d35cc75d17f35c8dc4a3a7450
parent 151297 8ee916cacd478cc3969410dc80e6e6982a6f79dd
child 151299 081e788525f92752c0eed6022077976b027eed14
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs920425
milestone27.0a1
Bug 920425 part.2 Implement mozilla::WidgetEvent::As*Event() methods r=roc
content/events/public/MutationEvent.h
widget/BasicEvents.h
widget/ContentEvents.h
widget/MiscEvents.h
widget/MouseEvents.h
widget/TextEvents.h
widget/TouchEvents.h
widget/shared/WidgetEventImpl.cpp
--- a/content/events/public/MutationEvent.h
+++ b/content/events/public/MutationEvent.h
@@ -11,16 +11,18 @@
 #include "nsIAtom.h"
 #include "nsIDOMNode.h"
 
 namespace mozilla {
 
 class InternalMutationEvent : public WidgetEvent
 {
 public:
+  virtual InternalMutationEvent* AsMutationEvent() MOZ_OVERRIDE { return this; }
+
   InternalMutationEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_MUTATION_EVENT),
     mAttrChange(0)
   {
     mFlags.mCancelable = false;
   }
 
   nsCOMPtr<nsIDOMNode> mRelatedNode;
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -617,17 +617,17 @@ public:
   {
     MOZ_COUNT_CTOR(WidgetEvent);
     mFlags.Clear();
     mFlags.mIsTrusted = aIsTrusted;
     mFlags.mCancelable = true;
     mFlags.mBubbles = true;
   }
 
-  ~WidgetEvent()
+  virtual ~WidgetEvent()
   {
     MOZ_COUNT_DTOR(WidgetEvent);
   }
 
   WidgetEvent(const WidgetEvent& aOther)
   {
     MOZ_COUNT_CTOR(WidgetEvent);
     *this = aOther;
@@ -672,16 +672,30 @@ public:
     originalTarget = aCopyTargets ? aEvent.originalTarget : nullptr;
   }
 
   /**
    * Utils for checking event types
    */
 
   /**
+   * As*Event() returns the pointer of the instance only when the instance is
+   * the class or one of its derived class.
+   */
+#define NS_ROOT_EVENT_CLASS(aPrefix, aName)
+#define NS_EVENT_CLASS(aPrefix, aName) \
+  virtual aPrefix##aName* As##aName(); \
+  const aPrefix##aName* As##aName() const;
+
+#include "mozilla/EventClassList.h"
+
+#undef NS_EVENT_CLASS
+#undef NS_ROOT_EVENT_CLASS
+
+  /**
    * Returns true if the event is WidgetInputEvent or inherits it.
    */
   bool IsInputDerivedEvent() const;
   /**
    * Returns true if the event is WidgetMouseEvent or inherits it.
    */
   bool IsMouseDerivedEvent() const;
   /**
@@ -800,16 +814,18 @@ protected:
   }
 
   WidgetGUIEvent() :
     pluginEvent(nullptr)
   {
   }
 
 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)
   {
   }
 
   /// Originator of the event
   nsCOMPtr<nsIWidget> widget;
@@ -887,16 +903,18 @@ protected:
   {
   }
 
   WidgetInputEvent()
   {
   }
 
 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)
   {
   }
 
   // true indicates the shift key is down
   bool IsShift() const
@@ -1001,16 +1019,18 @@ protected:
   InternalUIEvent(bool aIsTrusted, uint32_t aMessage,
                   nsEventStructType aStructType, int32_t aDetail) :
     WidgetGUIEvent(aIsTrusted, aMessage, nullptr, aStructType),
     detail(aDetail)
   {
   }
 
 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)
   {
   }
 
   int32_t detail;
 
--- a/widget/ContentEvents.h
+++ b/widget/ContentEvents.h
@@ -21,16 +21,21 @@ namespace mozilla {
 
 /******************************************************************************
  * mozilla::InternalScriptErrorEvent
  ******************************************************************************/
 
 class InternalScriptErrorEvent : public WidgetEvent
 {
 public:
+  virtual InternalScriptErrorEvent* AsScriptErrorEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   InternalScriptErrorEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_SCRIPT_ERROR_EVENT),
     lineNr(0), errorMsg(nullptr), fileName(nullptr)
   {
   }
 
   int32_t           lineNr;
   const PRUnichar*  errorMsg;
@@ -53,16 +58,21 @@ public:
 
 /******************************************************************************
  * mozilla::InternalScrollPortEvent
  ******************************************************************************/
 
 class InternalScrollPortEvent : public WidgetGUIEvent
 {
 public:
+  virtual InternalScrollPortEvent* AsScrollPortEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   enum orientType
   {
     vertical   = 0,
     horizontal = 1,
     both       = 2
   };
 
   InternalScrollPortEvent(bool aIsTrusted, uint32_t aMessage,
@@ -85,16 +95,21 @@ public:
 
 /******************************************************************************
  * mozilla::InternalScrollPortEvent
  ******************************************************************************/
 
 class InternalScrollAreaEvent : public WidgetGUIEvent
 {
 public:
+  virtual InternalScrollAreaEvent* AsScrollAreaEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   InternalScrollAreaEvent(bool aIsTrusted, uint32_t aMessage,
                           nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_SCROLLAREA_EVENT)
   {
   }
 
   nsRect mArea;
 
@@ -112,16 +127,18 @@ public:
  *
  * We hold the originating form control for form submit and reset events.
  * originator is a weak pointer (does not hold a strong reference).
  ******************************************************************************/
 
 class InternalFormEvent : public WidgetEvent
 {
 public:
+  virtual InternalFormEvent* AsFormEvent() MOZ_OVERRIDE { return this; }
+
   InternalFormEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_FORM_EVENT),
     originator(nullptr)
   {
   }
 
   nsIContent *originator;
 
@@ -135,16 +152,21 @@ public:
 
 /******************************************************************************
  * mozilla::InternalClipboardEvent
  ******************************************************************************/
 
 class InternalClipboardEvent : public WidgetEvent
 {
 public:
+  virtual InternalClipboardEvent* AsClipboardEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   InternalClipboardEvent(bool aIsTrusted, uint32_t aMessage) :
     WidgetEvent(aIsTrusted, aMessage, NS_CLIPBOARD_EVENT)
   {
   }
 
   nsCOMPtr<nsIDOMDataTransfer> clipboardData;
 
   void AssignClipboardEventData(const InternalClipboardEvent& aEvent,
@@ -158,16 +180,18 @@ public:
 
 /******************************************************************************
  * mozilla::InternalFocusEvent
  ******************************************************************************/
 
 class InternalFocusEvent : public InternalUIEvent
 {
 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)
   {
   }
 
   /// The possible related target
   nsCOMPtr<dom::EventTarget> relatedTarget;
@@ -187,16 +211,21 @@ public:
 
 /******************************************************************************
  * mozilla::InternalTransitionEvent
  ******************************************************************************/
 
 class InternalTransitionEvent : public WidgetEvent
 {
 public:
+  virtual InternalTransitionEvent* AsTransitionEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   InternalTransitionEvent(bool aIsTrusted, uint32_t aMessage,
                           const nsAString& aPropertyName, float aElapsedTime,
                           const nsAString& aPseudoElement) :
     WidgetEvent(aIsTrusted, aMessage, NS_TRANSITION_EVENT),
     propertyName(aPropertyName), elapsedTime(aElapsedTime),
     pseudoElement(aPseudoElement)
   {
   }
@@ -217,16 +246,21 @@ public:
 
 /******************************************************************************
  * mozilla::InternalAnimationEvent
  ******************************************************************************/
 
 class InternalAnimationEvent : public WidgetEvent
 {
 public:
+  virtual InternalAnimationEvent* AsAnimationEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   InternalAnimationEvent(bool aIsTrusted, uint32_t aMessage,
                          const nsAString& aAnimationName, float aElapsedTime,
                          const nsAString& aPseudoElement) :
     WidgetEvent(aIsTrusted, aMessage, NS_ANIMATION_EVENT),
     animationName(aAnimationName), elapsedTime(aElapsedTime),
     pseudoElement(aPseudoElement)
   {
   }
--- a/widget/MiscEvents.h
+++ b/widget/MiscEvents.h
@@ -17,16 +17,21 @@ namespace mozilla {
 
 /******************************************************************************
  * mozilla::WidgetContentCommandEvent
  ******************************************************************************/
 
 class WidgetContentCommandEvent : public WidgetGUIEvent
 {
 public:
+  virtual WidgetContentCommandEvent* AsContentCommandEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   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)
   {
   }
 
@@ -67,16 +72,18 @@ public:
  * in focused content, you should use WidgetContentCommandEvent instead.
  *
  * XXX Should be |WidgetChromeCommandEvent|?
  ******************************************************************************/
 
 class WidgetCommandEvent : public WidgetGUIEvent
 {
 public:
+  virtual WidgetCommandEvent* AsCommandEvent() MOZ_OVERRIDE { return this; }
+
   WidgetCommandEvent(bool aIsTrusted, nsIAtom* aEventType,
                      nsIAtom* aCommand, nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, NS_USER_DEFINED_EVENT, aWidget,
                    NS_COMMAND_EVENT),
     command(aCommand)
   {
     userType = aEventType;
   }
@@ -97,16 +104,18 @@ public:
  * mozilla::WidgetPluginEvent
  *
  * This event delivers only a native event to focused plugin.
  ******************************************************************************/
 
 class WidgetPluginEvent : public WidgetGUIEvent
 {
 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)
   {
   }
 
   // If true, this event needs to be retargeted to focused document.
   // Otherwise, never retargeted. Defaults to false.
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -41,29 +41,32 @@ namespace dom {
  ******************************************************************************/
 
 class WidgetMouseEventBase : public WidgetInputEvent
 {
 private:
   friend class dom::PBrowserParent;
   friend class dom::PBrowserChild;
 
-public:
+protected:
   WidgetMouseEventBase()
   {
   }
 
   WidgetMouseEventBase(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget,
                        nsEventStructType aStructType) :
     WidgetInputEvent(aIsTrusted, aMessage, aWidget, aStructType),
     button(0), buttons(0), pressure(0),
     inputSource(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE)
  {
  }
 
+public:
+  virtual WidgetMouseEventBase* AsMouseEventBase() MOZ_OVERRIDE { return this; }
+
   /// The possible related target
   nsCOMPtr<nsISupports> relatedTarget;
 
   enum buttonType
   {
     eLeftButton   = 0,
     eMiddleButton = 1,
     eRightButton  = 2
@@ -131,21 +134,21 @@ public:
   };
 
   enum exitType
   {
     eChild,
     eTopLevel
   };
 
+protected:
   WidgetMouseEvent()
   {
   }
 
-protected:
   WidgetMouseEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget,
                    nsEventStructType aStructType, reasonType aReason) :
     WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, aStructType),
     acceptActivation(false), ignoreRootScrollFrame(false),
     reason(aReason), context(eNormal), exit(eChild), clickCount(0)
   {
     switch (aMessage) {
       case NS_MOUSE_MOVE:
@@ -157,16 +160,17 @@ protected:
         mFlags.mCancelable = false;
         break;
       default:
         break;
     }
   }
 
 public:
+  virtual WidgetMouseEvent* AsMouseEvent() MOZ_OVERRIDE { return this; }
 
   WidgetMouseEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget,
                    reasonType aReason, contextType aContext = eNormal) :
     WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, NS_MOUSE_EVENT),
     acceptActivation(false), ignoreRootScrollFrame(false),
     reason(aReason), context(aContext), exit(eChild), clickCount(0)
   {
     switch (aMessage) {
@@ -182,17 +186,18 @@ public:
         button = (context == eNormal) ? eRightButton : eLeftButton;
         break;
       default:
         break;
     }
   }
 
 #ifdef DEBUG
-  ~WidgetMouseEvent() {
+  virtual ~WidgetMouseEvent()
+  {
     NS_WARN_IF_FALSE(message != NS_CONTEXTMENU ||
                      button ==
                        ((context == eNormal) ? eRightButton : eLeftButton),
                      "Wrong button set to NS_CONTEXTMENU event?");
   }
 #endif
 
   // Special return code for MOUSE_ACTIVATE to signal.
@@ -220,16 +225,18 @@ public:
 
 /******************************************************************************
  * mozilla::WidgetDragEvent
  ******************************************************************************/
 
 class WidgetDragEvent : public WidgetMouseEvent
 {
 public:
+  virtual WidgetDragEvent* AsDragEvent() MOZ_OVERRIDE { return this; }
+
   WidgetDragEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetMouseEvent(aIsTrusted, aMessage, aWidget, NS_DRAG_EVENT, eReal),
     userCancelled(false)
   {
     mFlags.mCancelable =
       (aMessage != NS_DRAGDROP_EXIT_SYNTH &&
        aMessage != NS_DRAGDROP_LEAVE_SYNTH &&
        aMessage != NS_DRAGDROP_END);
@@ -263,16 +270,21 @@ public:
 class WidgetMouseScrollEvent : public WidgetMouseEventBase
 {
 private:
   WidgetMouseScrollEvent()
   {
   }
 
 public:
+  virtual WidgetMouseScrollEvent* AsMouseScrollEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   WidgetMouseScrollEvent(bool aIsTrusted, uint32_t aMessage,
                          nsIWidget* aWidget) :
     WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, NS_MOUSE_SCROLL_EVENT),
     delta(0), isHorizontal(false)
   {
   }
 
   // The delta value of mouse scroll event.
@@ -307,16 +319,18 @@ private:
   friend class mozilla::dom::PBrowserParent;
   friend class mozilla::dom::PBrowserChild;
 
   WidgetWheelEvent()
   {
   }
 
 public:
+  virtual WidgetWheelEvent* AsWheelEvent() MOZ_OVERRIDE { return this; }
+
   WidgetWheelEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, NS_WHEEL_EVENT),
     deltaX(0.0), deltaY(0.0), deltaZ(0.0),
     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)
--- a/widget/TextEvents.h
+++ b/widget/TextEvents.h
@@ -65,21 +65,23 @@ struct AlternativeCharCode
  ******************************************************************************/
 
 class WidgetKeyboardEvent : public WidgetInputEvent
 {
 private:
   friend class dom::PBrowserParent;
   friend class dom::PBrowserChild;
 
-public:
   WidgetKeyboardEvent()
   {
   }
 
+public:
+  virtual WidgetKeyboardEvent* AsKeyboardEvent() MOZ_OVERRIDE { return this; }
+
   WidgetKeyboardEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetInputEvent(aIsTrusted, aMessage, aWidget, NS_KEY_EVENT),
     keyCode(0), charCode(0),
     location(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD), isChar(0),
     mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified),
     mNativeKeyEvent(nullptr),
     mUniqueId(0)
   {
@@ -309,16 +311,18 @@ private:
   WidgetTextEvent()
   {
   }
 
 public:
   uint32_t seqno;
 
 public:
+  virtual WidgetTextEvent* AsTextEvent() MOZ_OVERRIDE { return this; }
+
   WidgetTextEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_TEXT_EVENT),
     rangeCount(0), rangeArray(nullptr), isChar(false)
   {
   }
 
   // The composition string or the commit string.
   nsString theText;
@@ -358,16 +362,21 @@ private:
   WidgetCompositionEvent()
   {
   }
 
 public:
   uint32_t seqno;
 
 public:
+  virtual WidgetCompositionEvent* AsCompositionEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   WidgetCompositionEvent(bool aIsTrusted, uint32_t aMessage,
                          nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_COMPOSITION_EVENT)
   {
     // 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;
@@ -398,16 +407,21 @@ private:
   friend class dom::PBrowserChild;
 
   WidgetQueryContentEvent()
   {
     MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
   }
 
 public:
+  virtual WidgetQueryContentEvent* AsQueryContentEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   WidgetQueryContentEvent(bool aIsTrusted, uint32_t aMessage,
                           nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_QUERY_CONTENT_EVENT),
     mSucceeded(false), mWasAsync(false)
   {
   }
 
   void InitForQueryTextContent(uint32_t aOffset, uint32_t aLength)
@@ -508,16 +522,21 @@ private:
   {
     MOZ_CRASH("WidgetSelectionEvent is created without proper arguments");
   }
 
 public:
   uint32_t seqno;
 
 public:
+  virtual WidgetSelectionEvent* AsSelectionEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   WidgetSelectionEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_SELECTION_EVENT),
     mExpandToClusterBoundary(true), mSucceeded(false)
   {
   }
 
   // Start offset of selection
   uint32_t mOffset;
--- a/widget/TouchEvents.h
+++ b/widget/TouchEvents.h
@@ -26,16 +26,21 @@ namespace mozilla {
  * The event is dispatched to the layout and based on what is underneath
  * the initial contact point it's then decided if we should pan
  * (finger scrolling) or drag the target element.
  ******************************************************************************/
 
 class WidgetGestureNotifyEvent : public WidgetGUIEvent
 {
 public:
+  virtual WidgetGestureNotifyEvent* AsGestureNotifyEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   WidgetGestureNotifyEvent(bool aIsTrusted, uint32_t aMessage,
                            nsIWidget *aWidget) :
     WidgetGUIEvent(aIsTrusted, aMessage, aWidget, NS_GESTURENOTIFY_EVENT),
     panDirection(ePanNone), displayPanFeedback(false)
   {
   }
 
   enum ePanDirection
@@ -62,16 +67,21 @@ public:
 
 /******************************************************************************
  * mozilla::WidgetTouchEvent
  ******************************************************************************/
 
 class WidgetSimpleGestureEvent : public WidgetMouseEventBase
 {
 public:
+  virtual WidgetSimpleGestureEvent* AsSimpleGestureEvent() MOZ_OVERRIDE
+  {
+    return this;
+  }
+
   WidgetSimpleGestureEvent(bool aIsTrusted, uint32_t aMessage,
                            nsIWidget* aWidget, uint32_t aDirection,
                            double aDelta) :
     WidgetMouseEventBase(aIsTrusted, aMessage, aWidget,
                          NS_SIMPLE_GESTURE_EVENT),
     allowedDirections(0), direction(aDirection), delta(aDelta), clickCount(0)
   {
   }
@@ -109,16 +119,18 @@ public:
 
 /******************************************************************************
  * mozilla::WidgetTouchEvent
  ******************************************************************************/
 
 class WidgetTouchEvent : public WidgetInputEvent
 {
 public:
+  virtual WidgetTouchEvent* AsTouchEvent() MOZ_OVERRIDE { return this; }
+
   WidgetTouchEvent()
   {
   }
 
   WidgetTouchEvent(bool aIsTrusted, WidgetTouchEvent* aEvent) :
     WidgetInputEvent(aIsTrusted, aEvent->message, aEvent->widget,
                      NS_TOUCH_EVENT)
   {
@@ -129,17 +141,17 @@ public:
   }
 
   WidgetTouchEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget) :
     WidgetInputEvent(aIsTrusted, aMessage, aWidget, NS_TOUCH_EVENT)
   {
     MOZ_COUNT_CTOR(WidgetTouchEvent);
   }
 
-  ~WidgetTouchEvent()
+  virtual ~WidgetTouchEvent()
   {
     MOZ_COUNT_DTOR(WidgetTouchEvent);
   }
 
   nsTArray<nsRefPtr<mozilla::dom::Touch>> touches;
 
   void AssignTouchEventData(const WidgetTouchEvent& aEvent, bool aCopyTargets)
   {
--- a/widget/shared/WidgetEventImpl.cpp
+++ b/widget/shared/WidgetEventImpl.cpp
@@ -1,48 +1,62 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/BasicEvents.h"
+#include "mozilla/ContentEvents.h"
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/MutationEvent.h"
+#include "mozilla/TextEvents.h"
+#include "mozilla/TouchEvents.h"
 
 namespace mozilla {
 
 /******************************************************************************
+ * As*Event() implementation
+ ******************************************************************************/
+
+#define NS_ROOT_EVENT_CLASS(aPrefix, aName)
+#define NS_EVENT_CLASS(aPrefix, aName) \
+aPrefix##aName* \
+WidgetEvent::As##aName() \
+{ \
+  return nullptr; \
+} \
+\
+const aPrefix##aName* \
+WidgetEvent::As##aName() const \
+{ \
+  return const_cast<WidgetEvent*>(this)->As##aName(); \
+}
+
+#include "mozilla/EventClassList.h"
+
+#undef NS_EVENT_CLASS
+#undef NS_ROOT_EVENT_CLASS
+
+/******************************************************************************
  * mozilla::WidgetEvent
  *
  * Event struct type checking methods.
  ******************************************************************************/
 
 bool
 WidgetEvent::IsInputDerivedEvent() const
 {
-  switch (eventStructType) {
-    case NS_INPUT_EVENT:
-    case NS_MOUSE_EVENT:
-    case NS_KEY_EVENT:
-    case NS_TOUCH_EVENT:
-    case NS_DRAG_EVENT:
-    case NS_MOUSE_SCROLL_EVENT:
-    case NS_WHEEL_EVENT:
-    case NS_SIMPLE_GESTURE_EVENT:
-      return true;
-    default:
-      return false;
-  }
+  return AsInputEvent() != nullptr;
 }
 
 bool
 WidgetEvent::IsMouseDerivedEvent() const
 {
-  return eventStructType == NS_MOUSE_EVENT ||
-         eventStructType == NS_DRAG_EVENT;
+  return AsMouseEvent() != nullptr;
 }
 
 bool
 WidgetEvent::IsQueryContentEvent() const
 {
   return eventStructType == NS_QUERY_CONTENT_EVENT;
 }
 
@@ -150,43 +164,41 @@ WidgetEvent::HasPluginActivationEventMes
  * mozilla::WidgetEvent
  *
  * Specific event checking methods.
  ******************************************************************************/
 
 bool
 WidgetEvent::IsLeftClickEvent() const
 {
-  return eventStructType == NS_MOUSE_EVENT &&
-         message == NS_MOUSE_CLICK &&
-         static_cast<const WidgetMouseEvent*>(this)->button ==
-           WidgetMouseEvent::eLeftButton;
+  const WidgetMouseEvent* mouseEvent = AsMouseEvent();
+  return mouseEvent && message == NS_MOUSE_CLICK &&
+         mouseEvent->button == WidgetMouseEvent::eLeftButton;
 }
 
 bool
 WidgetEvent::IsContextMenuKeyEvent() const
 {
-  return eventStructType == NS_MOUSE_EVENT &&
-         message == NS_CONTEXTMENU &&
-         static_cast<const WidgetMouseEvent*>(this)->context ==
-            WidgetMouseEvent::eContextMenuKey;
+  const WidgetMouseEvent* mouseEvent = AsMouseEvent();
+  return mouseEvent && message == NS_CONTEXTMENU &&
+         mouseEvent->context == WidgetMouseEvent::eContextMenuKey;
 }
 
 bool
 WidgetEvent::IsRetargetedNativeEventDelivererForPlugin() const
 {
-  return IsNativeEventDelivererForPlugin() &&
-    static_cast<const WidgetPluginEvent*>(this)->retargetToFocusedDocument;
+  const WidgetPluginEvent* pluginEvent = AsPluginEvent();
+  return pluginEvent && pluginEvent->retargetToFocusedDocument;
 }
 
 bool
 WidgetEvent::IsNonRetargetedNativeEventDelivererForPlugin() const
 {
-  return IsNativeEventDelivererForPlugin() &&
-    !static_cast<const WidgetPluginEvent*>(this)->retargetToFocusedDocument;
+  const WidgetPluginEvent* pluginEvent = AsPluginEvent();
+  return pluginEvent && !pluginEvent->retargetToFocusedDocument;
 }
 
 bool
 WidgetEvent::IsIMERelatedEvent() const
 {
   return HasIMEEventMessage() || IsQueryContentEvent() || IsSelectionEvent();
 }
 
@@ -223,24 +235,22 @@ WidgetEvent::IsAllowedToDispatchDOMEvent
 {
   switch (eventStructType) {
     case NS_MOUSE_EVENT:
       // We want synthesized mouse moves to cause mouseover and mouseout
       // DOM events (nsEventStateManager::PreHandleEvent), but not mousemove
       // DOM events.
       // Synthesized button up events also do not cause DOM events because they
       // do not have a reliable refPoint.
-      return static_cast<const WidgetMouseEvent*>(this)->reason ==
-               WidgetMouseEvent::eReal;
+      return AsMouseEvent()->reason == WidgetMouseEvent::eReal;
 
     case NS_WHEEL_EVENT: {
       // wheel event whose all delta values are zero by user pref applied, it
       // shouldn't cause a DOM event.
-      const WidgetWheelEvent* wheelEvent =
-        static_cast<const WidgetWheelEvent*>(this);
+      const WidgetWheelEvent* wheelEvent = AsWheelEvent();
       return wheelEvent->deltaX != 0.0 || wheelEvent->deltaY != 0.0 ||
              wheelEvent->deltaZ != 0.0;
     }
 
     default:
       return true;
   }
 }