Bug 970141 Use CSS pixels rather than device pixels for delta values of WheelEvent r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Tue, 11 Mar 2014 14:14:07 +0900
changeset 172927 797110c218e31ea53b0bd749e018f13ef8c01d0b
parent 172926 9040a7cf26393432de57d6e01b78a3ce210bf60b
child 172928 9f92527ff03ba3bad3b301633acdc637f392d3ec
push id26384
push userryanvm@gmail.com
push dateTue, 11 Mar 2014 19:19:48 +0000
treeherdermozilla-central@9cdaf3f7c601 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs970141
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 970141 Use CSS pixels rather than device pixels for delta values of WheelEvent r=smaug
dom/events/WheelEvent.cpp
dom/events/WheelEvent.h
dom/events/test/window_wheel_default_action.html
--- a/dom/events/WheelEvent.cpp
+++ b/dom/events/WheelEvent.cpp
@@ -12,19 +12,27 @@ namespace mozilla {
 namespace dom {
 
 WheelEvent::WheelEvent(EventTarget* aOwner,
                        nsPresContext* aPresContext,
                        WidgetWheelEvent* aWheelEvent)
   : MouseEvent(aOwner, aPresContext,
                aWheelEvent ? aWheelEvent :
                              new WidgetWheelEvent(false, 0, nullptr))
+  , mAppUnitsPerDevPixel(0)
 {
   if (aWheelEvent) {
     mEventIsInternal = false;
+    // If the delta mode is pixel, the WidgetWheelEvent's delta values are in
+    // device pixels.  However, JS contents need the delta values in CSS pixels.
+    // We should store the value of mAppUnitsPerDevPixel here because
+    // it might be changed by changing zoom or something.
+    if (aWheelEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
+      mAppUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
+    }
   } else {
     mEventIsInternal = true;
     mEvent->time = PR_Now();
     mEvent->refPoint.x = mEvent->refPoint.y = 0;
     mEvent->AsWheelEvent()->inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
   }
 }
 
@@ -66,47 +74,59 @@ WheelEvent::InitWheelEvent(const nsAStri
   wheelEvent->deltaMode = aDeltaMode;
 
   return NS_OK;
 }
 
 double
 WheelEvent::DeltaX()
 {
-  return mEvent->AsWheelEvent()->deltaX;
+  if (!mAppUnitsPerDevPixel) {
+    return mEvent->AsWheelEvent()->deltaX;
+  }
+  return mEvent->AsWheelEvent()->deltaX *
+    mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel();
 }
 
 NS_IMETHODIMP
 WheelEvent::GetDeltaX(double* aDeltaX)
 {
   NS_ENSURE_ARG_POINTER(aDeltaX);
 
   *aDeltaX = DeltaX();
   return NS_OK;
 }
 
 double
 WheelEvent::DeltaY()
 {
-  return mEvent->AsWheelEvent()->deltaY;
+  if (!mAppUnitsPerDevPixel) {
+    return mEvent->AsWheelEvent()->deltaY;
+  }
+  return mEvent->AsWheelEvent()->deltaY *
+    mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel();
 }
 
 NS_IMETHODIMP
 WheelEvent::GetDeltaY(double* aDeltaY)
 {
   NS_ENSURE_ARG_POINTER(aDeltaY);
 
   *aDeltaY = DeltaY();
   return NS_OK;
 }
 
 double
 WheelEvent::DeltaZ()
 {
-  return mEvent->AsWheelEvent()->deltaZ;
+  if (!mAppUnitsPerDevPixel) {
+    return mEvent->AsWheelEvent()->deltaZ;
+  }
+  return mEvent->AsWheelEvent()->deltaZ *
+    mAppUnitsPerDevPixel / nsPresContext::AppUnitsPerCSSPixel();
 }
 
 NS_IMETHODIMP
 WheelEvent::GetDeltaZ(double* aDeltaZ)
 {
   NS_ENSURE_ARG_POINTER(aDeltaZ);
 
   *aDeltaZ = DeltaZ();
--- a/dom/events/WheelEvent.h
+++ b/dom/events/WheelEvent.h
@@ -38,18 +38,24 @@ public:
                                            ErrorResult& aRv);
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
   {
     return WheelEventBinding::Wrap(aCx, aScope, this);
   }
 
+  // NOTE: DeltaX(), DeltaY() and DeltaZ() return CSS pixels when deltaMode is
+  //       DOM_DELTA_PIXEL. (The internal event's delta values are device pixels
+  //       if it's dispatched by widget)
   double DeltaX();
   double DeltaY();
   double DeltaZ();
   uint32_t DeltaMode();
+
+private:
+  int32_t mAppUnitsPerDevPixel;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_WheelEvent_h_
--- a/dom/events/test/window_wheel_default_action.html
+++ b/dom/events/test/window_wheel_default_action.html
@@ -1142,85 +1142,103 @@ function doTestZoom(aSettings, aCallback
       });
     }, 20);
   }
   doNextTest();
 }
 
 function doTestZoomedScroll(aCallback)
 {
+  var zoom = 1.0;
+  function setFullZoom(aWindow, aZoom)
+  {
+    zoom = aZoom;
+    SpecialPowers.setFullZoom(aWindow, aZoom);
+  }
+
   function prepareTestZoomedPixelScroll()
   {
     // Reset zoom and store the scroll amount into the data.
     synthesizeKey("0", { accelKey: true });
+    zoom = 1.0;
     onZoomReset(testZoomedPixelScroll);
   }
 
   function testZoomedPixelScroll()
   {
     gScrollableElement.scrollTop = 1000;
     gScrollableElement.scrollLeft = 1000;
     // Ensure not to be in reflow.
     hitEventLoop(function () {
-      function handler(aEvent)
+      function mousePixelScrollHandler(aEvent)
       {
         if (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS) {
           is(aEvent.detail, 16,
              "doTestZoomedScroll: The detail of horizontal MozMousePixelScroll for pixel wheel event is wrong");
         } else if (aEvent.axis == MouseScrollEvent.VERTICAL_AXIS) {
           is(aEvent.detail, 16,
              "doTestZoomedScroll: The detail of vertical MozMousePixelScroll for pixel wheel event is wrong");
         } else {
           ok(false, "doTestZoomedScroll: The axis of MozMousePixelScroll for pixel wheel event is invalid, got " + aEvent.axis);
         }
       }
-      window.addEventListener("MozMousePixelScroll", handler, true);
+      function wheelHandler(aEvent)
+      {
+        is(aEvent.deltaX, 16.0 / zoom,
+           "doTestZoomedScroll: The deltaX of wheel for pixel is wrong");
+        is(aEvent.deltaY, 16.0 / zoom,
+           "doTestZoomedScroll: The deltaY of wheel for pixel is wrong");
+      }
+      window.addEventListener("MozMousePixelScroll", mousePixelScrollHandler, true);
+      window.addEventListener("wheel", wheelHandler, true);
       synthesizeWheel(gScrollableElement, 10, 10,
         { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
           deltaX: 16.0, deltaY: 16.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 });
       // wait scrolled actually.
       hitEventLoop(function () {
         var scrolledX = gScrollableElement.scrollLeft;
         var scrolledY = gScrollableElement.scrollTop;
         ok(scrolledX > 1000,
            "doTestZoomedScroll: scrolledX must be larger than 1000 for pixel wheel event, got " + scrolledX);
         ok(scrolledY > 1000,
            "doTestZoomedScroll: scrolledY must be larger than 1000 for pixel wheel event, got " + scrolledY);
 
         // Zoom
-        SpecialPowers.setFullZoom(window, 2.0);
+        setFullZoom(window, 2.0);
         // Ensure not to be in reflow.
         hitEventLoop(function () {
           gScrollableElement.scrollTop = 1000;
           gScrollableElement.scrollLeft = 1000;
           synthesizeWheel(gScrollableElement, 10, 10,
             { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
               deltaX: 16.0, deltaY: 16.0, lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 });
           // wait scrolled actually.
           hitEventLoop(function () {
             ok(Math.abs(gScrollableElement.scrollLeft - (1000 + (scrolledX - 1000) / 2)) <= 1,
                "doTestZoomedScroll: zoomed horizontal scroll amount by pixel wheel event is different from normal, scrollLeft=" +
                  gScrollableElement.scrollLeft + ", scrolledX=" + scrolledX);
             ok(Math.abs(gScrollableElement.scrollTop - (1000 + (scrolledY - 1000) / 2)) <= 1,
                "doTestZoomedScroll: zoomed vertical scroll amount by pixel wheel event is different from normal, scrollTop=" +
                  gScrollableElement.scrollTop + ", scrolledY=" + scrolledY);
-            window.removeEventListener("MozMousePixelScroll", handler, true);
+            window.removeEventListener("MozMousePixelScroll", mousePixelScrollHandler, true);
+            window.removeEventListener("wheel", wheelHandler, true);
 
             synthesizeKey("0", { accelKey: true });
             onZoomReset(prepareTestZoomedLineScroll);
           }, 20);
         }, 20);
       }, 20);
     }, 20);
   }
 
   function prepareTestZoomedLineScroll()
   {
     // Reset zoom and store the scroll amount into the data.
     synthesizeKey("0", { accelKey: true });
+    zoom = 1.0;
     onZoomReset(testZoomedLineScroll);
   }
   function testZoomedLineScroll()
   {
     gScrollableElement.scrollTop = 1000;
     gScrollableElement.scrollLeft = 1000;
     // Ensure not to be in reflow.
     hitEventLoop(function () {
@@ -1256,17 +1274,17 @@ function doTestZoomedScroll(aCallback)
         var scrolledX = gScrollableElement.scrollLeft;
         var scrolledY = gScrollableElement.scrollTop;
         ok(scrolledX > 1000,
            "doTestZoomedScroll: scrolledX must be larger than 1000 for line wheel event, got " + scrolledX);
         ok(scrolledY > 1000,
            "doTestZoomedScroll: scrolledY must be larger than 1000 for line wheel event, got " + scrolledY);
 
         // Zoom
-        SpecialPowers.setFullZoom(window, 2.0);
+        setFullZoom(window, 2.0);
         // Ensure not to be in reflow.
         hitEventLoop(function () {
           gScrollableElement.scrollTop = 1000;
           gScrollableElement.scrollLeft = 1000;
           synthesizeWheel(gScrollableElement, 10, 10,
             { deltaMode: WheelEvent.DOM_DELTA_LINE,
               deltaX: 1.0, deltaY: 1.0, lineOrPageDeltaX: 1, lineOrPageDeltaY: 1 });
           // wait scrolled actually.