Bug 719320 part.1 Add DOM3 WheelEvent r=smaug, sr=jst
authorMasayuki Nakano <masayuki@d-toybox.com>
Sun, 12 Aug 2012 10:42:34 +0900
changeset 107521 61d8207c4fa3b31c9823661980daa47136ebf8eb
parent 107520 28aa0856c08eed1bb26eeb0571120b01075d8976
child 107522 d1f62bfbc5e4772f2b4ab621e2266af102e3c287
push id1490
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 18:29:50 +0000
treeherdermozilla-beta@f335e7dacdc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, jst
bugs719320
milestone17.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 719320 part.1 Add DOM3 WheelEvent r=smaug, sr=jst
content/base/src/nsGkAtomList.h
content/events/public/nsEventNameList.h
content/events/src/DOMWheelEvent.cpp
content/events/src/DOMWheelEvent.h
content/events/src/Makefile.in
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMMouseEvent.cpp
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/events/src/nsEventDispatcher.cpp
content/events/src/nsEventStateManager.cpp
content/events/test/Makefile.in
content/events/test/test_dom_wheel_event.html
content/events/test/test_eventctors.html
content/xbl/src/nsXBLEventHandler.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/interfaces/events/Makefile.in
dom/interfaces/events/nsIDOMEvent.idl
dom/interfaces/events/nsIDOMWheelEvent.idl
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
js/xpconnect/src/dictionary_helper_gen.conf
layout/base/nsLayoutUtils.cpp
layout/base/nsPresShell.cpp
layout/xul/base/src/nsXULPopupManager.cpp
widget/gtk2/nsGtkKeyUtils.cpp
widget/nsEvent.h
widget/nsGUIEvent.h
widget/nsGUIEventIPC.h
widget/windows/KeyboardLayout.cpp
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -715,16 +715,17 @@ GK_ATOM(ontouchend, "ontouchend")
 GK_ATOM(ontouchmove, "ontouchmove")
 GK_ATOM(ontouchenter, "ontouchenter")
 GK_ATOM(ontouchleave, "ontouchleave")
 GK_ATOM(ontouchcancel, "ontouchcancel")
 GK_ATOM(ontransitionend, "ontransitionend")
 GK_ATOM(onunderflow, "onunderflow")
 GK_ATOM(onunload, "onunload")
 GK_ATOM(onupgradeneeded, "onupgradeneeded")
+GK_ATOM(onwheel, "onwheel")
 GK_ATOM(open, "open")
 GK_ATOM(optgroup, "optgroup")
 GK_ATOM(optimum, "optimum")
 GK_ATOM(option, "option")
 GK_ATOM(_or, "or")
 GK_ATOM(order, "order")
 GK_ATOM(ordinal, "ordinal")
 GK_ATOM(orient, "orient")
