1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_WheelHandlingHelper_h_
8 #define mozilla_WheelHandlingHelper_h_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/EventForwards.h"
16 class nsIScrollableFrame
;
21 class EventStateManager
;
24 * DeltaValues stores two delta values which are along X and Y axis. This is
25 * useful for arguments and results of some methods.
29 DeltaValues() : deltaX(0.0), deltaY(0.0) {}
31 DeltaValues(double aDeltaX
, double aDeltaY
)
32 : deltaX(aDeltaX
), deltaY(aDeltaY
) {}
34 explicit DeltaValues(WidgetWheelEvent
* aEvent
);
41 * WheelHandlingUtils provides some static methods which are useful at handling
45 class WheelHandlingUtils
{
48 * Returns true if aFrame is a scrollable frame and it can be scrolled to
49 * either aDirectionX or aDirectionY along each axis. Or if aFrame is a
50 * plugin frame (in this case, aDirectionX and aDirectionY are ignored).
53 static bool CanScrollOn(nsIFrame
* aFrame
, double aDirectionX
,
56 * Returns true if the scrollable frame can be scrolled to either aDirectionX
57 * or aDirectionY along each axis. Otherwise, false.
59 static bool CanScrollOn(nsIScrollableFrame
* aScrollFrame
, double aDirectionX
,
62 // For more details about the concept of a disregarded direction, refer to the
63 // code in struct mozilla::layers::ScrollMetadata which defines
64 // mDisregardedDirection.
65 static Maybe
<layers::ScrollDirection
> GetDisregardedWheelScrollDirection(
66 const nsIFrame
* aFrame
);
69 static bool CanScrollInRange(nscoord aMin
, nscoord aValue
, nscoord aMax
,
74 * ScrollbarsForWheel manages scrollbars state during wheel operation.
75 * E.g., on some platforms, scrollbars should show only while user attempts to
76 * scroll. At that time, scrollbars which may be possible to scroll by
77 * operation of wheel at the point should show temporarily.
80 class ScrollbarsForWheel
{
82 static void PrepareToScrollText(EventStateManager
* aESM
,
83 nsIFrame
* aTargetFrame
,
84 WidgetWheelEvent
* aEvent
);
85 static void SetActiveScrollTarget(nsIScrollableFrame
* aScrollTarget
);
86 // Hide all scrollbars (both mActiveOwner's and mActivatedScrollTargets')
87 static void MayInactivate();
88 static void Inactivate();
89 static bool IsActive();
90 static void OwnWheelTransaction(bool aOwn
);
93 static const size_t kNumberOfTargets
= 4;
94 static const DeltaValues directions
[kNumberOfTargets
];
95 static AutoWeakFrame sActiveOwner
;
96 static AutoWeakFrame sActivatedScrollTargets
[kNumberOfTargets
];
97 static bool sHadWheelStart
;
98 static bool sOwnWheelTransaction
;
101 * These two methods are called upon eWheelOperationStart/eWheelOperationEnd
102 * events to show/hide the right scrollbars.
104 static void TemporarilyActivateAllPossibleScrollTargets(
105 EventStateManager
* aESM
, nsIFrame
* aTargetFrame
,
106 WidgetWheelEvent
* aEvent
);
107 static void DeactivateAllTemporarilyActivatedScrollTargets();
111 * WheelTransaction manages a series of wheel events as a transaction.
112 * While in a transaction, every wheel event should scroll the same scrollable
113 * element even if a different scrollable element is under the mouse cursor.
115 * Additionally, this class also manages wheel scroll speed acceleration.
118 class WheelTransaction
{
120 static nsIFrame
* GetTargetFrame() { return sTargetFrame
; }
121 static void EndTransaction();
123 * WillHandleDefaultAction() is called before handling aWheelEvent on
126 * @return false if the caller cannot continue to handle the default
127 * action. Otherwise, true.
129 static bool WillHandleDefaultAction(WidgetWheelEvent
* aWheelEvent
,
130 AutoWeakFrame
& aTargetWeakFrame
);
131 static bool WillHandleDefaultAction(WidgetWheelEvent
* aWheelEvent
,
132 nsIFrame
* aTargetFrame
) {
133 AutoWeakFrame
targetWeakFrame(aTargetFrame
);
134 return WillHandleDefaultAction(aWheelEvent
, targetWeakFrame
);
136 static void OnEvent(WidgetEvent
* aEvent
);
137 static void Shutdown();
138 static uint32_t GetTimeoutTime() {
139 return Prefs::sMouseWheelTransactionTimeout
;
142 static void OwnScrollbars(bool aOwn
);
144 static DeltaValues
AccelerateWheelDelta(WidgetWheelEvent
* aEvent
,
145 bool aAllowScrollSpeedOverride
);
146 static void InitializeStatics() { Prefs::InitializeStatics(); }
149 static void BeginTransaction(nsIFrame
* aTargetFrame
,
150 const WidgetWheelEvent
* aEvent
);
151 // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
152 // frame might be destroyed in the event handler.
153 static bool UpdateTransaction(const WidgetWheelEvent
* aEvent
);
154 static void MayEndTransaction();
156 static LayoutDeviceIntPoint
GetScreenPoint(WidgetGUIEvent
* aEvent
);
157 static void OnFailToScrollTarget();
158 static void OnTimeout(nsITimer
* aTimer
, void* aClosure
);
159 static void SetTimeout();
160 static uint32_t GetIgnoreMoveDelayTime() {
161 return Prefs::sMouseWheelTransactionIgnoreMoveDelay
;
163 static int32_t GetAccelerationStart() {
164 return Prefs::sMouseWheelAccelerationStart
;
166 static int32_t GetAccelerationFactor() {
167 return Prefs::sMouseWheelAccelerationFactor
;
169 static DeltaValues
OverrideSystemScrollSpeed(WidgetWheelEvent
* aEvent
);
170 static double ComputeAcceleratedWheelDelta(double aDelta
, int32_t aFactor
);
171 static bool OutOfTime(uint32_t aBaseTime
, uint32_t aThreshold
);
173 static AutoWeakFrame sTargetFrame
;
174 static uint32_t sTime
; // in milliseconds
175 static uint32_t sMouseMoved
; // in milliseconds
176 static nsITimer
* sTimer
;
177 static int32_t sScrollSeriesCounter
;
178 static bool sOwnScrollbars
;
182 static void InitializeStatics();
183 static int32_t sMouseWheelAccelerationStart
;
184 static int32_t sMouseWheelAccelerationFactor
;
185 static uint32_t sMouseWheelTransactionTimeout
;
186 static uint32_t sMouseWheelTransactionIgnoreMoveDelay
;
187 static bool sTestMouseScroll
;
191 // For some kinds of scrollings, the delta values of WidgetWheelEvent are
192 // possbile to be adjusted. For example, the user has configured the pref to let
193 // [vertical wheel + Shift key] to perform horizontal scrolling instead of
194 // vertical scrolling.
195 // The values in this enumeration list all kinds of scrollings whose delta
196 // values are possible to be adjusted.
197 enum class WheelDeltaAdjustmentStrategy
: uint8_t {
198 // There is no strategy, don't adjust delta values in any cases.
200 // This strategy means we're receiving a horizontalized scroll, so we should
201 // apply horizontalization strategy for its delta values.
202 // Horizontalized scrolling means treating vertical wheel scrolling as
203 // horizontal scrolling by adjusting delta values.
204 // It's important to keep in mind with the percise concept of horizontalized
205 // scrolling: Delta values are *ONLY* going to be adjusted during the process
206 // of its default action handling; in views of any programmes other than the
207 // default action handler, such as a DOM event listener or a plugin, delta
208 // values are never going to be adjusted, they will still retrive original
209 // delta values when horizontalization occured for default actions.
211 // The following two strategies mean we're receving an auto-dir scroll, so we
212 // should apply auto-dir adjustment to the delta of the wheel event if needed.
213 // Auto-dir is a feature which treats any single-wheel scroll as a scroll in
214 // the only one scrollable direction if the target has only one scrollable
215 // direction. For example, if the user scrolls a vertical wheel inside a
216 // target which is horizontally scrollable but vertical unscrollable, then the
217 // vertical scroll is converted to a horizontal scroll for that target.
218 // So why do we need two different strategies for auto-dir scrolling? That's
219 // because when a wheel scroll is converted due to auto-dir, there is one
220 // thing called "honoured target" which decides which side the converted
221 // scroll goes towards. If the content of the honoured target horizontally
222 // is RTL content, then an upward scroll maps to a rightward scroll and a
223 // downward scroll maps to a leftward scroll; otherwise, an upward scroll maps
224 // to a leftward scroll and a downward scroll maps to a rightward scroll.
225 // |eAutoDir| considers the scrolling target as the honoured target.
226 // |eAutoDirWithRootHonour| takes the root element of the document with the
227 // scrolling element, and considers that as the honoured target. But note that
228 // there's one exception: for targets in an HTML document, the real root
229 // element(I.e. the <html> element) is typically not considered as a root
230 // element, but the <body> element is typically considered as a root element.
231 // If there is no <body> element, then consider the <html> element instead.
232 // And also note that like |eHorizontalize|, delta values are *ONLY* going to
233 // be adjusted during the process of its default action handling; in views of
234 // any programmes other than the default action handler, such as a DOM event
235 // listener or a plugin, delta values are never going to be adjusted.
237 eAutoDirWithRootHonour
,
238 // Not an actual strategy. This is just used as an upper bound for
239 // ContiguousEnumSerializer.
244 * When a *pure* vertical wheel event should be treated as if it was a
245 * horizontal scroll because the user wants to horizontalize the wheel scroll,
246 * an instance of this class will adjust the delta values upon calling
247 * Horizontalize(). And the horizontalized delta values will be restored
248 * automatically when the instance of this class is being destructed. Or you can
249 * restore them in advance by calling CancelHorizontalization().
251 class MOZ_STACK_CLASS WheelDeltaHorizontalizer final
{
254 * @param aWheelEvent A wheel event whose delta values will be adjusted
255 * upon calling Horizontalize().
257 explicit WheelDeltaHorizontalizer(WidgetWheelEvent
& aWheelEvent
)
258 : mWheelEvent(aWheelEvent
),
261 mOldOverflowDeltaX(0.0),
262 mOldLineOrPageDeltaX(0),
263 mHorizontalized(false) {}
265 * Converts vertical scrolling into horizontal scrolling by adjusting the
268 void Horizontalize();
269 ~WheelDeltaHorizontalizer();
270 void CancelHorizontalization();
273 WidgetWheelEvent
& mWheelEvent
;
276 double mOldOverflowDeltaX
;
277 int32_t mOldLineOrPageDeltaX
;
278 bool mHorizontalized
;
282 * This class is used to adjust the delta values for wheel scrolling with the
283 * auto-dir functionality.
284 * A traditional wheel scroll only allows the user use the wheel in the same
285 * scrollable direction as that of the scrolling target to scroll the target,
286 * whereas an auto-dir scroll lets the user use any wheel(either a vertical
287 * wheel or a horizontal tilt wheel) to scroll a frame which is scrollable in
288 * only one direction. For detailed information on auto-dir scrolling,
289 * @see mozilla::WheelDeltaAdjustmentStrategy.
291 class MOZ_STACK_CLASS AutoDirWheelDeltaAdjuster
{
294 * @param aDeltaX DeltaX for a wheel event whose delta values will
295 * be adjusted upon calling Adjust() when
296 * ShouldBeAdjusted() returns true.
297 * @param aDeltaY DeltaY for a wheel event, like DeltaX.
299 AutoDirWheelDeltaAdjuster(double& aDeltaX
, double& aDeltaY
)
302 mCheckedIfShouldBeAdjusted(false),
303 mShouldBeAdjusted(false) {}
307 * Gets whether the values of the delta should be adjusted for auto-dir
308 * scrolling. Note that if Adjust() has been called, this function simply
311 * @return true if the delta should be adjusted; otherwise false.
313 bool ShouldBeAdjusted();
315 * Adjusts the values of the delta values for auto-dir scrolling when
316 * ShouldBeAdjusted() returns true. If you call it when ShouldBeAdjusted()
317 * returns false, this function will simply do nothing.
323 * Called by Adjust() if Adjust() successfully adjusted the delta values.
325 virtual void OnAdjusted() {}
327 virtual bool CanScrollAlongXAxis() const = 0;
328 virtual bool CanScrollAlongYAxis() const = 0;
329 virtual bool CanScrollUpwards() const = 0;
330 virtual bool CanScrollDownwards() const = 0;
331 virtual bool CanScrollLeftwards() const = 0;
332 virtual bool CanScrollRightwards() const = 0;
335 * Gets whether the horizontal content starts at rightside.
337 * @return If the content is in vertical-RTL writing mode(E.g. "writing-mode:
338 * vertical-rl" in CSS), or if it's in horizontal-RTL writing-mode
339 * (E.g. "writing-mode: horizontal-tb; direction: rtl;" in CSS), then
340 * this function returns true. From the representation perspective,
341 * frames whose horizontal contents start at rightside also cause
342 * their horizontal scrollbars, if any, initially start at rightside.
343 * So we can also learn about the initial side of the horizontal
344 * scrollbar for the frame by calling this function.
346 virtual bool IsHorizontalContentRightToLeft() const = 0;
353 bool mCheckedIfShouldBeAdjusted
;
354 bool mShouldBeAdjusted
;
358 * This is the implementation of AutoDirWheelDeltaAdjuster for EventStateManager
360 * Detailed comments about some member functions are given in the base class
361 * AutoDirWheelDeltaAdjuster.
363 class MOZ_STACK_CLASS ESMAutoDirWheelDeltaAdjuster final
364 : public AutoDirWheelDeltaAdjuster
{
367 * @param aEvent The auto-dir wheel scroll event.
368 * @param aScrollFrame The scroll target for the event.
369 * @param aHonoursRoot If set to true, the honoured frame is the root
370 * frame in the same document where the target is;
371 * If false, the honoured frame is the scroll
372 * target. For the concept of an honoured target,
373 * @see mozilla::WheelDeltaAdjustmentStrategy
375 ESMAutoDirWheelDeltaAdjuster(WidgetWheelEvent
& aEvent
, nsIFrame
& aScrollFrame
,
379 virtual void OnAdjusted() override
;
380 virtual bool CanScrollAlongXAxis() const override
;
381 virtual bool CanScrollAlongYAxis() const override
;
382 virtual bool CanScrollUpwards() const override
;
383 virtual bool CanScrollDownwards() const override
;
384 virtual bool CanScrollLeftwards() const override
;
385 virtual bool CanScrollRightwards() const override
;
386 virtual bool IsHorizontalContentRightToLeft() const override
;
388 nsIScrollableFrame
* mScrollTargetFrame
;
389 bool mIsHorizontalContentRightToLeft
;
391 int32_t& mLineOrPageDeltaX
;
392 int32_t& mLineOrPageDeltaY
;
393 double& mOverflowDeltaX
;
394 double& mOverflowDeltaY
;
398 * This class is used for restoring the delta in an auto-dir wheel.
400 * An instance of this calss monitors auto-dir adjustment which may happen
401 * during its lifetime. If the delta values is adjusted during its lifetime, the
402 * instance will restore the adjusted delta when it's being destrcuted.
404 class MOZ_STACK_CLASS ESMAutoDirWheelDeltaRestorer final
{
407 * @param aEvent The wheel scroll event to be monitored.
409 explicit ESMAutoDirWheelDeltaRestorer(WidgetWheelEvent
& aEvent
);
410 ~ESMAutoDirWheelDeltaRestorer();
413 WidgetWheelEvent
& mEvent
;
416 int32_t mOldLineOrPageDeltaX
;
417 int32_t mOldLineOrPageDeltaY
;
418 double mOldOverflowDeltaX
;
419 double mOldOverflowDeltaY
;
422 } // namespace mozilla
424 #endif // mozilla_WheelHandlingHelper_h_