Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Mon, 13 Aug 2012 13:40:42 -0700
changeset 106677 22fe5c9f4433b25951d0471f44f1cf82f43b26c8
parent 106676 6c3ea389b47e3b620d343c3b7d9f051c0282fa27 (current diff)
parent 102211 75cdb3f932c629a06f811404fb1ff1322610a6be (diff)
child 106678 a8235a2a29c290f49f8f4c96bba193e26d6727c5
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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
Merge from mozilla-central.
accessible/src/base/nsARIAMap.cpp
accessible/src/base/nsARIAMap.h
accessible/src/generic/Accessible.cpp
browser/app/profile/firefox.js
browser/devtools/highlighter/test/browser_inspector_scrolling.js
build/mobile/robocop/Actions.java.in
configure.in
content/base/src/Makefile.in
content/base/src/nsContentIterator.cpp
content/base/src/nsDOMParser.h
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsGkAtomList.h
content/base/src/nsSyncLoadService.cpp
content/base/src/nsXMLHttpRequest.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/events/public/nsEventNameList.h
content/events/src/nsDOMEvent.cpp
content/events/src/nsDOMEvent.h
content/events/src/nsDOMMouseEvent.cpp
content/events/src/nsDOMMouseScrollEvent.cpp
content/events/src/nsDOMTouchEvent.h
content/events/src/nsDOMUIEvent.cpp
content/events/src/nsDOMUIEvent.h
content/events/src/nsEventDispatcher.cpp
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
content/events/test/Makefile.in
content/events/test/test_bug350471.xul
content/html/content/src/nsHTMLAudioElement.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
content/html/content/src/nsHTMLMediaElement.cpp
content/media/MediaResource.cpp
content/media/nsAudioStream.cpp
content/media/nsAudioStream.h
content/media/nsBuiltinDecoderReader.h
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/ogg/nsOggCodecState.cpp
content/media/ogg/nsOggCodecState.h
content/media/ogg/nsOggReader.cpp
content/svg/content/src/Makefile.in
content/xbl/src/nsXBLEventHandler.cpp
content/xml/document/src/nsXMLPrettyPrinter.cpp
content/xml/document/src/nsXMLPrettyPrinter.h
content/xslt/src/xpath/nsXPathEvaluator.cpp
content/xslt/src/xpath/txXPCOMExtensionFunction.cpp
content/xslt/src/xslt/txStylesheetCompiler.cpp
content/xul/document/src/nsXULPrototypeCache.cpp
docshell/base/nsDocShell.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfoClasses.h
dom/base/nsDOMWindowUtils.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsJSEnvironment.cpp
dom/base/nsPIDOMWindow.h
dom/indexedDB/IndexedDatabaseManager.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/ipc/AudioParent.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/plugins/ipc/PluginInstanceParent.cpp
dom/src/json/nsJSON.cpp
dom/workers/WorkerPrivate.cpp
editor/libeditor/base/nsEditRules.h
editor/libeditor/base/nsEditor.cpp
editor/libeditor/base/nsEditor.h
editor/libeditor/base/nsEditorUtils.h
editor/libeditor/html/nsHTMLAbsPosition.cpp
editor/libeditor/html/nsHTMLDataTransfer.cpp
editor/libeditor/html/nsHTMLEditRules.cpp
editor/libeditor/html/nsHTMLEditRules.h
editor/libeditor/html/nsHTMLEditor.cpp
editor/libeditor/html/nsHTMLEditor.h
editor/libeditor/html/nsHTMLEditorStyle.cpp
editor/libeditor/html/nsTableEditor.cpp
editor/libeditor/text/nsPlaintextEditor.cpp
editor/libeditor/text/nsPlaintextEditor.h
editor/libeditor/text/nsTextEditRules.cpp
editor/libeditor/text/nsTextEditRules.h
embedding/components/windowwatcher/src/nsWindowWatcher.cpp
embedding/components/windowwatcher/src/nsWindowWatcher.h
extensions/gio/nsGIOProtocolHandler.cpp
extensions/gnomevfs/nsGnomeVFSProtocolHandler.cpp
extensions/pref/autoconfig/src/nsReadConfig.cpp
extensions/spellcheck/src/mozInlineSpellChecker.cpp
extensions/spellcheck/src/mozInlineSpellChecker.h
extensions/widgetutils/src/nsWidgetUtils.cpp
gfx/layers/Layers.h
gfx/layers/basic/BasicLayerManager.cpp
gfx/layers/basic/BasicLayers.h
gfx/layers/basic/BasicThebesLayer.cpp
gfx/layers/d3d10/ContainerLayerD3D10.cpp
gfx/layers/d3d10/LayerManagerD3D10.cpp
gfx/layers/d3d10/LayerManagerD3D10.h
gfx/layers/d3d9/CanvasLayerD3D9.cpp
gfx/layers/d3d9/ContainerLayerD3D9.cpp
gfx/layers/d3d9/ImageLayerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.cpp
gfx/layers/d3d9/LayerManagerD3D9.h
gfx/layers/d3d9/ThebesLayerD3D9.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/thebes/gfxASurface.cpp
image/encoders/bmp/nsBMPEncoder.cpp
image/encoders/ico/nsICOEncoder.cpp
image/encoders/jpeg/nsJPEGEncoder.cpp
image/encoders/png/nsPNGEncoder.cpp
image/src/imgTools.cpp
js/src/builtin/Eval.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/ion/CodeGenerator.cpp
js/src/ion/IonCaches.cpp
js/src/ion/IonCaches.h
js/src/jsapi-tests/testProfileStrings.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsatom.cpp
js/src/jsbool.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/json.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsprobes.cpp
js/src/jsprobes.h
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jsreflect.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/jsxml.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/SPSProfiler.cpp
js/src/vm/SPSProfiler.h
js/src/vm/ScopeObject.cpp
js/src/vm/Stack.cpp
js/xpconnect/idl/xpccomponents.idl
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
layout/base/FrameLayerBuilder.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsChangeHint.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsIPresShell.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/base/nsPresShell.cpp
layout/base/nsPresShell.h
layout/base/nsRefreshDriver.cpp
layout/generic/nsFrame.cpp
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIFrame.h
layout/generic/nsIScrollableFrame.h
layout/generic/nsObjectFrame.cpp
layout/generic/nsPlaceholderFrame.cpp
layout/mathml/nsMathMLChar.cpp
layout/mathml/nsMathMLChar.h
layout/reftests/reftest.list
layout/style/nsFontFaceLoader.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleStruct.cpp
layout/svg/base/src/nsSVGGeometryFrame.cpp
layout/svg/base/src/nsSVGGeometryFrame.h
layout/svg/base/src/nsSVGGlyphFrame.cpp
layout/svg/base/src/nsSVGPathGeometryFrame.cpp
layout/svg/base/src/nsSVGUtils.cpp
layout/svg/base/src/nsSVGUtils.h
layout/tools/reftest/reftest.js
layout/tools/reftest/remotereftest.py
layout/xul/base/src/nsScrollBoxObject.cpp
layout/xul/base/src/nsXULPopupManager.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/Makefile.in
modules/libjar/nsJAR.cpp
modules/libjar/nsJARChannel.cpp
modules/libjar/nsJARInputStream.cpp
modules/libpref/src/Preferences.cpp
modules/libpref/src/init/all.js
netwerk/base/public/nsNetUtil.h
netwerk/base/src/nsBaseContentStream.cpp
netwerk/base/src/nsBufferedStreams.cpp
netwerk/base/src/nsDirectoryIndexStream.cpp
netwerk/base/src/nsFileStreams.cpp
netwerk/base/src/nsFileStreams.h
netwerk/base/src/nsInputStreamChannel.cpp
netwerk/base/src/nsInputStreamPump.cpp
netwerk/base/src/nsMIMEInputStream.cpp
netwerk/base/src/nsPreloadedStream.cpp
netwerk/base/src/nsSocketTransport2.cpp
netwerk/base/src/nsStreamTransportService.cpp
netwerk/base/src/nsSyncStreamListener.cpp
netwerk/cache/nsCacheEntryDescriptor.cpp
netwerk/cache/nsDiskCacheStreams.cpp
netwerk/protocol/file/nsFileChannel.cpp
netwerk/protocol/ftp/nsFtpConnectionThread.cpp
netwerk/protocol/ftp/nsFtpConnectionThread.h
netwerk/protocol/ftp/nsFtpControlConnection.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/SpdySession2.cpp
netwerk/protocol/http/SpdySession3.cpp
netwerk/protocol/http/nsAHttpTransaction.h
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpPipeline.cpp
netwerk/protocol/http/nsHttpTransaction.cpp
netwerk/protocol/http/nsHttpTransaction.h
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/streamconv/converters/nsFTPDirListingConv.cpp
parser/xml/src/nsSAXXMLReader.cpp
rdf/base/src/nsRDFXMLDataSource.cpp
security/manager/ssl/src/nsNSSComponent.cpp
services/sync/modules/service.js
services/sync/tests/unit/xpcshell.ini
startupcache/StartupCacheUtils.cpp
testing/mochitest/runtests.py
testing/mochitest/tests/SimpleTest/setup.js
testing/testsuite-targets.mk
toolkit/components/places/nsFaviconService.cpp
toolkit/components/startup/nsAppStartup.cpp
toolkit/mozapps/installer/packager.mk
view/src/nsViewManager.cpp
view/src/nsViewManager.h
widget/android/nsWindow.cpp
widget/android/nsWindow.h
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/gtk2/nsWindow.cpp
widget/nsGUIEvent.h
widget/nsIWidget.h
widget/os2/nsWindow.cpp
widget/qt/nsWindow.cpp
widget/windows/KeyboardLayout.cpp
widget/windows/nsWinGesture.cpp
widget/windows/nsWinGesture.h
widget/windows/nsWindow.cpp
xpcom/base/nsStackWalk.cpp
xpcom/base/nsTraceRefcntImpl.cpp
xpcom/io/nsBinaryStream.cpp
xpcom/io/nsInputStreamTee.cpp
xpcom/io/nsMultiplexInputStream.cpp
xpcom/io/nsPipe3.cpp
xpcom/io/nsStorageStream.cpp
xpcom/io/nsStreamUtils.cpp
xpcom/io/nsStringStream.cpp
xpcom/tests/TestBase64.cpp
--- a/accessible/src/base/nsARIAMap.cpp
+++ b/accessible/src/base/nsARIAMap.cpp
@@ -2,21 +2,22 @@
 /* vim:expandtab:shiftwidth=2:tabstop=2:
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsARIAMap.h"
 
+#include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "Role.h"
 #include "States.h"
 
-#include "nsIContent.h"
+#include "nsAttrName.h"
 #include "nsWhitespaceTokenizer.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 using namespace mozilla::a11y::aria;
 
 /**
  *  This list of WAI-defined roles are currently hardcoded.
@@ -679,8 +680,44 @@ aria::UniversalStatesFor(mozilla::dom::E
 {
   PRUint64 state = 0;
   PRUint32 index = 0;
   while (MapToState(sWAIUnivStateMap[index], aElement, &state))
     index++;
 
   return state;
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// AttrIterator class
+
+bool
+AttrIterator::Next(nsAString& aAttrName, nsAString& aAttrValue)
+{
+  while (mAttrIdx < mAttrCount) {
+    const nsAttrName* attr = mContent->GetAttrNameAt(mAttrIdx);
+    mAttrIdx++;
+    if (attr->NamespaceEquals(kNameSpaceID_None)) {
+      nsIAtom* attrAtom = attr->Atom();
+      nsDependentAtomString attrStr(attrAtom);
+      if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-")))
+        continue; // Not ARIA
+
+      PRUint8 attrFlags = nsAccUtils::GetAttributeCharacteristics(attrAtom);
+      if (attrFlags & ATTR_BYPASSOBJ)
+        continue; // No need to handle exposing as obj attribute here
+
+      if ((attrFlags & ATTR_VALTOKEN) &&
+           !nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
+        continue; // only expose token based attributes if they are defined
+
+      nsAutoString value;
+      if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
+        aAttrName.Assign(Substring(attrStr, 5));
+        aAttrValue.Assign(value);
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
--- a/accessible/src/base/nsARIAMap.h
+++ b/accessible/src/base/nsARIAMap.h
@@ -7,18 +7,18 @@
 
 #ifndef _nsARIAMap_H_
 #define _nsARIAMap_H_
 
 #include "ARIAStateMap.h"
 #include "mozilla/a11y/Role.h"
 
 #include "nsIAtom.h"
+#include "nsIContent.h"
 
-class nsIContent;
 class nsINode;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Value constants
 
 /**
  * Used to define if role requires to expose nsIAccessibleValue.
  */
