Bug 719320 part.8-6 Init lineOrPageDeltaX and lineOrPageDeltaY from accumulated delta values if the wheel event is caused by pixel scroll only device or the delta values have been modified with prefs r=smaug
authorMasayuki Nakano <masayuki@d-toybox.com>
Sun, 12 Aug 2012 10:42:36 +0900
changeset 107533 842d2eaa63bc6b4f7367c150dc6da2a6291c7de5
parent 107532 8a59a17c195cfa909b7f675305ecbf6a84761370
child 107534 b9472dc9837c337f85b48e2ef465088516edea20
push id1490
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 18:29:50 +0000
treeherdermozilla-beta@f335e7dacdc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs719320
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 719320 part.8-6 Init lineOrPageDeltaX and lineOrPageDeltaY from accumulated delta values if the wheel event is caused by pixel scroll only device or the delta values have been modified with prefs r=smaug
content/events/src/nsDOMEvent.cpp
content/events/src/nsEventStateManager.cpp
content/events/src/nsEventStateManager.h
widget/nsGUIEvent.h
widget/nsGUIEventIPC.h
--- a/content/events/src/nsDOMEvent.cpp
+++ b/content/events/src/nsDOMEvent.cpp
@@ -746,16 +746,17 @@ nsDOMEvent::DuplicatePrivateData()
       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->isPixelOnlyDevice = oldWheelEvent->isPixelOnlyDevice;
       wheelEvent->lineOrPageDeltaX = oldWheelEvent->lineOrPageDeltaX;
       wheelEvent->lineOrPageDeltaY = oldWheelEvent->lineOrPageDeltaY;
       wheelEvent->overflowDeltaX = oldWheelEvent->overflowDeltaX;
       wheelEvent->overflowDeltaY = oldWheelEvent->overflowDeltaY;
       newEvent = wheelEvent;
       break;
     }
     case NS_SCROLLPORT_EVENT:
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -133,18 +133,18 @@ nsCOMPtr<nsIContent> nsEventStateManager
 static PRUint32 gMouseOrKeyboardEventCounter = 0;
 static nsITimer* gUserInteractionTimer = nullptr;
 static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
 
 TimeStamp nsEventStateManager::sHandlingInputStart;
 
 nsEventStateManager::WheelPrefs*
   nsEventStateManager::WheelPrefs::sInstance = nullptr;
-nsEventStateManager::PixelDeltaAccumulator*
-  nsEventStateManager::PixelDeltaAccumulator::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));
 }
 
@@ -805,16 +805,17 @@ nsEventStateManager::~nsEventStateManage
       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();
@@ -830,17 +831,16 @@ nsEventStateManager::~nsEventStateManage
     }
   }
 
 }
 
 nsresult
 nsEventStateManager::Shutdown()
 {
-  PixelDeltaAccumulator::Shutdown();
   Preferences::RemoveObservers(this, kObservedPrefs);
   m_haveShutdown = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEventStateManager::Observe(nsISupports *aSubject,
                              const char *aTopic,
@@ -1127,16 +1127,23 @@ nsEventStateManager::PreHandleEvent(nsPr
                    "Untrusted wheel event shouldn't be here");
 
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
 
       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))
@@ -5135,101 +5142,105 @@ nsEventStateManager::ClearGlobalActiveCo
   }
   if (sActiveESM && aClearer != sActiveESM) {
     sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
   }
   sActiveESM = nullptr;
 }
 
 /******************************************************************/
-/* nsEventStateManager::PixelDeltaAccumulator                     */
+/* nsEventStateManager::DeltaAccumulator                          */
 /******************************************************************/
 
 void
