summaryrefslogtreecommitdiffstats
path: root/chromium/cc/input/scrollbar_controller.h
blob: e1b13dc2e03ffd7d6e4ec7ce61299fa260110fd0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_INPUT_SCROLLBAR_CONTROLLER_H_
#define CC_INPUT_SCROLLBAR_CONTROLLER_H_

#include "cc/cc_export.h"
#include "cc/input/input_handler.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"

namespace cc {
// This class is responsible for hit testing composited scrollbars, event
// handling and creating gesture scroll deltas.
class CC_EXPORT ScrollbarController {
 public:
  explicit ScrollbarController(LayerTreeHostImpl*);
  virtual ~ScrollbarController();

  InputHandlerPointerResult HandlePointerDown(
      const gfx::PointF position_in_widget,
      const bool shift_modifier);
  InputHandlerPointerResult HandlePointerMove(
      const gfx::PointF position_in_widget);
  InputHandlerPointerResult HandlePointerUp(
      const gfx::PointF position_in_widget);

  // "velocity" here is calculated based on the initial scroll delta (See
  // InitialDeltaToAutoscrollVelocity). This value carries a "sign" which is
  // needed to determine whether we should set up the autoscrolling in the
  // forwards or the backwards direction.
  void StartAutoScrollAnimation(float velocity,
                                ElementId element_id,
                                ScrollbarPart pressed_scrollbar_part);
  bool ScrollbarScrollIsActive() { return scrollbar_scroll_is_active_; }
  ScrollbarOrientation orientation() {
    return currently_captured_scrollbar_->orientation();
  }

  void WillBeginImplFrame();

 private:
  // "Autoscroll" here means the continuous scrolling that occurs when the
  // pointer is held down on a hit-testable area of the scrollbar such as an
  // arrows of the track itself.
  enum AutoScrollDirection { AUTOSCROLL_FORWARD, AUTOSCROLL_BACKWARD };

  struct CC_EXPORT AutoScrollState {
    // Can only be either AUTOSCROLL_FORWARD or AUTOSCROLL_BACKWARD.
    AutoScrollDirection direction = AutoScrollDirection::AUTOSCROLL_FORWARD;

    // Stores the autoscroll velocity. The sign is used to set the "direction".
    float velocity = 0.f;

    // Used to track the scroller length while autoscrolling. Helpful for
    // setting up infinite scrolling.
    float scroll_layer_length = 0.f;

    // Used to lookup the rect corresponding to the ScrollbarPart so that
    // autoscroll animations can be played/paused depending on the current
    // pointer location.
    ScrollbarPart pressed_scrollbar_part;
  };

  struct CC_EXPORT DragState {
    // This is used to track the pointer location relative to the thumb origin
    // when a drag has started.
    gfx::Vector2dF anchor_relative_to_thumb_;

    // This is needed for thumb snapping when the pointer moves too far away
    // from the track while scrolling.
    float scroll_position_at_start_;
  };

  // Returns the DSF based on whether use-zoom-for-dsf is enabled.
  float ScreenSpaceScaleFactor() const;

  // Helper to convert scroll offset to autoscroll velocity.
  float InitialDeltaToAutoscrollVelocity(gfx::ScrollOffset scroll_offset) const;

  // Returns the hit tested ScrollbarPart based on the position_in_widget.
  ScrollbarPart GetScrollbarPartFromPointerDown(
      const gfx::PointF position_in_widget);

  // Returns scroll offsets based on which ScrollbarPart was hit tested.
  gfx::ScrollOffset GetScrollOffsetForScrollbarPart(
      const ScrollbarPart scrollbar_part,
      const ScrollbarOrientation orientation,
      const bool shift_modifier);

  // Returns the rect for the ScrollbarPart.
  gfx::Rect GetRectForScrollbarPart(const ScrollbarPart scrollbar_part);

  LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget);
  int GetScrollDeltaForScrollbarPart(const ScrollbarPart scrollbar_part,
                                     const bool shift_modifier);

  // Makes position_in_widget relative to the scrollbar.
  gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget,
                                           bool* clipped);

  // Decides if the scroller should snap to the offset that it was originally at
  // (i.e the offset before the thumb drag).
  bool SnapToDragOrigin(const gfx::PointF pointer_position_in_widget);

  // Decides whether a track autoscroll should be aborted (or restarted) due to
  // the thumb reaching the pointer or the pointer leaving (or re-entering) the
  // bounds.
  void RecomputeAutoscrollStateIfNeeded();

  // Shift + click is expected to do a non-animated jump to a certain offset.
  float GetScrollDeltaForShiftClick();

  // Determines if the delta needs to be animated.
  ui::input_types::ScrollGranularity Granularity(
      const ScrollbarPart scrollbar_part,
      bool shift_modifier);

  // Calculates the scroll_offset based on position_in_widget and
  // drag_anchor_relative_to_thumb_.
  gfx::ScrollOffset GetScrollOffsetForDragPosition(
      const gfx::PointF pointer_position_in_widget);

  // Returns a Vector2dF for position_in_widget relative to the scrollbar thumb.
  gfx::Vector2dF GetThumbRelativePoint(const gfx::PointF position_in_widget);

  // Returns the ratio of the scroller length to the scrollbar length. This is
  // needed to scale the scroll delta for thumb drag.
  float GetScrollerToScrollbarRatio();
  LayerTreeHostImpl* layer_tree_host_impl_;

  // Used to safeguard against firing GSE without firing GSB and GSU. For
  // example, if mouse is pressed outside the scrollbar but released after
  // moving inside the scrollbar, a GSE will get queued up without this flag.
  bool scrollbar_scroll_is_active_;
  const ScrollbarLayerImplBase* currently_captured_scrollbar_;

  // This is relative to the RenderWidget's origin.
  gfx::PointF last_known_pointer_position_;

  // Holds information pertaining to autoscrolling. This member is empty if and
  // only if an autoscroll is *not* in progress.
  base::Optional<AutoScrollState> autoscroll_state_;

  // Holds information pertaining to thumb drags. Useful while making decisions
  // about thumb anchoring/snapping.
  base::Optional<DragState> drag_state_;

  // Used to track if a GSU was processed for the current frame or not. Without
  // this, thumb drag will appear jittery. The reason this happens is because
  // when the first GSU is processed, it gets queued in the compositor thread
  // event queue. So a second request within the same frame will end up
  // calculating an incorrect delta (as ComputeThumbQuadRect would not have
  // accounted for the delta in the first GSU that was not yet dispatched and
  // pointermoves are not VSync aligned).
  bool drag_processed_for_current_frame_;

  std::unique_ptr<base::CancelableClosure> cancelable_autoscroll_task_;
};

}  // namespace cc

#endif  // CC_INPUT_SCROLLBAR_CONTROLLER_H_