@@ -221,13 +221,38 @@ namespace aria {
 nsRoleMapEntry* GetRoleMap(nsINode* aNode);
 
 /**
  * Return accessible state from ARIA universal states applied to the given
  * element.
  */
 PRUint64 UniversalStatesFor(mozilla::dom::Element* aElement);
 
+ /**
+  * Represents a simple enumerator for iterating through ARIA attributes 
+  * exposed as object attributes on a given accessible. 
+  */
+class AttrIterator
+{
+public:
+  AttrIterator(nsIContent* aContent) : 
+    mContent(aContent), mAttrIdx(0) 
+  { 
+    mAttrCount = mContent->GetAttrCount();
+  }
+
+  bool Next(nsAString& aAttrName, nsAString& aAttrValue);
+
+private:
+  AttrIterator() MOZ_DELETE;
+  AttrIterator(const AttrIterator&) MOZ_DELETE;
+  AttrIterator& operator= (const AttrIterator&) MOZ_DELETE;
+
+  nsIContent* mContent;
+  PRUint32 mAttrIdx;
+  PRUint32 mAttrCount;
+};
+
 } // namespace aria
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -1220,35 +1220,21 @@ Accessible::GetAttributes(nsIPersistentP
     nsAccUtils::SetAccAttr(attributes, nsGkAtoms::checkable, NS_LITERAL_STRING("true"));
 
   // Group attributes (level/setsize/posinset)
   GroupPos groupPos = GroupPosition();
   nsAccUtils::SetAccGroupAttrs(attributes, groupPos.level,
                                groupPos.setSize, groupPos.posInSet);
 
   // Expose object attributes from ARIA attributes.
-  PRUint32 numAttrs = mContent->GetAttrCount();
-  for (PRUint32 count = 0; count < numAttrs; count ++) {
-    const nsAttrName *attr = mContent->GetAttrNameAt(count);
-    if (attr && attr->NamespaceEquals(kNameSpaceID_None)) {
-      nsIAtom *attrAtom = attr->Atom();
-      nsDependentAtomString attrStr(attrAtom);
-      if (!StringBeginsWith(attrStr, NS_LITERAL_STRING("aria-"))) 
-        continue; // Not ARIA
-      PRUint8 attrFlags = nsAccUtils::GetAttributeCharacteristics(attrAtom);
-      if (attrFlags & ATTR_BYPASSOBJ)
-        continue; // No need to handle exposing as obj attribute here
-      if ((attrFlags & ATTR_VALTOKEN) &&
-          !nsAccUtils::HasDefinedARIAToken(mContent, attrAtom))
-        continue; // only expose token based attributes if they are defined
-      nsAutoString value;
-      if (mContent->GetAttr(kNameSpaceID_None, attrAtom, value)) {
-        attributes->SetStringProperty(NS_ConvertUTF16toUTF8(Substring(attrStr, 5)), value, oldValueUnused);
-      }
-    }
+  aria::AttrIterator attribIter(mContent);
+  nsAutoString name, value;
+  while(attribIter.Next(name, value)) {
+    attributes->SetStringProperty(NS_ConvertUTF16toUTF8(name), value, 
+                                  oldValueUnused);
   }
 
   // If there is no aria-live attribute then expose default value of 'live'
   // object attribute used for ARIA role of this accessible.
   if (mRoleMapEntry) {
     nsAutoString live;
     nsAccUtils::GetAccAttr(attributes, nsGkAtoms::live, live);
     if (live.IsEmpty()) {
@@ -3253,8 +3239,9 @@ KeyBinding::ToAtkFormat(nsAString& aValu
   if (mModifierMask & kShift)
     aValue.Append(NS_LITERAL_STRING("<Shift>"));
 
   if (mModifierMask & kMeta)
       aValue.Append(NS_LITERAL_STRING("<Meta>"));
 
   aValue.Append(mKey);
 }
+
--- a/accessible/src/windows/uia/uiaRawElmProvider.cpp
+++ b/accessible/src/windows/uia/uiaRawElmProvider.cpp
@@ -3,16 +3,17 @@
 /* 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 "uiaRawElmProvider.h"
 
 #include "AccessibleWrap.h"
 #include "nsIPersistentProperties2.h"
+#include "nsARIAMap.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // uiaRawElmProvider
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -194,16 +195,40 @@ uiaRawElmProvider::GetPropertyValue(PROP
       if(!xmlRoles.IsEmpty()) {
         aPropertyValue->vt = VT_BSTR;
         aPropertyValue->bstrVal = ::SysAllocString(xmlRoles.get());
         return S_OK;
       }
 
       break;
     }
+
+    //ARIA Properties
+    case UIA_AriaPropertiesPropertyId: {
+      nsAutoString ariaProperties;
+
+      aria::AttrIterator attribIter(mAcc->GetContent());
+      nsAutoString attribName, attribValue;
+      while (attribIter.Next(attribName, attribValue)) {
+        ariaProperties.Append(attribName);
+        ariaProperties.Append('=');
+        ariaProperties.Append(attribValue);
+        ariaProperties.Append(';');
+      }
+
+      if (!ariaProperties.IsEmpty()) {
+        //remove last delimiter:
+        ariaProperties.Truncate(ariaProperties.Length()-1);
+        aPropertyValue->vt = VT_BSTR;
+        aPropertyValue->bstrVal = ::SysAllocString(ariaProperties.get());
+        return S_OK;
+      }
+
+      break;
+    }
   }
 
   return S_OK;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -467,16 +467,19 @@ pref("device.storage.enabled", true);
 pref("media.plugins.enabled", true);
 
 // Disable printing (particularly, window.print())
 pref("dom.disable_window_print", true);
 
 // Disable window.showModalDialog
 pref("dom.disable_window_showModalDialog", true);
 
+// Enable new experimental html forms
+pref("dom.experimental_forms", true);
+
 // Turns on gralloc-based direct texturing for Gonk
 pref("gfx.gralloc.enabled", false);
 
 // XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging 
 pref("javascript.options.mem.log", true);
 
 // Increase mark slice time from 10ms to 30ms
 pref("javascript.options.mem.gc_incremental_slice_ms", 30);
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -175,25 +175,25 @@ let FormAssistant = {
 };
 
 FormAssistant.init();
 
 
 function getJSON(element) {
   let type = element.type || "";
 
-  // FIXME/bug 344616 is input type="number"
-  // Until then, let's return 'number' even if the platform returns 'text'
+  // Until the input type=date/datetime/time have been implemented
+  // let's return their real type even if the platform returns 'text'
   // Related to Bug 769352 - Implement <input type=date>
+  // Related to Bug 777279 - Implement <input type=time>
   let attributeType = element.getAttribute("type") || "";
 
   if (attributeType) {
     var typeLowerCase = attributeType.toLowerCase(); 
     switch (typeLowerCase) {
-      case "number":
       case "date":
       case "time":
       case "datetime":
       case "datetime-local":
         type = typeLowerCase;
         break;
     }
   }
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0"?>
-<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1343854380000">
+<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1344613852000">
   <emItems>
       <emItem  blockID="i58" id="webmaster@buzzzzvideos.info">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i86" id="{45147e67-4020-47e2-8f7a-55464fb535aa}">
                         <versionRange  minVersion="0" maxVersion="*">
                     </versionRange>
@@ -115,16 +115,20 @@
                     </versionRange>
                   </emItem>
       <emItem  blockID="i18" id="msntoolbar@msn.com">
                         <versionRange  minVersion=" " maxVersion="6.*">
                     </versionRange>
                   </emItem>
       <emItem  blockID="i13" id="{E8E88AB0-7182-11DF-904E-6045E0D72085}">
                         </emItem>
+      <emItem  blockID="i117" id="{ce7e73df-6a44-4028-8079-5927a588c948}">
+                        <versionRange  minVersion="0" maxVersion="1.0.8" severity="1">
+                    </versionRange>
+                  </emItem>
       <emItem  blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}">
                         <versionRange  minVersion="0.1" maxVersion="1.3.328.4" severity="1">
                       <targetApplication  id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
                               <versionRange  minVersion="3.7a1pre" maxVersion="*" />
                           </targetApplication>
                     </versionRange>
                   </emItem>
       <emItem  blockID="i64" id="royal@facebook.com">
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -505,44 +505,33 @@ pref("browser.gesture.pinch.out.shift", 
 pref("browser.gesture.pinch.in.shift", "");
 #endif
 pref("browser.gesture.twist.latched", false);
 pref("browser.gesture.twist.threshold", 25);
 pref("browser.gesture.twist.right", "");
 pref("browser.gesture.twist.left", "");
 pref("browser.gesture.tap", "cmd_fullZoomReset");
 
-// 0=lines, 1=pages, 2=history , 3=text size
+// 0: Nothing happens
+// 1: Scrolling contents
+// 2: Go back or go forward, in your history
+// 3: Zoom in or out.
 #ifdef XP_MACOSX
 // On OS X, if the wheel has one axis only, shift+wheel comes through as a
 // horizontal scroll event. Thus, we can't assign anything other than normal
 // scrolling to shift+wheel.
-pref("mousewheel.withshiftkey.action",0);
-pref("mousewheel.withshiftkey.sysnumlines",true);
-pref("mousewheel.withshiftkey.numlines",1);
-pref("mousewheel.withaltkey.action",2);
-pref("mousewheel.withaltkey.sysnumlines",false);
-pref("mousewheel.withaltkey.numlines",1);
-pref("mousewheel.withmetakey.action",0);
-pref("mousewheel.withmetakey.sysnumlines",false);
-pref("mousewheel.withmetakey.numlines",1);
+pref("mousewheel.with_alt.action", 2);
+pref("mousewheel.with_shift.action", 1);
 #else
-pref("mousewheel.withshiftkey.action",2);
-pref("mousewheel.withshiftkey.sysnumlines",false);
-pref("mousewheel.withshiftkey.numlines",1);
-pref("mousewheel.withaltkey.action",0);
-pref("mousewheel.withaltkey.sysnumlines",false);
-pref("mousewheel.withaltkey.numlines",1);
-pref("mousewheel.withmetakey.action",0);
-pref("mousewheel.withmetakey.sysnumlines",true);
-pref("mousewheel.withmetakey.numlines",1);
+pref("mousewheel.with_alt.action", 1);
+pref("mousewheel.with_shift.action", 2);
 #endif
-pref("mousewheel.withcontrolkey.action",3);
-pref("mousewheel.withcontrolkey.sysnumlines",false);
-pref("mousewheel.withcontrolkey.numlines",1);
+pref("mousewheel.with_control.action",3);
+pref("mousewheel.with_meta.action", 1);  // command key on Mac
+pref("mousewheel.with_win.action", 1);
 
 // pref to control the alert notification 
 pref("alerts.slideIncrement", 1);
 pref("alerts.slideIncrementTime", 10);
 pref("alerts.totalOpenTime", 4000);
 
 pref("browser.xul.error_pages.enabled", true);
 pref("browser.xul.error_pages.expert_bad_cert", false);
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -227,16 +227,17 @@ endif
                  plugin_test3.html \
                  plugin_alternate_content.html \
                  plugin_both.html \
                  plugin_both2.html \
                  plugin_bug743421.html \
                  plugin_clickToPlayAllow.html \
                  plugin_clickToPlayDeny.html \
                  plugin_bug749455.html \
+                 plugin_hidden_to_visible.html \
                  alltabslistener.html \
                  zoom_test.html \
                  dummy_page.html \
                  browser_tabMatchesInAwesomebar.js \
                  file_bug550565_popup.html \
                  file_bug550565_favicon.ico \
                  browser_aboutHome.js \
                  app_bug575561.html \
--- a/browser/base/content/test/browser_overflowScroll.js
+++ b/browser/base/content/test/browser_overflowScroll.js
@@ -67,21 +67,21 @@ function runOverflowTests(aEvent) {
   isLeft(element, "Scrolled one page of tabs with a double click");
 
   EventUtils.synthesizeMouse(upButton, 1, 1, {clickCount: 3});
   var firstScrollableLeft = left(firstScrollable());
   ok(left(scrollbox) <= firstScrollableLeft, "Scrolled to the start with a triple click " +
      "(" + left(scrollbox) + " <= " + firstScrollableLeft + ")");
 
   for (var i = 2; i; i--)
-    EventUtils.synthesizeMouseScroll(scrollbox, 1, 1, {axis: "horizontal", delta: -1});
+    EventUtils.synthesizeWheel(scrollbox, 1, 1, { deltaX: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE });
   is(left(firstScrollable()), firstScrollableLeft, "Remained at the start with the mouse wheel");
 
   element = nextRightElement();
-  EventUtils.synthesizeMouseScroll(scrollbox, 1, 1, {axis: "horizontal", delta: 1});
+  EventUtils.synthesizeWheel(scrollbox, 1, 1, { deltaX: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE});
   isRight(element, "Scrolled one tab to the right with the mouse wheel");
 
   while (tabs.length > 1)
     gBrowser.removeTab(tabs[0]);
 
   tabstrip.smoothScroll = originalSmoothScroll;
   finish();
 }
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -684,10 +684,61 @@ function test19e() {
 }
 
 function test19f() {
   var doc = gTestBrowser.contentDocument;
   var plugin = doc.getElementById("test");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 19f, Plugin should be activated");
 
+  prepareTest(test20a, gTestRoot + "plugin_hidden_to_visible.html");
+}
+
+// Tests that a plugin in a div that goes from style="display: none" to
+// "display: block" can be clicked to activate.
+function test20a() {
+  var clickToPlayNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(clickToPlayNotification, "Test 20a, Should have a click-to-play notification");
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("plugin");
+  var mainBox = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
+  ok(mainBox, "Test 20a, plugin overlay should not be null");
+  var pluginRect = mainBox.getBoundingClientRect();
+  ok(pluginRect.width == 0, "Test 20a, plugin should have an overlay with 0px width");
+  ok(pluginRect.height == 0, "Test 20a, plugin should have an overlay with 0px height");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Test 20a, plugin should not be activated");
+  var div = doc.getElementById("container");
+  ok(div.style.display == "none", "Test 20a, container div should be display: none");
+
+  div.style.display = "block";
+  var condition = function() {
+    var pluginRect = mainBox.getBoundingClientRect();
+    return (pluginRect.width == 200);
+  }
+  waitForCondition(condition, test20b, "Test 20a, Waited too long for plugin to become visible");
+}
+
+function test20b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("plugin");
+  var pluginRect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
+  ok(pluginRect.width == 200, "Test 20b, plugin should have an overlay with 200px width");
+  ok(pluginRect.height == 200, "Test 20b, plugin should have an overlay with 200px height");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Test 20b, plugin should not be activated");
+
+  EventUtils.synthesizeMouseAtCenter(plugin, {}, gTestBrowser.contentWindow);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test20c, "Test 20b, Waited too long for plugin to activate");
+}
+
+function test20c() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("plugin");
+  var pluginRect = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox").getBoundingClientRect();
+  ok(pluginRect.width == 0, "Test 20c, plugin should have click-to-play overlay with zero width");
+  ok(pluginRect.height == 0, "Test 20c, plugin should have click-to-play overlay with zero height");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 20c, plugin should be activated");
+
   finishTest();
 }
--- a/browser/base/content/test/browser_social_shareButton.js
+++ b/browser/base/content/test/browser_social_shareButton.js
@@ -15,16 +15,17 @@ function test() {
   // Need to load a non-empty page for the social share button to appear
   let tab = gBrowser.selectedTab = gBrowser.addTab("about:", {skipAnimation: true});
   tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
     tab.linkedBrowser.removeEventListener("load", tabLoad, true);
     executeSoon(tabLoaded);
   }, true);
 
   registerCleanupFunction(function() {
+    Services.prefs.clearUserPref(prefName);
     gBrowser.removeTab(tab);
   });
 }
 
 function tabLoaded() {
   ok(Social, "Social module loaded");
 
   let manifest = { // normal provider
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/plugin_hidden_to_visible.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+  <div id="container" style="display: none">
+    <object id="plugin" type="application/x-test" style="width: 200px; height: 200px;"></object>
+  </div>
+</body>
+</html>
--- a/browser/devtools/highlighter/test/browser_inspector_scrolling.js
+++ b/browser/devtools/highlighter/test/browser_inspector_scrolling.js
@@ -46,18 +46,18 @@ function inspectNode()
   });
 }
 
 function performScrollingTest()
 {
   InspectorUI.highlighter.removeListener("nodeselected", performScrollingTest);
 
   executeSoon(function() {
-    EventUtils.synthesizeMouseScroll(div, 10, 10,
-      {axis:"vertical", delta:50, type:"MozMousePixelScroll"},
+    EventUtils.synthesizeWheel(div, 10, 10,
+      { deltaY: 50.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL },
       iframe.contentWindow);
   });
 
   gBrowser.selectedBrowser.addEventListener("scroll", function() {
     gBrowser.selectedBrowser.removeEventListener("scroll", arguments.callee,
       false);
 
     is(iframe.contentDocument.body.scrollTop, 50, "inspected iframe scrolled");
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -35,19 +35,16 @@ endif
 SUBMAKEFILES += \
 	$(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/Makefile \
 	$(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales/Makefile \
 	$(NULL)
 
 # This makefile uses variable overrides from the libs-% target to
 # build non-default locales to non-default dist/ locations. Be aware!
 
-# XXXCallek Unused?
-APP_VERSION := $(shell cat $(srcdir)/../config/version.txt)
-
 PWD := $(CURDIR)
 
 # These are defaulted to be compatible with the files the wget-en-US target
 # pulls. You may override them if you provide your own files. You _must_
 # override them when MOZ_PKG_PRETTYNAMES is defined - the defaults will not
 # work in that case.
 ZIP_IN ?= $(_ABS_DIST)/$(PACKAGE)
 WIN32_INSTALLER_IN ?= $(_ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
--- a/build/mobile/b2gautomation.py
+++ b/build/mobile/b2gautomation.py
@@ -30,26 +30,29 @@ class StdOutProc(ProcessHandlerMixin):
     def handle_output(self, line):
         self.queue.put_nowait(line)
 
 
 class B2GRemoteAutomation(Automation):
     _devicemanager = None
 
     def __init__(self, deviceManager, appName='', remoteLog=None,
-                 marionette=None):
+                 marionette=None, context_chrome=True):
         self._devicemanager = deviceManager
         self._appName = appName
         self._remoteProfile = None
         self._remoteLog = remoteLog
         self.marionette = marionette
+        self.context_chrome = context_chrome
         self._is_emulator = False
 
         # Default our product to b2g
         self._product = "b2g"
+        # Default log finish to mochitest standard
+        self.logFinish = 'INFO SimpleTest FINISHED' 
         Automation.__init__(self)
 
     def setEmulator(self, is_emulator):
         self._is_emulator = is_emulator
 
     def setDeviceManager(self, deviceManager):
         self._devicemanager = deviceManager
 
@@ -116,31 +119,31 @@ class B2GRemoteAutomation(Automation):
         return app, args
 
     def getLanIp(self):
         nettools = NetworkTools()
         return nettools.getLanIp()
 
     def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime,
                       debuggerInfo, symbolsPath):
-        """ Wait for mochitest to finish (as evidenced by a signature string
+        """ Wait for tests to finish (as evidenced by a signature string
             in logcat), or for a given amount of time to elapse with no
             output.
         """
         timeout = timeout or 120
 
         didTimeout = False
 
         done = time.time() + timeout
         while True:
             currentlog = proc.stdout
             if currentlog:
                 done = time.time() + timeout
                 print currentlog
-                if 'INFO SimpleTest FINISHED' in currentlog:
+                if hasattr(self, 'logFinish') and self.logFinish in currentlog:
                     return 0
             else:
                 if time.time() > done:
                     self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed "
                                   "out after %d seconds with no output",
                                   self.lastTestSeen, int(timeout))
                     return 1
 
@@ -157,16 +160,18 @@ class B2GRemoteAutomation(Automation):
                 thisSerial = result.group(1)
                 if not serial or thisSerial == serial:
                     serial = thisSerial
                     status = result.group(2)
 
         return (serial, status)
 
     def restartB2G(self):
+        # TODO hangs in subprocess.Popen without this delay
+        time.sleep(5)
         self._devicemanager.checkCmd(['shell', 'stop', 'b2g'])
         # Wait for a bit to make sure B2G has completely shut down.
         time.sleep(10)
         self._devicemanager.checkCmd(['shell', 'start', 'b2g'])
         if self._is_emulator:
             self.marionette.emulator.wait_for_port()
 
     def rebootDevice(self):
@@ -189,21 +194,21 @@ class B2GRemoteAutomation(Automation):
                 # device hasn't come back online in 2 minutes, something's wrong
                 raise Exception("Device %s (status: %s) not back online after reboot" % (serial, rstatus))
             time.sleep(5)
             rserial, rstatus = self.getDeviceStatus(serial)
         print 'device:', serial, 'status:', rstatus
 
     def Process(self, cmd, stdout=None, stderr=None, env=None, cwd=None):
         # On a desktop or fennec run, the Process method invokes a gecko
-        # process in which to run mochitests.  For B2G, we simply
+        # process in which to the tests.  For B2G, we simply
         # reboot the device (which was configured with a test profile
         # already), wait for B2G to start up, and then navigate to the
         # test url using Marionette.  There doesn't seem to be any way
-        # to pass env variables into the B2G process, but this doesn't 
+        # to pass env variables into the B2G process, but this doesn't
         # seem to matter.
 
         # reboot device so it starts up with the mochitest profile
         # XXX:  We could potentially use 'stop b2g' + 'start b2g' to achieve
         # a similar effect; will see which is more stable while attempting
         # to bring up the continuous integration.
         if not self._is_emulator:
             self.rebootDevice()
@@ -234,21 +239,37 @@ class B2GRemoteAutomation(Automation):
         else:
             time.sleep(5)
 
         # start a marionette session
         session = self.marionette.start_session()
         if 'b2g' not in session:
             raise Exception("bad session value %s returned by start_session" % session)
 
-        # Start the tests by navigating to the mochitest url, by setting it
-        # as the 'src' attribute to the homescreen mozbrowser element
-        # provided by B2G's shell.js.
-        self.marionette.set_context("chrome")
-        self.marionette.execute_script("document.getElementById('homescreen').src='%s';" % self.testURL)
+        if self.context_chrome:
+            self.marionette.set_context(self.marionette.CONTEXT_CHROME)
+
+        # start the tests
+        if hasattr(self, 'testURL'):
+            # Start the tests by navigating to the mochitest url, by setting it
+            # as the 'src' attribute to the homescreen mozbrowser element
+            # provided by B2G's shell.js.
+            self.marionette.execute_script("document.getElementById('homescreen').src='%s';" % self.testURL)
+        # run the script that starts the tests
+        elif hasattr(self, 'testScript'):
+            if os.path.isfile(self.testScript):
+                script = open(self.testScript, 'r')
+                self.marionette.execute_script(script.read())
+                script.close()
+            else:
+                # assume testScript is a string
+                self.marionette.execute_script(self.testScript)
+        else:
+            # assumes the tests are started on startup automatically
+            pass
 
         return instance
 
     # be careful here as this inner class doesn't have access to outer class members
     class B2GInstance(object):
         """Represents a B2G instance running on a device, and exposes
            some process-like methods/properties that are expected by the
            automation.
--- a/build/mobile/robocop/Actions.java.in
+++ b/build/mobile/robocop/Actions.java.in
@@ -38,17 +38,17 @@ public interface Actions {
 
     /**
      * Listens for a gecko event to be sent from the Gecko instance.
      * The returned object can be used to test if the event has been
      * received. Note that only one event is listened for.
      * 
      * @param geckoEvent The geckoEvent JSONObject's type
      */
-    EventExpecter expectGeckoEvent(String geckoEvent);
+    RepeatedEventExpecter expectGeckoEvent(String geckoEvent);
 
     /**
      * Listens for a paint event. Note that calling expectPaint() will
      * invalidate the event expecters returned from any previous calls
      * to expectPaint(); calling any methods on those invalidated objects
      * will result in undefined behaviour.
      */
     RepeatedEventExpecter expectPaint();
--- a/build/mobile/robocop/FennecNativeActions.java.in
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -60,18 +60,18 @@ public class FennecNativeActions impleme
         try {
             mClassLoader = activity.getClassLoader();
             mGel = mClassLoader.loadClass("org.mozilla.gecko.util.GeckoEventListener");
             mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
             mGas = mClassLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
             Class [] parameters = new Class[2];
             parameters[0] = String.class;
             parameters[1] = mGel;
-            mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
-            mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
+            mRegisterGEL = mGas.getMethod("registerEventListener", parameters);
+            mUnregisterGEL = mGas.getMethod("unregisterEventListener", parameters);
             parameters = new Class[1];
             parameters[0] = mGe;
             mSendGE = mGas.getMethod("sendEventToGecko", parameters);
 
             mGetLayerClient = activity.getClass().getMethod("getLayerClient");
             Class gslc = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoLayerClient");
             mDrawListener = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoLayerClient$DrawListener");
             mSetDrawListener = gslc.getDeclaredMethod("setDrawListener", mDrawListener);
@@ -110,17 +110,17 @@ public class FennecNativeActions impleme
             }
             FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG, 
                 "Waking up on "+methodName);
             mEventExpecter.notifyOfEvent();
             return null;
         }
     }
 
-    class GeckoEventExpecter implements EventExpecter {
+    class GeckoEventExpecter implements RepeatedEventExpecter {
         private final String mGeckoEvent;
         private final Object[] mRegistrationParams;
         private boolean mEventReceived;
         private static final int MAX_WAIT_MS = 90000;
 
         GeckoEventExpecter(String geckoEvent, Object[] registrationParams) {
             mGeckoEvent = geckoEvent;
             mRegistrationParams = registrationParams;
@@ -138,42 +138,90 @@ public class FennecNativeActions impleme
                 }
                 endTime = SystemClock.uptimeMillis();
                 if (!mEventReceived && (endTime - startTime >= MAX_WAIT_MS)) {
                     mAsserter.ok(false, "GeckoEventExpecter", 
                         "blockForEvent timeout: "+mGeckoEvent);
                     return;
                 }
             }
+            try {
+                mUnregisterGEL.invoke(null, mRegistrationParams);
+            } catch (IllegalAccessException e) {
+                FennecNativeDriver.log(LogLevel.ERROR, e);
+            } catch (InvocationTargetException e) {
+                FennecNativeDriver.log(LogLevel.ERROR, e);
+            }
+            FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
+                "unblocked on expecter for " + mGeckoEvent);
+        }
+
+        public synchronized void blockUntilClear(long millis) {
+            if (millis <= 0) {
+                throw new IllegalArgumentException("millis must be > 0");
+            }
+            // wait for at least one event
+            long startTime = SystemClock.uptimeMillis();
+            long endTime = 0;
+            while (!mEventReceived) {
+                try {
+                    this.wait(MAX_WAIT_MS);
+                } catch (InterruptedException ie) {
+                    FennecNativeDriver.log(LogLevel.ERROR, ie);
+                    break;
+                }
+                endTime = SystemClock.uptimeMillis();
+                if (!mEventReceived && (endTime - startTime >= MAX_WAIT_MS)) {
+                    mAsserter.ok(false, "GeckoEventExpecter", "blockUtilClear timeout");
+                    return;
+                }
+            }
+            // now wait for a period of millis where we don't get an event
+            startTime = SystemClock.uptimeMillis();
+            while (true) {
+                try {
+                    this.wait(millis);
+                } catch (InterruptedException ie) {
+                    FennecNativeDriver.log(LogLevel.ERROR, ie);
+                    break;
+                }
+                endTime = SystemClock.uptimeMillis();
+                if (endTime - startTime >= millis) {
+                    // success
+                    break;
+                }
+                // we got a notify() before we could wait long enough, so we need to start over
+                startTime = endTime;
+            }
+            try {
+                mUnregisterGEL.invoke(null, mRegistrationParams);
+            } catch (IllegalAccessException e) {
+                FennecNativeDriver.log(LogLevel.ERROR, e);
+            } catch (InvocationTargetException e) {
+                FennecNativeDriver.log(LogLevel.ERROR, e);
+            }
             FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
                 "unblocked on expecter for " + mGeckoEvent);
         }
 
         public synchronized boolean eventReceived() {
             return mEventReceived;
         }
 
         void notifyOfEvent() {
-            try {
-                mUnregisterGEL.invoke(null, mRegistrationParams);
-            } catch (IllegalAccessException e) {
-                FennecNativeDriver.log(LogLevel.ERROR, e);
-            } catch (InvocationTargetException e) {
-                FennecNativeDriver.log(LogLevel.ERROR, e);
-            }
             FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
                 "received event " + mGeckoEvent);
             synchronized (this) {
                 mEventReceived = true;
                 this.notifyAll();
             }
         }
     }
     
-    public EventExpecter expectGeckoEvent(String geckoEvent) {
+    public RepeatedEventExpecter expectGeckoEvent(String geckoEvent) {
         FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
             "waiting for "+geckoEvent);
         try {
             Class [] interfaces = new Class[1];
             interfaces[0] = mGel;
             Object[] finalParams = new Object[2];
             finalParams[0] = geckoEvent;
          
--- a/build/mobile/robocop/FennecNativeDriver.java.in
+++ b/build/mobile/robocop/FennecNativeDriver.java.in
@@ -89,18 +89,18 @@ public class FennecNativeDriver implemen
         try {
             mClassLoader = activity.getClassLoader();
             mGel = mClassLoader.loadClass("org.mozilla.gecko.util.GeckoEventListener");
             mGe = mClassLoader.loadClass("org.mozilla.gecko.GeckoEvent");
             mGas = mClassLoader.loadClass("org.mozilla.gecko.GeckoAppShell");
             Class [] parameters = new Class[2];
             parameters[0] = String.class;
             parameters[1] = mGel;
-            mRegisterGEL = mGas.getMethod("registerGeckoEventListener", parameters);
-            mUnregisterGEL = mGas.getMethod("unregisterGeckoEventListener", parameters);
+            mRegisterGEL = mGas.getMethod("registerEventListener", parameters);
+            mUnregisterGEL = mGas.getMethod("unregisterEventListener", parameters);
             parameters = new Class[1];
             parameters[0] = mGe;
             mSendGE = mGas.getMethod("sendEventToGecko", parameters);
 
             Class gfx = mClassLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
             _startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
             _stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
             _startCheckerboardRecording = gfx.getDeclaredMethod("startCheckerboardRecording");
--- a/build/mobile/sutagent/android/SUTAgentAndroid.java
+++ b/build/mobile/sutagent/android/SUTAgentAndroid.java
@@ -785,13 +785,16 @@ public class SUTAgentAndroid extends Act
             pw.println(datestamp + " : " + message);
             } 
             catch (IOException ioe) 
             {
                 Log.e("SUTAgentAndroid", "exception with file writer on: " + logFile);
             } 
             finally 
             {
-                pw.close();
+                if (pw != null)
+                {
+                    pw.close();
+                }
             }
 
         }
 }
--- a/config/config.mk
+++ b/config/config.mk
@@ -82,30 +82,22 @@ BUILD_TOOLS	= $(WIN_TOP_SRC)/build/unix
 else
 win_srcdir	:= $(srcdir)
 BUILD_TOOLS	= $(topsrcdir)/build/unix
 endif
 
 CONFIG_TOOLS	= $(MOZ_BUILD_ROOT)/config
 AUTOCONF_TOOLS	= $(topsrcdir)/build/autoconf
 
-ifeq ($(OS_ARCH),QNX)
-ifeq ($(OS_TARGET),NTO)
-LD		:= qcc -Vgcc_ntox86 -nostdlib
-else
-LD		:= $(CC)
-endif
-endif
-
 #
 # Strip off the excessively long version numbers on these platforms,
 # but save the version to allow multiple versions of the same base
 # platform to be built in the same tree.
 #
-ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD OSF1 SunOS,$(OS_ARCH)))
+ifneq (,$(filter FreeBSD HP-UX Linux NetBSD OpenBSD SunOS,$(OS_ARCH)))
 OS_RELEASE	:= $(basename $(OS_RELEASE))
 
 # Allow the user to ignore the OS_VERSION, which is usually irrelevant.
 ifdef WANT_MOZILLA_CONFIG_OS_VERSION
 OS_VERS		:= $(suffix $(OS_RELEASE))
 OS_VERSION	:= $(shell echo $(OS_VERS) | sed 's/-.*//')
 endif
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -496,27 +496,16 @@ ifdef IS_COMPONENT
 ifneq ($(HAS_EXTRAEXPORTS),1)
 MKSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 MKCSHLIB += -bE:$(MOZILLA_DIR)/build/unix/aix.exp -bnoexpall
 endif # HAS_EXTRAEXPORTS
 endif # IS_COMPONENT
 endif # AIX
 
 #
-# OSF1: add -B symbolic flag for components
-#
-ifeq ($(OS_ARCH),OSF1)
-ifdef IS_COMPONENT
-ifeq ($(GNU_CC)$(GNU_CXX),)
-EXTRA_DSO_LDOPTS += -B symbolic
-endif
-endif
-endif
-
-#
 # Linux: add -Bsymbolic flag for components
 #
 ifeq ($(OS_ARCH),Linux)
 ifdef IS_COMPONENT
 EXTRA_DSO_LDOPTS += -Wl,-Bsymbolic
 endif
 endif
 
--- a/configure.in
+++ b/configure.in
@@ -4145,17 +4145,16 @@ MOZ_JSDEBUGGER=1
 MOZ_AUTH_EXTENSION=1
 MOZ_OGG=1
 MOZ_RAW=
 MOZ_SYDNEYAUDIO=
 MOZ_SPEEX_RESAMPLER=1
 MOZ_CUBEB=
 MOZ_VORBIS=
 MOZ_TREMOR=
-MOZ_FLOATING_POINT_AUDIO=
 MOZ_WAVE=1
 MOZ_MEDIA=
 MOZ_OPUS=1
 MOZ_WEBM=1
 MOZ_WEBRTC=1
 MOZ_WEBRTC_SIGNALING=
 MOZ_MEDIA_PLUGINS=
 MOZ_MEDIA_NAVIGATOR=
@@ -5196,34 +5195,16 @@ if test -n "$MOZ_WEBRTC"; then
     MOZ_VP8=1
     MOZ_VP8_ENCODER=1
     MOZ_VP8_ERROR_CONCEALMENT=1
 fi
 
 AC_SUBST(MOZ_WEBRTC)
 
 dnl ========================================================
-dnl = Disable floating point audio.
-dnl ========================================================
-MOZ_ARG_DISABLE_BOOL(floating-point,
-[ --disable-floating-point     Disable floating point audio],
-    MOZ_FLOATING_POINT_AUDIO=,
-    MOZ_FLOATING_POINT_AUDIO=1)
-
-
-case "$target_cpu" in
-arm*)
-;;
-*)
-    AC_DEFINE(MOZ_FLOATING_POINT_AUDIO)
-    MOZ_FLOATING_POINT_AUDIO=1
-;;
-esac
-
-dnl ========================================================
 dnl = Enable Raw Codecs
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(raw,
 [  --enable-raw           Enable support for RAW media],
     MOZ_RAW=1,
     MOZ_RAW=)
 
 if test -n "$MOZ_RAW"; then
@@ -5241,16 +5222,24 @@ MOZ_ARG_DISABLE_BOOL(ogg,
     MOZ_OGG=,
     MOZ_OGG=1)
 
 if test -n "$MOZ_OGG"; then
     AC_DEFINE(MOZ_OGG)
     MOZ_SYDNEYAUDIO=1
     MOZ_CUBEB=1
     MOZ_MEDIA=1
