Bug 1572460 - Refactor `selection` out of the `InspectorFront`. r=yulia
[gecko.git] / dom / events / WheelHandlingHelper.h
blob1a4e07d1cc3902ebfb6ddd0e10fefea29794f3ec
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"
12 #include "nsCoord.h"
13 #include "nsIFrame.h"
14 #include "nsPoint.h"
16 class nsIScrollableFrame;
17 class nsITimer;
19 namespace mozilla {
21 class EventStateManager;
23 /**
24 * DeltaValues stores two delta values which are along X and Y axis. This is
25 * useful for arguments and results of some methods.
28 struct DeltaValues {
29 DeltaValues() : deltaX(0.0), deltaY(0.0) {}
31 DeltaValues(double aDeltaX, double aDeltaY)
32 : deltaX(aDeltaX), deltaY(aDeltaY) {}
34 explicit DeltaValues(WidgetWheelEvent* aEvent);
36 double deltaX;
37 double deltaY;
40 /**
41 * WheelHandlingUtils provides some static methods which are useful at handling
42 * wheel events.
45 class WheelHandlingUtils {
46 public:
47 /**
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).
51 * Otherwise, false.
53 static bool CanScrollOn(nsIFrame* aFrame, double aDirectionX,
54 double aDirectionY);
55 /**
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,
60 double aDirectionY);
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);
68 private:
69 static bool CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax,
70 double aDirection);
73 /**
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 {
81 public:
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);
92 protected:
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 {
119 public:
120 static nsIFrame* GetTargetFrame() { return sTargetFrame; }
121 static void EndTransaction();
123 * WillHandleDefaultAction() is called before handling aWheelEvent on
124 * aTargetFrame.
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(); }
148 protected:
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;
180 class Prefs {
181 public:
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.
199 eNone,
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.
210 eHorizontalize,
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.
236 eAutoDir,
237 eAutoDirWithRootHonour,
238 // Not an actual strategy. This is just used as an upper bound for
239 // ContiguousEnumSerializer.
240 eSentinel,
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 {
252 public:
254 * @param aWheelEvent A wheel event whose delta values will be adjusted
255 * upon calling Horizontalize().
257 explicit WheelDeltaHorizontalizer(WidgetWheelEvent& aWheelEvent)
258 : mWheelEvent(aWheelEvent),
259 mOldDeltaX(0.0),
260 mOldDeltaZ(0.0),
261 mOldOverflowDeltaX(0.0),
262 mOldLineOrPageDeltaX(0),
263 mHorizontalized(false) {}
265 * Converts vertical scrolling into horizontal scrolling by adjusting the
266 * its delta values.
268 void Horizontalize();
269 ~WheelDeltaHorizontalizer();
270 void CancelHorizontalization();
272 private:
273 WidgetWheelEvent& mWheelEvent;
274 double mOldDeltaX;
275 double mOldDeltaZ;
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 {
292 protected:
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)
300 : mDeltaX(aDeltaX),
301 mDeltaY(aDeltaY),
302 mCheckedIfShouldBeAdjusted(false),
303 mShouldBeAdjusted(false) {}
305 public:
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
309 * returns false.
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.
319 void Adjust();
321 private:
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;
348 protected:
349 double& mDeltaX;
350 double& mDeltaY;
352 private:
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 {
365 public:
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,
376 bool aHonoursRoot);
378 private:
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 {
405 public:
407 * @param aEvent The wheel scroll event to be monitored.
409 explicit ESMAutoDirWheelDeltaRestorer(WidgetWheelEvent& aEvent);
410 ~ESMAutoDirWheelDeltaRestorer();
412 private:
413 WidgetWheelEvent& mEvent;
414 double mOldDeltaX;
415 double mOldDeltaY;
416 int32_t mOldLineOrPageDeltaX;
417 int32_t mOldLineOrPageDeltaY;
418 double mOldOverflowDeltaX;
419 double mOldOverflowDeltaY;
422 } // namespace mozilla
424 #endif // mozilla_WheelHandlingHelper_h_