-nsEventStateManager::PixelDeltaAccumulator::OnMousePixelScrollEvent(
-                                                nsPresContext* aPresContext,
-                                                nsIFrame* aTargetFrame,
-                                                nsEventStateManager* aESM,
-                                                nsMouseScrollEvent* aEvent,
-                                                nsEventStatus* aStatus)
+nsEventStateManager::DeltaAccumulator::InitLineOrPageDelta(
+                                         nsIFrame* aTargetFrame,
+                                         nsEventStateManager* aESM,
+                                         widget::WheelEvent* aEvent)
 {
-  MOZ_ASSERT(aPresContext);
   MOZ_ASSERT(aESM);
   MOZ_ASSERT(aEvent);
-  MOZ_ASSERT(aEvent->message == NS_MOUSE_PIXEL_SCROLL);
-  MOZ_ASSERT(NS_IS_TRUSTED_EVENT(aEvent));
-  MOZ_ASSERT(aStatus);
-
-  if (!(aEvent->scrollFlags & nsMouseScrollEvent::kNoLines)) {
+
+  if (!(aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL &&
+        aEvent->isPixelOnlyDevice) &&
+      !WheelPrefs::GetInstance()->NeedToComputeLineOrPageDelta(aEvent)) {
     Reset();
     return;
   }
 
-#if 0
-  nsIScrollableFrame* scrollTarget =
-    aESM->ComputeScrollTarget(aTargetFrame, aEvent, false);
-  nsSize scrollAmount =
-    aESM->GetScrollAmount(aPresContext, aEvent, aTargetFrame, scrollTarget);
-  bool isHorizontal =
-    (aEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) != 0;
-  PRInt32 pixelsPerLine =
-    nsPresContext::AppUnitsToIntCSSPixels(isHorizontal ? scrollAmount.width :
-                                                         scrollAmount.height);
-
+  // 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();
-
-  // If the delta direction is changed, we should reset the accumulated values.
-  if (mX && isHorizontal && aEvent->delta &&
-      ((aEvent->delta > 0) != (mX > 0))) {
-    mX = 0;
-  }
-  if (mY && !isHorizontal && aEvent->delta &&
-      ((aEvent->delta > 0) != (mY > 0))) {
-    mY = 0;
-  }
-
-  PRInt32 numLines;
-  if (isHorizontal) {
-    // Adds delta value, first.
-    mX += aEvent->delta;
-    // Compute lines in integer scrolled by the accumulated delta value.
-    numLines =
-      static_cast<PRInt32>(NS_round(static_cast<double>(mX) / pixelsPerLine));
-    // Consume the lines from the accumulated delta value.
-    mX -= numLines * pixelsPerLine;
-  } else {
-    // Adds delta value, first.
-    mY += aEvent->delta;
-    // Compute lines in integer scrolled by the accumulated delta value.
-    numLines =
-      static_cast<PRInt32>(NS_round(static_cast<double>(mY) / pixelsPerLine));
-    // Consume the lines from the accumulated delta value.
-    mY -= numLines * pixelsPerLine;
-  }
-
-  if (!numLines) {
-    return;
-  }
-
-  aESM->SendLineScrollEvent(aTargetFrame, aEvent, aPresContext,
-                            aStatus, numLines);
-#endif
 }
 
 void
-nsEventStateManager::PixelDeltaAccumulator::Reset()
+nsEventStateManager::DeltaAccumulator::Reset()
 {
-  mX = mY = 0;
+  mX = mY = 0.0;
+  mHandlingDeltaMode = PR_UINT32_MAX;
+  mHandlingPixelOnlyDevice = false;
 }
 
 /******************************************************************/
 /* nsEventStateManager::WheelPrefs                                */
 /******************************************************************/
 
 // static
 nsEventStateManager::WheelPrefs*
@@ -5251,16 +5262,17 @@ nsEventStateManager::WheelPrefs::Shutdow
 
 // 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);
 }