+    case "$target_cpu" in
+    arm*)
+        MOZ_TREMOR=1
+    ;;
+    *)
+        MOZ_VORBIS=1
+    ;;
+    esac
 
     dnl Checks for __attribute__(aligned()) directive
     AC_CACHE_CHECK([__attribute__ ((aligned ())) support],
         [ac_cv_c_attribute_aligned],
         [ac_cv_c_attribute_aligned=0
          CFLAGS_save="${CFLAGS}"
          CFLAGS="${CFLAGS} -Werror"
          for ac_cv_c_attr_align_try in 64 32 16 8; do
@@ -5310,30 +5299,30 @@ MOZ_ARG_ENABLE_BOOL(media-navigator,
     MOZ_MEDIA_NAVIGATOR=1,
     MOZ_MEDIA_NAVIGATOR=)
 
 if test -n "$MOZ_MEDIA_NAVIGATOR"; then
   AC_DEFINE(MOZ_MEDIA_NAVIGATOR)
 fi
 
 dnl ========================================================
-dnl = Enable building OMX media plugin (B2G)
+dnl = Enable building OMX media plugin (B2G or Android)
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(omx-plugin,
 [  --enable-omx-plugin      Enable building OMX plugin (B2G)],
     MOZ_OMX_PLUGIN=1,
     MOZ_OMX_PLUGIN=)
 
 if test -n "$MOZ_OMX_PLUGIN"; then
-    if test "$OS_TARGET" = "Android" -a -n "$gonkdir"; then
-        dnl Only allow building OMX plugin on Gonk (B2G)
+    if test "$OS_TARGET" = "Android"; then
+        dnl Only allow building OMX plugin on Gonk (B2G) or Android
         AC_DEFINE(MOZ_OMX_PLUGIN)
     else
-       dnl fail if we're not building on Gonk
-       AC_MSG_ERROR([OMX media plugin can only be built on B2G])
+       dnl fail if we're not building on Gonk or Android
+       AC_MSG_ERROR([OMX media plugin can only be built on B2G or Android])
     fi
 fi
 
 dnl system libvpx Support
 dnl ========================================================
 MOZ_ARG_WITH_BOOL(system-libvpx,
 [  --with-system-libvpx    Use system libvpx (located with pkgconfig)],
     MOZ_NATIVE_LIBVPX=1)
@@ -5370,21 +5359,24 @@ fi
 AC_SUBST(MOZ_NATIVE_LIBVPX)
 AC_SUBST(MOZ_LIBVPX_CFLAGS)
 AC_SUBST(MOZ_LIBVPX_LIBS)
 
 if test "$MOZ_WEBM"; then
     MOZ_SYDNEYAUDIO=1
     MOZ_CUBEB=1
     MOZ_MEDIA=1
-    if test -n "$MOZ_FLOATING_POINT_AUDIO"; then
+    case "$target_cpu" in
+    arm*)
+        MOZ_TREMOR=1
+    ;;
+    *)
         MOZ_VORBIS=1
-    else
-        MOZ_TREMOR=1
-    fi
+    ;;
+    esac
 fi
 
 if test -n "$MOZ_VP8" -a -z "$MOZ_NATIVE_LIBVPX"; then
 
     dnl Detect if we can use an assembler to compile optimized assembly for libvpx.
     dnl We currently require yasm on all x86 platforms and require yasm 1.1.0 on Win32.
     dnl We currently require gcc on all arm platforms.
     VPX_AS=$YASM
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -10,17 +10,16 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
 LIBRARY_NAME	= gkconbase_s
 LIBXUL_LIBRARY	= 1
 
 
-
 EXPORTS		= \
 		nsAtomListUtils.h \
 		nsAttrName.h \
 		nsContentList.h \
 		nsContentSink.h \
 		nsGkAtomList.h \
 		nsGkAtoms.h \
 		nsNodeInfoManager.h \
--- a/content/base/src/nsContentIterator.cpp
+++ b/content/base/src/nsContentIterator.cpp
@@ -1194,18 +1194,18 @@ nsContentSubtreeIterator::Init(nsIDOMRan
   // get the start node and offset, convert to nsINode
   mCommonParent = mRange->GetCommonAncestor();
   nsINode* startParent = mRange->GetStartParent();
   PRInt32 startOffset = mRange->StartOffset();
   nsINode* endParent = mRange->GetEndParent();
   PRInt32 endOffset = mRange->EndOffset();
   MOZ_ASSERT(mCommonParent && startParent && endParent);
   // Bug 767169
-  MOZ_ASSERT(startOffset <= startParent->Length() &&
-             endOffset <= endParent->Length());
+  MOZ_ASSERT(PRUint32(startOffset) <= startParent->Length() &&
+             PRUint32(endOffset) <= endParent->Length());
 
   // short circuit when start node == end node
   if (startParent == endParent) {
     nsINode* child = startParent->GetFirstChild();
 
     if (!child || startOffset == endOffset) {
       // Text node, empty container, or collapsed
       MakeEmpty();
--- a/content/base/src/nsDOMParser.h
+++ b/content/base/src/nsDOMParser.h
@@ -52,13 +52,12 @@ private:
   };
   
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsIPrincipal> mOriginalPrincipal;
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mBaseURI;
   nsWeakPtr mScriptHandlingObject;
   
-  bool mLoopingForSyncLoad;
   bool mAttemptedInit;
 };
 
 #endif
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -803,19 +803,23 @@ nsFrameScriptExecutor::LoadFrameScriptIn
   NS_NewChannel(getter_AddRefs(channel), uri);
   if (!channel) {
     return;
   }
 
   nsCOMPtr<nsIInputStream> input;
   channel->Open(getter_AddRefs(input));
   nsString dataString;
-  PRUint32 avail = 0;
-  if (input && NS_SUCCEEDED(input->Available(&avail)) && avail) {
+  PRUint64 avail64 = 0;
+  if (input && NS_SUCCEEDED(input->Available(&avail64)) && avail64) {
+    if (avail64 > PR_UINT32_MAX) {
+      return;
+    }
     nsCString buffer;
+    PRUint32 avail = (PRUint32)NS_MIN(avail64, (PRUint64)PR_UINT32_MAX);
     if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, avail))) {
       return;
     }
     nsScriptLoader::ConvertToUTF16(channel, (PRUint8*)buffer.get(), avail,
                                    EmptyString(), nullptr, dataString);
   }
 
   if (!dataString.IsEmpty()) {
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -602,68 +602,58 @@ nsGenericElement::GetScrollFrame(nsIFram
 
   return nullptr;
 }
 
 PRInt32
 nsGenericElement::GetScrollTop()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
-
-  return sf ?
-         nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().y) :
-         0;
+  return sf ? sf->GetScrollPositionCSSPixels().y : 0;
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollTop(PRInt32* aScrollTop)
 {
   *aScrollTop = GetScrollTop();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
-    nsPoint pt = sf->GetScrollPosition();
-    sf->ScrollToCSSPixels(nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
-                                     aScrollTop));
+    sf->ScrollToCSSPixels(nsIntPoint(sf->GetScrollPositionCSSPixels().x, aScrollTop));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollLeft()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
-
-  return sf ?
-         nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollPosition().x) :
-         0;
+  return sf ? sf->GetScrollPositionCSSPixels().x : 0;
 }
 
 NS_IMETHODIMP
 nsGenericElement::GetScrollLeft(PRInt32* aScrollLeft)
 {
   *aScrollLeft = GetScrollLeft();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
-    nsPoint pt = sf->GetScrollPosition();
-    sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft,
-                                     nsPresContext::AppUnitsToIntCSSPixels(pt.y)));
+    sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft, sf->GetScrollPositionCSSPixels().y));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollHeight()
 {
   if (IsSVG())
--- 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/base/src/nsSyncLoadService.cpp
+++ b/content/base/src/nsSyncLoadService.cpp
@@ -347,30 +347,34 @@ nsSyncLoadService::PushSyncStreamToListe
         NS_ENSURE_SUCCESS(rv, rv);
 
         aIn = bufferedStream;
     }
 
     // Load
     rv = aListener->OnStartRequest(aChannel, nullptr);
     if (NS_SUCCEEDED(rv)) {
-        PRUint32 sourceOffset = 0;
+        PRUint64 sourceOffset = 0;
         while (1) {
-            PRUint32 readCount = 0;
+            PRUint64 readCount = 0;
             rv = aIn->Available(&readCount);
             if (NS_FAILED(rv) || !readCount) {
                 if (rv == NS_BASE_STREAM_CLOSED) {
                     // End of file, but not an error
                     rv = NS_OK;
                 }
                 break;
             }
 
+            if (readCount > PR_UINT32_MAX)
+                readCount = PR_UINT32_MAX;
+
             rv = aListener->OnDataAvailable(aChannel, nullptr, aIn,
-                                            sourceOffset, readCount);
+                                            (PRUint32)NS_MIN(sourceOffset, (PRUint64)PR_UINT32_MAX),
+                                            (PRUint32)readCount);
             if (NS_FAILED(rv)) {
                 break;
             }
             sourceOffset += readCount;
         }
     }
     if (NS_FAILED(rv)) {
         aChannel->Cancel(rv);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2957,17 +2957,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
                                        postDataStream, 
                                        4096);
         NS_ENSURE_SUCCESS(rv, rv);
 
         postDataStream = bufferedStream;
       }
 
       mUploadComplete = false;
-      PRUint32 uploadTotal = 0;
+      PRUint64 uploadTotal = 0;
       postDataStream->Available(&uploadTotal);
       mUploadTotal = uploadTotal;
 
       // We want to use a newer version of the upload channel that won't
       // ignore the necessary headers for an empty Content-Type.
       nsCOMPtr<nsIUploadChannel2> uploadChannel2(do_QueryInterface(httpChannel));
       // This assertion will fire if buggy extensions are installed
       NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
--- a/content/canvas/src/nsCanvasRenderingContext2D.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp
@@ -4311,18 +4311,21 @@ nsCanvasRenderingContext2D::SetMozImageS
 
 static PRUint8 g2DContextLayerUserData;
 
 already_AddRefed<CanvasLayer>
 nsCanvasRenderingContext2D::GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                            CanvasLayer *aOldLayer,
                                            LayerManager *aManager)
 {
-    if (!EnsureSurface()) 
+    // If we don't have anything to draw, don't bother.
+    if (!mValid || !mSurface || mSurface->CairoStatus() || !mThebes ||
+        !mSurfaceCreated) {
         return nullptr;
+    }
 
     if (!mResetLayer && aOldLayer) {
         CanvasRenderingContext2DUserData* userData =
             static_cast<CanvasRenderingContext2DUserData*>(
                     aOldLayer->GetUserData(&g2DContextLayerUserData));
         if (userData && userData->IsForContext(this)) {
             NS_ADDREF(aOldLayer);
             return aOldLayer;
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -4640,33 +4640,30 @@ nsCanvasRenderingContext2DAzure::GetCanv
   }
 
   nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
   if (!canvasLayer) {
     NS_WARNING("CreateCanvasLayer returned null!");
     return nullptr;
   }
   CanvasRenderingContext2DUserDataAzure *userData = nullptr;
-  if (aBuilder->IsPaintingToWindow()) {
-    // Make the layer tell us whenever a transaction finishes (including
-    // the current transaction), so we can clear our invalidation state and
-    // start invalidating again. We need to do this for the layer that is
-    // being painted to a window (there shouldn't be more than one at a time,
-    // and if there is, flushing the invalidation state more often than
-    // necessary is harmless).
-
-    // The layer will be destroyed when we tear down the presentation
-    // (at the latest), at which time this userData will be destroyed,
-    // releasing the reference to the element.
-    // The userData will receive DidTransactionCallbacks, which flush the
-    // the invalidation state to indicate that the canvas is up to date.
-    userData = new CanvasRenderingContext2DUserDataAzure(this);
-    canvasLayer->SetDidTransactionCallback(
-            CanvasRenderingContext2DUserDataAzure::DidTransactionCallback, userData);
-  }
+  // Make the layer tell us whenever a transaction finishes (including
+  // the current transaction), so we can clear our invalidation state and
+  // start invalidating again. We need to do this for all layers since
+  // callers of DrawWindow may be expecting to receive normal invalidation
+  // notifications after this paint.
+
+  // The layer will be destroyed when we tear down the presentation
+  // (at the latest), at which time this userData will be destroyed,
+  // releasing the reference to the element.
+  // The userData will receive DidTransactionCallbacks, which flush the
+  // the invalidation state to indicate that the canvas is up to date.
+  userData = new CanvasRenderingContext2DUserDataAzure(this);
+  canvasLayer->SetDidTransactionCallback(
+          CanvasRenderingContext2DUserDataAzure::DidTransactionCallback, userData);
   canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
 
   CanvasLayer::Data data;
 
   data.mDrawTarget = mTarget;
   data.mSize = nsIntSize(mWidth, mHeight);
 
   canvasLayer->Initialize(data);
--- 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
@@ -8,16 +8,17 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= content
 LIBRARY_NAME	= gkconevents_s
 LIBXUL_LIBRARY  = 1
+FAIL_ON_WARNINGS = 1
 
 EXPORTS		= \
 		nsEventStateManager.h \
 		nsEventListenerManager.h \
 		nsDOMEventTargetHelper.h \
 		nsDOMEvent.h \
 		nsDOMTouchEvent.h \
 		nsDOMUIEvent.h \
@@ -57,16 +58,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");
@@ -713,30 +715,56 @@ nsDOMEvent::DuplicatePrivateData()
       compositionEvent->data = oldCompositionEvent->data;
       newEvent = compositionEvent;
       break;
     }
     case NS_MOUSE_SCROLL_EVENT:
     {
       nsMouseScrollEvent* mouseScrollEvent =
         new nsMouseScrollEvent(false, msg, nullptr);
-      NS_ENSURE_TRUE(mouseScrollEvent, NS_ERROR_OUT_OF_MEMORY);
       isInputEvent = true;
       nsMouseScrollEvent* oldMouseScrollEvent =
         static_cast<nsMouseScrollEvent*>(mEvent);
-      mouseScrollEvent->scrollFlags = oldMouseScrollEvent->scrollFlags;
+      mouseScrollEvent->isHorizontal = oldMouseScrollEvent->isHorizontal;
       mouseScrollEvent->delta = oldMouseScrollEvent->delta;
       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;
+      wheelEvent->customizedByUserPrefs = oldWheelEvent->customizedByUserPrefs;
+      wheelEvent->isMomentum = oldWheelEvent->isMomentum;
+      wheelEvent->isPixelOnlyDevice = oldWheelEvent->isPixelOnlyDevice;
+      wheelEvent->lineOrPageDeltaX = oldWheelEvent->lineOrPageDeltaX;
+      wheelEvent->lineOrPageDeltaY = oldWheelEvent->lineOrPageDeltaY;
+      wheelEvent->scrollType = oldWheelEvent->scrollType;
+      wheelEvent->overflowDeltaX = oldWheelEvent->overflowDeltaX;
+      wheelEvent->overflowDeltaY = oldWheelEvent->overflowDeltaY;
+      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 +1180,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 +1240,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 +1415,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/nsDOMMouseScrollEvent.cpp
+++ b/content/events/src/nsDOMMouseScrollEvent.cpp
@@ -16,18 +16,17 @@ nsDOMMouseScrollEvent::nsDOMMouseScrollE
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
     static_cast<nsMouseEvent*>(mEvent)->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
   }
 
   if(mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
-    nsMouseScrollEvent* mouseEvent = static_cast<nsMouseScrollEvent*>(mEvent);
-    mDetail = mouseEvent->delta;
+    mDetail = static_cast<nsMouseScrollEvent*>(mEvent)->delta;
   }
 }
 
 nsDOMMouseScrollEvent::~nsDOMMouseScrollEvent()
 {
   if (mEventIsInternal && mEvent) {
     switch (mEvent->eventStructType)
     {
@@ -61,34 +60,33 @@ nsDOMMouseScrollEvent::InitMouseScrollEv
                                 PRInt32 aAxis)
 {
   nsresult rv = nsDOMMouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
                                                 aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
                                                 aAltKey, aShiftKey, aMetaKey, aButton, aRelatedTarget);
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
-    static_cast<nsMouseScrollEvent*>(mEvent)->scrollFlags =
-        (aAxis == HORIZONTAL_AXIS) ? nsMouseScrollEvent::kIsHorizontal
-                                   : nsMouseScrollEvent::kIsVertical;
+    static_cast<nsMouseScrollEvent*>(mEvent)->isHorizontal =
+                                                (aAxis == HORIZONTAL_AXIS);
   }
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsDOMMouseScrollEvent::GetAxis(PRInt32* aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
 
   if (mEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
-    PRUint32 flags = static_cast<nsMouseScrollEvent*>(mEvent)->scrollFlags;
-    *aResult = (flags & nsMouseScrollEvent::kIsHorizontal)
-         ? PRInt32(HORIZONTAL_AXIS) : PRInt32(VERTICAL_AXIS);
+    *aResult = static_cast<nsMouseScrollEvent*>(mEvent)->isHorizontal ?
+                 static_cast<PRInt32>(HORIZONTAL_AXIS) :
+                 static_cast<PRInt32>(VERTICAL_AXIS);
   } else {
     *aResult = 0;
   }
   return NS_OK;
 }
 
 nsresult NS_NewDOMMouseScrollEvent(nsIDOMEvent** aInstancePtrResult,
                                    nsPresContext* aPresContext,
--- a/content/events/src/nsDOMTouchEvent.h
+++ b/content/events/src/nsDOMTouchEvent.h
@@ -92,17 +92,17 @@ public:
   nsIntPoint mScreenPoint;
   nsIntPoint mRadius;
   float mRotationAngle;
   float mForce;
 protected:
   bool mPointsInitialized;
 };
 
-class nsDOMTouchList : public nsIDOMTouchList
+class nsDOMTouchList MOZ_FINAL : public nsIDOMTouchList
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouchList)
   NS_DECL_NSIDOMTOUCHLIST
 
   nsDOMTouchList() { }
   nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches);
--- 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
@@ -48,17 +48,17 @@
 #include "nsFocusManager.h"
 
 #include "nsIDOMXULElement.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMKeyEvent.h"
 #include "nsIObserverService.h"
 #include "nsIDocShell.h"
 #include "nsIMarkupDocumentViewer.h"
-#include "nsIDOMMouseScrollEvent.h"
+#include "nsIDOMWheelEvent.h"
 #include "nsIDOMDragEvent.h"
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMUIEvent.h"
 #include "nsDOMDragEvent.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsIDOMMozBrowserFrame.h"
 #include "nsIMozBrowserFrame.h"
 
@@ -129,26 +129,30 @@ nsWeakPtr nsEventStateManager::sPointerL
 // Reference to the document which requested pointer lock.
 nsWeakPtr nsEventStateManager::sPointerLockedDoc;
 nsCOMPtr<nsIContent> nsEventStateManager::sDragOverContent = nullptr;
 
 static PRUint32 gMouseOrKeyboardEventCounter = 0;
 static nsITimer* gUserInteractionTimer = nullptr;
 static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
 
-// Pixel scroll accumulation for synthetic line scrolls
-static nscoord gPixelScrollDeltaX = 0;
-static nscoord gPixelScrollDeltaY = 0;
-static PRUint32 gPixelScrollDeltaTimeout = 0;
-
-static nscoord
-GetScrollableLineHeight(nsIFrame* aTargetFrame);
-
 TimeStamp nsEventStateManager::sHandlingInputStart;
 
+nsEventStateManager::WheelPrefs*
+  nsEventStateManager::WheelPrefs::sInstance = nullptr;
+nsEventStateManager::DeltaAccumulator*
+  nsEventStateManager::DeltaAccumulator::sInstance = nullptr;
+
+static inline PRInt32
+RoundDown(double aDouble)
+{
+  return (aDouble > 0) ? static_cast<PRInt32>(floor(aDouble)) :
+                         static_cast<PRInt32>(ceil(aDouble));
+}
+
 static inline bool
 IsMouseEventReal(nsEvent* aEvent)
 {
   NS_ABORT_IF_FALSE(NS_IS_MOUSE_EVENT_STRUCT(aEvent), "Not a mouse event");
   // Return true if not synthesized.
   return static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal;
 }
 
@@ -245,24 +249,16 @@ nsUITimerCallback::Notify(nsITimer* aTim
   } else {
     obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
     nsEventStateManager::UpdateUserActivityTimer();
   }
   mPreviousCount = gMouseOrKeyboardEventCounter;
   return NS_OK;
 }
 
-enum {
- MOUSE_SCROLL_N_LINES,
- MOUSE_SCROLL_PAGE,
- MOUSE_SCROLL_HISTORY,
- MOUSE_SCROLL_ZOOM,
- MOUSE_SCROLL_PIXELS
-};
-
 // mask values for ui.key.chromeAccess and ui.key.contentAccess
 #define NS_MODIFIER_SHIFT    1
 #define NS_MODIFIER_CONTROL  2
 #define NS_MODIFIER_ALT      4
 #define NS_MODIFIER_META     8
 #define NS_MODIFIER_OS       16
 
 static nsIDocument *
@@ -297,81 +293,64 @@ GetAccessModifierMaskFromPref(PRInt32 aI
     return Preferences::GetInt("ui.key.chromeAccess", 0);
   case nsIDocShellTreeItem::typeContent:
     return Preferences::GetInt("ui.key.contentAccess", 0);
   default:
     return 0;
   }
 }
 
-static void
-GetBasePrefKeyForMouseWheel(nsMouseScrollEvent* aEvent, nsACString& aPref)
+struct DeltaValues
 {
-  NS_NAMED_LITERAL_CSTRING(prefbase,    "mousewheel");
-  NS_NAMED_LITERAL_CSTRING(horizscroll, ".horizscroll");
-  NS_NAMED_LITERAL_CSTRING(withshift,   ".withshiftkey");
-  NS_NAMED_LITERAL_CSTRING(withalt,     ".withaltkey");
-  NS_NAMED_LITERAL_CSTRING(withcontrol, ".withcontrolkey");
-  NS_NAMED_LITERAL_CSTRING(withmetakey, ".withmetakey");
-  NS_NAMED_LITERAL_CSTRING(withno,      ".withnokey");
-
-  aPref = prefbase;
-  if (aEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
-    aPref.Append(horizscroll);
+  DeltaValues() : deltaX(0.0), deltaY(0.0) {}
+
+  DeltaValues(double aDeltaX, double aDeltaY) :
+    deltaX(aDeltaX), deltaY(aDeltaY)
+  {
   }
-  if (aEvent->IsShift()) {
-    aPref.Append(withshift);
-  } else if (aEvent->IsControl()) {
-    aPref.Append(withcontrol);
-  } else if (aEvent->IsAlt()) {
-    aPref.Append(withalt);
-  } else if (aEvent->IsMeta()) {
-    aPref.Append(withmetakey);
-  } else {
-    aPref.Append(withno);
+
+  explicit DeltaValues(widget::WheelEvent* aEvent) :
+    deltaX(aEvent->deltaX), deltaY(aEvent->deltaY)
+  {
   }
-}
+
+  double deltaX;
+  double deltaY;
+};
 
 class nsMouseWheelTransaction {
 public:
   static nsIFrame* GetTargetFrame() { return sTargetFrame; }
   static void BeginTransaction(nsIFrame* aTargetFrame,
-                               PRInt32 aNumLines,
-                               bool aScrollHorizontal);
+                               widget::WheelEvent* aEvent);
   // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
   // frame might be destroyed in the event handler.
-  static bool UpdateTransaction(PRInt32 aNumLines,
-                                  bool aScrollHorizontal);
+  static bool UpdateTransaction(widget::WheelEvent* aEvent);
   static void EndTransaction();
   static void OnEvent(nsEvent* aEvent);
   static void Shutdown();
   static PRUint32 GetTimeoutTime();
-  static PRInt32 AccelerateWheelDelta(PRInt32 aScrollLines,
-                   bool aIsHorizontal, bool aAllowScrollSpeedOverride,
-                   nsIScrollableFrame::ScrollUnit *aScrollQuantity,
-                   bool aLimitToMaxOnePageScroll = true);
-  static bool IsAccelerationEnabled();
+
+
+  static DeltaValues AccelerateWheelDelta(widget::WheelEvent* aEvent,
+                                          bool aAllowScrollSpeedOverride);
 
   enum {
     kScrollSeriesTimeout = 80
   };
 protected:
   static nsIntPoint GetScreenPoint(nsGUIEvent* aEvent);
   static void OnFailToScrollTarget();
   static void OnTimeout(nsITimer *aTimer, void *aClosure);
   static void SetTimeout();
   static PRUint32 GetIgnoreMoveDelayTime();
   static PRInt32 GetAccelerationStart();
   static PRInt32 GetAccelerationFactor();
-  static PRInt32 OverrideSystemScrollSpeed(PRInt32 aScrollLines,
-                                           bool aIsHorizontal);
-  static PRInt32 ComputeAcceleratedWheelDelta(PRInt32 aDelta, PRInt32 aFactor);
-  static PRInt32 LimitToOnePageScroll(PRInt32 aScrollLines,
-                   bool aIsHorizontal,
-                   nsIScrollableFrame::ScrollUnit *aScrollQuantity);
+  static DeltaValues OverrideSystemScrollSpeed(widget::WheelEvent* aEvent);
+  static double ComputeAcceleratedWheelDelta(double aDelta, PRInt32 aFactor);
 
   static nsWeakFrame sTargetFrame;
   static PRUint32    sTime;        // in milliseconds
   static PRUint32    sMouseMoved;  // in milliseconds
   static nsITimer*   sTimer;
   static PRInt32     sScrollSeriesCounter;
 };
 
