Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/events/WheelHandlingHelper.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#ifndef mozilla_WheelHandlingHelper_h_
8
#define mozilla_WheelHandlingHelper_h_
9
10
#include "mozilla/Attributes.h"
11
#include "mozilla/EventForwards.h"
12
#include "nsCoord.h"
13
#include "nsIFrame.h"
14
#include "nsPoint.h"
15
16
class nsIScrollableFrame;
17
class nsITimer;
18
19
namespace mozilla {
20
21
class EventStateManager;
22
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.
26
 */
27
28
struct DeltaValues
29
{
30
  DeltaValues()
31
    : deltaX(0.0)
32
    , deltaY(0.0)
33
  {
34
  }
35
36
  DeltaValues(double aDeltaX, double aDeltaY)
37
    : deltaX(aDeltaX)
38
    , deltaY(aDeltaY)
39
12
  {
40
12
  }
41
42
  explicit DeltaValues(WidgetWheelEvent* aEvent);
43
44
  double deltaX;
45
  double deltaY;
46
};
47
48
/**
49
 * WheelHandlingUtils provides some static methods which are useful at handling
50
 * wheel events.
51
 */
52
53
class WheelHandlingUtils
54
{
55
public:
56
  /**
57
   * Returns true if aFrame is a scrollable frame and it can be scrolled to
58
   * either aDirectionX or aDirectionY along each axis.  Or if aFrame is a
59
   * plugin frame (in this case, aDirectionX and aDirectionY are ignored).
60
   * Otherwise, false.
61
   */
62
  static bool CanScrollOn(nsIFrame* aFrame,
63
                          double aDirectionX, double aDirectionY);
64
  /**
65
   * Returns true if the scrollable frame can be scrolled to either aDirectionX
66
   * or aDirectionY along each axis.  Otherwise, false.
67
   */
68
  static bool CanScrollOn(nsIScrollableFrame* aScrollFrame,
69
                          double aDirectionX, double aDirectionY);
70
71
  // For more details about the concept of a disregarded direction, refer to the
72
  // code in struct mozilla::layers::ScrollMetadata which defines
73
  // mDisregardedDirection.
74
  static Maybe<layers::ScrollDirection>
75
  GetDisregardedWheelScrollDirection(const nsIFrame* aFrame);
76
77
private:
78
  static bool CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax,
79
                               double aDirection);
80
};
81
82
/**
83
 * ScrollbarsForWheel manages scrollbars state during wheel operation.
84
 * E.g., on some platforms, scrollbars should show only while user attempts to
85
 * scroll.  At that time, scrollbars which may be possible to scroll by
86
 * operation of wheel at the point should show temporarily.
87
 */
88
89
class ScrollbarsForWheel
90
{
91
public:
92
  static void PrepareToScrollText(EventStateManager* aESM,
93
                                  nsIFrame* aTargetFrame,
94
                                  WidgetWheelEvent* aEvent);
95
  static void SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget);
96
  // Hide all scrollbars (both mActiveOwner's and mActivatedScrollTargets')
97
  static void MayInactivate();
98
  static void Inactivate();
99
  static bool IsActive();
100
  static void OwnWheelTransaction(bool aOwn);
101
102
protected:
103
  static const size_t kNumberOfTargets = 4;
104
  static const DeltaValues directions[kNumberOfTargets];
105
  static AutoWeakFrame sActiveOwner;
106
  static AutoWeakFrame sActivatedScrollTargets[kNumberOfTargets];
107
  static bool sHadWheelStart;
108
  static bool sOwnWheelTransaction;
109
110
111
  /**
112
   * These two methods are called upon eWheelOperationStart/eWheelOperationEnd
113
   * events to show/hide the right scrollbars.
114
   */
115
  static void TemporarilyActivateAllPossibleScrollTargets(
116
                EventStateManager* aESM,
117
                nsIFrame* aTargetFrame,
118
                WidgetWheelEvent* aEvent);
119
  static void DeactivateAllTemporarilyActivatedScrollTargets();
120
};
121
122
/**
123
 * WheelTransaction manages a series of wheel events as a transaction.
124
 * While in a transaction, every wheel event should scroll the same scrollable
125
 * element even if a different scrollable element is under the mouse cursor.
126
 *
127
 * Additionally, this class also manages wheel scroll speed acceleration.
128
 */