@@ -5405,8 +5417,19 @@ nsEventStateManager::WheelPrefs::ApplyUs
 
 nsEventStateManager::WheelPrefs::Action
 nsEventStateManager::WheelPrefs::GetActionFor(nsMouseScrollEvent* aEvent)
 {
   Index index = GetIndexFor(aEvent);
   Init(index);
   return 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
@@ -346,16 +346,22 @@ protected:
       ACTION_NONE = 0,
       ACTION_SCROLL,
       ACTION_HISTORY,
       ACTION_ZOOM,
       ACTION_LAST = ACTION_ZOOM
     };
     Action GetActionFor(nsMouseScrollEvent* 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
     {
@@ -494,62 +500,67 @@ protected:
    * 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.
    */
   PRInt32 ComputeWheelActionFor(nsMouseScrollEvent* aMouseEvent);
 
   /**
-   * PixelDeltaAccumulator class manages pixel delta values for dispatching
-   * DOMMouseScroll event.
+   * 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.
    */
-  class PixelDeltaAccumulator
+  class DeltaAccumulator
   {
   public:
-    static PixelDeltaAccumulator* GetInstance()
+    static DeltaAccumulator* GetInstance()
     {
       if (!sInstance) {
-        sInstance = new PixelDeltaAccumulator;
+        sInstance = new DeltaAccumulator;
       }
       return sInstance;
     }
 
     static void Shutdown()
     {
       delete sInstance;
       sInstance = nullptr;
     }
 
     /**
-     * OnMousePixelScrollEvent() stores pixel delta values.  And if the
-     * accumulated delta becomes a line height, dispatches DOMMouseScroll event
-     * automatically.
+     * 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 OnMousePixelScrollEvent(nsPresContext* aPresContext,
-                                 nsIFrame* aTargetFrame,
-                                 nsEventStateManager* aESM,
-                                 nsMouseScrollEvent* aEvent,
-                                 nsEventStatus* aStatus);
+    void InitLineOrPageDelta(nsIFrame* aTargetFrame,
+                             nsEventStateManager* aESM,
+                             mozilla::widget::WheelEvent* aEvent);
+
     /**
      * Reset() resets both delta values.
      */
     void Reset();
 
   private:
-    PixelDeltaAccumulator() :
-      mX(0), mY(0)
+    DeltaAccumulator() :
+      mX(0.0), mY(0.0), mHandlingDeltaMode(PR_UINT32_MAX),
+      mHandlingPixelOnlyDevice(false)
     {
     }
 
-    PRInt32 mX;
-    PRInt32 mY;
+    double mX;
+    double mY;
     TimeStamp mLastTime;
 
-    static PixelDeltaAccumulator* sInstance;
+    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.
--- a/widget/nsGUIEvent.h
+++ b/widget/nsGUIEvent.h
@@ -1403,33 +1403,39 @@ private:
   {
   }
 
 public:
   WheelEvent(bool aIsTrusted, PRUint32 aMessage, nsIWidget* aWidget) :
     nsMouseEvent_base(aIsTrusted, aMessage, aWidget, NS_WHEEL_EVENT),
     deltaX(0.0), deltaY(0.0), deltaZ(0.0),
     deltaMode(nsIDOMWheelEvent::DOM_DELTA_PIXEL),
-    customizedByUserPrefs(false),
+    customizedByUserPrefs(false), isPixelOnlyDevice(false),
     lineOrPageDeltaX(0), lineOrPageDeltaY(0),
     overflowDeltaX(0.0), overflowDeltaY(0.0)
   {
   }
 
   double deltaX;
   double deltaY;
   double deltaZ;
 
   // Should be one of nsIDOMWheelEvent::DOM_DELTA_*
   PRUint32 deltaMode;
 
   // If the delta values are computed from prefs, this value is true.
   // Otherwise, i.e., they are computed from native events, false.
   bool customizedByUserPrefs;
 
+  // If device event handlers don't know when they should set lineOrPageDeltaX
+  // and lineOrPageDeltaY, this is true.  Otherwise, false.
+  // If isPixelOnlyDevice is true, ESM will generate NS_MOUSE_SCROLL events
+  // when accumulated pixel delta values reach a line height.
+  bool isPixelOnlyDevice;
+
   // If widget sets lineOrPageDelta, nsEventStateManager will dispatch
   // NS_MOUSE_SCROLL event for compatibility.  Note that the delta value means
   // pages if the deltaMode is DOM_DELTA_PAGE, otherwise, lines.
   PRInt32 lineOrPageDeltaX;
   PRInt32 lineOrPageDeltaY;
 
   // overflowed delta values, these values are the result of dispatching this
   // event.
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -125,30 +125,32 @@ struct ParamTraits<mozilla::widget::Whee
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, static_cast<nsMouseEvent_base>(aParam));
     WriteParam(aMsg, aParam.deltaX);
     WriteParam(aMsg, aParam.deltaY);
     WriteParam(aMsg, aParam.deltaZ);
     WriteParam(aMsg, aParam.deltaMode);
     WriteParam(aMsg, aParam.customizedByUserPrefs);
+    WriteParam(aMsg, aParam.isPixelOnlyDevice);
     WriteParam(aMsg, aParam.lineOrPageDeltaX);
     WriteParam(aMsg, aParam.lineOrPageDeltaY);
     WriteParam(aMsg, aParam.overflowDeltaX);
     WriteParam(aMsg, aParam.overflowDeltaY);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, static_cast<nsMouseEvent_base*>(aResult)) &&
            ReadParam(aMsg, aIter, &aResult->deltaX) &&
            ReadParam(aMsg, aIter, &aResult->deltaY) &&
            ReadParam(aMsg, aIter, &aResult->deltaZ) &&
            ReadParam(aMsg, aIter, &aResult->deltaMode) &&
            ReadParam(aMsg, aIter, &aResult->customizedByUserPrefs) &&
+           ReadParam(aMsg, aIter, &aResult->isPixelOnlyDevice) &&
            ReadParam(aMsg, aIter, &aResult->lineOrPageDeltaX) &&
            ReadParam(aMsg, aIter, &aResult->lineOrPageDeltaY) &&
            ReadParam(aMsg, aIter, &aResult->overflowDeltaX) &&
            ReadParam(aMsg, aIter, &aResult->overflowDeltaY);
   }
 };
 
 template<>