@@ -384,57 +363,58 @@ PRInt32     nsMouseWheelTransaction::sSc
 static bool
 OutOfTime(PRUint32 aBaseTime, PRUint32 aThreshold)
 {
   PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow());
   return (now - aBaseTime > aThreshold);
 }
 
 static bool
-CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, PRInt32 aDirection)
+CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
 {
-  return aDirection > 0 ? aValue < aMax : aMin < aValue;
+  return aDirection > 0.0 ? aValue < static_cast<double>(aMax) :
+                            static_cast<double>(aMin) < aValue;
 }
 
 static bool
-CanScrollOn(nsIScrollableFrame* aScrollFrame, PRInt32 aNumLines,
-            bool aScrollHorizontal)
+CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDeltaX, double aDeltaY)
 {
-  NS_PRECONDITION(aScrollFrame, "aScrollFrame is null");
-  NS_PRECONDITION(aNumLines, "aNumLines must be non-zero");
+  MOZ_ASSERT(aScrollFrame);
+  NS_ASSERTION(aDeltaX || aDeltaY,
+               "One of the delta values must be non-zero at least");
+
   nsPoint scrollPt = aScrollFrame->GetScrollPosition();
   nsRect scrollRange = aScrollFrame->GetScrollRange();
 
-  return aScrollHorizontal
-    ? CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aNumLines)
-    : CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aNumLines);
+  return ((aDeltaX && CanScrollInRange(scrollRange.x, scrollPt.x,
+                                       scrollRange.XMost(), aDeltaX)) ||
+          (aDeltaY && CanScrollInRange(scrollRange.y, scrollPt.y,
+                                       scrollRange.YMost(), aDeltaY)));
 }
 
 void
 nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
-                                          PRInt32 aNumLines,
-                                          bool aScrollHorizontal)
+                                          widget::WheelEvent* aEvent)
 {
   NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
   sTargetFrame = aTargetFrame;
   sScrollSeriesCounter = 0;
-  if (!UpdateTransaction(aNumLines, aScrollHorizontal)) {
+  if (!UpdateTransaction(aEvent)) {
     NS_ERROR("BeginTransaction is called even cannot scroll the frame");
     EndTransaction();
   }
 }
 
 bool
-nsMouseWheelTransaction::UpdateTransaction(PRInt32 aNumLines,
-                                           bool aScrollHorizontal)
+nsMouseWheelTransaction::UpdateTransaction(widget::WheelEvent* aEvent)
 {
   nsIScrollableFrame* sf = GetTargetFrame()->GetScrollTargetFrame();
   NS_ENSURE_TRUE(sf, false);
 
-  if (!CanScrollOn(sf, aNumLines, aScrollHorizontal)) {
+  if (!CanScrollOn(sf, aEvent->deltaX, aEvent->deltaY)) {
     OnFailToScrollTarget();
     // We should not modify the transaction state when the view will not be
     // scrolled actually.
     return false;
   }
 
   SetTimeout();
 
@@ -470,28 +450,18 @@ nsMouseWheelTransaction::OnEvent(nsEvent
     // Even if the scroll event which is handled after timeout, but onTimeout
     // was not fired by timer, then the scroll event will scroll old frame,
     // therefore, we should call OnTimeout here and ensure to finish the old
     // transaction.
     OnTimeout(nullptr, nullptr);
     return;
   }
 
-  PRInt32 message = aEvent->message;
-  // If the event is query scroll target info event, that causes modifying
-  // wheel transaction because DoScrollText() needs to use them.  Therefore,
-  // we should handle the event as its mouse scroll event here.
-  if (message == NS_QUERY_SCROLL_TARGET_INFO) {
-    nsQueryContentEvent* queryEvent = static_cast<nsQueryContentEvent*>(aEvent);
-    message = queryEvent->mInput.mMouseScrollEvent->message;
-  }
-
-  switch (message) {
-    case NS_MOUSE_SCROLL:
-    case NS_MOUSE_PIXEL_SCROLL:
+  switch (aEvent->message) {
+    case NS_WHEEL_WHEEL:
       if (sMouseMoved != 0 &&
           OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
         // Terminate the current mousewheel transaction if the mouse moved more
         // than ignoremovedelay milliseconds ago
         EndTransaction();
       }
       return;
     case NS_MOUSE_MOVE:
@@ -612,134 +582,114 @@ nsMouseWheelTransaction::GetTimeoutTime(
 }
 
 PRUint32
 nsMouseWheelTransaction::GetIgnoreMoveDelayTime()
 {
   return Preferences::GetUint("mousewheel.transaction.ignoremovedelay", 100);
 }
 
-bool
-nsMouseWheelTransaction::IsAccelerationEnabled()
+DeltaValues
+nsMouseWheelTransaction::AccelerateWheelDelta(widget::WheelEvent* aEvent,
+                                              bool aAllowScrollSpeedOverride)
 {
-  return GetAccelerationStart() >= 0 && GetAccelerationFactor() > 0;
-}
-
-PRInt32
-nsMouseWheelTransaction::AccelerateWheelDelta(PRInt32 aScrollLines,
-                           bool aIsHorizontal,
-                           bool aAllowScrollSpeedOverride,
-                           nsIScrollableFrame::ScrollUnit *aScrollQuantity,
-                           bool aLimitToMaxOnePageScroll)
-{
+  DeltaValues result(aEvent);
+
+  // Don't accelerate the delta values if the event isn't line scrolling.
+  if (aEvent->deltaMode != nsIDOMWheelEvent::DOM_DELTA_LINE) {
+    return result;
+  }
+
   if (aAllowScrollSpeedOverride) {
-    aScrollLines = OverrideSystemScrollSpeed(aScrollLines, aIsHorizontal);
+    result = OverrideSystemScrollSpeed(aEvent);
   }
 
   // Accelerate by the sScrollSeriesCounter
   PRInt32 start = GetAccelerationStart();
   if (start >= 0 && sScrollSeriesCounter >= start) {
     PRInt32 factor = GetAccelerationFactor();
     if (factor > 0) {
-      aScrollLines = ComputeAcceleratedWheelDelta(aScrollLines, factor);
+      result.deltaX = ComputeAcceleratedWheelDelta(result.deltaX, factor);
+      result.deltaY = ComputeAcceleratedWheelDelta(result.deltaY, factor);
     }
   }
 
-  // If the computed delta is larger than the page, we should limit
-  // the delta value to the one page size.
-  return !aLimitToMaxOnePageScroll ? aScrollLines :
-    LimitToOnePageScroll(aScrollLines, aIsHorizontal, aScrollQuantity);
+  return result;
 }
 
-PRInt32
-nsMouseWheelTransaction::ComputeAcceleratedWheelDelta(PRInt32 aDelta,
+double
+nsMouseWheelTransaction::ComputeAcceleratedWheelDelta(double aDelta,
                                                       PRInt32 aFactor)
 {
-  if (aDelta == 0)
+  if (aDelta == 0.0) {
     return 0;
-
-  return PRInt32(NS_round(aDelta * sScrollSeriesCounter *
-                          (double)aFactor / 10));
+  }
+
+  return (aDelta * sScrollSeriesCounter * (double)aFactor / 10);
 }
 
 PRInt32
 nsMouseWheelTransaction::GetAccelerationStart()
 {
   return Preferences::GetInt("mousewheel.acceleration.start", -1);
 }
 
 PRInt32
 nsMouseWheelTransaction::GetAccelerationFactor()
 {
   return Preferences::GetInt("mousewheel.acceleration.factor", -1);
 }
 
-PRInt32
-nsMouseWheelTransaction::OverrideSystemScrollSpeed(PRInt32 aScrollLines,
-                                                   bool aIsHorizontal)
+DeltaValues
+nsMouseWheelTransaction::OverrideSystemScrollSpeed(widget::WheelEvent* aEvent)
 {
-  NS_PRECONDITION(sTargetFrame, "We don't have mouse scrolling transaction");
-
-  if (aScrollLines == 0) {
-    return 0;
+  MOZ_ASSERT(sTargetFrame, "We don't have mouse scrolling transaction");
+  MOZ_ASSERT(aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE);
+
+  DeltaValues result(aEvent);
+
+  // If the event doesn't scroll to both X and Y, we don't need to do anything
+  // here.  And also, if the event indicates the device supports high
+  // resolution scroll, we shouldn't need to override it.
+  if ((!aEvent->lineOrPageDeltaX && !aEvent->lineOrPageDeltaY) ||
+      (static_cast<double>(aEvent->lineOrPageDeltaX) != aEvent->deltaX) ||
+      (static_cast<double>(aEvent->lineOrPageDeltaY) != aEvent->deltaY)) {
+    return result;
   }
 
   // We shouldn't override the scrolling speed on non root scroll frame.
   if (sTargetFrame !=
         sTargetFrame->PresContext()->PresShell()->GetRootScrollFrame()) {
-    return aScrollLines;
+    return result;
   }
 
   // Compute the overridden speed to nsIWidget.  The widget can check the
   // conditions (e.g., checking the prefs, and also whether the user customized
   // the system settings of the mouse wheel scrolling or not), and can limit
   // the speed for preventing the unexpected high speed scrolling.
   nsCOMPtr<nsIWidget> widget(sTargetFrame->GetNearestWidget());
-  NS_ENSURE_TRUE(widget, aScrollLines);
-  PRInt32 overriddenDelta;
-  nsresult rv = widget->OverrideSystemMouseScrollSpeed(aScrollLines,
-                                                       aIsHorizontal,
-                                                       overriddenDelta);
-  NS_ENSURE_SUCCESS(rv, aScrollLines);
-  return overriddenDelta;
-}
-
-PRInt32
-nsMouseWheelTransaction::LimitToOnePageScroll(PRInt32 aScrollLines,
-                           bool aIsHorizontal,
-                           nsIScrollableFrame::ScrollUnit *aScrollQuantity)
-{
-  NS_ENSURE_TRUE(aScrollQuantity, aScrollLines);
-  NS_PRECONDITION(*aScrollQuantity == nsIScrollableFrame::LINES,
-                  "aScrollQuantity isn't by line");
-
-  NS_ENSURE_TRUE(sTargetFrame, aScrollLines);
-  nsIScrollableFrame* sf = sTargetFrame->GetScrollTargetFrame();
-  NS_ENSURE_TRUE(sf, aScrollLines);
-
-  // Limit scrolling to be at most one page, but if possible, try to
-  // just adjust the number of scrolled lines.
-  nsSize lineAmount = sf->GetLineScrollAmount();
-  nscoord lineScroll = aIsHorizontal ? lineAmount.width : lineAmount.height;
-
-  if (lineScroll == 0)
-    return aScrollLines;
-
-  nsSize pageAmount = sf->GetPageScrollAmount();
-  nscoord pageScroll = aIsHorizontal ? pageAmount.width : pageAmount.height;
-
-  if (NS_ABS(aScrollLines) * lineScroll < pageScroll)
-    return aScrollLines;
-
-  nscoord maxLines = (pageScroll / lineScroll);
-  if (maxLines >= 1)
-    return ((aScrollLines < 0) ? -1 : 1) * maxLines;
-
-  *aScrollQuantity = nsIScrollableFrame::PAGES;
-  return (aScrollLines < 0) ? -1 : 1;
+  NS_ENSURE_TRUE(widget, result);
+  PRInt32 overriddenDeltaX = 0, overriddenDeltaY = 0;
+  if (aEvent->lineOrPageDeltaX) {
+    nsresult rv =
+      widget->OverrideSystemMouseScrollSpeed(aEvent->lineOrPageDeltaX,
+                                             true, overriddenDeltaX);
+    if (NS_FAILED(rv)) {
+      return result;
+    }
+  }
+  if (aEvent->lineOrPageDeltaY) {
+    nsresult rv =
+      widget->OverrideSystemMouseScrollSpeed(aEvent->lineOrPageDeltaY,
+                                             false, overriddenDeltaY);
+    if (NS_FAILED(rv)) {
+      return result;
+    }
+  }
+  return DeltaValues(overriddenDeltaX, overriddenDeltaY);
 }
 
 /******************************************************************/
 /* nsEventStateManager                                            */
 /******************************************************************/
 
 nsEventStateManager::nsEventStateManager()
   : mLockCursor(0),
@@ -748,18 +698,16 @@ nsEventStateManager::nsEventStateManager
     mLastMouseOverFrame(nullptr),
     // init d&d gesture state machine variables
     mGestureDownPoint(0,0),
     mPresContext(nullptr),
     mLClickCount(0),
     mMClickCount(0),
     mRClickCount(0),
     m_haveShutdown(false),
-    mLastLineScrollConsumedX(false),
-    mLastLineScrollConsumedY(false),
     mClickHoldContextMenu(false)
 {
   if (sESMInstanceCount == 0) {
     gUserInteractionTimerCallback = new nsUITimerCallback();
     if (gUserInteractionTimerCallback)
       NS_ADDREF(gUserInteractionTimerCallback);
     UpdateUserActivityTimer();
   }
@@ -785,30 +733,16 @@ nsEventStateManager::UpdateUserActivityT
 
 static const char* kObservedPrefs[] = {
   "accessibility.accesskeycausesactivation",
   "nglayout.events.dispatchLeftClickOnly",
   "ui.key.generalAccessKey",
   "ui.key.chromeAccess",
   "ui.key.contentAccess",
   "ui.click_hold_context_menus",
-#if 0
-  "mousewheel.withaltkey.action",
-  "mousewheel.withaltkey.numlines",
-  "mousewheel.withaltkey.sysnumlines",
-  "mousewheel.withcontrolkey.action",
-  "mousewheel.withcontrolkey.numlines",
-  "mousewheel.withcontrolkey.sysnumlines",
-  "mousewheel.withnokey.action",
-  "mousewheel.withnokey.numlines",
-  "mousewheel.withnokey.sysnumlines",
-  "mousewheel.withshiftkey.action",
-  "mousewheel.withshiftkey.numlines",
-  "mousewheel.withshiftkey.sysnumlines",
-#endif
   "dom.popup_allowed_events",
   nullptr
 };
 
 nsresult
 nsEventStateManager::Init()
 {
   nsCOMPtr<nsIObserverService> observerService =
@@ -855,16 +789,18 @@ nsEventStateManager::~nsEventStateManage
     if (gUserInteractionTimerCallback) {
       gUserInteractionTimerCallback->Notify(nullptr);
       NS_RELEASE(gUserInteractionTimerCallback);
     }
     if (gUserInteractionTimer) {
       gUserInteractionTimer->Cancel();
       NS_RELEASE(gUserInteractionTimer);
     }
+    WheelPrefs::Shutdown();
+    DeltaAccumulator::Shutdown();
   }
 
   if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
     sDragOverContent = nullptr;
   }
 
   if (!m_haveShutdown) {
     Shutdown();
@@ -919,30 +855,16 @@ nsEventStateManager::Observe(nsISupports
       sChromeAccessModifier =
         GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeChrome);
     } else if (data.EqualsLiteral("ui.key.contentAccess")) {
       sContentAccessModifier =
         GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeContent);
     } else if (data.EqualsLiteral("ui.click_hold_context_menus")) {
       mClickHoldContextMenu =
         Preferences::GetBool("ui.click_hold_context_menus", false);
-#if 0
-    } else if (data.EqualsLiteral("mousewheel.withaltkey.action")) {
-    } else if (data.EqualsLiteral("mousewheel.withaltkey.numlines")) {
-    } else if (data.EqualsLiteral("mousewheel.withaltkey.sysnumlines")) {
-    } else if (data.EqualsLiteral("mousewheel.withcontrolkey.action")) {
-    } else if (data.EqualsLiteral("mousewheel.withcontrolkey.numlines")) {
-    } else if (data.EqualsLiteral("mousewheel.withcontrolkey.sysnumlines")) {
-    } else if (data.EqualsLiteral("mousewheel.withshiftkey.action")) {
-    } else if (data.EqualsLiteral("mousewheel.withshiftkey.numlines")) {
-    } else if (data.EqualsLiteral("mousewheel.withshiftkey.sysnumlines")) {
-    } else if (data.EqualsLiteral("mousewheel.withnokey.action")) {
-    } else if (data.EqualsLiteral("mousewheel.withnokey.numlines")) {
-    } else if (data.EqualsLiteral("mousewheel.withnokey.sysnumlines")) {
-#endif
     } else if (data.EqualsLiteral("dom.popup_allowed_events")) {
       nsDOMEvent::PopupAllowedEventsChanged();
     }
   }
 
   return NS_OK;
 }
 
@@ -1024,31 +946,31 @@ 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_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();
       }
@@ -1179,84 +1101,34 @@ nsEventStateManager::PreHandleEvent(nsPr
   case NS_KEY_DOWN:
   case NS_KEY_UP:
     {
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
     }
     break;
-  case NS_MOUSE_SCROLL:
+  case NS_WHEEL_WHEEL:
     {
-      nsIContent* content = GetFocusedContent();
-      if (content)
-        mCurrentTargetContent = content;
-
-      nsMouseScrollEvent* msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
-
-      msEvent->delta = ComputeWheelDeltaFor(msEvent);
-    }
-    break;
-  case NS_MOUSE_PIXEL_SCROLL:
-    {
+      NS_ASSERTION(NS_IS_TRUSTED_EVENT(aEvent),
+                   "Untrusted wheel event shouldn't be here");
+
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
 
-      nsMouseScrollEvent *msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
-
-      // Clear old deltas after a period of non action
-      if (OutOfTime(gPixelScrollDeltaTimeout, nsMouseWheelTransaction::GetTimeoutTime())) {
-        gPixelScrollDeltaX = gPixelScrollDeltaY = 0;
-      }
-      gPixelScrollDeltaTimeout = PR_IntervalToMilliseconds(PR_IntervalNow());
-
-      // If needed send a line scroll event for pixel scrolls with kNoLines
-      if (msEvent->scrollFlags & nsMouseScrollEvent::kNoLines) {
-        nscoord pixelHeight = aPresContext->AppUnitsToIntCSSPixels(
-          GetScrollableLineHeight(aTargetFrame));
-
-        if (msEvent->scrollFlags & nsMouseScrollEvent::kIsVertical) {
-          gPixelScrollDeltaX += msEvent->delta;
-          if (!gPixelScrollDeltaX || !pixelHeight)
-            break;
-
-          if (NS_ABS(gPixelScrollDeltaX) >= pixelHeight) {
-            PRInt32 numLines = (PRInt32)ceil((float)gPixelScrollDeltaX/(float)pixelHeight);
-
-            gPixelScrollDeltaX -= numLines*pixelHeight;
-
-            nsWeakFrame weakFrame(aTargetFrame);
-            SendLineScrollEvent(aTargetFrame, msEvent, aPresContext,
-              aStatus, numLines);
-            NS_ENSURE_STATE(weakFrame.IsAlive());
-          }
-        } else if (msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
-          gPixelScrollDeltaY += msEvent->delta;
-          if (!gPixelScrollDeltaY || !pixelHeight)
-            break;
-
-          if (NS_ABS(gPixelScrollDeltaY) >= pixelHeight) {
-            PRInt32 numLines = (PRInt32)ceil((float)gPixelScrollDeltaY/(float)pixelHeight);
-
-            gPixelScrollDeltaY -= numLines*pixelHeight;
-
-            nsWeakFrame weakFrame(aTargetFrame);
-            SendLineScrollEvent(aTargetFrame, msEvent, aPresContext,
-              aStatus, numLines);
-            NS_ENSURE_STATE(weakFrame.IsAlive());
-          }
-        }
-      }
-
-      // When the last line scroll has been canceled, eat the pixel scroll event
-      if ((msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) ?
-           mLastLineScrollConsumedX : mLastLineScrollConsumedY) {
-        *aStatus = nsEventStatus_eConsumeNoDefault;
-      }
+      widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(aEvent);
+      WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
+
+      // Init lineOrPageDelta values for line scroll events for some devices
+      // on some platforms which might dispatch wheel events which don't have
+      // lineOrPageDelta values.  And also, if delta values are customized by
+      // prefs, this recomputes them.
+      DeltaAccumulator::GetInstance()->
+        InitLineOrPageDelta(aTargetFrame, this, wheelEvent);
     }
     break;
   case NS_QUERY_SELECTED_TEXT:
     DoQuerySelectedText(static_cast<nsQueryContentEvent*>(aEvent));
     break;
   case NS_QUERY_TEXT_CONTENT:
     {
       if (RemoteQueryContentEvent(aEvent))
@@ -1309,22 +1181,16 @@ nsEventStateManager::PreHandleEvent(nsPr
     break;
   case NS_QUERY_DOM_WIDGET_HITTEST:
     {
       // XXX remote event
       nsContentEventHandler handler(mPresContext);
       handler.OnQueryDOMWidgetHittest(static_cast<nsQueryContentEvent*>(aEvent));
     }
     break;
-  case NS_QUERY_SCROLL_TARGET_INFO:
-    {
-      DoQueryScrollTargetInfo(static_cast<nsQueryContentEvent*>(aEvent),
-                              aTargetFrame);
-      break;
-    }
   case NS_SELECTION_SET:
     {
       nsSelectionEvent *selectionEvent =
           static_cast<nsSelectionEvent*>(aEvent);
       if (IsTargetCrossProcess(selectionEvent)) {
         // Will not be handled locally, remote the event
         if (GetCrossProcessTarget()->SendSelectionEvent(*selectionEvent))
           selectionEvent->mSucceeded = true;
@@ -1654,19 +1520,19 @@ nsEventStateManager::DispatchCrossProces
   case NS_MOUSE_EVENT: {
     nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
     return remote->SendRealMouseEvent(*mouseEvent);
   }
   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);
   }
@@ -1705,17 +1571,17 @@ nsEventStateManager::IsRemoteTarget(nsIC
   return false;
 }
 
 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:
@@ -2613,383 +2479,457 @@ GetParentFrameToScroll(nsIFrame* aFrame)
 
   if (aFrame->GetStyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
       nsLayoutUtils::IsReallyFixedPos(aFrame))
     return aFrame->PresContext()->GetPresShell()->GetRootScrollFrame();
 
   return aFrame->GetParent();
 }
 
-static nscoord
-GetScrollableLineHeight(nsIFrame* aTargetFrame)
+void
+nsEventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
+                                                     widget::WheelEvent* aEvent,
+                                                     nsEventStatus* aStatus)
 {
-  for (nsIFrame* f = aTargetFrame; f; f = GetParentFrameToScroll(f)) {
-    nsIScrollableFrame* sf = f->GetScrollTargetFrame();
-    if (sf)
-      return sf->GetLineScrollAmount().height;
+  MOZ_ASSERT(aEvent);
+  MOZ_ASSERT(aStatus);
+
+  if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
+    return;
   }
 
-  // Fall back to the font height of the target frame.
-  nsRefPtr<nsFontMetrics> fm;
-  nsLayoutUtils::GetFontMetricsForFrame(aTargetFrame, getter_AddRefs(fm),
-    nsLayoutUtils::FontSizeInflationFor(aTargetFrame));
-  NS_ASSERTION(fm, "FontMetrics is null!");
-  if (fm)
-    return fm->MaxHeight();
-  return 0;
+  // Ignore mouse wheel transaction for computing legacy mouse wheel
+  // events' delta value.
+  nsIScrollableFrame* scrollTarget =
+    ComputeScrollTarget(aTargetFrame, aEvent, false);
+
+  nsIFrame* scrollFrame = do_QueryFrame(scrollTarget);
+  nsPresContext* pc =
+    scrollFrame ? scrollFrame->PresContext() : aTargetFrame->PresContext();
+
+  // DOM event's delta vales are computed from CSS pixels.
+  nsSize scrollAmount = GetScrollAmount(pc, aEvent, scrollTarget);
+  nsIntSize scrollAmountInCSSPixels(
+    nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width),
+    nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height));
+
+  PRInt32 scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
+  switch (aEvent->deltaMode) {
+    case nsIDOMWheelEvent::DOM_DELTA_PAGE:
+      scrollDeltaX =
+        !aEvent->lineOrPageDeltaX ? 0 :
+          (aEvent->lineOrPageDeltaX > 0  ? nsIDOMUIEvent::SCROLL_PAGE_DOWN :
+                                           nsIDOMUIEvent::SCROLL_PAGE_UP);
+      scrollDeltaY =
+        !aEvent->lineOrPageDeltaY ? 0 :
+          (aEvent->lineOrPageDeltaY > 0  ? nsIDOMUIEvent::SCROLL_PAGE_DOWN :
+                                           nsIDOMUIEvent::SCROLL_PAGE_UP);
+      pixelDeltaX = RoundDown(aEvent->deltaX * scrollAmountInCSSPixels.width);
+      pixelDeltaY = RoundDown(aEvent->deltaY * scrollAmountInCSSPixels.height);
+      break;
+
+    case nsIDOMWheelEvent::DOM_DELTA_LINE:
+      scrollDeltaX = aEvent->lineOrPageDeltaX;
+      scrollDeltaY = aEvent->lineOrPageDeltaY;
+      pixelDeltaX = RoundDown(aEvent->deltaX * scrollAmountInCSSPixels.width);
+      pixelDeltaY = RoundDown(aEvent->deltaY * scrollAmountInCSSPixels.height);
+      break;
+
+    case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
+      scrollDeltaX = aEvent->lineOrPageDeltaX;
+      scrollDeltaY = aEvent->lineOrPageDeltaY;
+      pixelDeltaX = RoundDown(aEvent->deltaX);
+      pixelDeltaY = RoundDown(aEvent->deltaY);
+      break;
+
+    default:
+      MOZ_NOT_REACHED("Invalid deltaMode value comes");
+      return;
+  }
+
+  // Send the legacy events in following order:
+  // 1. Vertical scroll
+  // 2. Vertical pixel scroll (even if #1 isn't consumed)
+  // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
+  // 4. Horizontal pixel scroll (even if #3 isn't consumed)
+
+  nsWeakFrame targetFrame(aTargetFrame);
+
+  nsEventStatus statusX = *aStatus;
+  nsEventStatus statusY = *aStatus;
+  if (scrollDeltaY) {
+    SendLineScrollEvent(aTargetFrame, aEvent, &statusY,
+                        scrollDeltaY, DELTA_DIRECTION_Y);
+    if (!targetFrame.IsAlive()) {
+      *aStatus = nsEventStatus_eConsumeNoDefault;
+      return;
+    }
+  }
+
+  if (pixelDeltaY) {
+    SendPixelScrollEvent(aTargetFrame, aEvent, &statusY,
+                         pixelDeltaY, DELTA_DIRECTION_Y);
+    if (!targetFrame.IsAlive()) {
+      *aStatus = nsEventStatus_eConsumeNoDefault;
+      return;
+    }
+  }
+
+  if (scrollDeltaX) {
+    SendLineScrollEvent(aTargetFrame, aEvent, &statusX,
+                        scrollDeltaX, DELTA_DIRECTION_X);
+    if (!targetFrame.IsAlive()) {
+      *aStatus = nsEventStatus_eConsumeNoDefault;
+      return;
+    }
+  }
+
+  if (pixelDeltaX) {
+    SendPixelScrollEvent(aTargetFrame, aEvent, &statusX,
+                         pixelDeltaX, DELTA_DIRECTION_X);
+    if (!targetFrame.IsAlive()) {
+      *aStatus = nsEventStatus_eConsumeNoDefault;
+      return;
+    }
+  }
+
+  if (statusY == nsEventStatus_eConsumeNoDefault ||
+      statusX == nsEventStatus_eConsumeNoDefault) {
+    *aStatus = nsEventStatus_eConsumeNoDefault;
+    return;
+  }
+  if (statusY == nsEventStatus_eConsumeDoDefault ||
+      statusX == nsEventStatus_eConsumeDoDefault) {
+    *aStatus = nsEventStatus_eConsumeDoDefault;
+  }
 }
 
 void
 nsEventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
-                                         nsMouseScrollEvent* aEvent,
-                                         nsPresContext* aPresContext,
+                                         widget::WheelEvent* aEvent,
                                          nsEventStatus* aStatus,
-                                         PRInt32 aNumLines)
+                                         PRInt32 aDelta,
+                                         DeltaDirection aDeltaDirection)
 {
   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
   if (!targetContent)
     targetContent = GetFocusedContent();
   if (!targetContent)
     return;
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
-  bool isTrusted = (aEvent->flags & NS_EVENT_FLAG_TRUSTED) != 0;
-  nsMouseScrollEvent event(isTrusted, NS_MOUSE_SCROLL, nullptr);
+  nsMouseScrollEvent event(NS_IS_TRUSTED_EVENT(aEvent), NS_MOUSE_SCROLL,
+                           aEvent->widget);
+  if (*aStatus == nsEventStatus_eConsumeNoDefault) {
+    event.flags |= NS_EVENT_FLAG_NO_DEFAULT;
+  }
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.modifiers = aEvent->modifiers;
   event.buttons = aEvent->buttons;
-  event.scrollFlags = aEvent->scrollFlags;
-  event.delta = aNumLines;
-  event.inputSource = static_cast<nsMouseEvent_base*>(aEvent)->inputSource;
-
-  nsEventDispatcher::Dispatch(targetContent, aPresContext, &event, nullptr, aStatus);
+  event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
+  event.delta = aDelta;
+  event.inputSource = aEvent->inputSource;
+
+  nsEventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
+                              &event, nullptr, aStatus);
 }
 
 void
 nsEventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