129
130
class WheelTransaction
131
{
132
public:
133
0
  static nsIFrame* GetTargetFrame() { return sTargetFrame; }
134
  static void EndTransaction();
135
  /**
136
   * WillHandleDefaultAction() is called before handling aWheelEvent on
137
   * aTargetFrame.
138
   *
139
   * @return    false if the caller cannot continue to handle the default
140
   *            action.  Otherwise, true.
141
   */
142
  static bool WillHandleDefaultAction(WidgetWheelEvent* aWheelEvent,
143
                                      AutoWeakFrame& aTargetWeakFrame);
144
  static bool WillHandleDefaultAction(WidgetWheelEvent* aWheelEvent,
145
                                      nsIFrame* aTargetFrame)
146
0
  {
147
0
    AutoWeakFrame targetWeakFrame(aTargetFrame);
148
0
    return WillHandleDefaultAction(aWheelEvent, targetWeakFrame);
149
0
  }
150
  static void OnEvent(WidgetEvent* aEvent);
151
  static void Shutdown();
152
  static uint32_t GetTimeoutTime()
153
0
  {
154
0
    return Prefs::sMouseWheelTransactionTimeout;
155
0
  }
156
157
  static void OwnScrollbars(bool aOwn);
158
159
  static DeltaValues AccelerateWheelDelta(WidgetWheelEvent* aEvent,
160
                                          bool aAllowScrollSpeedOverride);
161
  static void InitializeStatics()
162
0
  {
163
0
    Prefs::InitializeStatics();
164
0
  }
165
166
protected:
167
  static void BeginTransaction(nsIFrame* aTargetFrame,
168
                               const WidgetWheelEvent* aEvent);
169
  // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
170
  // frame might be destroyed in the event handler.
171
  static bool UpdateTransaction(const WidgetWheelEvent* aEvent);
172
  static void MayEndTransaction();
173
174
  static LayoutDeviceIntPoint GetScreenPoint(WidgetGUIEvent* aEvent);
175
  static void OnFailToScrollTarget();
176
  static void OnTimeout(nsITimer* aTimer, void* aClosure);
177
  static void SetTimeout();
178
  static uint32_t GetIgnoreMoveDelayTime()
179
0
  {
180
0
    return Prefs::sMouseWheelTransactionIgnoreMoveDelay;
181
0
  }
182
  static int32_t GetAccelerationStart()
183
0
  {
184
0
    return Prefs::sMouseWheelAccelerationStart;
185
0
  }
186
  static int32_t GetAccelerationFactor()
187
0
  {
188
0
    return Prefs::sMouseWheelAccelerationFactor;
189
0
  }
190
  static DeltaValues OverrideSystemScrollSpeed(WidgetWheelEvent* aEvent);
191
  static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor);
192
  static bool OutOfTime(uint32_t aBaseTime, uint32_t aThreshold);
193
194
  static AutoWeakFrame sTargetFrame;
195
  static uint32_t sTime; // in milliseconds
196
  static uint32_t sMouseMoved; // in milliseconds
197
  static nsITimer* sTimer;
198
  static int32_t sScrollSeriesCounter;
199
  static bool sOwnScrollbars;
200
201
  class Prefs
202
  {
203
  public:
204
    static void InitializeStatics();
205
    static int32_t sMouseWheelAccelerationStart;
206
    static int32_t sMouseWheelAccelerationFactor;
207
    static uint32_t sMouseWheelTransactionTimeout;
208
    static uint32_t sMouseWheelTransactionIgnoreMoveDelay;
209
    static bool sTestMouseScroll;
210
  };