--- a/content/events/public/nsEventNameList.h
+++ b/content/events/public/nsEventNameList.h
@@ -595,16 +595,20 @@ NON_IDL_EVENT(draggesture,
 NON_IDL_EVENT(overflow,
               NS_SCROLLPORT_OVERFLOW,
               EventNameType_XUL,
               NS_EVENT_NULL)
 NON_IDL_EVENT(underflow,
               NS_SCROLLPORT_UNDERFLOW,
               EventNameType_XUL,
               NS_EVENT_NULL)
+NON_IDL_EVENT(wheel,
+              NS_WHEEL_WHEEL,
+              EventNameType_XUL,
+              NS_WHEEL_EVENT)
 
 // Various SVG events
 NON_IDL_EVENT(SVGLoad,
               NS_SVG_LOAD,
               EventNameType_None,
               NS_SVG_EVENT)
 NON_IDL_EVENT(SVGUnload,
               NS_SVG_UNLOAD,
new file mode 100644
--- /dev/null
+++ b/content/events/src/DOMWheelEvent.cpp
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "DOMWheelEvent.h"
+#include "nsGUIEvent.h"
+#include "nsIContent.h"
+#include "nsContentUtils.h"
+#include "DictionaryHelpers.h"
+#include "nsDOMClassInfoID.h"
+
+DOMCI_DATA(WheelEvent, mozilla::dom::DOMWheelEvent)
+
+namespace mozilla {
+namespace dom {
+
+DOMWheelEvent::DOMWheelEvent(nsPresContext* aPresContext,
+                             widget::WheelEvent* aWheelEvent)
+  : nsDOMMouseEvent(aPresContext, aWheelEvent ? aWheelEvent :
+                                    new widget::WheelEvent(false, 0, nullptr))
+{
+  if (aWheelEvent) {
+    mEventIsInternal = false;
+  } else {
+    mEventIsInternal = true;
+    mEvent->time = PR_Now();
+    mEvent->refPoint.x = mEvent->refPoint.y = 0;
+    static_cast<widget::WheelEvent*>(mEvent)->inputSource =
+      nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
+  }
+}
+
+DOMWheelEvent::~DOMWheelEvent()
+{
+  if (mEventIsInternal && mEvent) {
+    MOZ_ASSERT(mEvent->eventStructType == NS_WHEEL_EVENT,
+               "The mEvent must be WheelEvent");
+    delete static_cast<widget::WheelEvent*>(mEvent);
+    mEvent = nullptr;
+  }
+}
+
+NS_IMPL_ADDREF_INHERITED(DOMWheelEvent, nsDOMMouseEvent)
+NS_IMPL_RELEASE_INHERITED(DOMWheelEvent, nsDOMMouseEvent)
+
+NS_INTERFACE_MAP_BEGIN(DOMWheelEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMWheelEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WheelEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMMouseEvent)
+
+NS_IMETHODIMP
+DOMWheelEvent::InitWheelEvent(const nsAString & aType,
+                              bool aCanBubble,
+                              bool aCancelable,
+                              nsIDOMWindow *aView,
+                              PRInt32 aDetail,
+                              PRInt32 aScreenX,
+                              PRInt32 aScreenY,
+                              PRInt32 aClientX,
+                              PRInt32 aClientY, 
+                              PRUint16 aButton,
+                              nsIDOMEventTarget *aRelatedTarget,
+                              const nsAString& aModifiersList,
+                              double aDeltaX,
+                              double aDeltaY,
+                              double aDeltaZ,
+                              PRUint32 aDeltaMode)
+{
+  nsresult rv =
+    nsDOMMouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView,
+                                    aDetail, aScreenX, aScreenY,
+                                    aClientX, aClientY, aButton,
+                                    aRelatedTarget, aModifiersList);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(mEvent);
+  wheelEvent->deltaX = aDeltaX;
+  wheelEvent->deltaY = aDeltaY;
+  wheelEvent->deltaZ = aDeltaZ;
+  wheelEvent->deltaMode = aDeltaMode;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMWheelEvent::GetDeltaX(double* aDeltaX)
+{
+  NS_ENSURE_ARG_POINTER(aDeltaX);
+
+  *aDeltaX = static_cast<widget::WheelEvent*>(mEvent)->deltaX;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMWheelEvent::GetDeltaY(double* aDeltaY)
+{
+  NS_ENSURE_ARG_POINTER(aDeltaY);
+
+  *aDeltaY = static_cast<widget::WheelEvent*>(mEvent)->deltaY;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMWheelEvent::GetDeltaZ(double* aDeltaZ)
+{
+  NS_ENSURE_ARG_POINTER(aDeltaZ);
+
+  *aDeltaZ = static_cast<widget::WheelEvent*>(mEvent)->deltaZ;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DOMWheelEvent::GetDeltaMode(PRUint32* aDeltaMode)
+{
+  NS_ENSURE_ARG_POINTER(aDeltaMode);
+
+  *aDeltaMode = static_cast<widget::WheelEvent*>(mEvent)->deltaMode;
+  return NS_OK;
+}
+
+nsresult
+DOMWheelEvent::InitFromCtor(const nsAString& aType,
+                            JSContext* aCx, jsval* aVal)
+{
+  WheelEventInit d;
+  nsresult rv = d.Init(aCx, aVal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString modifierList;
+  if (d.ctrlKey) {
+    modifierList.AppendLiteral(NS_DOM_KEYNAME_CONTROL);
+  }
+  if (d.shiftKey) {
+    if (!modifierList.IsEmpty()) {
+      modifierList.AppendLiteral(" ");
+    }
+    modifierList.AppendLiteral(NS_DOM_KEYNAME_SHIFT);
+  }
+  if (d.altKey) {
+    if (!modifierList.IsEmpty()) {
+      modifierList.AppendLiteral(" ");
+    }
+    modifierList.AppendLiteral(NS_DOM_KEYNAME_ALT);
+  }
+  if (d.metaKey) {
+    if (!modifierList.IsEmpty()) {
+      modifierList.AppendLiteral(" ");
+    }
+    modifierList.AppendLiteral(NS_DOM_KEYNAME_META);
+  }
+
+  rv = InitWheelEvent(aType, d.bubbles, d.cancelable,
+                      d.view, d.detail, d.screenX, d.screenY,
+                      d.clientX, d.clientY, d.button, d.relatedTarget,
+                      modifierList, d.deltaX, d.deltaY, d.deltaZ, d.deltaMode);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  static_cast<widget::WheelEvent*>(mEvent)->buttons = d.buttons;
+
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
+
+using namespace mozilla;
+
+nsresult NS_NewDOMWheelEvent(nsIDOMEvent** aInstancePtrResult,
+                             nsPresContext* aPresContext,
+                             widget::WheelEvent *aEvent)
+{
+  dom::DOMWheelEvent* it = new dom::DOMWheelEvent(aPresContext, aEvent);
+  return CallQueryInterface(it, aInstancePtrResult);
+}
new file mode 100644
--- /dev/null
+++ b/content/events/src/DOMWheelEvent.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_dom_DOMWheelEvent_h__
+#define mozilla_dom_DOMWheelEvent_h__
+
+#include "nsIDOMWheelEvent.h"
+#include "nsDOMMouseEvent.h"
+
+namespace mozilla {
+namespace dom {
+
+class DOMWheelEvent : public nsDOMMouseEvent,
+                      public nsIDOMWheelEvent
+{
+public:
+  DOMWheelEvent(nsPresContext* aPresContext,
+                widget::WheelEvent* aWheelEvent);
+  virtual ~DOMWheelEvent();
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  // nsIDOMWheelEvent Interface
+  NS_DECL_NSIDOMWHEELEVENT
+  
+  // Forward to base class
+  NS_FORWARD_TO_NSDOMMOUSEEVENT
+
+  virtual nsresult InitFromCtor(const nsAString& aType,
+                                JSContext* aCx, jsval* aVal);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DOMWheelEvent_h__
--- a/content/events/src/Makefile.in
+++ b/content/events/src/Makefile.in
@@ -57,16 +57,17 @@ CPPSRCS		= \
 		nsDOMSimpleGestureEvent.cpp \
 		nsDOMMozTouchEvent.cpp \
 		nsDOMEventTargetHelper.cpp \
 		nsDOMScrollAreaEvent.cpp \
 		nsDOMTransitionEvent.cpp \
 		nsDOMAnimationEvent.cpp \
 		nsDOMTouchEvent.cpp \
 		nsDOMCompositionEvent.cpp \
+		DOMWheelEvent.cpp \
 		$(NULL)
 
 ifdef MOZ_B2G_RIL
 CPPSRCS += \
     nsDOMWifiEvent.cpp \
     $(NULL)
 endif
 
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -47,17 +47,17 @@ static const char* const sEventNames[] =
   "popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate",
   "dragenter", "dragover", "dragexit", "dragdrop", "draggesture",
   "drag", "dragend", "dragstart", "dragleave", "drop", "resize",
   "scroll", "overflow", "underflow", "overflowchanged",
   "DOMSubtreeModified", "DOMNodeInserted", "DOMNodeRemoved", 
   "DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument",
   "DOMAttrModified", "DOMCharacterDataModified",
   "DOMActivate", "DOMFocusIn", "DOMFocusOut",
-  "pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll",
+  "pageshow", "pagehide", "DOMMouseScroll", "MozMousePixelScroll", "wheel",
   "offline", "online", "copy", "cut", "paste", "open", "message", "show",
   "SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll",
   "SVGZoom",
   "beginEvent", "endEvent", "repeatEvent",
 #ifdef MOZ_MEDIA
   "loadstart", "progress", "suspend", "emptied", "stalled", "play", "pause",
   "loadedmetadata", "loadeddata", "waiting", "playing", "canplay",
   "canplaythrough", "seeking", "seeked", "timeupdate", "ended", "ratechange",
@@ -186,16 +186,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMEv
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMEvent)
   if (tmp->mEventIsInternal) {
     tmp->mEvent->target = nullptr;
     tmp->mEvent->currentTarget = nullptr;
     tmp->mEvent->originalTarget = nullptr;
     switch (tmp->mEvent->eventStructType) {
       case NS_MOUSE_EVENT:
       case NS_MOUSE_SCROLL_EVENT:
+      case NS_WHEEL_EVENT:
       case NS_SIMPLE_GESTURE_EVENT:
       case NS_MOZTOUCH_EVENT:
         static_cast<nsMouseEvent_base*>(tmp->mEvent)->relatedTarget = nullptr;
         break;
       case NS_DRAG_EVENT:
         static_cast<nsDragEvent*>(tmp->mEvent)->dataTransfer = nullptr;
         static_cast<nsMouseEvent_base*>(tmp->mEvent)->relatedTarget = nullptr;
         break;
@@ -213,16 +214,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMEvent)
   if (tmp->mEventIsInternal) {
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEvent->target)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEvent->currentTarget)
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mEvent->originalTarget)
     switch (tmp->mEvent->eventStructType) {
       case NS_MOUSE_EVENT:
       case NS_MOUSE_SCROLL_EVENT:
+      case NS_WHEEL_EVENT:
       case NS_SIMPLE_GESTURE_EVENT:
       case NS_MOZTOUCH_EVENT:
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
         cb.NoteXPCOMChild(
           static_cast<nsMouseEvent_base*>(tmp->mEvent)->relatedTarget);
         break;
       case NS_DRAG_EVENT:
         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->dataTransfer");
@@ -727,16 +729,35 @@ nsDOMEvent::DuplicatePrivateData()
       mouseScrollEvent->relatedTarget = oldMouseScrollEvent->relatedTarget;
       mouseScrollEvent->button = oldMouseScrollEvent->button;
       mouseScrollEvent->buttons = oldMouseScrollEvent->buttons;
       static_cast<nsMouseEvent_base*>(mouseScrollEvent)->inputSource =
         static_cast<nsMouseEvent_base*>(oldMouseScrollEvent)->inputSource;
       newEvent = mouseScrollEvent;
       break;
     }
+    case NS_WHEEL_EVENT:
+    {
+      widget::WheelEvent* wheelEvent =
+        new widget::WheelEvent(false, msg, nullptr);
+      isInputEvent = true;
+      widget::WheelEvent* oldWheelEvent =
+        static_cast<widget::WheelEvent*>(mEvent);
+      wheelEvent->deltaX = oldWheelEvent->deltaX;
+      wheelEvent->deltaY = oldWheelEvent->deltaY;
+      wheelEvent->deltaZ = oldWheelEvent->deltaZ;
+      wheelEvent->deltaMode = oldWheelEvent->deltaMode;
+      wheelEvent->relatedTarget = oldWheelEvent->relatedTarget;
+      wheelEvent->button = oldWheelEvent->button;
+      wheelEvent->buttons = oldWheelEvent->buttons;
+      wheelEvent->modifiers = oldWheelEvent->modifiers;
+      wheelEvent->inputSource = oldWheelEvent->inputSource;
+      newEvent = wheelEvent;
+      break;
+    }
     case NS_SCROLLPORT_EVENT:
     {
       newEvent = new nsScrollPortEvent(false, msg, nullptr);
       NS_ENSURE_TRUE(newEvent, NS_ERROR_OUT_OF_MEMORY);
       static_cast<nsScrollPortEvent*>(newEvent)->orient =
         static_cast<nsScrollPortEvent*>(mEvent)->orient;
       break;
     }
@@ -1152,16 +1173,17 @@ nsDOMEvent::GetScreenCoords(nsPresContex
   if (nsEventStateManager::sIsPointerLocked) {
     return nsEventStateManager::sLastScreenPoint;
   }
 
   if (!aEvent || 
        (aEvent->eventStructType != NS_MOUSE_EVENT &&
         aEvent->eventStructType != NS_POPUP_EVENT &&
         aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+        aEvent->eventStructType != NS_WHEEL_EVENT &&
         aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
         aEvent->eventStructType != NS_TOUCH_EVENT &&
         aEvent->eventStructType != NS_DRAG_EVENT &&
         aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
     return nsIntPoint(0, 0);
   }
 
   nsGUIEvent* guiEvent = static_cast<nsGUIEvent*>(aEvent);
@@ -1211,16 +1233,17 @@ nsDOMEvent::GetClientCoords(nsPresContex
   if (nsEventStateManager::sIsPointerLocked) {
     return nsEventStateManager::sLastClientPoint;
   }
 
   if (!aEvent ||
       (aEvent->eventStructType != NS_MOUSE_EVENT &&
        aEvent->eventStructType != NS_POPUP_EVENT &&
        aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+       aEvent->eventStructType != NS_WHEEL_EVENT &&
        aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
        aEvent->eventStructType != NS_TOUCH_EVENT &&
        aEvent->eventStructType != NS_DRAG_EVENT &&
        aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
       !aPresContext ||
       !((nsGUIEvent*)aEvent)->widget) {
     return aDefaultPoint;
   }
@@ -1385,16 +1408,18 @@ const char* nsDOMEvent::GetEventName(PRU
   case NS_PAGE_SHOW:
     return sEventNames[eDOMEvents_pageshow];
   case NS_PAGE_HIDE:
     return sEventNames[eDOMEvents_pagehide];
   case NS_MOUSE_SCROLL:
     return sEventNames[eDOMEvents_DOMMouseScroll];
   case NS_MOUSE_PIXEL_SCROLL:
     return sEventNames[eDOMEvents_MozMousePixelScroll];
+  case NS_WHEEL_WHEEL:
+    return sEventNames[eDOMEvents_wheel];
   case NS_OFFLINE:
     return sEventNames[eDOMEvents_offline];
   case NS_ONLINE:
     return sEventNames[eDOMEvents_online];
   case NS_COPY:
     return sEventNames[eDOMEvents_copy];
   case NS_CUT:
     return sEventNames[eDOMEvents_cut];
--- a/content/events/src/nsDOMEvent.h
+++ b/content/events/src/nsDOMEvent.h
@@ -97,16 +97,17 @@ public:
     eDOMEvents_characterdatamodified,
     eDOMEvents_DOMActivate,
     eDOMEvents_DOMFocusIn,
     eDOMEvents_DOMFocusOut,
     eDOMEvents_pageshow,
     eDOMEvents_pagehide,
     eDOMEvents_DOMMouseScroll,
     eDOMEvents_MozMousePixelScroll,
+    eDOMEvents_wheel,
     eDOMEvents_offline,
     eDOMEvents_online,
     eDOMEvents_copy,
     eDOMEvents_cut,
     eDOMEvents_paste,
     eDOMEvents_open,
     eDOMEvents_message,
     eDOMEvents_show,
--- a/content/events/src/nsDOMMouseEvent.cpp
+++ b/content/events/src/nsDOMMouseEvent.cpp
@@ -80,16 +80,17 @@ nsDOMMouseEvent::InitMouseEvent(const ns
 {
   nsresult rv = nsDOMUIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
   NS_ENSURE_SUCCESS(rv, rv);
 
   switch(mEvent->eventStructType)
   {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
     case NS_MOZTOUCH_EVENT:
     {
        static_cast<nsMouseEvent_base*>(mEvent)->relatedTarget = aRelatedTarget;
        static_cast<nsMouseEvent_base*>(mEvent)->button = aButton;
        nsInputEvent* inputEvent = static_cast<nsInputEvent*>(mEvent);
        inputEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
@@ -134,16 +135,17 @@ nsDOMMouseEvent::InitMouseEvent(const ns
                                (modifiers & widget::MODIFIER_SHIFT) != 0,
                                (modifiers & widget::MODIFIER_META) != 0,
                                aButton, aRelatedTarget);
   NS_ENSURE_SUCCESS(rv, rv);
 
   switch(mEvent->eventStructType) {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
     case NS_MOZTOUCH_EVENT:
       static_cast<nsInputEvent*>(mEvent)->modifiers = modifiers;
       return NS_OK;
     default:
       MOZ_NOT_REACHED("There is no space to store the modifiers");
       return NS_ERROR_FAILURE;
@@ -162,16 +164,17 @@ nsDOMMouseEvent::InitFromCtor(const nsAS
                       d.clientX, d.clientY, 
                       d.ctrlKey, d.altKey, d.shiftKey, d.metaKey,
                       d.button, d.relatedTarget);
   NS_ENSURE_SUCCESS(rv, rv);
 
   switch(mEvent->eventStructType) {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
     case NS_MOZTOUCH_EVENT:
       static_cast<nsMouseEvent_base*>(mEvent)->buttons = d.buttons;
       break;
     default:
       break;
   }
@@ -201,16 +204,17 @@ nsDOMMouseEvent::InitNSMouseEvent(const 
 NS_IMETHODIMP
 nsDOMMouseEvent::GetButton(PRUint16* aButton)
 {
   NS_ENSURE_ARG_POINTER(aButton);
   switch(mEvent->eventStructType)
   {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
     case NS_MOZTOUCH_EVENT:
       *aButton = static_cast<nsMouseEvent_base*>(mEvent)->button;
       break;
     default:
       NS_WARNING("Tried to get mouse button for non-mouse event!");
       *aButton = nsMouseEvent::eLeftButton;
@@ -222,16 +226,17 @@ nsDOMMouseEvent::GetButton(PRUint16* aBu
 NS_IMETHODIMP
 nsDOMMouseEvent::GetButtons(PRUint16* aButtons)
 {
   NS_ENSURE_ARG_POINTER(aButtons);
   switch(mEvent->eventStructType)
   {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
     case NS_MOZTOUCH_EVENT:
       *aButtons = static_cast<nsMouseEvent_base*>(mEvent)->buttons;
       break;
     default:
       MOZ_NOT_REACHED("Tried to get mouse buttons for non-mouse event!");
       *aButtons = 0;
@@ -245,16 +250,17 @@ nsDOMMouseEvent::GetRelatedTarget(nsIDOM
 {
   NS_ENSURE_ARG_POINTER(aRelatedTarget);
   *aRelatedTarget = nullptr;
   nsISupports* relatedTarget = nullptr;
   switch(mEvent->eventStructType)
   {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
     case NS_MOZTOUCH_EVENT:
       relatedTarget = static_cast<nsMouseEvent_base*>(mEvent)->relatedTarget;
       break;
     default:
       break;
   }
--- a/content/events/src/nsDOMUIEvent.cpp
+++ b/content/events/src/nsDOMUIEvent.cpp
@@ -109,16 +109,17 @@ nsDOMUIEvent::GetMovementPoint()
     return mMovementPoint;
   }
 
   if (!mEvent ||
       !((nsGUIEvent*)mEvent)->widget ||
        (mEvent->eventStructType != NS_MOUSE_EVENT &&
         mEvent->eventStructType != NS_POPUP_EVENT &&
         mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+        mEvent->eventStructType != NS_WHEEL_EVENT &&
         mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
         mEvent->eventStructType != NS_DRAG_EVENT &&
         mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
     return nsIntPoint(0, 0);
   }
 
   // Calculate the delta between the last screen point and the current one.
   nsIntPoint current = DevPixelsToCSSPixels(mEvent->refPoint, mPresContext);
@@ -307,16 +308,17 @@ nsDOMUIEvent::SetCancelBubble(bool aCanc
 
 nsIntPoint
 nsDOMUIEvent::GetLayerPoint()
 {
   if (!mEvent ||
       (mEvent->eventStructType != NS_MOUSE_EVENT &&
        mEvent->eventStructType != NS_POPUP_EVENT &&
        mEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+       mEvent->eventStructType != NS_WHEEL_EVENT &&
        mEvent->eventStructType != NS_MOZTOUCH_EVENT &&
        mEvent->eventStructType != NS_TOUCH_EVENT &&
        mEvent->eventStructType != NS_DRAG_EVENT &&
        mEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
       !mPresContext ||
       mEventIsInternal) {
     return mLayerPoint;
   }
--- a/content/events/src/nsDOMUIEvent.h
+++ b/content/events/src/nsDOMUIEvent.h
@@ -34,16 +34,17 @@ public:
 
   static nsIntPoint CalculateScreenPoint(nsPresContext* aPresContext,
                                          nsEvent* aEvent)
   {
     if (!aEvent ||
         (aEvent->eventStructType != NS_MOUSE_EVENT &&
          aEvent->eventStructType != NS_POPUP_EVENT &&
          aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+         aEvent->eventStructType != NS_WHEEL_EVENT &&
          aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
          aEvent->eventStructType != NS_DRAG_EVENT &&
          aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
       return nsIntPoint(0, 0);
     }
 
     if (!((nsGUIEvent*)aEvent)->widget ) {
       return aEvent->refPoint;
@@ -59,16 +60,17 @@ public:
   static nsIntPoint CalculateClientPoint(nsPresContext* aPresContext,
                                          nsEvent* aEvent,
                                          nsIntPoint* aDefaultClientPoint)
   {
     if (!aEvent ||
         (aEvent->eventStructType != NS_MOUSE_EVENT &&
          aEvent->eventStructType != NS_POPUP_EVENT &&
          aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+         aEvent->eventStructType != NS_WHEEL_EVENT &&
          aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
          aEvent->eventStructType != NS_DRAG_EVENT &&
          aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
         !aPresContext ||
         !((nsGUIEvent*)aEvent)->widget) {
       return (nullptr == aDefaultClientPoint ? nsIntPoint(0, 0) :
         nsIntPoint(aDefaultClientPoint->x, aDefaultClientPoint->y));
     }
--- a/content/events/src/nsEventDispatcher.cpp
+++ b/content/events/src/nsEventDispatcher.cpp
@@ -17,16 +17,18 @@
 #include "nsINode.h"
 #include "nsPIDOMWindow.h"
 #include "nsFrameLoader.h"
 #include "nsDOMTouchEvent.h"
 #include "nsDOMStorage.h"
 #include "sampler.h"
 #include "GeneratedEvents.h"
 
+using namespace mozilla;
+
 #define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH  (1 << 0)
 #define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
 #define NS_TARGET_CHAIN_MAY_HAVE_MANAGER        (1 << 2)
 
 static nsEventTargetChainItem* gCachedETCI = nullptr;
 
 // nsEventTargetChainItem represents a single item in the event target chain.
 class nsEventTargetChainItem
@@ -729,16 +731,19 @@ nsEventDispatcher::CreateEvent(nsPresCon
         aDOMEvent, aPresContext, static_cast<nsCompositionEvent*>(aEvent));
     case NS_MOUSE_EVENT:
     case NS_POPUP_EVENT:
       return NS_NewDOMMouseEvent(aDOMEvent, aPresContext,
                                  static_cast<nsInputEvent*>(aEvent));
     case NS_MOUSE_SCROLL_EVENT:
       return NS_NewDOMMouseScrollEvent(aDOMEvent, aPresContext,
                                  static_cast<nsInputEvent*>(aEvent));
+    case NS_WHEEL_EVENT:
+      return NS_NewDOMWheelEvent(aDOMEvent, aPresContext,
+                                 static_cast<widget::WheelEvent*>(aEvent));
     case NS_DRAG_EVENT:
       return NS_NewDOMDragEvent(aDOMEvent, aPresContext,
                                  static_cast<nsDragEvent*>(aEvent));
     case NS_TEXT_EVENT:
       return NS_NewDOMTextEvent(aDOMEvent, aPresContext,
                                 static_cast<nsTextEvent*>(aEvent));
     case NS_SVG_EVENT:
       return NS_NewDOMSVGEvent(aDOMEvent, aPresContext,
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -1024,31 +1024,33 @@ nsEventStateManager::PreHandleEvent(nsPr
       "sIsPointerLocked is true. Drag events should be suppressed when the pointer is locked.");
   }
 #endif
   // Store last known screenPoint and clientPoint so pointer lock
   // can use these values as constants.
   if (NS_IS_TRUSTED_EVENT(aEvent) &&
       ((NS_IS_MOUSE_EVENT_STRUCT(aEvent) &&
        IsMouseEventReal(aEvent)) ||
-       aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT)) {
+       aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ||
+       aEvent->eventStructType == NS_WHEEL_EVENT)) {
     if (!sIsPointerLocked) {
       sLastScreenPoint = nsDOMUIEvent::CalculateScreenPoint(aPresContext, aEvent);
       sLastClientPoint = nsDOMUIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr);
     }
   }
 
   // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page
   // when user is not active doesn't change the state to active.
   if (NS_IS_TRUSTED_EVENT(aEvent) &&
       ((aEvent->eventStructType == NS_MOUSE_EVENT  &&
         IsMouseEventReal(aEvent) &&
         aEvent->message != NS_MOUSE_ENTER &&
         aEvent->message != NS_MOUSE_EXIT) ||
        aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ||
+       aEvent->eventStructType == NS_WHEEL_EVENT ||
        aEvent->eventStructType == NS_KEY_EVENT)) {
     if (gMouseOrKeyboardEventCounter == 0) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       if (obs) {
         obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
         UpdateUserActivityTimer();
       }
@@ -1658,16 +1660,20 @@ nsEventStateManager::DispatchCrossProces
   case NS_KEY_EVENT: {
     nsKeyEvent* keyEvent = static_cast<nsKeyEvent*>(aEvent);
     return remote->SendRealKeyEvent(*keyEvent);
   }
   case NS_MOUSE_SCROLL_EVENT: {
     nsMouseScrollEvent* scrollEvent = static_cast<nsMouseScrollEvent*>(aEvent);
     return remote->SendMouseScrollEvent(*scrollEvent);
   }
+  case NS_WHEEL_EVENT: {
+    widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(aEvent);
+    return remote->SendMouseWheelEvent(*wheelEvent);
+  }
   case NS_TOUCH_EVENT: {
     // Let the child process synthesize a mouse event if needed, and
     // ensure we don't synthesize one in this process.
     *aStatus = nsEventStatus_eConsumeNoDefault;
     nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(aEvent);
     return remote->SendRealTouchEvent(*touchEvent);
   }
   default: {
@@ -1706,16 +1712,17 @@ nsEventStateManager::IsRemoteTarget(nsIC
 }
 
 bool
 CrossProcessSafeEvent(const nsEvent& aEvent)
 {
   switch (aEvent.eventStructType) {
   case NS_KEY_EVENT:
   case NS_MOUSE_SCROLL_EVENT:
+  case NS_WHEEL_EVENT:
     return true;
   case NS_MOUSE_EVENT:
     switch (aEvent.message) {
     case NS_MOUSE_BUTTON_DOWN:
     case NS_MOUSE_BUTTON_UP:
     case NS_MOUSE_MOVE:
       return true;
     default:
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -79,16 +79,17 @@ MOCHITEST_FILES = \
 		empty.js \
 		test_bug689564.html \
 		test_bug698929.html \
 		test_eventctors.html \
 		test_bug635465.html \
 		test_bug741666.html \
 		test_dom_keyboard_event.html \
 		test_dom_mouse_event.html \
+		test_dom_wheel_event.html \
 		test_bug603008.html \
 		test_bug716822.html \
 		test_bug742376.html \
 		$(NULL)
 
 #bug 585630
 ifneq (mobile,$(MOZ_BUILD_APP))
 MOCHITEST_FILES += \
new file mode 100644
--- /dev/null
+++ b/content/events/test/test_dom_wheel_event.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for D3E WheelEvent</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests, window);
+
+function testMakingUntrustedEvent()
+{
+  const kCreateEventArgs = [
+    "WheelEvent", "wheelevent", "wheelEvent", "Wheelevent"
+  ];
+
+  for (var i = 0; i < kCreateEventArgs.length; i++) {
+    try {
+      // We never support WheelEvent construction with document.createEvent().
+      var event = document.createEvent(kCreateEventArgs[i]);
+      ok(false, "document.createEvent(" + kCreateEventArgs[i] + ") should throw an error");
+    } catch (e) {
+      ok(true, "document.createEvent(" + kCreateEventArgs[i] + ") threw an error");
+    }
+  }
+
+  var wheelEvent = new WheelEvent("wheel");
+  ok(wheelEvent instanceof WheelEvent,
+     "new WheelEvent() should create an instance of WheelEvent");
+  ok(typeof(wheelEvent.initWheelEvent) != "function",
+     "WheelEvent must not have initWheelEvent()");
+}
+
+function runTests()
+{
+  testMakingUntrustedEvent();
+  SimpleTest.finish();
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/events/test/test_eventctors.html
+++ b/content/events/test/test_eventctors.html
@@ -446,26 +446,26 @@ is(receivedEvent, e, "Wrong event!");
 
 // MouseEvent
 
 try {
   e = new MouseEvent();
 } catch(exp) {
   ex = true;
 }
-ok(ex, "First parameter is required!");
+ok(ex, "MouseEvent: First parameter is required!");
 ex = false;
 
 e = new MouseEvent("hello");
-ok(e.type, "hello", "Wrong event type!");
-ok(!e.isTrusted, "Event shouldn't be trusted!");
-ok(!e.bubbles, "Event shouldn't bubble!");
-ok(!e.cancelable, "Event shouldn't be cancelable!");
+ok(e.type, "hello", "MouseEvent: Wrong event type!");
+ok(!e.isTrusted, "MouseEvent: Event shouldn't be trusted!");
+ok(!e.bubbles, "MouseEvent: Event shouldn't bubble!");
+ok(!e.cancelable, "MouseEvent: Event shouldn't be cancelable!");
 document.dispatchEvent(e);
-is(receivedEvent, e, "Wrong event!");
+is(receivedEvent, e, "MouseEvent: Wrong event!");
 
 var mouseEventProps =
 [ { screenX: 0 },
   { screenY: 0 },
   { clientX: 0 },
   { clientY: 0 },
   { ctrlKey: false },
   { shiftKey: false },
@@ -489,29 +489,106 @@ var testProps =
   { button: 5 },
   { buttons: 6 },
   { relatedTarget: window }
 ];
 
 var defaultMouseEventValues = {};
 for (var i = 0; i < mouseEventProps.length; ++i) {
   for (prop in mouseEventProps[i]) {
-    ok(prop in e, "MouseEvent doesn't have property " + prop + "!");
+    ok(prop in e, "MouseEvent: MouseEvent doesn't have property " + prop + "!");
     defaultMouseEventValues[prop] = mouseEventProps[i][prop]; 
   }
 }
 
 while (testProps.length) {
   var p = testProps.shift();
   e = new MouseEvent("foo", p);
   for (var def in defaultMouseEventValues) {
     if (!(def in p)) {
-      is(e[def], defaultMouseEventValues[def], "Wrong default value for " + def + "!");
+      is(e[def], defaultMouseEventValues[def],
+         "MouseEvent: Wrong default value for " + def + "!");
     } else {
-      is(e[def], p[def], "Wrong event init value for " + def + "!");
+      is(e[def], p[def], "MouseEvent: Wrong event init value for " + def + "!");
+    }
+  }
+}
+
+// WheelEvent
+
+try {
+  e = new WheelEvent();
+} catch(exp) {
+  ex = true;
+}
+ok(ex, "WheelEvent: First parameter is required!");
+ex = false;
+
+e = new WheelEvent("hello");
+ok(e.type, "hello", "WheelEvent: Wrong event type!");
+ok(!e.isTrusted, "WheelEvent: Event shouldn't be trusted!");
+ok(!e.bubbles, "WheelEvent: Event shouldn't bubble!");
+ok(!e.cancelable, "WheelEvent: Event shouldn't be cancelable!");
+document.dispatchEvent(e);
+is(receivedEvent, e, "WheelEvent: Wrong event!");
+
+var wheelEventProps =
+[ { screenX: 0 },
+  { screenY: 0 },
+  { clientX: 0 },
+  { clientY: 0 },
+  { ctrlKey: false },
+  { shiftKey: false },
+  { altKey: false },
+  { metaKey: false },
+  { button: 0 },
+  { buttons: 0 },
+  { relatedTarget: null },
+  { deltaX: 0.0 },
+  { deltaY: 0.0 },
+  { deltaZ: 0.0 },
+  { deltaMode: 0 }
+];
+
+var testWheelProps =
+[
+  { screenX: 1 },
+  { screenY: 2 },
+  { clientX: 3 },
+  { clientY: 4 },
+  { ctrlKey: true },
+  { shiftKey: true },
+  { altKey: true },
+  { metaKey: true },
+  { button: 5 },
+  { buttons: 6 },
+  { relatedTarget: window },
+  { deltaX: 7.8 },
+  { deltaY: 9.1 },
+  { deltaZ: 2.3 },
+  { deltaMode: 4 }
+];
+
+var defaultWheelEventValues = {};
+for (var i = 0; i < wheelEventProps.length; ++i) {
+  for (prop in wheelEventProps[i]) {
+    ok(prop in e, "WheelEvent: WheelEvent doesn't have property " + prop + "!");
+    defaultWheelEventValues[prop] = wheelEventProps[i][prop]; 
+  }
+}
+
+while (testWheelProps.length) {
+  var p = testWheelProps.shift();
+  e = new WheelEvent("foo", p);
+  for (var def in defaultWheelEventValues) {
+    if (!(def in p)) {
+      is(e[def], defaultWheelEventValues[def],
+         "WheelEvent: Wrong default value for " + def + "!");
+    } else {
+      is(e[def], p[def], "WheelEvent: Wrong event init value for " + def + "!");
     }
   }
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/xbl/src/nsXBLEventHandler.cpp
+++ b/content/xbl/src/nsXBLEventHandler.cpp
@@ -146,16 +146,17 @@ nsresult
 NS_NewXBLEventHandler(nsXBLPrototypeHandler* aHandler,
                       nsIAtom* aEventType,
                       nsXBLEventHandler** aResult)
 {
   switch (nsContentUtils::GetEventCategory(nsDependentAtomString(aEventType))) {
     case NS_DRAG_EVENT:
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
       *aResult = new nsXBLMouseEventHandler(aHandler);
       break;
     default:
       *aResult = new nsXBLEventHandler(aHandler);
       break;
   }
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -194,16 +194,17 @@
 #include "nsIDOMComment.h"
 #include "nsIDOMCDATASection.h"
 #include "nsIDOMProcessingInstruction.h"
 #include "nsIDOMDataContainerEvent.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMCompositionEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "nsIDOMMouseScrollEvent.h"
+#include "nsIDOMWheelEvent.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIDOMCommandEvent.h"
 #include "nsIDOMPopupBlockedEvent.h"
 #include "nsIDOMBeforeUnloadEvent.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIDOMSmartCardEvent.h"
 #include "nsIDOMXULCommandEvent.h"
 #include "nsIDOMMessageEvent.h"
@@ -809,16 +810,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(MutationEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(UIEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MouseEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MouseScrollEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(WheelEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DragEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(KeyboardEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CompositionEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(PopupBlockedEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1744,16 +1747,17 @@ NS_DEFINE_CONTRACT_CTOR(MozActivity, NS_
     nsresult rv = NS_NewDOM##_class(&e, nullptr, nullptr);    \
     *aInstancePtrResult = e;                                \
     return rv;                                              \
   }
 
 NS_DEFINE_EVENT_CTOR(Event)
 NS_DEFINE_EVENT_CTOR(UIEvent)
 NS_DEFINE_EVENT_CTOR(MouseEvent)
+NS_DEFINE_EVENT_CTOR(WheelEvent)
 #ifdef MOZ_B2G_RIL
 NS_DEFINE_EVENT_CTOR(MozWifiStatusChangeEvent)
 NS_DEFINE_EVENT_CTOR(MozWifiConnectionInfoEvent)
 #endif
 
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CTOR(_event_interface)
@@ -1782,16 +1786,17 @@ struct nsConstructorFuncMapData
 static const nsConstructorFuncMapData kConstructorFuncMap[] =
 {
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, nsDOMMultipartFile::NewBlob)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMFileFile::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozBlobBuilder, NS_NewBlobBuilder)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(Event)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(UIEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MouseEvent)
+  NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(WheelEvent)
 #ifdef MOZ_B2G_RIL
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiStatusChangeEvent)
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(MozWifiConnectionInfoEvent)
 #endif
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) \
   NS_DEFINE_EVENT_CONSTRUCTOR_FUNC_DATA(_event_interface)
 #include "GeneratedEvents.h"
@@ -2652,16 +2657,22 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MouseScrollEvent, nsIDOMMouseScrollEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMouseScrollEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMouseEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN(WheelEvent, nsIDOMWheelEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMWheelEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMouseEvent)
+    DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN(DragEvent, nsIDOMDragEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDragEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMouseEvent)
     DOM_CLASSINFO_UI_EVENT_MAP_ENTRIES
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -34,16 +34,17 @@ DOMCI_CLASS(NodeList)
 DOMCI_CLASS(NamedNodeMap)
 
 // Event classes
 DOMCI_CLASS(Event)
 DOMCI_CLASS(MutationEvent)
 DOMCI_CLASS(UIEvent)
 DOMCI_CLASS(MouseEvent)
 DOMCI_CLASS(MouseScrollEvent)
+DOMCI_CLASS(WheelEvent)
 DOMCI_CLASS(DragEvent)
 DOMCI_CLASS(KeyboardEvent)
 DOMCI_CLASS(CompositionEvent)
 DOMCI_CLASS(PopupBlockedEvent)
 #define MOZ_GENERATED_EVENT_LIST
 #define MOZ_GENERATED_EVENT(_event_interface) DOMCI_CLASS(_event_interface)
 #include "GeneratedEvents.h"
 #undef MOZ_GENERATED_EVENT_LIST
--- a/dom/interfaces/events/Makefile.in
+++ b/dom/interfaces/events/Makefile.in
@@ -52,12 +52,13 @@ XPIDLSRCS =					\
 	nsIDOMTransitionEvent.idl		\
 	nsIDOMAnimationEvent.idl		\
 	nsIDOMPopStateEvent.idl			\
 	nsIDOMCloseEvent.idl			\
 	nsIDOMTouchEvent.idl			\
 	nsIDOMHashChangeEvent.idl		\
 	nsIDOMCustomEvent.idl			\
 	nsIDOMCompositionEvent.idl		\
+	nsIDOMWheelEvent.idl			\
 	nsIWifiEventInits.idl \
 	$(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/interfaces/events/nsIDOMEvent.idl
+++ b/dom/interfaces/events/nsIDOMEvent.idl
@@ -17,16 +17,21 @@ interface nsIDOMEventTarget;
 
 class nsEvent;
 class nsCommandEvent;
 class nsPresContext;
 class nsInvalidateRequestList;
 namespace IPC {
 class Message;
 }
+namespace mozilla {
+namespace widget {
+class WheelEvent;
+} // namespace widget
+} // namespace mozilla
 %}
 
 /**
  * The nsIDOMEvent interface is the primary datatype for all events in
  * the Document Object Model.
  *
  * For more information on this interface please see 
  * http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html and
@@ -262,16 +267,18 @@ nsresult
 NS_NewDOMDataContainerEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent *aEvent);
 nsresult
 NS_NewDOMUIEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsGUIEvent *aEvent);
 nsresult
 NS_NewDOMMouseEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent);
 nsresult
 NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent);
 nsresult
+NS_NewDOMWheelEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, mozilla::widget::WheelEvent *aEvent);
+nsresult
 NS_NewDOMDragEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsDragEvent *aEvent);
 nsresult
 NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsKeyEvent *aEvent);
 nsresult
 NS_NewDOMCompositionEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsCompositionEvent *aEvent);
 nsresult
 NS_NewDOMMutationEvent(nsIDOMEvent** aResult, nsPresContext* aPresContext, class nsMutationEvent* aEvent);
 nsresult
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/events/nsIDOMWheelEvent.idl
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 "nsIDOMMouseEvent.idl"
+
+[scriptable, builtinclass, uuid(5b689c9c-ce82-4836-bb7b-f2fa0c3d2f32)]
+interface nsIDOMWheelEvent : nsIDOMMouseEvent
+{
+  const unsigned long DOM_DELTA_PIXEL = 0x00;
+  const unsigned long DOM_DELTA_LINE  = 0x01;
+  const unsigned long DOM_DELTA_PAGE  = 0x02;
+
+  // Note that DOM Level 3 Events defines the type of delta values as float.
+  // However, we should use double for them.  Javascript engine always uses
+  // double even if interface attributes are float.  If we defined them
+  // as float, that would cause error at casting from float to double.
+  // E.g., following function may return false if the deltaX is float:
+  //
+  // function () {
+  //   var event = new WheelEvent("wheel", { deltaX: 0.1 });
+  //   return (event.deltaX == 0.1);
+  // }
+
+  readonly attribute double        deltaX;
+  readonly attribute double        deltaY;
+  readonly attribute double        deltaZ;
+  readonly attribute unsigned long deltaMode;
+
+  [noscript] void initWheelEvent(in DOMString typeArg,
+                                 in boolean canBubbleArg,
+                                 in boolean cancelableArg,
+                                 in nsIDOMWindow viewArg,
+                                 in long detailArg,
+                                 in long screenXArg,
+                                 in long screenYArg,
+                                 in long clientXArg,
+                                 in long clientYArg,
+                                 in unsigned short buttonArg,
+                                 in nsIDOMEventTarget relatedTargetArg,
+                                 in DOMString modifiersListArg,
+                                 in double deltaXArg,
+                                 in double deltaYArg,
+                                 in double deltaZArg,
+                                 in unsigned long deltaMode);
+};
+
+dictionary WheelEventInit : MouseEventInit
+{
+  double deltaX;
+  double deltaY;
+  double deltaZ;
+  unsigned long deltaMode;
+};
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -37,16 +37,17 @@ using nscolor;
 using nsCompositionEvent;
 using nsIMEUpdatePreference;
 using nsIntPoint;
 using nsIntRect;
 using nsIntSize;
 using nsKeyEvent;
 using nsMouseEvent;
 using nsMouseScrollEvent;
+using mozilla::widget::WheelEvent;
 using nsQueryContentEvent;
 using nsRect;
 using nsSelectionEvent;
 using nsTextEvent;
 using nsTouchEvent;
 using RemoteDOMEvent;
 
 namespace mozilla {
@@ -301,16 +302,17 @@ child:
                PRInt32 aButton,
                PRInt32 aClickCount,
                PRInt32 aModifiers,
                bool aIgnoreRootScrollFrame);
 
     RealMouseEvent(nsMouseEvent event);
     RealKeyEvent(nsKeyEvent event);
     MouseScrollEvent(nsMouseScrollEvent event);
+    MouseWheelEvent(WheelEvent event);
     RealTouchEvent(nsTouchEvent event);
 
     /**
      * @see nsIDOMWindowUtils sendKeyEvent.
      */
     KeyEvent(nsString aType,
              PRInt32 aKeyCode,
              PRInt32 aCharCode,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -67,16 +67,17 @@
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::indexedDB;
+using namespace mozilla::widget;
 
 NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener)
 
 NS_IMETHODIMP
 ContentListener::HandleEvent(nsIDOMEvent* aEvent)
 {
   RemoteDOMEvent remoteEvent;
   remoteEvent.mEvent = do_QueryInterface(aEvent);
@@ -825,16 +826,24 @@ bool
 TabChild::RecvMouseScrollEvent(const nsMouseScrollEvent& event)
 {
   nsMouseScrollEvent localEvent(event);
   DispatchWidgetEvent(localEvent);
   return true;
 }
 
 bool
+TabChild::RecvMouseWheelEvent(const WheelEvent& event)
+{
+  WheelEvent localEvent(event);
+  DispatchWidgetEvent(localEvent);
+  return true;
+}
+
+bool
 TabChild::RecvRealTouchEvent(const nsTouchEvent& aEvent)
 {
     nsTouchEvent localEvent(aEvent);
     nsEventStatus status = DispatchWidgetEvent(localEvent);
     if (status == nsEventStatus_eConsumeNoDefault) {
         return true;
     }
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -184,16 +184,17 @@ public:
                                 const float&    aY,
                                 const PRInt32&  aButton,
                                 const PRInt32&  aClickCount,
                                 const PRInt32&  aModifiers,
                                 const bool&     aIgnoreRootScrollFrame);
     virtual bool RecvRealMouseEvent(const nsMouseEvent& event);
     virtual bool RecvRealKeyEvent(const nsKeyEvent& event);
     virtual bool RecvMouseScrollEvent(const nsMouseScrollEvent& event);
+    virtual bool RecvMouseWheelEvent(const mozilla::widget::WheelEvent& event);
     virtual bool RecvRealTouchEvent(const nsTouchEvent& event);
     virtual bool RecvKeyEvent(const nsString& aType,
                               const PRInt32&  aKeyCode,
                               const PRInt32&  aCharCode,
                               const PRInt32&  aModifiers,
                               const bool&     aPreventDefault);
     virtual bool RecvCompositionEvent(const nsCompositionEvent& event);
     virtual bool RecvTextEvent(const nsTextEvent& event);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -342,16 +342,23 @@ bool TabParent::SendRealMouseEvent(nsMou
 
 bool TabParent::SendMouseScrollEvent(nsMouseScrollEvent& event)
 {
   nsMouseScrollEvent e(event);
   MaybeForwardEventToRenderFrame(event, &e);
   return PBrowserParent::SendMouseScrollEvent(e);
 }
 
+bool TabParent::SendMouseWheelEvent(WheelEvent& event)
+{
+  WheelEvent e(event);
+  MaybeForwardEventToRenderFrame(event, &e);
+  return PBrowserParent::SendMouseWheelEvent(event);
+}
+
 bool TabParent::SendRealKeyEvent(nsKeyEvent& event)
 {
   nsKeyEvent e(event);
   MaybeForwardEventToRenderFrame(event, &e);
   return PBrowserParent::SendRealKeyEvent(e);
 }
 
 bool TabParent::SendRealTouchEvent(nsTouchEvent& event)
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -139,16 +139,17 @@ public:
     void SendMouseEvent(const nsAString& aType, float aX, float aY,
                         PRInt32 aButton, PRInt32 aClickCount,
                         PRInt32 aModifiers, bool aIgnoreRootScrollFrame);
     void SendKeyEvent(const nsAString& aType, PRInt32 aKeyCode,
                       PRInt32 aCharCode, PRInt32 aModifiers,
                       bool aPreventDefault);
     bool SendRealMouseEvent(nsMouseEvent& event);
     bool SendMouseScrollEvent(nsMouseScrollEvent& event);
+    bool SendMouseWheelEvent(mozilla::widget::WheelEvent& event);
     bool SendRealKeyEvent(nsKeyEvent& event);
     bool SendRealTouchEvent(nsTouchEvent& event);
 
     virtual PDocumentRendererParent*
     AllocPDocumentRenderer(const nsRect& documentRect, const gfxMatrix& transform,
                            const nsString& bgcolor,
                            const PRUint32& renderFlags, const bool& flushLayout,
                            const nsIntSize& renderSize);
--- a/js/xpconnect/src/dictionary_helper_gen.conf
+++ b/js/xpconnect/src/dictionary_helper_gen.conf
@@ -2,16 +2,17 @@
 # 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/.
 
 # Dictionary interface name, interface file name
 dictionaries = [
      [ 'EventInit', 'nsIDOMEvent.idl' ],
      [ 'UIEventInit', 'nsIDOMUIEvent.idl' ],
      [ 'MouseEventInit', 'nsIDOMMouseEvent.idl' ],
+     [ 'WheelEventInit', 'nsIDOMWheelEvent.idl' ],
      [ 'IDBObjectStoreParameters', 'nsIIDBDatabase.idl' ],
      [ 'IDBIndexParameters', 'nsIIDBObjectStore.idl' ],
      [ 'BlobPropertyBag', 'nsIDOMFile.idl' ],
      [ 'MutationObserverInit', 'nsIDOMMutationObserver.idl' ],
      [ 'WifiConnectionInfoEventInit', 'nsIWifiEventInits.idl' ],
      [ 'WifiStatusChangeEventInit', 'nsIWifiEventInits.idl' ],
      [ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ],
      [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1019,16 +1019,17 @@ nsLayoutUtils::GetDOMEventCoordinatesRel
   return GetEventCoordinatesRelativeTo(event, aFrame);
 }
 
 nsPoint
 nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aFrame)
 {
   if (!aEvent || (aEvent->eventStructType != NS_MOUSE_EVENT &&
                   aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
+                  aEvent->eventStructType != NS_WHEEL_EVENT &&
                   aEvent->eventStructType != NS_DRAG_EVENT &&
                   aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT &&
                   aEvent->eventStructType != NS_GESTURENOTIFY_EVENT &&
                   aEvent->eventStructType != NS_MOZTOUCH_EVENT &&
                   aEvent->eventStructType != NS_TOUCH_EVENT &&
                   aEvent->eventStructType != NS_QUERY_CONTENT_EVENT))
     return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
 
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -5640,18 +5640,20 @@ PresShell::HandleEvent(nsIFrame        *
 #endif
 
   if (!nsContentUtils::IsSafeToRunScript())
     return NS_OK;
 
   NS_TIME_FUNCTION_MIN(1.0);
 
   nsIContent* capturingContent =
-    NS_IS_MOUSE_EVENT(aEvent) || aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ?
-      GetCapturingContent() : nullptr;
+    NS_IS_MOUSE_EVENT(aEvent) ||
+      aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ||
+      aEvent->eventStructType == NS_WHEEL_EVENT ?
+        GetCapturingContent() : nullptr;
 
   nsCOMPtr<nsIDocument> retargetEventDoc;
   if (!aDontRetargetEvents) {
     // key and IME related events should not cross top level window boundary.
     // Basically, such input events should be fired only on focused widget.
     // However, some IMEs might need to clean up composition after focused
     // window is deactivated.  And also some tests on MozMill want to test key
     // handling on deactivated window because MozMill window can be activated
--- a/layout/xul/base/src/nsXULPopupManager.cpp
+++ b/layout/xul/base/src/nsXULPopupManager.cpp
@@ -431,17 +431,18 @@ nsXULPopupManager::InitTriggerEvent(nsID
         if (presShell && (presContext = presShell->GetPresContext())) {
           nsPresContext* rootDocPresContext =
             presContext->GetRootPresContext();
           if (!rootDocPresContext)
             return;
           nsIFrame* rootDocumentRootFrame = rootDocPresContext->
               PresShell()->FrameManager()->GetRootFrame();
           if ((event->eventStructType == NS_MOUSE_EVENT || 
-               event->eventStructType == NS_MOUSE_SCROLL_EVENT) &&
+               event->eventStructType == NS_MOUSE_SCROLL_EVENT ||
+               event->eventStructType == NS_WHEEL_EVENT) &&
                !(static_cast<nsGUIEvent *>(event))->widget) {
             // no widget, so just use the client point if available
             nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
             nsIntPoint clientPt;
             mouseEvent->GetClientX(&clientPt.x);
             mouseEvent->GetClientY(&clientPt.y);
 
             // XXX this doesn't handle IFRAMEs in transforms
--- a/widget/gtk2/nsGtkKeyUtils.cpp
+++ b/widget/gtk2/nsGtkKeyUtils.cpp
@@ -613,16 +613,17 @@ KeymapWrapper::InitInputEvent(nsInputEve
          GetBoolName(aInputEvent.modifiers & MODIFIER_ALTGRAPH),
          GetBoolName(aInputEvent.modifiers & MODIFIER_CAPSLOCK),
          GetBoolName(aInputEvent.modifiers & MODIFIER_NUMLOCK),
          GetBoolName(aInputEvent.modifiers & MODIFIER_SCROLLLOCK)));
 
     switch(aInputEvent.eventStructType) {
         case NS_MOUSE_EVENT:
         case NS_MOUSE_SCROLL_EVENT:
+        case NS_WHEEL_EVENT:
         case NS_DRAG_EVENT:
         case NS_SIMPLE_GESTURE_EVENT:
         case NS_MOZTOUCH_EVENT:
             break;
         default:
             return;
     }
 
--- a/widget/nsEvent.h
+++ b/widget/nsEvent.h
@@ -80,16 +80,18 @@ class nsSimpleGestureEvent;
 class nsTransitionEvent;
 class nsAnimationEvent;
 class nsUIStateChangeEvent;
 class nsPluginEvent;
 
 namespace mozilla {
 namespace widget {
 
+class WheelEvent;
+
 // All modifier keys should be defined here.  This is used for managing
 // modifier states for DOM Level 3 or later.
 enum Modifier {
   MODIFIER_ALT        = 0x0001,
   MODIFIER_ALTGRAPH   = 0x0002,
   MODIFIER_CAPSLOCK   = 0x0004,
   MODIFIER_CONTROL    = 0x0008,
   MODIFIER_FN         = 0x0010,
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -11,16 +11,17 @@
 #include "nsRect.h"
 #include "nsRegion.h"
 #include "nsEvent.h"
 #include "nsStringGlue.h"
 #include "nsCOMPtr.h"
 #include "nsIAtom.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIDOMMouseEvent.h"
+#include "nsIDOMWheelEvent.h"
 #include "nsIDOMDataTransfer.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMTouchEvent.h"
 #include "nsWeakPtr.h"
 #include "nsIWidget.h"
 #include "nsTArray.h"
 #include "nsTraceRefcnt.h"
 #include "nsITransferable.h"
@@ -87,16 +88,17 @@ class nsHashKey;
 #define NS_SIMPLE_GESTURE_EVENT           37
 #define NS_SELECTION_EVENT                38
 #define NS_CONTENT_COMMAND_EVENT          39
 #define NS_GESTURENOTIFY_EVENT            40
 #define NS_UISTATECHANGE_EVENT            41
 #define NS_MOZTOUCH_EVENT                 42
 #define NS_PLUGIN_EVENT                   43
 #define NS_TOUCH_EVENT                    44
+#define NS_WHEEL_EVENT                    45
 
 // These flags are sort of a mess. They're sort of shared between event
 // listener flags and event flags, but only some of them. You've been
 // warned!
 #define NS_EVENT_FLAG_NONE                0x0000
 #define NS_EVENT_FLAG_TRUSTED             0x0001
 #define NS_EVENT_FLAG_BUBBLE              0x0002
 #define NS_EVENT_FLAG_CAPTURE             0x0004
@@ -532,16 +534,19 @@ class nsHashKey;
 #define NS_TOUCH_LEAVE               (NS_TOUCH_EVENT_START+4)
 #define NS_TOUCH_CANCEL              (NS_TOUCH_EVENT_START+5)
 
 // Pointerlock DOM API
 #define NS_POINTERLOCK_START         5300
 #define NS_POINTERLOCKCHANGE         (NS_POINTERLOCK_START)
 #define NS_POINTERLOCKERROR          (NS_POINTERLOCK_START + 1)
 
+#define NS_WHEEL_EVENT_START         5400
+#define NS_WHEEL_WHEEL               (NS_WHEEL_EVENT_START)
+
 /**
  * Return status for event processors, nsEventStatus, is defined in
  * nsEvent.h.
  */
 
 /**
  * different types of (top-level) window z-level positioning
  */
@@ -1376,16 +1381,52 @@ public:
   {
   }
 
   PRInt32               scrollFlags;
   PRInt32               delta;
   PRInt32               scrollOverflow;
 };
 
+/**
+ * WheelEvent is used only for DOM Level 3 WheelEvent (dom::DOMWheelEvent).
+ */
+
+namespace mozilla {
+namespace widget {
+
+class WheelEvent : public nsMouseEvent_base
+{
+private:
+  friend class mozilla::dom::PBrowserParent;
+  friend class mozilla::dom::PBrowserChild;
+
+  WheelEvent()
+  {
+  }
+
+public:
+  WheelEvent(bool aIsTrusted, PRUint32 aMessage, nsIWidget* aWidget) :
+    nsMouseEvent_base(aIsTrusted, aMessage, aWidget, NS_WHEEL_EVENT),
+    deltaX(0.0), deltaY(0.0), deltaZ(0.0),
+    deltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL)
+  {
+  }
+
+  double deltaX;
+  double deltaY;
+  double deltaZ;
+
+  // Should be one of nsIDOMWheelEvent::DOM_DELTA_*
+  PRUint32 deltaMode;
+};
+
+} // namespace widget
+} // namespace mozilla
+
 /*
  * Gesture Notify Event:
  *
  * This event is the first event generated when the user touches
  * the screen with a finger, and it's meant to decide what kind
  * of action we'll use for that touch interaction.
  *
  * The event is dispatched to the layout and based on what is underneath
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -112,16 +112,39 @@ struct ParamTraits<nsMouseScrollEvent>
   {
     return ReadParam(aMsg, aIter, static_cast<nsMouseEvent_base*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->scrollFlags) &&
            ReadParam(aMsg, aIter, &aResult->delta) &&
            ReadParam(aMsg, aIter, &aResult->scrollOverflow);
   }
 };
 
+template<>
+struct ParamTraits<mozilla::widget::WheelEvent>
+{
+  typedef mozilla::widget::WheelEvent paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, static_cast<nsMouseEvent_base>(aParam));
+    WriteParam(aMsg, aParam.deltaX);
+    WriteParam(aMsg, aParam.deltaY);
+    WriteParam(aMsg, aParam.deltaZ);
+    WriteParam(aMsg, aParam.deltaMode);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return ReadParam(aMsg, aIter, static_cast<nsMouseEvent_base*>(aResult)) &&
+           ReadParam(aMsg, aIter, &aResult->deltaX) &&
+           ReadParam(aMsg, aIter, &aResult->deltaY) &&
+           ReadParam(aMsg, aIter, &aResult->deltaZ) &&
+           ReadParam(aMsg, aIter, &aResult->deltaMode);
+  }
+};
 
 template<>
 struct ParamTraits<nsMouseEvent>
 {
   typedef nsMouseEvent paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -110,16 +110,17 @@ ModifierKeyState::Update()
 void
 ModifierKeyState::InitInputEvent(nsInputEvent& aInputEvent) const
 {
   aInputEvent.modifiers = mModifiers;
 
   switch(aInputEvent.eventStructType) {
     case NS_MOUSE_EVENT:
     case NS_MOUSE_SCROLL_EVENT:
+    case NS_WHEEL_EVENT:
     case NS_DRAG_EVENT:
     case NS_SIMPLE_GESTURE_EVENT:
     case NS_MOZTOUCH_EVENT:
       InitMouseEvent(aInputEvent);
       break;
   }
 }