-                                          nsMouseScrollEvent* aEvent,
-                                          nsPresContext* aPresContext,
-                                          nsEventStatus* aStatus)
+                                          widget::WheelEvent* aEvent,
+                                          nsEventStatus* aStatus,
+                                          PRInt32 aPixelDelta,
+                                          DeltaDirection aDeltaDirection)
 {
   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
   if (!targetContent) {
     targetContent = GetFocusedContent();
     if (!targetContent)
       return;
   }
 
   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
     targetContent = targetContent->GetParent();
   }
 
-  nscoord lineHeight = GetScrollableLineHeight(aTargetFrame);
-
-  bool isTrusted = (aEvent->flags & NS_EVENT_FLAG_TRUSTED) != 0;
-  nsMouseScrollEvent event(isTrusted, NS_MOUSE_PIXEL_SCROLL, nullptr);
+  nsMouseScrollEvent event(NS_IS_TRUSTED_EVENT(aEvent), NS_MOUSE_PIXEL_SCROLL,
+                           aEvent->widget);
+  if (*aStatus == nsEventStatus_eConsumeNoDefault) {
+    event.flags |= NS_EVENT_FLAG_NO_DEFAULT;
+  }
   event.refPoint = aEvent->refPoint;
   event.widget = aEvent->widget;
   event.time = aEvent->time;
   event.modifiers = aEvent->modifiers;
   event.buttons = aEvent->buttons;
-  event.scrollFlags = aEvent->scrollFlags;
-  event.inputSource = static_cast<nsMouseEvent_base*>(aEvent)->inputSource;
-  event.delta = aPresContext->AppUnitsToIntCSSPixels(aEvent->delta * lineHeight);
-
-  nsEventDispatcher::Dispatch(targetContent, aPresContext, &event, nullptr, aStatus);
+  event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
+  event.delta = aPixelDelta;
+  event.inputSource = aEvent->inputSource;
+
+  nsEventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
+                              &event, nullptr, aStatus);
 }
 
