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 102063 61d8207c4fa3b31c9823661980daa47136ebf8eb
parent 102062 28aa0856c08eed1bb26eeb0571120b01075d8976
child 102064 d1f62bfbc5e4772f2b4ab621e2266af102e3c287
push id1001
push userttaubert@mozilla.com
push dateTue, 14 Aug 2012 04:19:19 +0000
treeherderfx-team@22288130fea2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, jst
bugs719320
milestone17.0a1
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;
   }
 }