[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "content/browser/renderer_host/overscroll_controller.h" |
| 6 | |
[email protected] | 3aad43b | 2013-11-05 20:20:18 | [diff] [blame] | 7 | #include "base/command_line.h" |
[email protected] | fc4b06d0 | 2013-10-23 20:47:11 | [diff] [blame] | 8 | #include "base/logging.h" |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 9 | #include "content/browser/renderer_host/overscroll_controller_delegate.h" |
[email protected] | 1cd76c2d8 | 2012-11-29 07:36:47 | [diff] [blame] | 10 | #include "content/public/browser/overscroll_configuration.h" |
[email protected] | 3aad43b | 2013-11-05 20:20:18 | [diff] [blame] | 11 | #include "content/public/common/content_switches.h" |
dtapuska | 234bb451 | 2016-12-19 21:46:18 | [diff] [blame] | 12 | #include "third_party/WebKit/public/platform/WebMouseWheelEvent.h" |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 13 | |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 14 | using blink::WebInputEvent; |
[email protected] | a7f99f0 | 2013-08-29 14:15:19 | [diff] [blame] | 15 | |
[email protected] | 3aad43b | 2013-11-05 20:20:18 | [diff] [blame] | 16 | namespace { |
| 17 | |
| 18 | bool IsScrollEndEffectEnabled() { |
[email protected] | 47927870 | 2014-08-11 20:32:09 | [diff] [blame] | 19 | return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
[email protected] | 3aad43b | 2013-11-05 20:20:18 | [diff] [blame] | 20 | switches::kScrollEndEffect) == "1"; |
| 21 | } |
| 22 | |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 23 | bool IsGestureEventFromTouchpad(const blink::WebInputEvent& event) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 24 | DCHECK(blink::WebInputEvent::IsGestureEventType(event.GetType())); |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 25 | const blink::WebGestureEvent& gesture = |
| 26 | static_cast<const blink::WebGestureEvent&>(event); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 27 | return gesture.source_device == blink::kWebGestureDeviceTouchpad; |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 28 | } |
| 29 | |
[email protected] | 3aad43b | 2013-11-05 20:20:18 | [diff] [blame] | 30 | } // namespace |
| 31 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 32 | namespace content { |
| 33 | |
[email protected] | fc4b06d0 | 2013-10-23 20:47:11 | [diff] [blame] | 34 | OverscrollController::OverscrollController() |
| 35 | : overscroll_mode_(OVERSCROLL_NONE), |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 36 | scroll_state_(STATE_UNKNOWN), |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 37 | overscroll_delta_x_(0.f), |
| 38 | overscroll_delta_y_(0.f), |
dtapuska | e7dd21de | 2016-06-09 13:41:56 | [diff] [blame] | 39 | delegate_(NULL) {} |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 40 | |
| 41 | OverscrollController::~OverscrollController() { |
| 42 | } |
| 43 | |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 44 | bool OverscrollController::ShouldProcessEvent( |
| 45 | const blink::WebInputEvent& event) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 46 | switch (event.GetType()) { |
| 47 | case blink::WebInputEvent::kMouseWheel: |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 48 | return false; |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 49 | case blink::WebInputEvent::kGestureScrollBegin: |
| 50 | case blink::WebInputEvent::kGestureScrollUpdate: |
| 51 | case blink::WebInputEvent::kGestureScrollEnd: { |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 52 | const blink::WebGestureEvent& gesture = |
| 53 | static_cast<const blink::WebGestureEvent&>(event); |
mcnee | 19fd249 | 2017-06-01 14:42:43 | [diff] [blame^] | 54 | |
| 55 | // GestureScrollBegin and GestureScrollEnd events are created to wrap |
| 56 | // individual resent GestureScrollUpdates from a plugin. Hence these |
| 57 | // should not be used to indicate the beginning/end of the overscroll. |
| 58 | // TODO(mcnee): When we remove BrowserPlugin, delete this code. |
| 59 | // See crbug.com/533069 |
| 60 | if (gesture.resending_plugin_id != -1 && |
| 61 | event.GetType() != blink::WebInputEvent::kGestureScrollUpdate) |
| 62 | return false; |
| 63 | |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 64 | blink::WebGestureEvent::ScrollUnits scrollUnits; |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 65 | switch (event.GetType()) { |
| 66 | case blink::WebInputEvent::kGestureScrollBegin: |
| 67 | scrollUnits = gesture.data.scroll_begin.delta_hint_units; |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 68 | break; |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 69 | case blink::WebInputEvent::kGestureScrollUpdate: |
| 70 | scrollUnits = gesture.data.scroll_update.delta_units; |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 71 | break; |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 72 | case blink::WebInputEvent::kGestureScrollEnd: |
| 73 | scrollUnits = gesture.data.scroll_end.delta_units; |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 74 | break; |
| 75 | default: |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 76 | scrollUnits = blink::WebGestureEvent::kPixels; |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 77 | break; |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 78 | } |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 79 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 80 | return scrollUnits == blink::WebGestureEvent::kPrecisePixels; |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 81 | } |
dtapuska | 8c4dae1 | 2017-01-13 00:23:06 | [diff] [blame] | 82 | default: |
| 83 | break; |
| 84 | } |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 85 | return true; |
| 86 | } |
| 87 | |
[email protected] | 277857a | 2014-06-03 10:38:01 | [diff] [blame] | 88 | bool OverscrollController::WillHandleEvent(const blink::WebInputEvent& event) { |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 89 | if (!ShouldProcessEvent(event)) |
| 90 | return false; |
| 91 | |
mfomitchev | 8a785bef | 2015-04-13 18:35:05 | [diff] [blame] | 92 | bool reset_scroll_state = false; |
| 93 | if (scroll_state_ != STATE_UNKNOWN || |
| 94 | overscroll_delta_x_ || overscroll_delta_y_) { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 95 | switch (event.GetType()) { |
| 96 | case blink::WebInputEvent::kGestureScrollEnd: |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 97 | // Avoid resetting the state on GestureScrollEnd generated |
| 98 | // from the touchpad since it is sent based on a timeout. |
| 99 | reset_scroll_state = !IsGestureEventFromTouchpad(event); |
| 100 | break; |
| 101 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 102 | case blink::WebInputEvent::kGestureFlingStart: |
mfomitchev | 8a785bef | 2015-04-13 18:35:05 | [diff] [blame] | 103 | reset_scroll_state = true; |
[email protected] | b31beeb | 2013-06-17 15:54:27 | [diff] [blame] | 104 | break; |
| 105 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 106 | case blink::WebInputEvent::kMouseWheel: { |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 107 | const blink::WebMouseWheelEvent& wheel = |
| 108 | static_cast<const blink::WebMouseWheelEvent&>(event); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 109 | if (!wheel.has_precise_scrolling_deltas || |
| 110 | wheel.phase == blink::WebMouseWheelEvent::kPhaseEnded || |
| 111 | wheel.phase == blink::WebMouseWheelEvent::kPhaseCancelled) { |
mfomitchev | 8a785bef | 2015-04-13 18:35:05 | [diff] [blame] | 112 | reset_scroll_state = true; |
[email protected] | b31beeb | 2013-06-17 15:54:27 | [diff] [blame] | 113 | } |
| 114 | break; |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 115 | } |
[email protected] | b31beeb | 2013-06-17 15:54:27 | [diff] [blame] | 116 | |
| 117 | default: |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 118 | if (blink::WebInputEvent::IsMouseEventType(event.GetType()) || |
| 119 | blink::WebInputEvent::IsKeyboardEventType(event.GetType())) { |
mfomitchev | 8a785bef | 2015-04-13 18:35:05 | [diff] [blame] | 120 | reset_scroll_state = true; |
[email protected] | b31beeb | 2013-06-17 15:54:27 | [diff] [blame] | 121 | } |
| 122 | break; |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 123 | } |
| 124 | } |
| 125 | |
mfomitchev | 8a785bef | 2015-04-13 18:35:05 | [diff] [blame] | 126 | if (reset_scroll_state) |
| 127 | scroll_state_ = STATE_UNKNOWN; |
| 128 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 129 | if (DispatchEventCompletesAction(event)) { |
| 130 | CompleteAction(); |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 131 | |
[email protected] | 277857a | 2014-06-03 10:38:01 | [diff] [blame] | 132 | // Let the event be dispatched to the renderer. |
| 133 | return false; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | if (overscroll_mode_ != OVERSCROLL_NONE && DispatchEventResetsState(event)) { |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 137 | SetOverscrollMode(OVERSCROLL_NONE, OverscrollSource::NONE); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 138 | |
| 139 | // Let the event be dispatched to the renderer. |
[email protected] | 277857a | 2014-06-03 10:38:01 | [diff] [blame] | 140 | return false; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | if (overscroll_mode_ != OVERSCROLL_NONE) { |
[email protected] | 2422e5c | 2013-09-13 19:05:02 | [diff] [blame] | 144 | // Consume the event only if it updates the overscroll state. |
| 145 | if (ProcessEventForOverscroll(event)) |
[email protected] | 277857a | 2014-06-03 10:38:01 | [diff] [blame] | 146 | return true; |
mfomitchev | 8a785bef | 2015-04-13 18:35:05 | [diff] [blame] | 147 | } else if (reset_scroll_state) { |
| 148 | overscroll_delta_x_ = overscroll_delta_y_ = 0.f; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 149 | } |
| 150 | |
mfomitchev | 8a785bef | 2015-04-13 18:35:05 | [diff] [blame] | 151 | |
[email protected] | 277857a | 2014-06-03 10:38:01 | [diff] [blame] | 152 | return false; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 153 | } |
| 154 | |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 155 | void OverscrollController::ReceivedEventACK(const blink::WebInputEvent& event, |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 156 | bool processed) { |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 157 | if (!ShouldProcessEvent(event)) |
| 158 | return; |
| 159 | |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 160 | if (processed) { |
| 161 | // If a scroll event is consumed by the page, i.e. some content on the page |
| 162 | // has been scrolled, then there is not going to be an overscroll gesture, |
| 163 | // until the current scroll ends, and a new scroll gesture starts. |
| 164 | if (scroll_state_ == STATE_UNKNOWN && |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 165 | (event.GetType() == blink::WebInputEvent::kMouseWheel || |
| 166 | event.GetType() == blink::WebInputEvent::kGestureScrollUpdate)) { |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 167 | scroll_state_ = STATE_CONTENT_SCROLLING; |
| 168 | } |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 169 | return; |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 170 | } |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 171 | ProcessEventForOverscroll(event); |
| 172 | } |
| 173 | |
[email protected] | b31beeb | 2013-06-17 15:54:27 | [diff] [blame] | 174 | void OverscrollController::DiscardingGestureEvent( |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 175 | const blink::WebGestureEvent& gesture) { |
[email protected] | b31beeb | 2013-06-17 15:54:27 | [diff] [blame] | 176 | if (scroll_state_ != STATE_UNKNOWN && |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 177 | (gesture.GetType() == blink::WebInputEvent::kGestureScrollEnd || |
| 178 | gesture.GetType() == blink::WebInputEvent::kGestureFlingStart)) { |
[email protected] | b31beeb | 2013-06-17 15:54:27 | [diff] [blame] | 179 | scroll_state_ = STATE_UNKNOWN; |
| 180 | } |
| 181 | } |
| 182 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 183 | void OverscrollController::Reset() { |
| 184 | overscroll_mode_ = OVERSCROLL_NONE; |
| 185 | overscroll_delta_x_ = overscroll_delta_y_ = 0.f; |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 186 | scroll_state_ = STATE_UNKNOWN; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 187 | } |
| 188 | |
[email protected] | 63ad7383 | 2013-06-17 15:41:04 | [diff] [blame] | 189 | void OverscrollController::Cancel() { |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 190 | SetOverscrollMode(OVERSCROLL_NONE, OverscrollSource::NONE); |
[email protected] | 63ad7383 | 2013-06-17 15:41:04 | [diff] [blame] | 191 | overscroll_delta_x_ = overscroll_delta_y_ = 0.f; |
| 192 | scroll_state_ = STATE_UNKNOWN; |
| 193 | } |
| 194 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 195 | bool OverscrollController::DispatchEventCompletesAction ( |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 196 | const blink::WebInputEvent& event) const { |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 197 | if (overscroll_mode_ == OVERSCROLL_NONE) |
| 198 | return false; |
| 199 | |
| 200 | // Complete the overscroll gesture if there was a mouse move or a scroll-end |
| 201 | // after the threshold. |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 202 | if (event.GetType() != blink::WebInputEvent::kMouseMove && |
| 203 | event.GetType() != blink::WebInputEvent::kGestureScrollEnd && |
| 204 | event.GetType() != blink::WebInputEvent::kGestureFlingStart) |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 205 | return false; |
| 206 | |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 207 | // Avoid completing the action on GestureScrollEnd generated |
| 208 | // from the touchpad since it is sent based on a timeout not |
| 209 | // when the user has stopped interacting. |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 210 | if (event.GetType() == blink::WebInputEvent::kGestureScrollEnd && |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 211 | IsGestureEventFromTouchpad(event)) |
| 212 | return false; |
| 213 | |
[email protected] | 0da15c2d | 2013-10-30 16:47:20 | [diff] [blame] | 214 | if (!delegate_) |
| 215 | return false; |
| 216 | |
[email protected] | fc4b06d0 | 2013-10-23 20:47:11 | [diff] [blame] | 217 | gfx::Rect bounds = delegate_->GetVisibleBounds(); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 218 | if (bounds.IsEmpty()) |
| 219 | return false; |
| 220 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 221 | if (event.GetType() == blink::WebInputEvent::kGestureFlingStart) { |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 222 | // Check to see if the fling is in the same direction of the overscroll. |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 223 | const blink::WebGestureEvent gesture = |
| 224 | static_cast<const blink::WebGestureEvent&>(event); |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 225 | switch (overscroll_mode_) { |
| 226 | case OVERSCROLL_EAST: |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 227 | if (gesture.data.fling_start.velocity_x < 0) |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 228 | return false; |
| 229 | break; |
| 230 | case OVERSCROLL_WEST: |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 231 | if (gesture.data.fling_start.velocity_x > 0) |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 232 | return false; |
| 233 | break; |
| 234 | case OVERSCROLL_NORTH: |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 235 | if (gesture.data.fling_start.velocity_y > 0) |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 236 | return false; |
| 237 | break; |
| 238 | case OVERSCROLL_SOUTH: |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 239 | if (gesture.data.fling_start.velocity_y < 0) |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 240 | return false; |
| 241 | break; |
| 242 | case OVERSCROLL_NONE: |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 243 | NOTREACHED(); |
| 244 | } |
| 245 | } |
| 246 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 247 | float ratio, threshold; |
| 248 | if (overscroll_mode_ == OVERSCROLL_WEST || |
[email protected] | e42b1f8 | 2012-11-16 21:18:46 | [diff] [blame] | 249 | overscroll_mode_ == OVERSCROLL_EAST) { |
| 250 | ratio = fabs(overscroll_delta_x_) / bounds.width(); |
[email protected] | 1cd76c2d8 | 2012-11-29 07:36:47 | [diff] [blame] | 251 | threshold = GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 252 | } else { |
[email protected] | e42b1f8 | 2012-11-16 21:18:46 | [diff] [blame] | 253 | ratio = fabs(overscroll_delta_y_) / bounds.height(); |
[email protected] | 1cd76c2d8 | 2012-11-29 07:36:47 | [diff] [blame] | 254 | threshold = GetOverscrollConfig(OVERSCROLL_CONFIG_VERT_THRESHOLD_COMPLETE); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 255 | } |
[email protected] | 6658c6a | 2013-01-23 23:42:22 | [diff] [blame] | 256 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 257 | return ratio >= threshold; |
| 258 | } |
| 259 | |
| 260 | bool OverscrollController::DispatchEventResetsState( |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 261 | const blink::WebInputEvent& event) const { |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 262 | switch (event.GetType()) { |
| 263 | case blink::WebInputEvent::kMouseWheel: { |
[email protected] | b16ac820 | 2013-02-06 15:54:23 | [diff] [blame] | 264 | // Only wheel events with precise deltas (i.e. from trackpad) contribute |
| 265 | // to the overscroll gesture. |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 266 | const blink::WebMouseWheelEvent& wheel = |
| 267 | static_cast<const blink::WebMouseWheelEvent&>(event); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 268 | return !wheel.has_precise_scrolling_deltas; |
[email protected] | b16ac820 | 2013-02-06 15:54:23 | [diff] [blame] | 269 | } |
| 270 | |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 271 | // Avoid resetting overscroll on GestureScrollBegin/End generated |
| 272 | // from the touchpad since it is sent based on a timeout. |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 273 | case blink::WebInputEvent::kGestureScrollBegin: |
| 274 | case blink::WebInputEvent::kGestureScrollEnd: |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 275 | return !IsGestureEventFromTouchpad(event); |
| 276 | |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 277 | case blink::WebInputEvent::kGestureScrollUpdate: |
| 278 | case blink::WebInputEvent::kGestureFlingCancel: |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 279 | return false; |
| 280 | |
| 281 | default: |
[email protected] | c4ddb5c4 | 2012-11-17 01:09:57 | [diff] [blame] | 282 | // Touch events can arrive during an overscroll gesture initiated by |
| 283 | // touch-scrolling. These events should not reset the overscroll state. |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 284 | return !blink::WebInputEvent::IsTouchEventType(event.GetType()); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | |
[email protected] | 2422e5c | 2013-09-13 19:05:02 | [diff] [blame] | 288 | bool OverscrollController::ProcessEventForOverscroll( |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 289 | const blink::WebInputEvent& event) { |
[email protected] | 2422e5c | 2013-09-13 19:05:02 | [diff] [blame] | 290 | bool event_processed = false; |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 291 | switch (event.GetType()) { |
| 292 | case blink::WebInputEvent::kMouseWheel: { |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 293 | const blink::WebMouseWheelEvent& wheel = |
| 294 | static_cast<const blink::WebMouseWheelEvent&>(event); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 295 | if (!wheel.has_precise_scrolling_deltas) |
[email protected] | 2422e5c | 2013-09-13 19:05:02 | [diff] [blame] | 296 | break; |
[email protected] | bfab3d0 | 2014-08-20 03:16:55 | [diff] [blame] | 297 | event_processed = |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 298 | ProcessOverscroll(wheel.delta_x * wheel.acceleration_ratio_x, |
| 299 | wheel.delta_y * wheel.acceleration_ratio_y, true); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 300 | break; |
| 301 | } |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 302 | case blink::WebInputEvent::kGestureScrollUpdate: { |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 303 | const blink::WebGestureEvent& gesture = |
| 304 | static_cast<const blink::WebGestureEvent&>(event); |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 305 | event_processed = ProcessOverscroll( |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 306 | gesture.data.scroll_update.delta_x, |
| 307 | gesture.data.scroll_update.delta_y, |
| 308 | gesture.source_device == blink::kWebGestureDeviceTouchpad); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 309 | break; |
| 310 | } |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 311 | case blink::WebInputEvent::kGestureFlingStart: { |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 312 | const float kFlingVelocityThreshold = 1100.f; |
[email protected] | 180ef24 | 2013-11-07 06:50:46 | [diff] [blame] | 313 | const blink::WebGestureEvent& gesture = |
| 314 | static_cast<const blink::WebGestureEvent&>(event); |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 315 | float velocity_x = gesture.data.fling_start.velocity_x; |
| 316 | float velocity_y = gesture.data.fling_start.velocity_y; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 317 | if (fabs(velocity_x) > kFlingVelocityThreshold) { |
| 318 | if ((overscroll_mode_ == OVERSCROLL_WEST && velocity_x < 0) || |
| 319 | (overscroll_mode_ == OVERSCROLL_EAST && velocity_x > 0)) { |
| 320 | CompleteAction(); |
[email protected] | 2422e5c | 2013-09-13 19:05:02 | [diff] [blame] | 321 | event_processed = true; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 322 | break; |
| 323 | } |
| 324 | } else if (fabs(velocity_y) > kFlingVelocityThreshold) { |
| 325 | if ((overscroll_mode_ == OVERSCROLL_NORTH && velocity_y < 0) || |
| 326 | (overscroll_mode_ == OVERSCROLL_SOUTH && velocity_y > 0)) { |
| 327 | CompleteAction(); |
[email protected] | 2422e5c | 2013-09-13 19:05:02 | [diff] [blame] | 328 | event_processed = true; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 329 | break; |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | // Reset overscroll state if fling didn't complete the overscroll gesture. |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 334 | SetOverscrollMode(OVERSCROLL_NONE, OverscrollSource::NONE); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 335 | break; |
| 336 | } |
| 337 | |
| 338 | default: |
Blink Reformat | 1c4d759e | 2017-04-09 16:34:54 | [diff] [blame] | 339 | DCHECK(blink::WebInputEvent::IsGestureEventType(event.GetType()) || |
| 340 | blink::WebInputEvent::IsTouchEventType(event.GetType())) |
| 341 | << "Received unexpected event: " << event.GetType(); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 342 | } |
[email protected] | 2422e5c | 2013-09-13 19:05:02 | [diff] [blame] | 343 | return event_processed; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 344 | } |
| 345 | |
[email protected] | bfab3d0 | 2014-08-20 03:16:55 | [diff] [blame] | 346 | bool OverscrollController::ProcessOverscroll(float delta_x, |
[email protected] | a7f99f0 | 2013-08-29 14:15:19 | [diff] [blame] | 347 | float delta_y, |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 348 | bool is_touchpad) { |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 349 | if (scroll_state_ != STATE_CONTENT_SCROLLING) |
| 350 | overscroll_delta_x_ += delta_x; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 351 | overscroll_delta_y_ += delta_y; |
| 352 | |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 353 | float horiz_threshold = GetOverscrollConfig( |
dtapuska | 19ebfa51 | 2016-02-19 22:27:40 | [diff] [blame] | 354 | is_touchpad ? OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHPAD |
| 355 | : OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN); |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 356 | float vert_threshold = GetOverscrollConfig( |
| 357 | OVERSCROLL_CONFIG_VERT_THRESHOLD_START); |
| 358 | if (fabs(overscroll_delta_x_) <= horiz_threshold && |
| 359 | fabs(overscroll_delta_y_) <= vert_threshold) { |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 360 | SetOverscrollMode(OVERSCROLL_NONE, OverscrollSource::NONE); |
[email protected] | bfab3d0 | 2014-08-20 03:16:55 | [diff] [blame] | 361 | return true; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 362 | } |
| 363 | |
[email protected] | a23d04af | 2013-02-19 17:41:10 | [diff] [blame] | 364 | // Compute the current overscroll direction. If the direction is different |
| 365 | // from the current direction, then always switch to no-overscroll mode first |
| 366 | // to make sure that subsequent scroll events go through to the page first. |
| 367 | OverscrollMode new_mode = OVERSCROLL_NONE; |
[email protected] | 14749ddb | 2013-02-23 06:56:10 | [diff] [blame] | 368 | const float kMinRatio = 2.5; |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 369 | if (fabs(overscroll_delta_x_) > horiz_threshold && |
| 370 | fabs(overscroll_delta_x_) > fabs(overscroll_delta_y_) * kMinRatio) |
[email protected] | a23d04af | 2013-02-19 17:41:10 | [diff] [blame] | 371 | new_mode = overscroll_delta_x_ > 0.f ? OVERSCROLL_EAST : OVERSCROLL_WEST; |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 372 | else if (fabs(overscroll_delta_y_) > vert_threshold && |
| 373 | fabs(overscroll_delta_y_) > fabs(overscroll_delta_x_) * kMinRatio) |
[email protected] | a23d04af | 2013-02-19 17:41:10 | [diff] [blame] | 374 | new_mode = overscroll_delta_y_ > 0.f ? OVERSCROLL_SOUTH : OVERSCROLL_NORTH; |
| 375 | |
[email protected] | 3aad43b | 2013-11-05 20:20:18 | [diff] [blame] | 376 | // The vertical oversrcoll currently does not have any UX effects other then |
| 377 | // for the scroll end effect, so testing if it is enabled. |
| 378 | if ((new_mode == OVERSCROLL_SOUTH || new_mode == OVERSCROLL_NORTH) && |
| 379 | !IsScrollEndEffectEnabled()) |
| 380 | new_mode = OVERSCROLL_NONE; |
| 381 | |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 382 | if (overscroll_mode_ == OVERSCROLL_NONE) { |
| 383 | SetOverscrollMode(new_mode, is_touchpad ? OverscrollSource::TOUCHPAD |
| 384 | : OverscrollSource::TOUCHSCREEN); |
| 385 | } else if (new_mode != overscroll_mode_) { |
| 386 | SetOverscrollMode(OVERSCROLL_NONE, OverscrollSource::NONE); |
| 387 | } |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 388 | |
| 389 | if (overscroll_mode_ == OVERSCROLL_NONE) |
[email protected] | bfab3d0 | 2014-08-20 03:16:55 | [diff] [blame] | 390 | return false; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 391 | |
| 392 | // Tell the delegate about the overscroll update so that it can update |
| 393 | // the display accordingly (e.g. show history preview etc.). |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 394 | if (delegate_) { |
| 395 | // Do not include the threshold amount when sending the deltas to the |
| 396 | // delegate. |
| 397 | float delegate_delta_x = overscroll_delta_x_; |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 398 | if (fabs(delegate_delta_x) > horiz_threshold) { |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 399 | if (delegate_delta_x < 0) |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 400 | delegate_delta_x += horiz_threshold; |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 401 | else |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 402 | delegate_delta_x -= horiz_threshold; |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 403 | } else { |
| 404 | delegate_delta_x = 0.f; |
| 405 | } |
| 406 | |
| 407 | float delegate_delta_y = overscroll_delta_y_; |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 408 | if (fabs(delegate_delta_y) > vert_threshold) { |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 409 | if (delegate_delta_y < 0) |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 410 | delegate_delta_y += vert_threshold; |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 411 | else |
[email protected] | fa6db25 | 2013-07-26 03:38:20 | [diff] [blame] | 412 | delegate_delta_y -= vert_threshold; |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 413 | } else { |
| 414 | delegate_delta_y = 0.f; |
| 415 | } |
[email protected] | bfab3d0 | 2014-08-20 03:16:55 | [diff] [blame] | 416 | return delegate_->OnOverscrollUpdate(delegate_delta_x, delegate_delta_y); |
[email protected] | 9f4f47e | 2012-11-20 02:21:43 | [diff] [blame] | 417 | } |
[email protected] | bfab3d0 | 2014-08-20 03:16:55 | [diff] [blame] | 418 | return false; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 419 | } |
| 420 | |
| 421 | void OverscrollController::CompleteAction() { |
| 422 | if (delegate_) |
| 423 | delegate_->OnOverscrollComplete(overscroll_mode_); |
[email protected] | e42b1f8 | 2012-11-16 21:18:46 | [diff] [blame] | 424 | overscroll_mode_ = OVERSCROLL_NONE; |
| 425 | overscroll_delta_x_ = overscroll_delta_y_ = 0.f; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 426 | } |
| 427 | |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 428 | void OverscrollController::SetOverscrollMode(OverscrollMode mode, |
| 429 | OverscrollSource source) { |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 430 | if (overscroll_mode_ == mode) |
| 431 | return; |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 432 | |
| 433 | // If the mode changes to NONE, source is also NONE. |
| 434 | DCHECK(mode != OVERSCROLL_NONE || source == OverscrollSource::NONE); |
| 435 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 436 | OverscrollMode old_mode = overscroll_mode_; |
| 437 | overscroll_mode_ = mode; |
| 438 | if (overscroll_mode_ == OVERSCROLL_NONE) |
| 439 | overscroll_delta_x_ = overscroll_delta_y_ = 0.f; |
[email protected] | a414164 | 2013-05-23 04:10:58 | [diff] [blame] | 440 | else |
| 441 | scroll_state_ = STATE_OVERSCROLLING; |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 442 | if (delegate_) |
mfomitchev | 09f0d64a | 2017-03-02 19:40:07 | [diff] [blame] | 443 | delegate_->OnOverscrollModeChange(old_mode, overscroll_mode_, source); |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 444 | } |
| 445 | |
[email protected] | b4df9df | 2012-11-16 01:58:58 | [diff] [blame] | 446 | } // namespace content |