-PRInt32
-nsEventStateManager::ComputeWheelDeltaFor(nsMouseScrollEvent* aMouseEvent)
-{
-  PRInt32 delta = aMouseEvent->delta;
-  bool useSysNumLines = UseSystemScrollSettingFor(aMouseEvent);
-  if (!useSysNumLines) {
-    // If the scroll event's delta isn't to our liking, we can
-    // override it with the "numlines" parameter.  There are two
-    // things we can do:
-    //
-    // (1) Pick a different number.  Instead of scrolling 3
-    //     lines ("delta" in Gtk2), we would scroll 1 line.
-    // (2) Swap directions.  Instead of scrolling down, scroll up.
-    //
-    // For the first item, the magnitude of the parameter is
-    // used instead of the magnitude of the delta.  For the
-    // second item, if the parameter is negative we swap
-    // directions.
-
-    PRInt32 numLines = GetScrollLinesFor(aMouseEvent);
-
-    bool swapDirs = (numLines < 0);
-    PRInt32 userSize = swapDirs ? -numLines : numLines;
-
-    bool deltaUp = (delta < 0);
-    if (swapDirs) {
-      deltaUp = !deltaUp;
-    }
-    delta = deltaUp ? -userSize : userSize;
-  }
-
-  if (ComputeWheelActionFor(aMouseEvent, useSysNumLines) == MOUSE_SCROLL_PAGE) {
-    delta = (delta > 0) ? PRInt32(nsIDOMUIEvent::SCROLL_PAGE_DOWN) :
-                          PRInt32(nsIDOMUIEvent::SCROLL_PAGE_UP);
-  }
-
-  return delta;
-}
-
-PRInt32
-nsEventStateManager::ComputeWheelActionFor(nsMouseScrollEvent* aMouseEvent,
-                                           bool aUseSystemSettings)
+nsIScrollableFrame*
+nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
+                                         widget::WheelEvent* aEvent,
+                                         bool aForDefaultAction)
 {
-  PRInt32 action = GetWheelActionFor(aMouseEvent);
-  if (aUseSystemSettings &&
-      (aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsFullPage)) {
-    action = MOUSE_SCROLL_PAGE;
-  }
-
-  if (aMouseEvent->message == NS_MOUSE_PIXEL_SCROLL) {
-    if (action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE ||
-        (aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
-      action = MOUSE_SCROLL_PIXELS;
-    } else {
-      // Do not scroll pixels when zooming
-      action = -1;
-    }
-  } else if (((aMouseEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) &&
-              (aUseSystemSettings ||
-               action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE)) ||
-             ((aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum) &&
-              (action == MOUSE_SCROLL_HISTORY || action == MOUSE_SCROLL_ZOOM))) {
-    // Don't scroll lines or page when a pixel scroll event will follow.
-    // Also, don't do history scrolling or zooming for momentum scrolls,
-    // no matter what's going on with pixel scrolling.
-    action = -1;
-  }
-
-  return action;
-}
-
-PRInt32
-nsEventStateManager::GetWheelActionFor(nsMouseScrollEvent* aMouseEvent)
-{
-  nsCAutoString prefName;
-  GetBasePrefKeyForMouseWheel(aMouseEvent, prefName);
-  prefName.Append(".action");
-  return Preferences::GetInt(prefName.get());
-}
-
-PRInt32
-nsEventStateManager::GetScrollLinesFor(nsMouseScrollEvent* aMouseEvent)
-{
-  NS_ASSERTION(!UseSystemScrollSettingFor(aMouseEvent),
-    "GetScrollLinesFor() called when should use system settings");
-  nsCAutoString prefName;
-  GetBasePrefKeyForMouseWheel(aMouseEvent, prefName);
-  prefName.Append(".numlines");
-  return Preferences::GetInt(prefName.get());
-}
-
-bool
-nsEventStateManager::UseSystemScrollSettingFor(nsMouseScrollEvent* aMouseEvent)
-{
-  nsCAutoString prefName;
-  GetBasePrefKeyForMouseWheel(aMouseEvent, prefName);
-  prefName.Append(".sysnumlines");
-  return Preferences::GetBool(prefName.get());
-}
-
-nsresult
-nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame,
-                                  nsMouseScrollEvent* aMouseEvent,
-                                  nsIScrollableFrame::ScrollUnit aScrollQuantity,
-                                  bool aAllowScrollSpeedOverride,
-                                  nsQueryContentEvent* aQueryEvent,
-                                  nsIAtom *aOrigin)
-{
-  nsIScrollableFrame* frameToScroll = nullptr;
-  nsIFrame* scrollFrame = aTargetFrame;
-  PRInt32 numLines = aMouseEvent->delta;
-  bool isHorizontal = aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal;
-  aMouseEvent->scrollOverflow = 0;
-
-  // If the user recently scrolled with the mousewheel, then they probably want
-  // to scroll the same view as before instead of the view under the cursor.
-  // nsMouseWheelTransaction tracks the frame currently being scrolled with the
-  // mousewheel. We consider the transaction ended when the mouse moves more than
-  // "mousewheel.transaction.ignoremovedelay" milliseconds after the last scroll
-  // operation, or any time the mouse moves out of the frame, or when more than
-  // "mousewheel.transaction.timeout" milliseconds have passed after the last
-  // operation, even if the mouse hasn't moved.
-  nsIFrame* lastScrollFrame = nsMouseWheelTransaction::GetTargetFrame();
-  if (lastScrollFrame) {
-    frameToScroll = lastScrollFrame->GetScrollTargetFrame();
-    if (frameToScroll) {
-      nsMouseWheelTransaction::UpdateTransaction(numLines, isHorizontal);
-      // When the scroll event will not scroll any views, UpdateTransaction
-      // fired MozMouseScrollFailed event which is for automated testing.
-      // In the event handler, the target frame might be destroyed.  Then,
-      // we should not keep handling this scroll event.
-      if (!nsMouseWheelTransaction::GetTargetFrame())
-        return NS_OK;
-    } else {
-      nsMouseWheelTransaction::EndTransaction();
-      lastScrollFrame = nullptr;
+  if (aForDefaultAction) {
+    // If the user recently scrolled with the mousewheel, then they probably
+    // want to scroll the same view as before instead of the view under the
+    // cursor.  nsMouseWheelTransaction tracks the frame currently being
+    // scrolled with the mousewheel. We consider the transaction ended when the
+    // mouse moves more than "mousewheel.transaction.ignoremovedelay"
+    // milliseconds after the last scroll operation, or any time the mouse moves
+    // out of the frame, or when more than "mousewheel.transaction.timeout"
+    // milliseconds have passed after the last operation, even if the mouse
+    // hasn't moved.
+    nsIFrame* lastScrollFrame = nsMouseWheelTransaction::GetTargetFrame();
+    if (lastScrollFrame) {
+      nsIScrollableFrame* frameToScroll =
+        lastScrollFrame->GetScrollTargetFrame();
+      if (frameToScroll) {
+        return frameToScroll;
+      }
     }
   }
-  bool passToParent = lastScrollFrame ? false : true;
-
-  for (; scrollFrame && passToParent;
+
+  // If the event doesn't cause scroll actually, we cannot find scroll target
+  // because we check if the event can cause scroll actually on each found
+  // scrollable frame.
+  if (!aEvent->deltaX && !aEvent->deltaY) {
+    return nullptr;
+  }
+
+  nsIScrollableFrame* frameToScroll = nullptr;
+  for (nsIFrame* scrollFrame = aTargetFrame; scrollFrame;
        scrollFrame = GetParentFrameToScroll(scrollFrame)) {
     // Check whether the frame wants to provide us with a scrollable view.
     frameToScroll = scrollFrame->GetScrollTargetFrame();
     if (!frameToScroll) {
       continue;
     }
 
+    // At computing scroll target for legacy mouse events, we should return
+    // first scrollable element even when it's not scrollable to the direction.
+    if (!aForDefaultAction) {
+      return frameToScroll;
+    }
+
     nsPresContext::ScrollbarStyles ss = frameToScroll->GetScrollbarStyles();
-    if (NS_STYLE_OVERFLOW_HIDDEN ==
-        (isHorizontal ? ss.mHorizontal : ss.mVertical)) {
+    bool hiddenForV = (NS_STYLE_OVERFLOW_HIDDEN == ss.mVertical);
+    bool hiddenForH = (NS_STYLE_OVERFLOW_HIDDEN == ss.mHorizontal);
+    if ((hiddenForV && hiddenForH) ||
+        (aEvent->deltaY && !aEvent->deltaX && hiddenForV) ||
+        (aEvent->deltaX && !aEvent->deltaY && hiddenForH)) {
       continue;
     }
 
     // Check if the scrollable view can be scrolled any further.
-    nscoord lineHeight = frameToScroll->GetLineScrollAmount().height;
-    if (lineHeight != 0) {
-      if (CanScrollOn(frameToScroll, numLines, isHorizontal)) {
-        passToParent = false;
-        nsMouseWheelTransaction::BeginTransaction(scrollFrame,
-                                                  numLines, isHorizontal);
-      }
-
+    if (frameToScroll->GetLineScrollAmount().height) {
+      // For default action, we should climb up the tree if cannot scroll it
+      // by the event actually.
+      bool canScroll = CanScrollOn(frameToScroll,
+                                   aEvent->deltaX, aEvent->deltaY);
       // Comboboxes need special care.
       nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
       if (comboBox) {
         if (comboBox->IsDroppedDown()) {
           // Don't propagate to parent when drop down menu is active.
-          if (passToParent) {
-            passToParent = false;
-            frameToScroll = nullptr;
-            nsMouseWheelTransaction::EndTransaction();
-          }
-        } else {
-          // Always propagate when not dropped down (even if focused).
-          if (!passToParent) {
-            passToParent = true;
-            nsMouseWheelTransaction::EndTransaction();
-          }
+          return canScroll ? frameToScroll : nullptr;
         }
+        // Always propagate when not dropped down (even if focused).
+        continue;
+      }
+
+      if (canScroll) {
+        return frameToScroll;
       }
     }
   }
 
-  if (!passToParent && frameToScroll) {
-    if (aScrollQuantity == nsIScrollableFrame::LINES) {
-      // When this is called for querying the scroll target information,
-      // we shouldn't limit the scrolling amount to less one page.
-      // Otherwise, we shouldn't scroll more one page at once.
-      numLines =
-        nsMouseWheelTransaction::AccelerateWheelDelta(numLines, isHorizontal,
-                                                      aAllowScrollSpeedOverride,
-                                                      &aScrollQuantity,
-                                                      !aQueryEvent);
-    }
-#ifdef DEBUG
-    else {
-      NS_ASSERTION(!aAllowScrollSpeedOverride,
-        "aAllowScrollSpeedOverride is true but the quantity isn't by-line scrolling.");
-    }
-#endif
-
-    if (aScrollQuantity == nsIScrollableFrame::PAGES) {
-      numLines = (numLines > 0) ? 1 : -1;
-    }
-
-    if (aQueryEvent) {
-      // If acceleration is enabled, pixel scroll shouldn't be used for
-      // high resolution scrolling.
-      if (nsMouseWheelTransaction::IsAccelerationEnabled()) {
-        return NS_OK;
+  nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame(
+      aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
+  return newFrame ?
+    ComputeScrollTarget(newFrame, aEvent, aForDefaultAction) : nullptr;
+}
+
+nsSize
+nsEventStateManager::GetScrollAmount(nsPresContext* aPresContext,
+                                     widget::WheelEvent* aEvent,
+                                     nsIScrollableFrame* aScrollableFrame)
+{
+  MOZ_ASSERT(aPresContext);
+  MOZ_ASSERT(aEvent);
+
+  bool isPage = (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE);
+  if (aScrollableFrame) {
+    return isPage ? aScrollableFrame->GetPageScrollAmount() :
+                    aScrollableFrame->GetLineScrollAmount();
+  }
+
+  // If there is no scrollable frame and page scrolling, use view port size.
+  if (isPage) {
+    return aPresContext->GetVisibleArea().Size();
+  }
+
+  // If there is no scrollable frame, we should use root frame's information.
+  nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
+  if (!rootFrame) {
+    return nsSize(0, 0);
+  }
+  nsRefPtr<nsFontMetrics> fm;
+  nsLayoutUtils::GetFontMetricsForFrame(rootFrame, getter_AddRefs(fm),
+    nsLayoutUtils::FontSizeInflationFor(rootFrame));
+  NS_ENSURE_TRUE(fm, nsSize(0, 0));
+  PRInt32 fontHeight = fm->MaxHeight();
+  return nsSize(fontHeight, fontHeight);
+}
+
+void
+nsEventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
+                                  widget::WheelEvent* aEvent)
+{
+  MOZ_ASSERT(aScrollableFrame);
+  MOZ_ASSERT(aEvent);
+
+  aEvent->overflowDeltaX = aEvent->deltaX;
+  aEvent->overflowDeltaY = aEvent->deltaY;
+  WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
+
+  nsIFrame* scrollFrame = do_QueryFrame(aScrollableFrame);
+  MOZ_ASSERT(scrollFrame);
+  nsWeakFrame scrollFrameWeak(scrollFrame);
+
+  nsIFrame* lastScrollFrame = nsMouseWheelTransaction::GetTargetFrame();
+  if (!lastScrollFrame) {
+    nsMouseWheelTransaction::BeginTransaction(scrollFrame, aEvent);
+  } else if (lastScrollFrame != scrollFrame) {
+    nsMouseWheelTransaction::EndTransaction();
+    nsMouseWheelTransaction::BeginTransaction(scrollFrame, aEvent);
+  } else {
+    nsMouseWheelTransaction::UpdateTransaction(aEvent);
+  }
+
+  // When the scroll event will not scroll any views, UpdateTransaction
+  // fired MozMouseScrollFailed event which is for automated testing.
+  // In the event handler, the target frame might be destroyed.  Then,
+  // we should not try scrolling anything.
+  if (!scrollFrameWeak.IsAlive()) {
+    nsMouseWheelTransaction::EndTransaction();
+    return;
+  }
+
+  // If the wheel event is line scroll and the delta value is computed from
+  // system settings, allow to override the system speed.
+  bool allowScrollSpeedOverride =
+    (!aEvent->customizedByUserPrefs &&
+     aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE);
+  DeltaValues acceleratedDelta =
+    nsMouseWheelTransaction::AccelerateWheelDelta(aEvent,
+                                                  allowScrollSpeedOverride);
+
+  bool isDeltaModePixel =
+    (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL);
+
+  // Default action's actual scroll amount should be computed from device
+  // pixels.
+  nsPresContext* pc = scrollFrame->PresContext();
+  nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollableFrame);
+  nsIntSize scrollAmountInDevPixels(
+    pc->AppUnitsToDevPixels(scrollAmount.width),
+    pc->AppUnitsToDevPixels(scrollAmount.height));
+
+  nsIntPoint actualDevPixelScrollAmount(0, 0);
+  if (isDeltaModePixel) {
+    actualDevPixelScrollAmount.x = RoundDown(acceleratedDelta.deltaX);
+    actualDevPixelScrollAmount.y = RoundDown(acceleratedDelta.deltaY);
+  } else {
+    actualDevPixelScrollAmount.x =
+      RoundDown(scrollAmountInDevPixels.width * acceleratedDelta.deltaX);
+    actualDevPixelScrollAmount.y =
+      RoundDown(scrollAmountInDevPixels.height * acceleratedDelta.deltaY);
+  }
+
+  nsIAtom* origin = nullptr;
+  switch (aEvent->deltaMode) {
+    case nsIDOMWheelEvent::DOM_DELTA_LINE:
+      origin = nsGkAtoms::mouseWheel;
+      break;
+    case nsIDOMWheelEvent::DOM_DELTA_PAGE:
+      origin = nsGkAtoms::pages;
+      break;
+    case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
+      origin = nsGkAtoms::pixels;
+      break;
+    default:
+      MOZ_NOT_REACHED("Invalid deltaMode value comes");
+      return;
+  }
+
+  // We shouldn't scroll more one page at once.
+  nsSize pageSize = aScrollableFrame->GetPageScrollAmount();
+  nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
+                             pc->AppUnitsToDevPixels(pageSize.height));
+  if (NS_ABS(actualDevPixelScrollAmount.x) > devPixelPageSize.width) {
+    actualDevPixelScrollAmount.x =
+      (actualDevPixelScrollAmount.x >= 0) ? devPixelPageSize.width :
+                                            -devPixelPageSize.width;
+  }
+
+  if (NS_ABS(actualDevPixelScrollAmount.y) > devPixelPageSize.height) {
+    actualDevPixelScrollAmount.y =
+      (actualDevPixelScrollAmount.y >= 0) ? devPixelPageSize.height :
+                                            -devPixelPageSize.height;
+  }
+
+  nsIScrollableFrame::ScrollMode mode;
+  switch (aEvent->scrollType) {
+    case widget::WheelEvent::SCROLL_DEFAULT:
+      if (isDeltaModePixel) {
+        mode = nsIScrollableFrame::NORMAL;
+      } else {
+        mode = nsIScrollableFrame::SMOOTH;
       }
-
-      nscoord appUnitsPerDevPixel =
-        aTargetFrame->PresContext()->AppUnitsPerDevPixel();
-      aQueryEvent->mReply.mLineHeight =
-        frameToScroll->GetLineScrollAmount().height / appUnitsPerDevPixel;
-      aQueryEvent->mReply.mPageHeight =
-        frameToScroll->GetPageScrollAmount().height / appUnitsPerDevPixel;
-      aQueryEvent->mReply.mPageWidth =
-        frameToScroll->GetPageScrollAmount().width / appUnitsPerDevPixel;
-
-      // Returns computed numLines to widget which is needed to compute the
-      // pixel scrolling amout for high resolution scrolling.
-      aQueryEvent->mReply.mComputedScrollAmount = numLines;
-
-      switch (aScrollQuantity) {
-        case nsIScrollableFrame::LINES:
-          aQueryEvent->mReply.mComputedScrollAction =
-            nsQueryContentEvent::SCROLL_ACTION_LINE;
-          break;
-        case nsIScrollableFrame::PAGES:
-          aQueryEvent->mReply.mComputedScrollAction =
-            nsQueryContentEvent::SCROLL_ACTION_PAGE;
-          break;
-        default:
-          aQueryEvent->mReply.mComputedScrollAction =
-            nsQueryContentEvent::SCROLL_ACTION_NONE;
-          break;
-      }
-
-      aQueryEvent->mSucceeded = true;
-      return NS_OK;
-    }
-
-    PRInt32 scrollX = 0;
-    PRInt32 scrollY = numLines;
-
-    if (isHorizontal) {
-      scrollX = scrollY;
-      scrollY = 0;
-    }
-
-    nsIScrollableFrame::ScrollMode mode;
-    if (aMouseEvent->scrollFlags & nsMouseScrollEvent::kNoDefer) {
+      break;
+    case widget::WheelEvent::SCROLL_SYNCHRONOUSLY:
       mode = nsIScrollableFrame::INSTANT;
-    } else if (aScrollQuantity != nsIScrollableFrame::DEVICE_PIXELS ||
-               (aMouseEvent->scrollFlags &
-                  nsMouseScrollEvent::kAllowSmoothScroll) != 0) {
-      mode = nsIScrollableFrame::SMOOTH;
-    } else {
+      break;
+    case widget::WheelEvent::SCROLL_ASYNCHRONOUSELY:
       mode = nsIScrollableFrame::NORMAL;
-    }
-
-    // XXX Why don't we limit the pixel scroll amount to less one page??
-
-    nsIntPoint overflow;
-    frameToScroll->ScrollBy(nsIntPoint(scrollX, scrollY), aScrollQuantity,
-                            mode, &overflow, aOrigin);
-    aMouseEvent->scrollOverflow = isHorizontal ? overflow.x : overflow.y;
-    return NS_OK;
+      break;
+    case widget::WheelEvent::SCROLL_SMOOTHLY:
+      mode = nsIScrollableFrame::SMOOTH;
+      break;
+    default:
+      MOZ_NOT_REACHED("Invalid scrollType value comes");
+      return;
   }
-  
-  if (passToParent) {
-    nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame(
-        aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
-    if (newFrame)
-      return DoScrollText(newFrame, aMouseEvent, aScrollQuantity,
-                          aAllowScrollSpeedOverride, aQueryEvent, aOrigin);
+
+  nsIntPoint overflow;
+  aScrollableFrame->ScrollBy(actualDevPixelScrollAmount,
+                             nsIScrollableFrame::DEVICE_PIXELS,
+                             mode, &overflow, origin);
+
+  if (isDeltaModePixel) {
+    aEvent->overflowDeltaX = overflow.x;
+    aEvent->overflowDeltaY = overflow.y;
+  } else {
+    aEvent->overflowDeltaX =
+      static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
+    aEvent->overflowDeltaY =
+      static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
   }
-
-  aMouseEvent->scrollOverflow = numLines;
-
-  return NS_OK;
+  WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
 }
 
 void
 nsEventStateManager::DecideGestureEvent(nsGestureNotifyEvent* aEvent,
                                         nsIFrame* targetFrame)
 {
 
   NS_ASSERTION(aEvent->message == NS_GESTURENOTIFY_EVENT_START,
@@ -3291,74 +3231,49 @@ nsEventStateManager::PostHandleEvent(nsP
 
       nsIPresShell *shell = presContext->GetPresShell();
       if (shell) {
         nsRefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
         frameSelection->SetMouseDownState(false);
       }
     }
     break;
-  case NS_MOUSE_SCROLL:
-  case NS_MOUSE_PIXEL_SCROLL:
+  case NS_WHEEL_WHEEL:
     {
-      nsMouseScrollEvent *msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
-
-      if (aEvent->message == NS_MOUSE_SCROLL) {
-        // Mark the subsequent pixel scrolls as valid / invalid, based on the
-        // observation if the previous line scroll has been canceled
-        if (msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
-          mLastLineScrollConsumedX = (nsEventStatus_eConsumeNoDefault == *aStatus);
-        } else if (msEvent->scrollFlags & nsMouseScrollEvent::kIsVertical) {
-          mLastLineScrollConsumedY = (nsEventStatus_eConsumeNoDefault == *aStatus);
-        }
-        if (!(msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels)) {
-          // No generated pixel scroll event will follow.
-          // Create and send a pixel scroll DOM event now.
-          nsWeakFrame weakFrame(aTargetFrame);
-          SendPixelScrollEvent(aTargetFrame, msEvent, presContext, aStatus);
-          NS_ENSURE_STATE(weakFrame.IsAlive());
-        }
+      MOZ_ASSERT(NS_IS_TRUSTED_EVENT(aEvent));
+
+      if (*aStatus == nsEventStatus_eConsumeNoDefault) {
+        break;
       }
 
-      if (*aStatus != nsEventStatus_eConsumeNoDefault) {
-        bool useSysNumLines = UseSystemScrollSettingFor(msEvent);
-        PRInt32 action = ComputeWheelActionFor(msEvent, useSysNumLines);
-
-        switch (action) {
-        case MOUSE_SCROLL_N_LINES:
-          DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::LINES,
-                       useSysNumLines, nullptr, nsGkAtoms::mouseWheel);
-          break;
-
-        case MOUSE_SCROLL_PAGE:
-          DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::PAGES,
-                       false);
-          break;
-
-        case MOUSE_SCROLL_PIXELS:
-          {
-            bool fromLines = msEvent->scrollFlags & nsMouseScrollEvent::kFromLines;
-            DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::DEVICE_PIXELS,
-                         false, nullptr, (fromLines ? nsGkAtoms::mouseWheel : nullptr));
+      widget::WheelEvent* wheelEvent = static_cast<widget::WheelEvent*>(aEvent);
+      switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
+        case WheelPrefs::ACTION_SCROLL: {
+          // For scrolling of default action, we should honor the mouse wheel
+          // transaction.
+          nsIScrollableFrame* scrollTarget =
+            ComputeScrollTarget(aTargetFrame, wheelEvent, true);
+          if (scrollTarget) {
+            DoScrollText(scrollTarget, wheelEvent);
+          } else {
+            nsMouseWheelTransaction::EndTransaction();
           }
           break;
-
-        case MOUSE_SCROLL_HISTORY:
-          DoScrollHistory(msEvent->delta);
+        }
+        case WheelPrefs::ACTION_HISTORY:
+          DoScrollHistory(wheelEvent->GetPreferredIntDelta());
           break;
 
-        case MOUSE_SCROLL_ZOOM:
-          DoScrollZoom(aTargetFrame, msEvent->delta);
+        case WheelPrefs::ACTION_ZOOM:
+          DoScrollZoom(aTargetFrame, wheelEvent->GetPreferredIntDelta());
           break;
-
-        default:  // Including -1 (do nothing)
+        default:
           break;
-        }
-        *aStatus = nsEventStatus_eConsumeNoDefault;
       }
+      *aStatus = nsEventStatus_eConsumeNoDefault;
     }
     break;
 
   case NS_GESTURENOTIFY_EVENT_START:
     {
       if (nsEventStatus_eConsumeNoDefault != *aStatus)
         DecideGestureEvent(static_cast<nsGestureNotifyEvent*>(aEvent), mCurrentTarget);
     }
@@ -5089,19 +5004,20 @@ nsEventStateManager::DoContentCommandScr
     default:
       return NS_ERROR_INVALID_ARG;
   }
 
   aEvent->mSucceeded = true;
 
   nsIScrollableFrame* sf =
     ps->GetFrameToScrollAsScrollable(nsIPresShell::eEither);
-  aEvent->mIsEnabled = sf ? CanScrollOn(sf, aEvent->mScroll.mAmount,
-                                        aEvent->mScroll.mIsHorizontal) :
-                            false;
+  aEvent->mIsEnabled = sf ?
+    (aEvent->mScroll.mIsHorizontal ?
+      CanScrollOn(sf, aEvent->mScroll.mAmount, 0) :
+      CanScrollOn(sf, 0, aEvent->mScroll.mAmount)) : false;
 
   if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
     return NS_OK;
   }
 
   nsIntPoint pt(0, 0);
   if (aEvent->mScroll.mIsHorizontal) {
     pt.x = aEvent->mScroll.mAmount;
@@ -5110,56 +5026,16 @@ nsEventStateManager::DoContentCommandScr
   }
 
   // The caller may want synchronous scrolling.
   sf->ScrollBy(pt, scrollUnit, nsIScrollableFrame::INSTANT);
   return NS_OK;
 }
 
 void
-nsEventStateManager::DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
-                                             nsIFrame* aTargetFrame)
-{
-  // Don't modify the test event which in mInput.
-  nsMouseScrollEvent msEvent(
-    NS_IS_TRUSTED_EVENT(aEvent->mInput.mMouseScrollEvent),
-    aEvent->mInput.mMouseScrollEvent->message,
-    aEvent->mInput.mMouseScrollEvent->widget);
-
-  msEvent.modifiers = aEvent->mInput.mMouseScrollEvent->modifiers;
-  msEvent.buttons = aEvent->mInput.mMouseScrollEvent->buttons;
-
-  msEvent.scrollFlags = aEvent->mInput.mMouseScrollEvent->scrollFlags;
-  msEvent.delta = ComputeWheelDeltaFor(aEvent->mInput.mMouseScrollEvent);
-  msEvent.scrollOverflow = aEvent->mInput.mMouseScrollEvent->scrollOverflow;
-
-  bool useSystemSettings = UseSystemScrollSettingFor(&msEvent);
-
-  nsIScrollableFrame::ScrollUnit unit;
-  bool allowOverrideSystemSettings;
-  switch (ComputeWheelActionFor(&msEvent, useSystemSettings)) {
-    case MOUSE_SCROLL_N_LINES:
-      unit = nsIScrollableFrame::LINES;
-      allowOverrideSystemSettings = useSystemSettings;
-      break;
-    case MOUSE_SCROLL_PAGE:
-      unit = nsIScrollableFrame::PAGES;
-      allowOverrideSystemSettings = false;
-      break;
-    default:
-      // Don't use high resolution scrolling when the action doesn't scroll
-      // contents.
-      return;
-  }
-
-  DoScrollText(aTargetFrame, &msEvent, unit,
-               allowOverrideSystemSettings, aEvent);
-}
-
-void
 nsEventStateManager::DoQuerySelectedText(nsQueryContentEvent* aEvent)
 {
   if (RemoteQueryContentEvent(aEvent)) {
     return;
   }
   nsContentEventHandler handler(mPresContext);
   handler.OnQuerySelectedText(aEvent);
 }
@@ -5186,8 +5062,337 @@ nsEventStateManager::ClearGlobalActiveCo
       aClearer->SetContentState(nullptr, NS_EVENT_STATE_DRAGOVER);
     }
   }
   if (sActiveESM && aClearer != sActiveESM) {
     sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
   }
   sActiveESM = nullptr;
 }
+
+/******************************************************************/
+/* nsEventStateManager::DeltaAccumulator                          */
+/******************************************************************/
+
+void
+nsEventStateManager::DeltaAccumulator::InitLineOrPageDelta(
+                                         nsIFrame* aTargetFrame,
+                                         nsEventStateManager* aESM,
+                                         widget::WheelEvent* aEvent)
+{
+  MOZ_ASSERT(aESM);
+  MOZ_ASSERT(aEvent);
+
+  if (!(aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL &&
+        aEvent->isPixelOnlyDevice) &&
+      !WheelPrefs::GetInstance()->NeedToComputeLineOrPageDelta(aEvent)) {
+    Reset();
+    return;
+  }
+
+  // Reset if the previous wheel event is too old.
+  if (!mLastTime.IsNull()) {
+    TimeDuration duration = TimeStamp::Now() - mLastTime;
+    if (duration.ToMilliseconds() > nsMouseWheelTransaction::GetTimeoutTime()) {
+      Reset();
+    }
+  }
+  // If we have accumulated delta,  we may need to reset it.
+  if (mHandlingDeltaMode != PR_UINT32_MAX) {
+    // If wheel event type is changed, reset the values.
+    if (mHandlingDeltaMode != aEvent->deltaMode ||
+        mHandlingPixelOnlyDevice != aEvent->isPixelOnlyDevice) {
+      Reset();
+    } else {
+      // If the delta direction is changed, we should reset only the
+      // accumulated values.
+      if (mX && aEvent->deltaX && ((aEvent->deltaX > 0.0) != (mX > 0.0))) {
+        mX = 0.0;
+      }
+      if (mY && aEvent->deltaY && ((aEvent->deltaY > 0.0) != (mY > 0.0))) {
+        mY = 0.0;
+      }
+    }
+  }
+
+  mHandlingDeltaMode = aEvent->deltaMode;
+  mHandlingPixelOnlyDevice = aEvent->isPixelOnlyDevice;
+
+  mX += aEvent->deltaX;
+  mY += aEvent->deltaY;
+
+  if (mHandlingDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
+    // Records pixel delta values and init lineOrPageDeltaX and
+    // lineOrPageDeltaY for wheel events which are caused by pixel only
+    // devices.  Ignore mouse wheel transaction for computing this.  The
+    // lineOrPageDelta values will be used by dispatching legacy
+    // NS_MOUSE_SCROLL_EVENT (DOMMouseScroll) but not be used for scrolling
+    // of default action.  The transaction should be used only for the default
+    // action.
+    nsIScrollableFrame* scrollTarget =
+      aESM->ComputeScrollTarget(aTargetFrame, aEvent, false);
+    nsIFrame* frame = do_QueryFrame(scrollTarget);
+    nsPresContext* pc =
+      frame ? frame->PresContext() : aTargetFrame->PresContext();
+    nsSize scrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
+    nsIntSize scrollAmountInCSSPixels(
+      nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width),
+      nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height));
+
+    aEvent->lineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
+    aEvent->lineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
+
+    mX -= aEvent->lineOrPageDeltaX * scrollAmountInCSSPixels.width;
+    mY -= aEvent->lineOrPageDeltaY * scrollAmountInCSSPixels.height;
+  } else {
+    aEvent->lineOrPageDeltaX = RoundDown(mX);
+    aEvent->lineOrPageDeltaY = RoundDown(mY);
+    mX -= aEvent->lineOrPageDeltaX;
+    mY -= aEvent->lineOrPageDeltaY;
+  }
+
+  mLastTime = TimeStamp::Now();
+}
+
+void
+nsEventStateManager::DeltaAccumulator::Reset()
+{
+  mX = mY = 0.0;
+  mHandlingDeltaMode = PR_UINT32_MAX;
+  mHandlingPixelOnlyDevice = false;
+}
+
+/******************************************************************/
+/* nsEventStateManager::WheelPrefs                                */
+/******************************************************************/
+
+// static
+nsEventStateManager::WheelPrefs*
+nsEventStateManager::WheelPrefs::GetInstance()
+{
+  if (!sInstance) {
+    sInstance = new WheelPrefs();
+  }
+  return sInstance;
+}
+
+// static
+void
+nsEventStateManager::WheelPrefs::Shutdown()
+{
+  delete sInstance;
+  sInstance = nullptr;
+}
+
+// static
+int
+nsEventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
+                                               void* aClosure)
+{
+  // forget all prefs, it's not problem for performance.
+  sInstance->Reset();
+  DeltaAccumulator::GetInstance()->Reset();
+  return 0;
+}
+
+nsEventStateManager::WheelPrefs::WheelPrefs()
+{
+  Reset();
+  Preferences::RegisterCallback(OnPrefChanged, "mousewheel.", nullptr);
+}
+
+nsEventStateManager::WheelPrefs::~WheelPrefs()
+{
+  Preferences::UnregisterCallback(OnPrefChanged, "mousewheel.", nullptr);
+}
+
+void
+nsEventStateManager::WheelPrefs::Reset()
+{
+  memset(mInit, 0, sizeof(mInit));
+
+}
+
+nsEventStateManager::WheelPrefs::Index
+nsEventStateManager::WheelPrefs::GetIndexFor(widget::WheelEvent* aEvent)
+{
+  if (!aEvent) {
+    return INDEX_DEFAULT;
+  }
+
+  widget::Modifiers modifiers =
+    (aEvent->modifiers & (widget::MODIFIER_ALT |
+                          widget::MODIFIER_CONTROL |
+                          widget::MODIFIER_META |
+                          widget::MODIFIER_SHIFT |
+                          widget::MODIFIER_OS));
+
+  switch (modifiers) {
+    case widget::MODIFIER_ALT:
+      return INDEX_ALT;
+    case widget::MODIFIER_CONTROL:
+      return INDEX_CONTROL;
+    case widget::MODIFIER_META:
+      return INDEX_META;
+    case widget::MODIFIER_SHIFT:
+      return INDEX_SHIFT;
+    case widget::MODIFIER_OS:
+      return INDEX_OS;
+    default:
+      // If two or more modifier keys are pressed, we should use default
+      // settings.
+      return INDEX_DEFAULT;
+  }
+}
+
+void
+nsEventStateManager::WheelPrefs::GetBasePrefName(
+                       nsEventStateManager::WheelPrefs::Index aIndex,
+                       nsACString& aBasePrefName)
+{
+  aBasePrefName.AssignLiteral("mousewheel.");
+  switch (aIndex) {
+    case INDEX_ALT:
+      aBasePrefName.AppendLiteral("with_alt.");
+      break;
+    case INDEX_CONTROL:
+      aBasePrefName.AppendLiteral("with_control.");
+      break;
+    case INDEX_META:
+      aBasePrefName.AppendLiteral("with_meta.");
+      break;
+    case INDEX_SHIFT:
+      aBasePrefName.AppendLiteral("with_shift.");
+      break;
+    case INDEX_OS:
+      aBasePrefName.AppendLiteral("with_win.");
+      break;
+    case INDEX_DEFAULT:
+    default:
+      aBasePrefName.AppendLiteral("default.");
+      break;
+  }
+}
+
+void
+nsEventStateManager::WheelPrefs::Init(
+                       nsEventStateManager::WheelPrefs::Index aIndex)
+{
+  if (mInit[aIndex]) {
+    return;
+  }
+  mInit[aIndex] = true;
+
+  nsCAutoString basePrefName;
+  GetBasePrefName(aIndex, basePrefName);
+
+  nsCAutoString prefNameX(basePrefName);
+  prefNameX.AppendLiteral("delta_multiplier_x");
+  mMultiplierX[aIndex] =
+    static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
+  if (mMultiplierX[aIndex] < 1.0 && mMultiplierX[aIndex] > -1.0) {
+    mMultiplierX[aIndex] = mMultiplierX[aIndex] < 0.0 ? -1.0 : 1.0;
+  }
+
+  nsCAutoString prefNameY(basePrefName);
+  prefNameY.AppendLiteral("delta_multiplier_y");
+  mMultiplierY[aIndex] =
+    static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
+  if (mMultiplierY[aIndex] < 1.0 && mMultiplierY[aIndex] > -1.0) {
+    mMultiplierY[aIndex] = mMultiplierY[aIndex] < 0.0 ? -1.0 : 1.0;
+  }
+
+  nsCAutoString prefNameZ(basePrefName);
+  prefNameZ.AppendLiteral("delta_multiplier_z");
+  mMultiplierZ[aIndex] =
+    static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
+  if (mMultiplierZ[aIndex] < 1.0 && mMultiplierZ[aIndex] > -1.0) {
+    mMultiplierZ[aIndex] = mMultiplierZ[aIndex] < 0.0 ? -1.0 : 1.0;
+  }
+
+  nsCAutoString prefNameAction(basePrefName);
+  prefNameAction.AppendLiteral("action");
+  mActions[aIndex] =
+    static_cast<Action>(Preferences::GetInt(prefNameAction.get(),
+                                            ACTION_SCROLL));
+  if (mActions[aIndex] < ACTION_NONE || mActions[aIndex] > ACTION_LAST) {
+    NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.");
+    mActions[aIndex] = ACTION_SCROLL;
+  }
+}
+
+void
+nsEventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
+                                   widget::WheelEvent* aEvent)
+{
+  Index index = GetIndexFor(aEvent);
+  Init(index);
+
+  aEvent->deltaX *= mMultiplierX[index];
+  aEvent->deltaY *= mMultiplierY[index];
+  aEvent->deltaZ *= mMultiplierZ[index];
+
+  // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
+  // value, we should use lineOrPageDelta values which were set by widget.
+  // Otherwise, we need to compute them from accumulated delta values.
+  if (!NeedToComputeLineOrPageDelta(aEvent)) {
+    aEvent->lineOrPageDeltaX *= static_cast<PRInt32>(mMultiplierX[index]);
+    aEvent->lineOrPageDeltaY *= static_cast<PRInt32>(mMultiplierY[index]);
+  } else {
+    aEvent->lineOrPageDeltaX = 0;
+    aEvent->lineOrPageDeltaY = 0;
+  }
+
+  aEvent->customizedByUserPrefs =
+    ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
+     (mMultiplierZ[index] != 1.0));
+}
+
+void
+nsEventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
+                                                   widget::WheelEvent* aEvent)
+{
+  Index index = GetIndexFor(aEvent);
+  Init(index);
+
+  NS_ASSERTION(mMultiplierX[index] && mMultiplierY[index],
+               "The absolute values of both multipliers must be 1 or larger");
+  aEvent->overflowDeltaX /= mMultiplierX[index];
+  aEvent->overflowDeltaY /= mMultiplierY[index];
+}
+
+nsEventStateManager::WheelPrefs::Action
+nsEventStateManager::WheelPrefs::ComputeActionFor(widget::WheelEvent* aEvent)
+{
+  if (!aEvent->deltaX && !aEvent->deltaY) {
+    return ACTION_NONE;
+  }
+
+  Index index = GetIndexFor(aEvent);
+  Init(index);
+
+  if (mActions[index] == ACTION_NONE || mActions[index] == ACTION_SCROLL) {
+    return mActions[index];
+  }
+
+  // Momentum events shouldn't run special actions.
+  if (aEvent->isMomentum) {
+    // Use the default action.  Note that user might kill the wheel scrolling.
+    Init(INDEX_DEFAULT);
+    return (mActions[INDEX_DEFAULT] == ACTION_SCROLL) ? ACTION_SCROLL :
+                                                        ACTION_NONE;
+  }
+
+  // If this event doesn't cause NS_MOUSE_SCROLL event or the direction is
+  // oblique, history and zoom shouldn't be executed.
+  return !aEvent->GetPreferredIntDelta() ? ACTION_NONE : mActions[index];
+}
+
+bool
+nsEventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
+                                   widget::WheelEvent* aEvent)
+{
+  Index index = GetIndexFor(aEvent);
+  Init(index);
+
+  return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
+         (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
+}
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -81,16 +81,24 @@ public:
    * also contain any centralized event processing which must occur after
    * DOM and frame processing.
    */
   nsresult PostHandleEvent(nsPresContext* aPresContext,
                            nsEvent *aEvent,
                            nsIFrame* aTargetFrame,
                            nsEventStatus* aStatus);
 
+  /**
+   * DispatchLegacyMouseScrollEvents() dispatches NS_MOUSE_SCROLL event and
+   * NS_MOUSE_PIXEL_SCROLL event for compatiblity with old Gecko.
+   */
+  void DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
+                                       mozilla::widget::WheelEvent* aEvent,
+                                       nsEventStatus* aStatus);
+
   void NotifyDestroyPresContext(nsPresContext* aPresContext);
   void SetPresContext(nsPresContext* aPresContext);
   void ClearFrameRefs(nsIFrame* aFrame);
 
   nsIFrame* GetEventTarget();
   already_AddRefed<nsIContent> GetEventTargetContent(nsEvent* aEvent);
 
   /**
@@ -312,77 +320,251 @@ protected:
   //---------------------------------------------
   // DocShell Focus Traversal Methods
   //---------------------------------------------
 
   nsIContent* GetFocusedContent();
   bool IsShellVisible(nsIDocShell* aShell);
 
   // These functions are for mousewheel and pixel scrolling
-  void SendLineScrollEvent(nsIFrame* aTargetFrame,
-                           nsMouseScrollEvent* aEvent,
-                           nsPresContext* aPresContext,
-                           nsEventStatus* aStatus,
-                           PRInt32 aNumLines);
-  void SendPixelScrollEvent(nsIFrame* aTargetFrame,
-                            nsMouseScrollEvent* aEvent,
-                            nsPresContext* aPresContext,
-                            nsEventStatus* aStatus);
+
+  class WheelPrefs
+  {
+  public:
+    static WheelPrefs* GetInstance();
+    static void Shutdown();
+
+    /**
+     * ApplyUserPrefsToDelta() overrides the wheel event's delta values with
+     * user prefs.
+     */
+    void ApplyUserPrefsToDelta(mozilla::widget::WheelEvent* aEvent);
+
+    /**
+     * If ApplyUserPrefsToDelta() changed the delta values with customized
+     * prefs, the overflowDelta values would be inflated.
+     * CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation.
+     */
+    void CancelApplyingUserPrefsFromOverflowDelta(
+                                    mozilla::widget::WheelEvent* aEvent);
+
+    /**
+     * Computes the default action for the aEvent with the prefs.
+     */
+    enum Action
+    {
+      ACTION_NONE = 0,
+      ACTION_SCROLL,
+      ACTION_HISTORY,
+      ACTION_ZOOM,
+      ACTION_LAST = ACTION_ZOOM
+    };
+    Action ComputeActionFor(mozilla::widget::WheelEvent* aEvent);
+
+    /**
+     * NeedToComputeLineOrPageDelta() returns if the aEvent needs to be
+     * computed the lineOrPageDelta values.
+     */
+    bool NeedToComputeLineOrPageDelta(mozilla::widget::WheelEvent* aEvent);
+
+  private:
+    WheelPrefs();
+    ~WheelPrefs();
+
+    static int OnPrefChanged(const char* aPrefName, void* aClosure);
+
+    enum Index
+    {
+      INDEX_DEFAULT = 0,
+      INDEX_ALT,
+      INDEX_CONTROL,
+      INDEX_META,
+      INDEX_SHIFT,
+      INDEX_OS,
+      COUNT_OF_MULTIPLIERS
+    };
+
+    /**
+     * GetIndexFor() returns the index of the members which should be used for
+     * the aEvent.  When only one modifier key of MODIFIER_ALT,
+     * MODIFIER_CONTROL, MODIFIER_META, MODIFIER_SHIFT or MODIFIER_OS is
+     * pressed, returns the index for the modifier.  Otherwise, this return the
+     * default index which is used at either no modifier key is pressed or
+     * two or modifier keys are pressed.
+     */
+    Index GetIndexFor(mozilla::widget::WheelEvent* aEvent);
+
+    /**
+     * GetPrefNameBase() returns the base pref name for aEvent.
+     * It's decided by GetModifierForPref() which modifier should be used for
+     * the aEvent.
+     *
+     * @param aBasePrefName The result, must be "mousewheel.with_*." or
+     *                      "mousewheel.default.".
+     */
+    void GetBasePrefName(Index aIndex, nsACString& aBasePrefName);
+
+    void Init(Index aIndex);
+
+    void Reset();
+
+    bool mInit[COUNT_OF_MULTIPLIERS];
+    double mMultiplierX[COUNT_OF_MULTIPLIERS];
+    double mMultiplierY[COUNT_OF_MULTIPLIERS];
+    double mMultiplierZ[COUNT_OF_MULTIPLIERS];
+    Action mActions[COUNT_OF_MULTIPLIERS];
+
+    static WheelPrefs* sInstance;
+  };
+
   /**
-   * @param aQueryEvent If you set vailid pointer for this, DoScrollText()
-   *                    computes the line-height and page size of current
-   *                    mouse wheel scroll target and sets it to the event.
-   *                    And then, this method does NOT scroll any scrollable
-   *                    elements.  I.e., you can just query the scroll target
-   *                    information.
+   * DeltaDirection is used for specifying whether the called method should
+   * handle vertical delta or horizontal delta.
+   * This is clearer than using bool.
+   */
+  enum DeltaDirection
+  {
+    DELTA_DIRECTION_X = 0,
+    DELTA_DIRECTION_Y
+  };
+
+  /**
+   * SendLineScrollEvent() dispatches a DOMMouseScroll event for the
+   * widget::WheelEvent.  This method shouldn't be called for non-trusted
+   * wheel event because it's not necessary for compatiblity.
+   *
+   * @param aTargetFrame        The event target of wheel event.
+   * @param aEvent              The original Wheel event.
+   * @param aStatus             The event status, must not be
+   *                            nsEventStatus_eConsumeNoDefault.
+   * @param aDelta              The delta value of the event.
+   * @param aDeltaDirection     The X/Y direction of dispatching event.
+   */
+  void SendLineScrollEvent(nsIFrame* aTargetFrame,
+                           mozilla::widget::WheelEvent* aEvent,
+                           nsEventStatus* aStatus,
+                           PRInt32 aDelta,
+                           DeltaDirection aDeltaDirection);
+
+  /**
+   * SendPixelScrollEvent() dispatches a MozMousePixelScroll event for the
+   * widget::WheelEvent.  This method shouldn't be called for non-trusted
+   * wheel event because it's not necessary for compatiblity.
+   *
+   * @param aTargetFrame        The event target of wheel event.
+   * @param aEvent              The original Wheel event.
+   * @param aStatus             The event status, must not be
+   *                            nsEventStatus_eConsumeNoDefault.
+   * @param aPixelDelta         The delta value of the event.
+   * @param aDeltaDirection     The X/Y direction of dispatching event.
    */