211
};
212
213
// For some kinds of scrollings, the delta values of WidgetWheelEvent are
214
// possbile to be adjusted. For example, the user has configured the pref to let
215
// [vertical wheel + Shift key] to perform horizontal scrolling instead of
216
// vertical scrolling.
217
// The values in this enumeration list all kinds of scrollings whose delta
218
// values are possible to be adjusted.
219
enum class WheelDeltaAdjustmentStrategy : uint8_t
220
{
221
  // There is no strategy, don't adjust delta values in any cases.
222
  eNone,
223
  // This strategy means we're receiving a horizontalized scroll, so we should
224
  // apply horizontalization strategy for its delta values.
225
  // Horizontalized scrolling means treating vertical wheel scrolling as
226
  // horizontal scrolling by adjusting delta values.
227
  // It's important to keep in mind with the percise concept of horizontalized
228
  // scrolling: Delta values are *ONLY* going to be adjusted during the process
229
  // of its default action handling; in views of any programmes other than the
230
  // default action handler, such as a DOM event listener or a plugin, delta
231
  // values are never going to be adjusted, they will still retrive original
232
  // delta values when horizontalization occured for default actions.
233
  eHorizontalize,
234
  // The following two strategies mean we're receving an auto-dir scroll, so we
235
  // should apply auto-dir adjustment to the delta of the wheel event if needed.
236
  // Auto-dir is a feature which treats any single-wheel scroll as a scroll in
237
  // the only one scrollable direction if the target has only one scrollable
238
  // direction. For example, if the user scrolls a vertical wheel inside a
239
  // target which is horizontally scrollable but vertical unscrollable, then the
240
  // vertical scroll is converted to a horizontal scroll for that target.
241
  // So why do we need two different strategies for auto-dir scrolling? That's
242
  // because when a wheel scroll is converted due to auto-dir, there is one
243
  // thing called "honoured target" which decides which side the converted
244
  // scroll goes towards. If the content of the honoured target horizontally
245
  // is RTL content, then an upward scroll maps to a rightward scroll and a
246
  // downward scroll maps to a leftward scroll; otherwise, an upward scroll maps
247
  // to a leftward scroll and a downward scroll maps to a rightward scroll.
248
  // |eAutoDir| considers the scrolling target as the honoured target.
249
  // |eAutoDirWithRootHonour| takes the root element of the document with the
250
  // scrolling element, and considers that as the honoured target. But note that
251
  // there's one exception: for targets in an HTML document, the real root
252
  // element(I.e. the <html> element) is typically not considered as a root
253
  // element, but the <body> element is typically considered as a root element.
254
  // If there is no <body> element, then consider the <html> element instead.
255
  // And also note that like |eHorizontalize|, delta values are *ONLY* going to
256
  // be adjusted during the process of its default action handling; in views of
257
  // any programmes other than the default action handler, such as a DOM event
258
  // listener or a plugin, delta values are never going to be adjusted.
259
  eAutoDir,
260
  eAutoDirWithRootHonour,
261
  // Not an actual strategy. This is just used as an upper bound for
262
  // ContiguousEnumSerializer.
263
  eSentinel,
264
};
265
266
/**
267
 * When a *pure* vertical wheel event should be treated as if it was a
268
 * horizontal scroll because the user wants to horizontalize the wheel scroll,
269
 * an instance of this class will adjust the delta values upon calling
270
 * Horizontalize(). And the horizontalized delta values will be restored
271
 * automatically when the instance of this class is being destructed. Or you can
272
 * restore them in advance by calling CancelHorizontalization().
273
 */
274
class MOZ_STACK_CLASS WheelDeltaHorizontalizer final
275
{
276
public:
277
  /**
278
   * @param aWheelEvent        A wheel event whose delta values will be adjusted
279
   *                           upon calling Horizontalize().
280
   */
281
  explicit WheelDeltaHorizontalizer(WidgetWheelEvent& aWheelEvent)
282
    : mWheelEvent(aWheelEvent)
283
    , mOldDeltaX(0.0)
284
    , mOldDeltaZ(0.0)
285
    , mOldOverflowDeltaX(0.0)
286
    , mOldLineOrPageDeltaX(0)
287
    , mHorizontalized(false)
288
  {
289
  }
290
  /**
291
   * Converts vertical scrolling into horizontal scrolling by adjusting the
292
   * its delta values.
293
   */
294
  void Horizontalize();
295
  ~WheelDeltaHorizontalizer();
296
  void CancelHorizontalization();
297
298
private:
299
  WidgetWheelEvent& mWheelEvent;
300
  double mOldDeltaX;
301
  double mOldDeltaZ;
302
  double mOldOverflowDeltaX;
303
  int32_t mOldLineOrPageDeltaX;
304
  bool mHorizontalized;
305
};
306
307
/**
308
 * This class is used to adjust the delta values for wheel scrolling with the
309
 * auto-dir functionality.
310
 * A traditional wheel scroll only allows the user use the wheel in the same
311
 * scrollable direction as that of the scrolling target to scroll the target,
312
 * whereas an auto-dir scroll lets the user use any wheel(either a vertical
313
 * wheel or a horizontal tilt wheel) to scroll a frame which is scrollable in
314
 * only one direction. For detailed information on auto-dir scrolling,
315
 * @see mozilla::WheelDeltaAdjustmentStrategy.
316
 */
