From e98c45fc9fde4b355a29d42d2ffa8f60f9487476 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sun, 12 Aug 2012 10:42:36 +0900 Subject: [PATCH] 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 | 1 + content/events/src/nsEventStateManager.cpp | 153 ++++++++++++--------- content/events/src/nsEventStateManager.h | 47 ++++--- widget/nsGUIEvent.h | 8 +- widget/nsGUIEventIPC.h | 2 + 5 files changed, 127 insertions(+), 84 deletions(-) diff --git a/content/events/src/nsDOMEvent.cpp b/content/events/src/nsDOMEvent.cpp index 463df302c64f..e78318fa72dc 100644 --- a/content/events/src/nsDOMEvent.cpp +++ b/content/events/src/nsDOMEvent.cpp @@ -751,6 +751,7 @@ nsDOMEvent::DuplicatePrivateData() 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; diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 64b717b053d8..f05ca1984094 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -138,8 +138,8 @@ 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) @@ -810,6 +810,7 @@ nsEventStateManager::~nsEventStateManager() NS_RELEASE(gUserInteractionTimer); } WheelPrefs::Shutdown(); + DeltaAccumulator::Shutdown(); } if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) { @@ -835,7 +836,6 @@ nsEventStateManager::~nsEventStateManager() nsresult nsEventStateManager::Shutdown() { - PixelDeltaAccumulator::Shutdown(); Preferences::RemoveObservers(this, kObservedPrefs); m_haveShutdown = true; return NS_OK; @@ -1132,6 +1132,13 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, widget::WheelEvent* wheelEvent = static_cast(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: @@ -5140,91 +5147,95 @@ nsEventStateManager::ClearGlobalActiveContent(nsEventStateManager* aClearer) } /******************************************************************/ -/* 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(NS_round(static_cast(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(NS_round(static_cast(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; } /******************************************************************/ @@ -5256,6 +5267,7 @@ nsEventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName, { // forget all prefs, it's not problem for performance. sInstance->Reset(); + DeltaAccumulator::GetInstance()->Reset(); return 0; } @@ -5410,3 +5422,14 @@ nsEventStateManager::WheelPrefs::GetActionFor(nsMouseScrollEvent* 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); +} diff --git a/content/events/src/nsEventStateManager.h b/content/events/src/nsEventStateManager.h index 40a76fd7bad0..df993973fafe 100644 --- a/content/events/src/nsEventStateManager.h +++ b/content/events/src/nsEventStateManager.h @@ -351,6 +351,12 @@ protected: }; 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(); @@ -499,16 +505,18 @@ protected: 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; } @@ -520,31 +528,34 @@ protected: } /** - * 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 diff --git a/widget/nsGUIEvent.h b/widget/nsGUIEvent.h index 132e5a03d2d7..d560b2de03ce 100644 --- a/widget/nsGUIEvent.h +++ b/widget/nsGUIEvent.h @@ -1408,7 +1408,7 @@ public: 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) { @@ -1425,6 +1425,12 @@ public: // 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. diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h index 0d7b13e0f8aa..07b901b5ca65 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h @@ -130,6 +130,7 @@ struct ParamTraits 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); @@ -144,6 +145,7 @@ struct ParamTraits 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) &&