-  nsresult DoScrollText(nsIFrame* aTargetFrame,
-                        nsMouseScrollEvent* aMouseEvent,
-                        nsIScrollableFrame::ScrollUnit aScrollQuantity,
-                        bool aAllowScrollSpeedOverride,
-                        nsQueryContentEvent* aQueryEvent = nullptr,
-                        nsIAtom *aOrigin = nullptr);
+  void SendPixelScrollEvent(nsIFrame* aTargetFrame,
+                            mozilla::widget::WheelEvent* aEvent,
+                            nsEventStatus* aStatus,
+                            PRInt32 aPixelDelta,
+                            DeltaDirection aDeltaDirection);
+
+  /**
+   * ComputeScrollTarget() returns the scrollable frame which should be
+   * scrolled.
+   *
+   * @param aTargetFrame        The event target of the wheel event.
+   * @param aEvent              The handling mouse wheel event.
+   * @param aForDefaultAction   Whether this uses wheel transaction or not.
+   *                            If true, returns the latest scrolled frame if
+   *                            there is it.  Otherwise, the nearest ancestor
+   *                            scrollable frame from aTargetFrame.
+   * @return                    The scrollable frame which should be scrolled.
+   */
+  nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
+                                          mozilla::widget::WheelEvent* aEvent,
+                                          bool aForDefaultAction);
+
+  /**
+   * GetScrollAmount() returns the scroll amount in app uints of one line or
+   * one page.  If the wheel event scrolls a page, returns the page width and
+   * height.  Otherwise, returns line height for both its width and height.
+   *
+   * @param aScrollableFrame    A frame which will be scrolled by the event.
+   *                            The result of ComputeScrollTarget() is
+   *                            expected for this value.
+   *                            This can be NULL if there is no scrollable
+   *                            frame.  Then, this method uses root frame's
+   *                            line height or visible area's width and height.
+   */
+  nsSize GetScrollAmount(nsPresContext* aPresContext,
+                         mozilla::widget::WheelEvent* aEvent,
+                         nsIScrollableFrame* aScrollableFrame);
+
+  /**
+   * DoScrollText() scrolls the scrollable frame for aEvent.
+   */
+  void DoScrollText(nsIScrollableFrame* aScrollableFrame,
+                    mozilla::widget::WheelEvent* aEvent);
+
   void DoScrollHistory(PRInt32 direction);
   void DoScrollZoom(nsIFrame *aTargetFrame, PRInt32 adjustment);
   nsresult GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv);
   nsresult ChangeTextSize(PRInt32 change);
   nsresult ChangeFullZoom(PRInt32 change);
-  /**
-   * Computes actual delta value used for scrolling.  If user customized the
-   * scrolling speed and/or direction, this would return the customized value.
-   * Otherwise, it would return the original delta value of aMouseEvent.
-   */
-  PRInt32 ComputeWheelDeltaFor(nsMouseScrollEvent* aMouseEvent);
-  /**
-   * Computes the action for the aMouseEvent with prefs.  The result is
-   * MOUSE_SCROLL_N_LINES, MOUSE_SCROLL_PAGE, MOUSE_SCROLL_HISTORY,
-   * MOUSE_SCROLL_ZOOM, MOUSE_SCROLL_PIXELS or -1.
-   * When the result is -1, nothing happens for the event.
-   *
-   * @param aUseSystemSettings    Set the result of UseSystemScrollSettingFor().
-   */
-  PRInt32 ComputeWheelActionFor(nsMouseScrollEvent* aMouseEvent,
-                                bool aUseSystemSettings);
+
   /**
-   * Gets the wheel action for the aMouseEvent ONLY with the pref.
-   * When you actually do something for the event, probably you should use
-   * ComputeWheelActionFor().
+   * DeltaAccumulator class manages delta values for dispatching DOMMouseScroll
+   * event.  If wheel events are caused by pixel scroll only devices or
+   * the delta values are customized by prefs, this class stores the delta
+   * values and set lineOrPageDelta values.
    */
-  PRInt32 GetWheelActionFor(nsMouseScrollEvent* aMouseEvent);
-  /**
-   * Gets the pref value for line scroll amount for the aMouseEvent.
-   * Note that this method doesn't check whether the aMouseEvent is line scroll
-   * event and doesn't use system settings.
-   */
-  PRInt32 GetScrollLinesFor(nsMouseScrollEvent* aMouseEvent);
-  /**
-   * Whether use system scroll settings or settings in our prefs for the event.
-   * TRUE, if use system scroll settings.  Otherwise, FALSE.
-   */
-  bool UseSystemScrollSettingFor(nsMouseScrollEvent* aMouseEvent);
+  class DeltaAccumulator
+  {
+  public:
+    static DeltaAccumulator* GetInstance()
+    {
+      if (!sInstance) {
+        sInstance = new DeltaAccumulator;
+      }
+      return sInstance;
+    }
+
+    static void Shutdown()
+    {
+      delete sInstance;
+      sInstance = nullptr;
+    }
+
+    /**
+     * InitLineOrPageDelta() stores pixel delta values of WheelEvents which are
+     * caused if it's needed.  And if the accumulated delta becomes a
+     * line height, sets lineOrPageDeltaX and lineOrPageDeltaY automatically.
+     */
+    void InitLineOrPageDelta(nsIFrame* aTargetFrame,
+                             nsEventStateManager* aESM,
+                             mozilla::widget::WheelEvent* aEvent);
+
+    /**
+     * Reset() resets both delta values.
+     */
+    void Reset();
+
+  private:
+    DeltaAccumulator() :
+      mX(0.0), mY(0.0), mHandlingDeltaMode(PR_UINT32_MAX),
+      mHandlingPixelOnlyDevice(false)
+    {
+    }
+
+    double mX;
+    double mY;
+    TimeStamp mLastTime;
+
+    PRUint32 mHandlingDeltaMode;
+    bool mHandlingPixelOnlyDevice;
+
+    static DeltaAccumulator* sInstance;
+  };
+
   // end mousewheel functions
 
   /*
    * When a touch gesture is about to start, this function determines what
    * kind of gesture interaction we will want to use, based on what is
    * underneath the initial touch point.
    * Currently it decides between panning (finger scrolling) or dragging
    * the target element, as well as the orientation to trigger panning and
@@ -435,18 +617,16 @@ protected:
    * BeginTrackingDragGesture). aEvent->widget must be
    * mCurrentTarget->GetNearestWidget().
    */
   void FillInEventFromGestureDown(nsMouseEvent* aEvent);
 
   nsresult DoContentCommandEvent(nsContentCommandEvent* aEvent);
   nsresult DoContentCommandScrollEvent(nsContentCommandEvent* aEvent);
 
-  void DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
-                               nsIFrame* aTargetFrame);
   void DoQuerySelectedText(nsQueryContentEvent* aEvent);
 
   bool RemoteQueryContentEvent(nsEvent *aEvent);
   mozilla::dom::TabParent *GetCrossProcessTarget();
   bool IsTargetCrossProcess(nsGUIEvent *aEvent);
 
   bool DispatchCrossProcessEvent(nsEvent* aEvent, nsFrameLoader* remote,
                                  nsEventStatus *aStatus);
@@ -525,20 +705,16 @@ private:
   // Time at which we began handling user input.
   static TimeStamp sHandlingInputStart;
 
 public:
   static nsresult UpdateUserActivityTimer(void);
   // Array for accesskey support
   nsCOMArray<nsIContent> mAccessKeys;
 
-  // Unlocks pixel scrolling
-  bool mLastLineScrollConsumedX;
-  bool mLastLineScrollConsumedY;
-
   static PRInt32 sUserInputEventDepth;
   
   static bool sNormalLMouseEventInProcess;
 
   static nsEventStateManager* sActiveESM;
   
   static void ClearGlobalActiveContent(nsEventStateManager* aClearer);
 
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -79,16 +79,21 @@ 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_continuous_wheel_events.html \
+		test_moz_mouse_pixel_scroll_event.html \
+		test_wheel_default_action.html \
+		window_wheel_default_action.html \
 		test_bug603008.html \
 		test_bug716822.html \
 		test_bug742376.html \
 		$(NULL)
 
 #bug 585630
 ifneq (mobile,$(MOZ_BUILD_APP))
 MOCHITEST_FILES += \
@@ -101,17 +106,16 @@ ifneq (Linux,$(OS_ARCH))
 MOCHITEST_FILES += \
 		test_bug493251.html \
 		$(NULL)
 endif
 
 MOCHITEST_CHROME_FILES = \
 		test_bug336682_2.xul \
 		test_bug336682.js \
-		test_bug350471.xul \
 		test_bug586961.xul \
 		test_bug415498.xul \
 		bug415498-doc1.html \
 		bug415498-doc2.html \
 		test_bug591249.xul \
 		bug591249_iframe.xul \
 		bug602962.xul \
 		test_bug602962.xul \
deleted file mode 100644
--- a/content/events/test/test_bug350471.xul
+++ /dev/null
@@ -1,264 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=350471
--->
-<window title="Mozilla Bug 350471"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
-  <title>Test for Bug 350471</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
-<body  xmlns="http://www.w3.org/1999/xhtml">
-  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=350471">Mozilla Bug 350471</a>
-
-  <p id="display"></p>
-<div id="content" style="display: none">
-</div>
-</body>
-
-<script class="testbody" type="application/javascript;version=1.7"><![CDATA[
-
-/** Test for Bug 350471 **/
-
-const minLineHeight = 10, maxLineHeight = 20;
-
-function between(x, min, max) (min <= max) ? (min <= x && x <= max) : (max <= x && x <= min);
-function isbetween(x, min, max, msg) ok(between(x, min, max), msg + " - Expected " + min + " to " + max + ", got " + x);
-
-function testEventDispatching(aWin) {
-  function helper(aAxis, aDelta, aKind, aShiftKey, aCtrlKey, aAltKey, aMetaKey) {
-    let expectedEvents = [];
-    let deltaUnit = "";
-    function listener(e) {
-      if (!expectedEvents.length) {
-        ok(false, "Received an event that I didn't expect. type: " + e.type +
-           ", axis: " + e.axis + ", delta: " + e.delta);
-        return;
-      }
-      let expected = expectedEvents.shift();
-      
-      ["type", "shiftKey", "ctrlKey", "altKey", "metaKey"].forEach(function(field) {
-        is(e[field], expected[field],
-          "e." + field + " (" + e[field] + ") does not match expected value (" + expected[field] + ")");
-      });
-      
-      let expectedAxis = expected.axis == "horizontal" ? e.HORIZONTAL_AXIS : e.VERTICAL_AXIS;
-      is(e.axis, expectedAxis,
-         "e.axis (" + e.axis + ") does not match expected value (" + expectedAxis + ")");
-      
-      // When modifier keys are pressed, cancel the event.
-      // We don't want to zoom or navigate back / forward (history scroll).
-      if (aShiftKey || aCtrlKey || aAltKey || aMetaKey) {
-        e.preventDefault();
-        // Note: If this is a DOMMouseScroll event without hasPixels, we still
-        // expect a follow-up MozMousePixelScroll event.
-      } else {
-        // Only check the delta if no modifiers are pressed.
-        // History scroll and zoom change the deltas in nsESM::PreHandleEvent.
-        if (deltaUnit == (e.type == "DOMMouseScroll" ? "lines" : "pixels")) {
-          // no unit conversion necessary
-          is(e.detail, expected.delta,
-             "e.detail (" + e.detail + ") does not match expected value (" + expected.delta + ")");
-        } else if (e.type == "MozMousePixelScroll") {
-          // We sent a line scroll event but are receiving a pixel scroll event,
-          // so we need to convert the delta.
-          let minDelta = expected.delta * minLineHeight;
-          let maxDelta = expected.delta * maxLineHeight;
-          isbetween(e.detail, minDelta, maxDelta, "wrong pixel scroll event delta");
-        }
-      }
-      e.stopPropagation();
-    }
-    // Set up the expected values.
-    if (aKind == 0 || aKind == 1) {
-      expectedEvents.push({
-        type: "DOMMouseScroll",
-        axis: aAxis,
-        delta: aDelta,
-        hasPixels: (aKind == 1),
-        shiftKey: aShiftKey,
-        ctrlKey: aCtrlKey,
-        altKey: aAltKey,
-        metaKey: aMetaKey
-      });
-    }
-    if (aKind == 0 || aKind == 2) {
-      expectedEvents.push({
-        type: "MozMousePixelScroll",
-        axis: aAxis,
-        delta: aDelta,
-        shiftKey: aShiftKey,
-        ctrlKey: aCtrlKey,
-        altKey: aAltKey,
-        metaKey: aMetaKey
-      });
-    }
-    deltaUnit = aKind == 2 ? "pixels" : "lines";
-    
-    aWin.document.addEventListener("DOMMouseScroll", listener, true);
-    aWin.document.addEventListener("MozMousePixelScroll", listener, true);
-  
-    // Send the event to the documentElement.
-    synthesizeMouseScroll(aWin.document.documentElement, 10, 10, expectedEvents[0], aWin);
-  
-    aWin.document.removeEventListener("DOMMouseScroll", listener, true);
-    aWin.document.removeEventListener("MozMousePixelScroll", listener, true);
-  
-    // expectedEvents should be empty now. If it's not, print errors.
-    expectedEvents.forEach(function(e) {
-      ok(false, "Didn't receive expected event: " + JSON.stringify(e));
-    });
-  };
-  let i = 0;
-  [0, 1, 2].forEach(function(aKind) {
-    ["horizontal", "vertical"].forEach(function(aAxis) {
-      [false, true].forEach(function(aShift) {
-        [false, true].forEach(function(aCtrl) {
-          [false, true].forEach(function(aAlt) {
-            [false, true].forEach(function(aMeta) {
-              helper(aAxis, [-5, -1, 0, 1, 5][i++ % 5], aKind, aShift, aCtrl, aAlt, aMeta);
-            });
-          });
-        });
-      });
-    });
-  });
-}
-
-function testDefaultHandling(aWin, andThen) {
-  let scrollbox = aWin.document.getElementById("scrollbox");
-
-  function scrollWithPreventDefault(aEvent, aDoConsume) {
-    function listener(e) {
-      if (aDoConsume[e.type])
-        e.preventDefault();
-    }
-    scrollbox.addEventListener("DOMMouseScroll", listener, true);
-    scrollbox.addEventListener("MozMousePixelScroll", listener, true);
-    synthesizeMouseScroll(scrollbox, 10, 10, aEvent, aWin);
-    scrollbox.removeEventListener("DOMMouseScroll", listener, true);
-    scrollbox.removeEventListener("MozMousePixelScroll", listener, true);
-  }
-  
-  let tests = [];
-  function helper(aType, aHasPixels, aAxis, aStart, aDelta, aConsumeLine, aConsumePixel, aPositionShouldChange, aCurrentTest) {
-    tests.push([aType, aHasPixels, aAxis, aStart, aDelta, aConsumeLine, aConsumePixel, aPositionShouldChange, aCurrentTest]);
-  }
-  function exec() {
-    let [aType, aHasPixels, aAxis, aStart, aDelta, aConsumeLine, aConsumePixel, aPositionShouldChange, currentTest] = tests[0];
-    tests.shift();
-    scrollbox.scrollLeft = aStart;
-    scrollbox.scrollTop = aStart;
-    scrollWithPreventDefault({
-      type: aType,
-      axis: aAxis,
-      hasPixels: aHasPixels,
-      delta: aDelta
-    }, {
-      "DOMMouseScroll": aConsumeLine,
-      "MozMousePixelScroll": aConsumePixel
-    });
-    setTimeout(function() {
-      let newPos = scrollbox[aAxis == "horizontal" ? "scrollLeft" : "scrollTop"];
-      let newPosWrongAxis = scrollbox[aAxis == "horizontal" ? "scrollTop" : "scrollLeft"];
-  
-      is(newPosWrongAxis, aStart, currentTest + " wrong axis scrolled - type: " + aType);
-  
-      if (aPositionShouldChange) {
-        if (aType == "MozMousePixelScroll") {
-          // aDelta is in pixels, no conversion necessary
-          is(newPos, aStart + aDelta, currentTest + " wrong scroll position - type: " + aType);
-        } else {
-          // Use minLineHeight and maxLineHeight as an estimate for the conversion factor.
-          isbetween(newPos, aStart + aDelta * minLineHeight, aStart + aDelta * maxLineHeight,
-                    currentTest + " wrong scroll position - type: " + aType);
-        }
-      } else {
-        is(newPos, aStart, currentTest + " The scroll position shouldn't have changed. - type: " + aType);
-      }
-      if (tests.length)
-        exec();
-      else
-        andThen();
-    }, 20);
-  }
-
-  ["horizontal", "vertical"].forEach(function(aAxis) {
-    [-5, 5].forEach(function(aDelta) {
-      [false, true].forEach(function(aConsumeLine) {
-        [false, true].forEach(function(aConsumePixel) {
-          let shouldScroll = !aConsumeLine && !aConsumePixel;
-          let currentTest = "";
-          
-          currentTest = "normal DOMMouseScroll: only scroll if neither line nor pixel scroll are consumed.";
-          helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, aConsumePixel, shouldScroll, currentTest);
-          
-          currentTest = "DOMMouseScroll with hasPixels: never scroll.";
-          helper("DOMMouseScroll", true, aAxis, 4000, aDelta, aConsumeLine, aConsumePixel, false, currentTest);
-          
-          currentTest = "MozMousePixelScroll (consumed: " + aConsumePixel +
-                        ") with preceding DOMMouseScroll (consumed: " + aConsumeLine +
-                        "): " + (shouldScroll ? "scroll." : "don't scroll.");
-          // It shouldn't matter:
-          //  1. whether hasPixels is set on the preceding DOMMouseScroll event or
-          //  2. whether the preceding DOMMouseScroll event's MozMousePixelScroll event is consumed.
-          helper("DOMMouseScroll", true, aAxis, 4000, aDelta, aConsumeLine, false, false, currentTest);
-          helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll, currentTest);
-          helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, false, !aConsumeLine, currentTest);
-          helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll, currentTest);
-          helper("DOMMouseScroll", false, aAxis, 4000, aDelta, aConsumeLine, true, false, currentTest);
-          helper("MozMousePixelScroll", false, aAxis, 4000, aDelta, false, aConsumePixel, shouldScroll, currentTest);
-        });
-      });
-    });
-  });
-  
-  exec();
-}
-
-function initPrefs()
-{
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
-                  getService(Components.interfaces.nsIPrefBranch);
-  // Disables the app level scroll acceleration
-  prefSvc.setIntPref("mousewheel.acceleration.start", -1);
-  prefSvc.setBoolPref("mousewheel.system_scroll_override_on_root_content.enabled", false);
-  prefSvc.setBoolPref("general.smoothScroll", false);
-}
-
-function clearPrefs()
-{
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
-                  getService(Components.interfaces.nsIPrefBranch);
-
-  prefSvc.clearUserPref("mousewheel.acceleration.start");
-  prefSvc.clearUserPref("mousewheel.system_scroll_override_on_root_content.enabled");
-  prefSvc.clearUserPref("general.smoothScroll");
-}
-
-window.onload = function () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-
-  let win = window.open('data:application/vnd.mozilla.xul+xml,<?xml version="1.0"?><?xml-stylesheet href="chrome://global/skin" type="text/css"?><window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"><vbox style="height: 150px; background: cyan; overflow: auto;" id="scrollbox"><hbox style="height: 8000px;"><vbox style="width: 8000px;"/></hbox></vbox></window>', '_blank', 'chrome,width=400,height=200');
-  win.onload = function() {
-    setTimeout(function() {
-      initPrefs();
-      testEventDispatching(win);
-      testDefaultHandling(win, function() {
-        clearPrefs();
-        win.close();
-        SimpleTest.finish();
-      });
-    }, 20);
-  }
-}
-
-SimpleTest.waitForExplicitFinish();
-
-]]></script>
-
-</window>
--- a/content/events/test/test_bug574663.html
+++ b/content/events/test/test_bug574663.html
@@ -18,35 +18,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 <pre id="test">
 <script type="application/javascript;version=1.7">
 
 /** Test for Bug 574663 **/
 
 function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum) {
   var win = scrollbox.ownerDocument.defaultView;
   let event = {
-    'type': "DOMMouseScroll",
-    'axis': "vertical",
-    'delta': direction,
-    'hasPixels': true,
-    'ctrlKey': ctrl,
-    'isMomentum': momentum,
+    deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+    deltaY: direction * 3,
+    lineOrPageDeltaY: direction,
+    ctrlKey: ctrl,
+    isMomentum: momentum
   };
-  // first a line scroll
-  synthesizeMouseScroll(scrollbox, 10, 10, event, win);
-  // Then a line scroll with hasPixels set to false
-  event.hasPixels = false;
-  synthesizeMouseScroll(scrollbox, 10, 10, event, win);
-  // then 5 pixel scrolls
-  event.hasPixels = true;
-  event.delta *= 3;
-  event.type = "MozMousePixelScroll";
-  event.hasPixels = false;
+  synthesizeWheel(scrollbox, 10, 10, event, win);
+  // then 5 additional pixel scrolls
+  event.lineOrPageDeltaY = 0;
   for (let i = 0; i < 5; ++i) {
-    synthesizeMouseScroll(scrollbox, 10, 10, event, win);
+    synthesizeWheel(scrollbox, 10, 10, event, win);
   }
 }
 
 function runTest() {
   var win = open('data:text/html,<!DOCTYPE html>\n' +
     '<div id="scrollbox" style="height: 100px; overflow: auto;">' +
     '  <div style="height: 1000px;"></div>' +
     '</div>', '_blank', 'width=300,height=300');
@@ -105,29 +97,29 @@ function initPrefs()
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
                   getService(Components.interfaces.nsIPrefBranch);
   prefSvc.setBoolPref("general.smoothScroll", false);
   // Disables the app level scroll acceleration
   prefSvc.setIntPref("mousewheel.acceleration.start", -1);
   prefSvc.setBoolPref("mousewheel.system_scroll_override_on_root_content.enabled", false);
   // Enable zooming for ctrl-scrolling
-  prefSvc.setIntPref("mousewheel.withcontrolkey.action", 3);
+  prefSvc.setIntPref("mousewheel.with_control.action", 3);
 }
 
 function clearPrefs()
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].
                   getService(Components.interfaces.nsIPrefBranch);
 
   prefSvc.clearUserPref("general.smoothScroll");
   prefSvc.clearUserPref("mousewheel.acceleration.start");
   prefSvc.clearUserPref("mousewheel.system_scroll_override_on_root_content.enabled");