317
class MOZ_STACK_CLASS AutoDirWheelDeltaAdjuster
318
{
319
protected:
320
  /**
321
   * @param aDeltaX            DeltaX for a wheel event whose delta values will
322
   *                           be adjusted upon calling Adjust() when
323
   *                           ShouldBeAdjusted() returns true.
324
   * @param aDeltaY            DeltaY for a wheel event, like DeltaX.
325
   */
326
  AutoDirWheelDeltaAdjuster(double& aDeltaX,
327
                            double& aDeltaY)
328
    : mDeltaX(aDeltaX)
329
    , mDeltaY(aDeltaY)
330
    , mCheckedIfShouldBeAdjusted(false)
331
    , mShouldBeAdjusted(false)
332
  {
333
  }
334
335
public:
336
  /**
337
   * Gets whether the values of the delta should be adjusted for auto-dir
338
   * scrolling. Note that if Adjust() has been called, this function simply
339
   * returns false.
340
   *
341
   * @return true if the delta should be adjusted; otherwise false.
342
   */
343
  bool ShouldBeAdjusted();
344
  /**
345
   * Adjusts the values of the delta values for auto-dir scrolling when
346
   * ShouldBeAdjusted() returns true. If you call it when ShouldBeAdjusted()
347
   * returns false, this function will simply do nothing.
348
   */
349
  void Adjust();
350
351
private:
352
  /**
353
   * Called by Adjust() if Adjust() successfully adjusted the delta values.
354
   */
355
  virtual void OnAdjusted()
356
  {
357
  }
358
359
  virtual bool CanScrollAlongXAxis() const = 0;
360
  virtual bool CanScrollAlongYAxis() const = 0;
361
  virtual bool CanScrollUpwards() const = 0;
362
  virtual bool CanScrollDownwards() const = 0;
363
  virtual bool CanScrollLeftwards() const = 0;
364
  virtual bool CanScrollRightwards() const = 0;
365
366
  /**
367
   * Gets whether the horizontal content starts at rightside.
368
   *
369
   * @return If the content is in vertical-RTL writing mode(E.g. "writing-mode:
370
   *         vertical-rl" in CSS), or if it's in horizontal-RTL writing-mode
371
   *         (E.g. "writing-mode: horizontal-tb; direction: rtl;" in CSS), then
372
   *         this function returns true. From the representation perspective,
373
   *         frames whose horizontal contents start at rightside also cause
374
   *         their horizontal scrollbars, if any, initially start at rightside.
375
   *         So we can also learn about the initial side of the horizontal
376
   *         scrollbar for the frame by calling this function.
377
   */
378
  virtual bool IsHorizontalContentRightToLeft() const = 0;
379
380
protected:
381
  double& mDeltaX;
382
  double& mDeltaY;
383
384
private:
385
  bool mCheckedIfShouldBeAdjusted;
386
  bool mShouldBeAdjusted;
387
};
388
389
/**
390
 * This is the implementation of AutoDirWheelDeltaAdjuster for EventStateManager
391
 *
392
 * Detailed comments about some member functions are given in the base class
393
 * AutoDirWheelDeltaAdjuster.
394
 */
395
class MOZ_STACK_CLASS ESMAutoDirWheelDeltaAdjuster final
396
                        : public AutoDirWheelDeltaAdjuster
397
{
398
public:
399
  /**
400
   * @param aEvent             The auto-dir wheel scroll event.
401
   * @param aScrollFrame       The scroll target for the event.
402
   * @param aHonoursRoot       If set to true, the honoured frame is the root
403
   *                           frame in the same document where the target is;
404
   *                           If false, the honoured frame is the scroll
405
   *                           target. For the concept of an honoured target,
406
   *                           @see mozilla::WheelDeltaAdjustmentStrategy
407
   */
408
  ESMAutoDirWheelDeltaAdjuster(WidgetWheelEvent& aEvent,
409
                               nsIFrame& aScrollFrame,
410
                               bool aHonoursRoot);
411
412
private:
413
  virtual void OnAdjusted() override;
414
  virtual bool CanScrollAlongXAxis() const override;
415
  virtual bool CanScrollAlongYAxis() const override;
416
  virtual bool CanScrollUpwards() const override;
417
  virtual bool CanScrollDownwards() const override;
418
  virtual bool CanScrollLeftwards() const override;
419
  virtual bool CanScrollRightwards() const override;
420
  virtual bool IsHorizontalContentRightToLeft() const override;
421
422
  nsIScrollableFrame* mScrollTargetFrame;
423
  bool mIsHorizontalContentRightToLeft;
424
425
  int32_t& mLineOrPageDeltaX;
426
  int32_t& mLineOrPageDeltaY;
427
  double& mOverflowDeltaX;
428
  double& mOverflowDeltaY;
429
};
430
431
/**
432
 * This class is used for restoring the delta in an auto-dir wheel.
433
 *
434
 * An instance of this calss monitors auto-dir adjustment which may happen
435
 * during its lifetime. If the delta values is adjusted during its lifetime, the
436
 * instance will restore the adjusted delta when it's being destrcuted.
437
 */
438
class MOZ_STACK_CLASS ESMAutoDirWheelDeltaRestorer final
439
{
440
public:
441
  /**
442
   * @param aEvent             The wheel scroll event to be monitored.
443
   */
444
  explicit ESMAutoDirWheelDeltaRestorer(WidgetWheelEvent& aEvent);
445
  ~ESMAutoDirWheelDeltaRestorer();
446
447
private:
448
  WidgetWheelEvent& mEvent;
449
  double mOldDeltaX;
450
  double mOldDeltaY;
451
  int32_t mOldLineOrPageDeltaX;
452
  int32_t mOldLineOrPageDeltaY;
453
  double mOldOverflowDeltaX;
454
  double mOldOverflowDeltaY;
455
};
456
457
} // namespace mozilla
458
459
#endif // mozilla_WheelHandlingHelper_h_