-  prefSvc.clearUserPref("mousewheel.withcontrolkey.action");
+  prefSvc.clearUserPref("mousewheel.with_control.action");
 }
 
 window.onload = function () {
   initPrefs();
   SimpleTest.executeSoon(runTest);
 }
 
 SimpleTest.waitForExplicitFinish();
--- a/content/events/test/test_bug607464.html
+++ b/content/events/test/test_bug607464.html
@@ -21,29 +21,26 @@ https://bugzilla.mozilla.org/show_bug.cg
 /**
  * Test for Bug 607464:
  * Pixel scrolling shouldn't scroll smoothly, even if general.smoothScroll is on.
  **/
 
 function scrollDown15PxWithPixelScrolling(scrollbox) {
   var win = scrollbox.ownerDocument.defaultView;
   let event = {
-    'type': "DOMMouseScroll",
-    'axis': "vertical",
-    'delta': 1,
-    'hasPixels': true,
+    deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+    deltaY: 3.0,
+    lineOrPageDeltaY: 1
   };
-  // first a line scroll
-  synthesizeMouseScroll(scrollbox, 10, 10, event, win);
-  // then 5 pixel scrolls with 3px each
-  event.delta *= 3;
-  event.type = "MozMousePixelScroll";
-  event.hasPixels = false;
-  for (let i = 0; i < 5; ++i) {
-    synthesizeMouseScroll(scrollbox, 10, 10, event, win);
+  // A pixel scroll with lineOrPageDeltaY.
+  synthesizeWheel(scrollbox, 10, 10, event, win);
+  // then 4 pixel scrolls without lineOrPageDeltaY.
+  event.lineOrPageDeltaY = 0;
+  for (let i = 0; i < 4; ++i) {
+    synthesizeWheel(scrollbox, 10, 10, event, win);
   }
 
   // Note: the line scroll shouldn't have any effect because it has
   // hasPixels = true set on it. We send it to emulate normal
   // behavior.
 }
 
 function runTest() {
new file mode 100644
--- /dev/null
+++ b/content/events/test/test_continuous_wheel_events.html
@@ -0,0 +1,3286 @@
+<!DOCTYPE HTML>
+<html style="font-size: 32px;">
+<head>
+  <title>Test for D3E WheelEvent</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="scrollable" style="font-size: 16px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
+  <div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+    Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
+  </div>
+</div>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests, window);
+
+var gScrollableElement = document.getElementById("scrollable");
+var gScrolledElement = document.getElementById("scrolled");
+
+var gLineHeight = 0;
+var gPageHeight = 0;
+var gPageWidth  = 0;
+
+function prepareScrollUnits()
+{
+  var result = -1;
+  function handler(aEvent)
+  {
+    result = aEvent.detail;
+    aEvent.preventDefault();
+  }
+  window.addEventListener("MozMousePixelScroll", handler, true);
+
+  synthesizeWheel(gScrollableElement, 10, 10,
+                  { deltaMode: WheelEvent.DOM_DELTA_LINE,
+                    deltaY: 1.0, lineOrPageDeltaY: 1 });
+  gLineHeight = result;
+  ok(gLineHeight > 10 && gLineHeight < 25, "prepareScrollUnits: gLineHeight may be illegal value, got " + gLineHeight);
+
+  result = -1;
+  synthesizeWheel(gScrollableElement, 10, 10,
+                  { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+                    deltaY: 1.0, lineOrPageDeltaY: 1 });
+  gPageHeight = result;
+  // XXX Cannot we know the actual scroll port size?
+  ok(gPageHeight >= 150 && gPageHeight <= 200,
+     "prepareScrollUnits: gPageHeight is strange value, got " + gPageHeight);
+
+  result = -1;
+  synthesizeWheel(gScrollableElement, 10, 10,
+                  { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+                    deltaX: 1.0, lineOrPageDeltaX: 1 });
+  gPageWidth = result;
+  ok(gPageWidth >= 150 && gPageWidth <= 200,
+     "prepareScrollUnits: gPageWidth is strange value, got " + gPageWidth);
+
+  window.removeEventListener("MozMousePixelScroll", handler, true);
+}
+
+// Tests continuous trusted wheel events. Trusted wheel events should cause
+// legacy mouse scroll events when its lineOrPageDelta value is not zero or
+// accumulated delta values of pixel scroll events of pixel only device
+// become over the line height.
+function testContinuousTrustedEvents()
+{
+  const kSynthesizedWheelEventTests = [
+    { description: "Simple horizontal wheel event by pixels (16.0 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 16 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Simple horizontal wheel event by pixels (16.0 - 1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 16 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Simple horizontal wheel event by pixels (16.0 - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 16.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 16 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Simple vertical wheel event by pixels (16.0 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: 16 } }
+    },
+    { description: "Simple vertical wheel event by pixels (16.0 - 1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: 16 } }
+    },
+    { description: "Simple vertical wheel event by pixels (16.0 - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 16.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: 16 } }
+    },
+
+    { description: "Simple z-direction wheel event by pixels (16.0 - 1)",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 0.0, deltaZ: 16.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 0.0, deltaZ: 16.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: false,  preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: false,  preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Simple horizontal wheel event by pixels (-16.0 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -16 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Simple horizontal wheel event by pixels (-16.0 - -1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -16 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Simple horizontal wheel event by pixels (-16.0 - -1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -16.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -16 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Simple vertical wheel event by pixels (-16.0 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: -16 } }
+    },
+    { description: "Simple vertical wheel event by pixels (-16.0 - -1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: -16 } }
+    },
+    { description: "Simple vertical wheel event by pixels (-16.0 - -1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -16.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: true,   preventDefault: false, detail: -16 } }
+    },
+
+    { description: "Simple z-direction wheel event by pixels (-16.0 - -1)",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 0.0, deltaZ: -16.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 0.0, deltaZ: -16.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: false,  preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false,  preventDefault: false, detail: 0 },
+        vertical:   { expected: false,  preventDefault: false, detail: 0 } }
+    },
+
+    // 3 scroll events per line, and legacy line scroll will be fired first.
+    { description: "Horizontal wheel event by pixels (5.3 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Vertical wheel event by pixels (5.3 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "Vertical wheel event by pixels (5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "Vertical wheel event by pixels (5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+
+    { description: "Horizontal wheel event by pixels (-5.3 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (-5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (-5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Vertical wheel event by pixels (-5.3 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "Vertical wheel event by pixels (-5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "Vertical wheel event by pixels (-5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+
+    // 3 scroll events per line, and legacy line scroll will be fired last.
+    { description: "Horizontal wheel event by pixels (5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (5.3 - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Vertical wheel event by pixels (5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "Vertical wheel event by pixels (5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "Vertical wheel event by pixels (5.3 - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+
+    { description: "Horizontal wheel event by pixels (-5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (-5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Horizontal wheel event by pixels (-5.3 - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Vertical wheel event by pixels (-5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "Vertical wheel event by pixels (-5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "Vertical wheel event by pixels (-5.3 - -1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+
+    // Oblique scroll.
+    { description: "To bottom-right wheel event by pixels (5.3/5.2 - 1/1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "To bottom-right wheel event by pixels (5.3/5.2 - 0/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "To bottom-right wheel event by pixels (5.3/5.2 - 0/0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 5.2, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+
+    { description: "To bottom-left wheel event by pixels (-5.3/5.3 - -1/1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: true,  preventDefault: false, detail:  1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail:  5 } }
+    },
+    { description: "To bottom-left wheel event by pixels (-5.3/5.3 - 0/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail:  5 } }
+    },
+    { description: "To bottom-left wheel event by pixels (-5.3/5.3 - 0/0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail:  5 } }
+    },
+
+    { description: "To top-left wheel event by pixels (-5.2/-5.3 - -1/-1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "To top-left wheel event by pixels (-5.2/-5.3 - 0/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "To top-left wheel event by pixels (-5.2/-5.3 - 0/0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.2, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+
+    { description: "To top-right wheel event by pixels (5.3/-5.3 - 1/-1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  1 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "To top-right wheel event by pixels (5.3/-5.3 - 0/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+
+    // Pixel scroll only device's test. the lineOrPageDelta values should be computed
+    // by ESM. When changing the direction for each delta value, it should be
+    // reset at that time.
+    { description: "Pixel only device's horizontal wheel event by pixels (5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Pixel only device's horizontal wheel event by pixels (5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Pixel only device's horizontal wheel event by pixels (5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Pixel only device's horizontal wheel event by pixels (5.3 - 0) #4",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+    { description: "Pixel only device's Vertical wheel event by pixels (5.3 - 1) #4",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 5 } }
+    },
+
+    { description: "Pixel only device's horizontal wheel event by pixels (-5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Pixel only device's horizontal wheel event by pixels (-5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Pixel only device's horizontal wheel event by pixels (-5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Pixel only device's horizontal wheel event by pixels (-5.3 - 0) #4",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - 0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+    { description: "Pixel only device's Vertical wheel event by pixels (-5.3 - -1) #4",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -5.3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -5 } }
+    },
+
+    // ESM should reset an accumulated delta value only when the direction of it
+    // is changed but shouldn't reset the other delta.
+    { description: "Pixel only device's bottom-right wheel event by pixels (5.3/4.9 - 0/0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 4 } }
+    },
+    { description: "Pixel only device's bottom-right wheel event by pixels (5.3/4.9 - 0/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 4 } }
+    },
+    { description: "Pixel only device's bottom-right wheel event by pixels (5.3/4.9 - 0/0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 4 } }
+    },
+    { description: "Pixel only device's bottom-left wheel event by pixels (-5.3/4.9 - 0/0) #4",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 4 } }
+    },
+    // the accumulated X should be 0 here, but Y shouldn't be reset.
+    { description: "Pixel only device's bottom-right wheel event by pixels (5.3/4.9 - 0/0) #5",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 5.3, deltaY: 4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 5 },
+        vertical:   { expected: true,  preventDefault: false, detail: 4 } }
+    },
+
+    { description: "Pixel only device's top-left wheel event by pixels (-5.3/-4.9 - 0/0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -4 } }
+    },
+    { description: "Pixel only device's top-left wheel event by pixels (-5.3/-4.9 - 0/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -4 } }
+    },
+    { description: "Pixel only device's top-left wheel event by pixels (-5.3/-4.9 - 0/0) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -4 } }
+    },
+    { description: "Pixel only device's bottom-left wheel event by pixels (5.3/-4.9 - 0/0) #4",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: 4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail:  4 } }
+    },
+    // the accumulated Y should be 0 here, but X shouldn't be reset.
+    { description: "Pixel only device's top-left wheel event by pixels (5.3/4.9 - 0/0) #5",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
+               deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: true,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -5.3, deltaY: -4.9, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -5 },
+        vertical:   { expected: true,  preventDefault: false, detail: -4 } }
+    },
+
+    // Simple line scroll tests.
+    { description: "Simple horizontal wheel event by lines (1.0 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: gLineHeight },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Simple horizontal wheel event by lines (1.0 - 1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: gLineHeight },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Simple horizontal wheel event by lines (-1.0 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -gLineHeight },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+    { description: "Simple horizontal wheel event by lines (-1.0 - -1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -gLineHeight },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+
+    { description: "Simple vertical wheel event by lines (-1.0 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -gLineHeight } }
+    },
+    { description: "Simple vertical wheel event by lines (-1.0 - -1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -gLineHeight } }
+    },
+
+    { description: "Simple vertical wheel event by lines (1.0 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: gLineHeight } }
+    },
+    { description: "Simple vertical wheel event by lines (1.0 - 1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: gLineHeight } }
+    },
+
+    // high resolution line scroll
+    { description: "High resolution horizontal wheel event by lines (0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "High resolution horizontal wheel event by lines (0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "High resolution horizontal wheel event by lines (0.333... - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "High resolution horizontal wheel event by lines (-0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -Math.floor(gLineHeight / 3) },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+    { description: "High resolution horizontal wheel event by lines (-0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -Math.floor(gLineHeight / 3) },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+    { description: "High resolution horizontal wheel event by lines (-0.333... - -1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -Math.floor(gLineHeight / 3) },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+
+    { description: "High resolution vertical wheel event by lines (0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by lines (0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by lines (0.333... - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+    },
+
+    { description: "High resolution vertical wheel event by lines (-0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -Math.floor(gLineHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by lines (-0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -Math.floor(gLineHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by lines (-0.333... - -1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -Math.floor(gLineHeight / 3) } }
+    },
+
+    // Oblique line scroll
+    { description: "Oblique wheel event by lines (-1.0/2.0 - -1/2)",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 2, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -1 },
+        vertical:   { expected: true,  preventDefault: false, detail:  2 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -gLineHeight },
+        vertical:   { expected: true,  preventDefault: false, detail:  gLineHeight * 2 } }
+    },
+
+    { description: "Oblique wheel event by lines (1.0/-2.0 - 1/-2)",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: -2, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  1 },
+        vertical:   { expected: true,  preventDefault: false, detail: -2 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  gLineHeight },
+        vertical:   { expected: true,  preventDefault: false, detail: -gLineHeight * 2 } }
+    },
+
+    { description: "High resolution oblique wheel event by lines (0.5/0.333.../-0.8 - 0/0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 2) },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+    },
+    { description: "High resolution oblique wheel event by lines (0.5/0.333.../-0.8 - 1/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: 1 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 2) },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+    },
+    { description: "High resolution oblique wheel event by lines (0.5/0.333.../-0.8 - 0/1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
+               deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: 1 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 2) },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gLineHeight / 3) } }
+    },
+
+    // Simple page scroll tests.
+    { description: "Simple horizontal wheel event by pages (1.0 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: gPageWidth },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "Simple horizontal wheel event by pages (1.0 - 1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: gPageWidth },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "Simple horizontal wheel event by pages (-1.0 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -gPageWidth },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+    { description: "Simple horizontal wheel event by pages (-1.0 - -1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -gPageWidth },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+
+    { description: "Simple vertical wheel event by pages (-1.0 - -1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -gPageHeight } }
+    },
+    { description: "Simple vertical wheel event by pages (-1.0 - -1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -gPageHeight } }
+    },
+
+    { description: "Simple vertical wheel event by pages (1.0 - 1) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: gPageHeight } }
+    },
+    { description: "Simple vertical wheel event by pages (1.0 - 1) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: gPageHeight } }
+    },
+
+    // high resolution page scroll
+    { description: "High resolution horizontal wheel event by pages (0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gPageWidth / 3) },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "High resolution horizontal wheel event by pages (0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gPageWidth / 3) },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+    { description: "High resolution horizontal wheel event by pages (0.333... - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gPageWidth / 3) },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } }
+    },
+
+    { description: "High resolution horizontal wheel event by pages (-0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -Math.floor(gPageWidth / 3) },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+    { description: "High resolution horizontal wheel event by pages (-0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -Math.floor(gPageWidth / 3) },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+    { description: "High resolution horizontal wheel event by pages (-0.333... - -1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0 / 3, deltaY: 0.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -Math.floor(gPageWidth / 3) },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } }
+    },
+
+    { description: "High resolution vertical wheel event by pages (0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by pages (0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by pages (0.333... - 1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: 1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+    },
+
+    { description: "High resolution vertical wheel event by pages (-0.333... - 0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -Math.floor(gPageHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by pages (-0.333... - 0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: false, preventDefault: false, detail:  0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -Math.floor(gPageHeight / 3) } }
+    },
+    { description: "High resolution vertical wheel event by pages (-0.333... - -1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: -1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.0, deltaY: -1.0 / 3, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP } },
+      MozMousePixelScroll: {
+        horizontal: { expected: false, preventDefault: false, detail:  0 },
+        vertical:   { expected: true,  preventDefault: false, detail: -Math.floor(gPageHeight / 3) } }
+    },
+
+    // Oblique page scroll
+    { description: "Oblique wheel event by pages (-1.0/2.0 - -1/2)",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: -1, lineOrPageDeltaY: 2, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: -1.0, deltaY: 2.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP },
+        vertical:   { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_DOWN } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: -gPageWidth },
+        vertical:   { expected: true,  preventDefault: false, detail:  gPageHeight * 2 } }
+    },
+
+    { description: "Oblique wheel event by pages (1.0/-2.0 - 1/-2)",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: -2, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 1.0, deltaY: -2.0, deltaZ: 0.0
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_DOWN },
+        vertical:   { expected: true,  preventDefault: false, detail:  UIEvent.SCROLL_PAGE_UP } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail:  gPageWidth },
+        vertical:   { expected: true,  preventDefault: false, detail: -gPageHeight * 2 } }
+    },
+
+    { description: "High resolution oblique wheel event by pages (0.5/0.333.../-0.8 - 0/0) #1",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: false, preventDefault: false, detail: 0 },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gPageWidth / 2) },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+    },
+    { description: "High resolution oblique wheel event by pages (0.5/0.333.../-0.8 - 1/0) #2",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+               lineOrPageDeltaX: 1, lineOrPageDeltaY: 0, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false, ctrlKey: false, altKey: false, metaKey: false },
+      wheel: {
+        expected: true, preventDefault: false,
+        deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8
+      },
+      DOMMouseScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: UIEvent.SCROLL_PAGE_DOWN },
+        vertical:   { expected: false, preventDefault: false, detail: 0 } },
+      MozMousePixelScroll: {
+        horizontal: { expected: true,  preventDefault: false, detail: Math.floor(gPageWidth / 2) },
+        vertical:   { expected: true,  preventDefault: false, detail: Math.floor(gPageHeight / 3) } }
+    },
+    { description: "High resolution oblique wheel event by pages (0.5/0.333.../-0.8 - 0/1) #3",
+      event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+               deltaX: 0.5, deltaY: 1.0 / 3, deltaZ: -0.8, isMomentum: false,
+               lineOrPageDeltaX: 0, lineOrPageDeltaY: 1, isPixelOnlyDevice: false,
+               isCustomizedByPrefs: false,
+               shiftKey: false,