blob: 24f6fdd027030cfc96f75ef053f80cc8e6539152 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[email protected]5d0bbdfa92013-12-10 00:35:512// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Kartar Singhd084e582024-06-12 19:22:245#include "components/input/touch_action_filter.h"
[email protected]5d0bbdfa92013-12-10 00:35:516
[email protected]a18f67a2013-12-20 19:44:367#include <math.h>
8
Hans Wennborg0917de892020-04-28 20:21:159#include "base/check_op.h"
Hans Wennborg0917de892020-04-28 20:21:1510#include "base/notreached.h"
David Bokand0c973dd2020-04-09 19:36:3611#include "base/trace_event/trace_event.h"
Dave Tapuska129cef82019-12-19 16:36:4812#include "third_party/blink/public/common/input/web_gesture_event.h"
Michelle9e74c52f2023-06-02 10:21:3413#include "ui/base/ui_base_features.h"
Xida Chenf164239c2018-11-13 01:59:0414#include "ui/events/blink/blink_features.h"
[email protected]5d0bbdfa92013-12-10 00:35:5115
16using blink::WebInputEvent;
17using blink::WebGestureEvent;
18
Kartar Singhd084e582024-06-12 19:22:2419namespace input {
dtapuskaa98ac8d72015-05-08 19:29:0920namespace {
21
22// Actions on an axis are disallowed if the perpendicular axis has a filter set
23// and no filter is set for the queried axis.
xidachenfa0199e72017-05-11 11:34:2624bool IsYAxisActionDisallowed(cc::TouchAction action) {
Henrique Ferreiro00e24f12019-12-17 01:14:4825 return ((action & cc::TouchAction::kPanX) != cc::TouchAction::kNone) &&
26 ((action & cc::TouchAction::kPanY) == cc::TouchAction::kNone);
dtapuskaa98ac8d72015-05-08 19:29:0927}
28
xidachenfa0199e72017-05-11 11:34:2629bool IsXAxisActionDisallowed(cc::TouchAction action) {
Henrique Ferreiro00e24f12019-12-17 01:14:4830 return ((action & cc::TouchAction::kPanY) != cc::TouchAction::kNone) &&
31 ((action & cc::TouchAction::kPanX) == cc::TouchAction::kNone);
dtapuskaa98ac8d72015-05-08 19:29:0932}
33
Shimi Zhang9287e2cd2020-10-31 00:40:3534void SetCursorControlIfNecessary(WebGestureEvent* event,
35 cc::TouchAction action) {
36 if (event->data.scroll_begin.pointer_count != 1)
37 return;
38 const float abs_delta_x = fabs(event->data.scroll_begin.delta_x_hint);
39 const float abs_delta_y = fabs(event->data.scroll_begin.delta_y_hint);
40 if (abs_delta_x <= abs_delta_y)
41 return;
42
43 // We shouldn't reach here if kPanX is not allowed for horizontal scroll.
44 DCHECK_NE(action & cc::TouchAction::kPanX, cc::TouchAction::kNone);
45 if ((action & cc::TouchAction::kInternalPanXScrolls) ==
46 cc::TouchAction::kInternalPanXScrolls)
47 return;
48
49 event->data.scroll_begin.cursor_control = true;
50}
51
dtapuskaa98ac8d72015-05-08 19:29:0952} // namespace
[email protected]5d0bbdfa92013-12-10 00:35:5153
David Bokanc8973d42020-04-07 05:58:0954TouchActionFilter::TouchActionFilter() {
Xida Chen0d326b42018-08-22 20:39:2655 ResetTouchAction();
56}
[email protected]5d0bbdfa92013-12-10 00:35:5157
Sorin Jianu58421902024-10-10 21:33:4558TouchActionFilter::~TouchActionFilter() = default;
Xida Chenee78df32018-08-03 17:40:4059
Xida Chene051a6c2018-05-02 16:35:1360FilterGestureEventResult TouchActionFilter::FilterGestureEvent(
61 WebGestureEvent* gesture_event) {
David Bokand0c973dd2020-04-09 19:36:3662 TRACE_EVENT0("input", "TouchActionFilter::FilterGestureEvent");
Daniel Cheng7f9ec902019-04-18 05:07:0063 if (gesture_event->SourceDevice() != blink::WebGestureDevice::kTouchscreen)
Kartar Singh3a968862024-07-19 11:46:1064 return FilterGestureEventResult::kAllowed;
dtapuska3a5f4db2016-05-12 20:53:4965
David Bokanc8973d42020-04-07 05:58:0966 if (has_deferred_events_) {
David Bokand0c973dd2020-04-09 19:36:3667 TRACE_EVENT_INSTANT0("input", "Has Deferred", TRACE_EVENT_SCOPE_THREAD);
Kartar Singh3a968862024-07-19 11:46:1068 return FilterGestureEventResult::kDelayed;
Xida Chen360707992018-11-20 14:25:5169 }
Xida Chenf164239c2018-11-13 01:59:0470
David Bokand0c973dd2020-04-09 19:36:3671 TRACE_EVENT_INSTANT1(
72 "input", "active_action", TRACE_EVENT_SCOPE_THREAD, "action",
73 (active_touch_action_.has_value()
74 ? cc::TouchActionToString(active_touch_action_.value())
75 : "n/a"));
76 TRACE_EVENT_INSTANT1(
77 "input", "allowed_action", TRACE_EVENT_SCOPE_THREAD, "action",
78 (allowed_touch_action_.has_value()
79 ? cc::TouchActionToString(allowed_touch_action_.value())
80 : "n/a"));
Philip Rogersa2c73772020-06-22 14:54:1381 TRACE_EVENT_INSTANT1(
82 "input", "compositor_allowed_action", TRACE_EVENT_SCOPE_THREAD, "action",
83 cc::TouchActionToString(compositor_allowed_touch_action_));
David Bokand0c973dd2020-04-09 19:36:3684
Xida Chen77aa9e72019-02-14 02:01:3285 cc::TouchAction touch_action = active_touch_action_.has_value()
86 ? active_touch_action_.value()
Philip Rogersa2c73772020-06-22 14:54:1387 : compositor_allowed_touch_action_;
Xida Chen84d0845e2018-11-02 20:36:5488
[email protected]5d0bbdfa92013-12-10 00:35:5189 // Filter for allowable touch actions first (eg. before the TouchEventQueue
90 // can decide to send a touch cancel event).
Blink Reformat1c4d759e2017-04-09 16:34:5491 switch (gesture_event->GetType()) {
Dave Tapuskab5a72eb2020-04-21 22:12:5692 case WebInputEvent::Type::kGestureScrollBegin: {
Xida Chen166974ea2018-09-10 21:02:3593 // In VR or virtual keyboard (https://crbug.com/880701),
94 // GestureScrollBegin could come without GestureTapDown.
David Bokanf22d61602020-04-06 21:54:3795 // TODO(bokan): This can also happen due to the fling controller
96 // filtering out the GestureTapDown due to tap suppression (i.e. tapping
97 // during a fling should stop the fling, not be sent to the page). We
98 // should not reset the touch action in this case! We currently work
Philip Rogersa2c73772020-06-22 14:54:1399 // around this by resetting the compositor allowed touch action in this
100 // case as well but we should investigate not filtering the TapDown.
Xida Chen45630992018-08-29 19:54:20101 if (!gesture_sequence_in_progress_) {
David Bokand0c973dd2020-04-09 19:36:36102 TRACE_EVENT_INSTANT0("input", "No Sequence at GSB!",
103 TRACE_EVENT_SCOPE_THREAD);
Xida Chen45630992018-08-29 19:54:20104 gesture_sequence_in_progress_ = true;
Xida Chen77aa9e72019-02-14 02:01:32105 if (allowed_touch_action_.has_value()) {
106 active_touch_action_ = allowed_touch_action_;
107 touch_action = allowed_touch_action_.value();
108 } else {
Philip Rogersa2c73772020-06-22 14:54:13109 touch_action = compositor_allowed_touch_action_;
Xida Chenf164239c2018-11-13 01:59:04110 }
Xida Chen45630992018-08-29 19:54:20111 }
Shimi Zhang9287e2cd2020-10-31 00:40:35112 drop_scroll_events_ = ShouldSuppressScrolling(
113 *gesture_event, touch_action, active_touch_action_.has_value());
Xida Chen360707992018-11-20 14:25:51114 FilterGestureEventResult res;
115 if (!drop_scroll_events_) {
Michelle55a24392023-05-19 01:39:37116 if (allow_cursor_control_) {
117 SetCursorControlIfNecessary(gesture_event, touch_action);
118 }
Kartar Singh3a968862024-07-19 11:46:10119 res = FilterGestureEventResult::kAllowed;
Xida Chen360707992018-11-20 14:25:51120 } else if (active_touch_action_.has_value()) {
Kartar Singh3a968862024-07-19 11:46:10121 res = FilterGestureEventResult::kFiltered;
Xida Chen360707992018-11-20 14:25:51122 } else {
David Bokand0c973dd2020-04-09 19:36:36123 TRACE_EVENT_INSTANT0("input", "Deferring Events",
124 TRACE_EVENT_SCOPE_THREAD);
Xida Chen360707992018-11-20 14:25:51125 has_deferred_events_ = true;
Kartar Singh3a968862024-07-19 11:46:10126 res = FilterGestureEventResult::kDelayed;
Xida Chen360707992018-11-20 14:25:51127 }
Xida Chen360707992018-11-20 14:25:51128 return res;
Xida Chen2eec314f2018-06-07 11:42:42129 }
[email protected]a18f67a2013-12-20 19:44:36130
Dave Tapuskab5a72eb2020-04-21 22:12:56131 case WebInputEvent::Type::kGestureScrollUpdate: {
Xida Chen360707992018-11-20 14:25:51132 if (drop_scroll_events_) {
David Bokand0c973dd2020-04-09 19:36:36133 TRACE_EVENT_INSTANT0("input", "Drop Events", TRACE_EVENT_SCOPE_THREAD);
Kartar Singh3a968862024-07-19 11:46:10134 return FilterGestureEventResult::kFiltered;
Xida Chen360707992018-11-20 14:25:51135 }
mustaq16ce4602017-03-14 16:22:36136
137 // Scrolls restricted to a specific axis shouldn't permit movement
138 // in the perpendicular axis.
139 //
140 // Note the direction suppression with pinch-zoom here, which matches
141 // Edge: a "touch-action: pan-y pinch-zoom" region allows vertical
142 // two-finger scrolling but a "touch-action: pan-x pinch-zoom" region
143 // doesn't.
144 // TODO(mustaq): Add it to spec?
Xida Chen77aa9e72019-02-14 02:01:32145 if (IsYAxisActionDisallowed(touch_action)) {
David Bokanc8973d42020-04-07 05:58:09146 if (!active_touch_action_.has_value() &&
Xida Chenf164239c2018-11-13 01:59:04147 gesture_event->data.scroll_update.delta_y != 0) {
David Bokand0c973dd2020-04-09 19:36:36148 TRACE_EVENT_INSTANT0("input", "Defer Due to YAxis",
149 TRACE_EVENT_SCOPE_THREAD);
Xida Chenf164239c2018-11-13 01:59:04150 has_deferred_events_ = true;
Kartar Singh3a968862024-07-19 11:46:10151 return FilterGestureEventResult::kDelayed;
Xida Chenf164239c2018-11-13 01:59:04152 }
Blink Reformat1c4d759e2017-04-09 16:34:54153 gesture_event->data.scroll_update.delta_y = 0;
Xida Chen77aa9e72019-02-14 02:01:32154 } else if (IsXAxisActionDisallowed(touch_action)) {
David Bokanc8973d42020-04-07 05:58:09155 if (!active_touch_action_.has_value() &&
Xida Chenf164239c2018-11-13 01:59:04156 gesture_event->data.scroll_update.delta_x != 0) {
David Bokand0c973dd2020-04-09 19:36:36157 TRACE_EVENT_INSTANT0("input", "Defer Due to XAxis",
158 TRACE_EVENT_SCOPE_THREAD);
Xida Chenf164239c2018-11-13 01:59:04159 has_deferred_events_ = true;
Kartar Singh3a968862024-07-19 11:46:10160 return FilterGestureEventResult::kDelayed;
Xida Chenf164239c2018-11-13 01:59:04161 }
Blink Reformat1c4d759e2017-04-09 16:34:54162 gesture_event->data.scroll_update.delta_x = 0;
[email protected]5d0bbdfa92013-12-10 00:35:51163 }
164 break;
Xida Chen2eec314f2018-06-07 11:42:42165 }
[email protected]5d0bbdfa92013-12-10 00:35:51166
Dave Tapuskab5a72eb2020-04-21 22:12:56167 case WebInputEvent::Type::kGestureFlingStart:
Xida Chence09732e2018-05-30 15:22:48168 // Fling controller processes FlingStart event, and we should never get
169 // it here.
Peter Boström0af5ffa12024-11-08 11:47:04170 NOTREACHED();
[email protected]a18f67a2013-12-20 19:44:36171
Dave Tapuskab5a72eb2020-04-21 22:12:56172 case WebInputEvent::Type::kGestureScrollEnd:
Philip Rogersa2c73772020-06-22 14:54:13173 // Do not reset |compositor_allowed_touch_action_|. In the fling cancel
174 // case, the ack for the second touch sequence start, which sets the
175 // compositor allowed touch action, could arrive before the GSE of the
176 // first fling sequence, we do not want to reset the compositor allowed
177 // touch action.
Xida Chen7a7759f2018-08-22 16:42:31178 gesture_sequence_in_progress_ = false;
Xida Chen06a04422018-10-30 05:35:30179 return FilterScrollEventAndResetState();
[email protected]aec5f6f2014-01-03 17:41:58180
Xida Chen06a04422018-10-30 05:35:30181 // Evaluate the |drop_pinch_events_| here instead of GSB because pinch
182 // events could arrive without GSB, e.g. double-tap-drag.
Dave Tapuskab5a72eb2020-04-21 22:12:56183 case WebInputEvent::Type::kGesturePinchBegin:
Henrique Ferreiro00e24f12019-12-17 01:14:48184 drop_pinch_events_ = (touch_action & cc::TouchAction::kPinchZoom) ==
185 cc::TouchAction::kNone;
Roland Bock1556a482022-01-04 16:28:40186 [[fallthrough]];
Dave Tapuskab5a72eb2020-04-21 22:12:56187 case WebInputEvent::Type::kGesturePinchUpdate:
Xida Chen97762762019-02-21 02:51:14188 if (!drop_pinch_events_)
Kartar Singh3a968862024-07-19 11:46:10189 return FilterGestureEventResult::kAllowed;
David Bokanc8973d42020-04-07 05:58:09190 if (!active_touch_action_.has_value()) {
Xida Chen97762762019-02-21 02:51:14191 has_deferred_events_ = true;
Kartar Singh3a968862024-07-19 11:46:10192 return FilterGestureEventResult::kDelayed;
Xida Chen97762762019-02-21 02:51:14193 }
Kartar Singh3a968862024-07-19 11:46:10194 return FilterGestureEventResult::kFiltered;
Dave Tapuskab5a72eb2020-04-21 22:12:56195 case WebInputEvent::Type::kGesturePinchEnd:
Xida Chen06a04422018-10-30 05:35:30196 return FilterPinchEventAndResetState();
[email protected]a18f67a2013-12-20 19:44:36197
Mustaq Ahmed70a68cf82018-10-11 20:58:20198 // The double tap gesture is a tap ending event. If a double-tap gesture is
199 // filtered out, replace it with a tap event but preserve the tap-count to
200 // allow firing dblclick event in Blink.
201 //
202 // TODO(mustaq): This replacement of a double-tap gesture with a tap seems
203 // buggy, it produces an inconsistent gesture event stream: GestureTapCancel
204 // followed by GestureTap. See crbug.com/874474#c47 for a repro. We don't
205 // know of any bug resulting from it, but it's better to fix the broken
206 // assumption here at least to avoid introducing new bugs in future.
Dave Tapuskab5a72eb2020-04-21 22:12:56207 case WebInputEvent::Type::kGestureDoubleTap:
Xida Chen7a7759f2018-08-22 16:42:31208 gesture_sequence_in_progress_ = false;
Blink Reformat1c4d759e2017-04-09 16:34:54209 DCHECK_EQ(1, gesture_event->data.tap.tap_count);
Mustaq Ahmed70a68cf82018-10-11 20:58:20210 if (!allow_current_double_tap_event_) {
Dave Tapuskab5a72eb2020-04-21 22:12:56211 gesture_event->SetType(WebInputEvent::Type::kGestureTap);
Mustaq Ahmed70a68cf82018-10-11 20:58:20212 gesture_event->data.tap.tap_count = 2;
213 }
[email protected]3571a33e2014-03-04 22:18:02214 allow_current_double_tap_event_ = true;
[email protected]0783edd2014-02-19 20:48:20215 break;
216
217 // If double tap is disabled, there's no reason for the tap delay.
Dave Tapuskab5a72eb2020-04-21 22:12:56218 case WebInputEvent::Type::kGestureTapUnconfirmed: {
Blink Reformat1c4d759e2017-04-09 16:34:54219 DCHECK_EQ(1, gesture_event->data.tap.tap_count);
Xida Chen06a04422018-10-30 05:35:30220 allow_current_double_tap_event_ =
Henrique Ferreiro00e24f12019-12-17 01:14:48221 (touch_action & cc::TouchAction::kDoubleTapZoom) !=
222 cc::TouchAction::kNone;
[email protected]3571a33e2014-03-04 22:18:02223 if (!allow_current_double_tap_event_) {
Dave Tapuskab5a72eb2020-04-21 22:12:56224 gesture_event->SetType(WebInputEvent::Type::kGestureTap);
[email protected]0783edd2014-02-19 20:48:20225 drop_current_tap_ending_event_ = true;
226 }
227 break;
Xida Chen2eec314f2018-06-07 11:42:42228 }
[email protected]0783edd2014-02-19 20:48:20229
Dave Tapuskab5a72eb2020-04-21 22:12:56230 case WebInputEvent::Type::kGestureTap:
Xida Chen7a7759f2018-08-22 16:42:31231 gesture_sequence_in_progress_ = false;
[email protected]0783edd2014-02-19 20:48:20232 if (drop_current_tap_ending_event_) {
233 drop_current_tap_ending_event_ = false;
Kartar Singh3a968862024-07-19 11:46:10234 return FilterGestureEventResult::kFiltered;
[email protected]0783edd2014-02-19 20:48:20235 }
236 break;
237
Dave Tapuskab5a72eb2020-04-21 22:12:56238 case WebInputEvent::Type::kGestureTapCancel:
Xida Chenb9001ac2018-08-27 18:57:50239 if (drop_current_tap_ending_event_) {
240 drop_current_tap_ending_event_ = false;
Kartar Singh3a968862024-07-19 11:46:10241 return FilterGestureEventResult::kFiltered;
Xida Chenb9001ac2018-08-27 18:57:50242 }
243 break;
244
Dave Tapuskab5a72eb2020-04-21 22:12:56245 case WebInputEvent::Type::kGestureTapDown:
Xida Chen7a7759f2018-08-22 16:42:31246 gesture_sequence_in_progress_ = true;
Michelle9e74c52f2023-06-02 10:21:34247 allow_cursor_control_ =
248 !::features::IsTouchTextEditingRedesignEnabled() ||
249 gesture_event->data.tap_down.tap_down_count <= 1;
Xida Chene1460a2f2018-11-02 15:30:20250 // In theory, the num_of_active_touches_ should be > 0 at this point. But
251 // crash reports suggest otherwise.
Xida Chen84d0845e2018-11-02 20:36:54252 if (num_of_active_touches_ <= 0)
Henrique Ferreiro00e24f12019-12-17 01:14:48253 SetTouchAction(cc::TouchAction::kAuto);
Xida Chen06a04422018-10-30 05:35:30254 active_touch_action_ = allowed_touch_action_;
[email protected]0783edd2014-02-19 20:48:20255 DCHECK(!drop_current_tap_ending_event_);
256 break;
257
Michelle55a24392023-05-19 01:39:37258 case WebInputEvent::Type::kGestureLongPress:
259 allow_cursor_control_ = false;
260 break;
261
Dave Tapuskab5a72eb2020-04-21 22:12:56262 case WebInputEvent::Type::kGestureLongTap:
263 case WebInputEvent::Type::kGestureTwoFingerTap:
Xida Chenb9001ac2018-08-27 18:57:50264 gesture_sequence_in_progress_ = false;
265 break;
266
[email protected]5d0bbdfa92013-12-10 00:35:51267 default:
268 // Gesture events unrelated to touch actions (panning/zooming) are left
269 // alone.
270 break;
271 }
272
Kartar Singh3a968862024-07-19 11:46:10273 return FilterGestureEventResult::kAllowed;
[email protected]5d0bbdfa92013-12-10 00:35:51274}
275
Xida Chen2eec314f2018-06-07 11:42:42276void TouchActionFilter::SetTouchAction(cc::TouchAction touch_action) {
David Bokand0c973dd2020-04-09 19:36:36277 TRACE_EVENT1("input", "TouchActionFilter::SetTouchAction", "action",
278 cc::TouchActionToString(touch_action));
Xida Chen2eec314f2018-06-07 11:42:42279 allowed_touch_action_ = touch_action;
Xida Chen06a04422018-10-30 05:35:30280 active_touch_action_ = allowed_touch_action_;
Philip Rogersa2c73772020-06-22 14:54:13281 compositor_allowed_touch_action_ = touch_action;
Xida Chen2eec314f2018-06-07 11:42:42282}
283
Xida Chen06a04422018-10-30 05:35:30284FilterGestureEventResult TouchActionFilter::FilterPinchEventAndResetState() {
285 if (drop_pinch_events_) {
286 drop_pinch_events_ = false;
Kartar Singh3a968862024-07-19 11:46:10287 return FilterGestureEventResult::kFiltered;
[email protected]a18f67a2013-12-20 19:44:36288 }
Kartar Singh3a968862024-07-19 11:46:10289 return FilterGestureEventResult::kAllowed;
Xida Chen06a04422018-10-30 05:35:30290}
291
292FilterGestureEventResult TouchActionFilter::FilterScrollEventAndResetState() {
293 if (drop_scroll_events_) {
294 drop_scroll_events_ = false;
Kartar Singh3a968862024-07-19 11:46:10295 return FilterGestureEventResult::kFiltered;
Xida Chen06a04422018-10-30 05:35:30296 }
Kartar Singh3a968862024-07-19 11:46:10297 return FilterGestureEventResult::kAllowed;
[email protected]a18f67a2013-12-20 19:44:36298}
299
Xida Chen0f7980b2018-10-12 12:40:53300void TouchActionFilter::ForceResetTouchActionForTest() {
301 allowed_touch_action_.reset();
Xida Chen06a04422018-10-30 05:35:30302 active_touch_action_.reset();
Xida Chen0f7980b2018-10-12 12:40:53303}
304
xidachenfa0199e72017-05-11 11:34:26305void TouchActionFilter::OnSetTouchAction(cc::TouchAction touch_action) {
David Bokand0c973dd2020-04-09 19:36:36306 TRACE_EVENT2("input", "TouchActionFilter::OnSetTouchAction", "action",
307 cc::TouchActionToString(touch_action), "allowed",
308 (allowed_touch_action_.has_value()
309 ? cc::TouchActionToString(allowed_touch_action_.value())
310 : "n/a"));
Alison Gale53c77f62024-04-22 15:16:27311 // TODO(crbug.com/40579429): add a DCHECK for
Xida Chen2eec314f2018-06-07 11:42:42312 // |has_touch_event_handler_|.
[email protected]5d0bbdfa92013-12-10 00:35:51313 // For multiple fingers, we take the intersection of the touch actions for
[email protected]aec5f6f2014-01-03 17:41:58314 // all fingers that have gone down during this action. In the majority of
315 // real-world scenarios the touch action for all fingers will be the same.
316 // This is left as implementation-defined in the pointer events
317 // specification because of the relationship to gestures (which are off
318 // limits for the spec). I believe the following are desirable properties
319 // of this choice:
320 // 1. Not sensitive to finger touch order. Behavior of putting two fingers
321 // down "at once" will be deterministic.
322 // 2. Only subtractive - eg. can't trigger scrolling on a element that
323 // otherwise has scrolling disabling by the addition of a finger.
Xida Chen2eec314f2018-06-07 11:42:42324 allowed_touch_action_ =
Henrique Ferreiro00e24f12019-12-17 01:14:48325 allowed_touch_action_.value_or(cc::TouchAction::kAuto) & touch_action;
chaopenge5f829bb2017-08-25 00:35:26326
327 // When user enabled force enable zoom, we should always allow pinch-zoom
328 // except for touch-action:none.
Henrique Ferreiro00e24f12019-12-17 01:14:48329 if (force_enable_zoom_ && allowed_touch_action_ != cc::TouchAction::kNone) {
Xida Chen2eec314f2018-06-07 11:42:42330 allowed_touch_action_ =
Henrique Ferreiro00e24f12019-12-17 01:14:48331 allowed_touch_action_.value() | cc::TouchAction::kPinchZoom;
Xida Chen2eec314f2018-06-07 11:42:42332 }
Xida Chen06a04422018-10-30 05:35:30333 active_touch_action_ = allowed_touch_action_;
Xida Chenf164239c2018-11-13 01:59:04334 has_deferred_events_ = false;
[email protected]a18f67a2013-12-20 19:44:36335}
336
Xida Chene1460a2f2018-11-02 15:30:20337void TouchActionFilter::IncreaseActiveTouches() {
David Bokand0c973dd2020-04-09 19:36:36338 TRACE_EVENT1("input", "TouchActionFilter::IncreaseActiveTouches", "num",
339 num_of_active_touches_);
Xida Chene1460a2f2018-11-02 15:30:20340 num_of_active_touches_++;
341}
342
343void TouchActionFilter::DecreaseActiveTouches() {
David Bokand0c973dd2020-04-09 19:36:36344 TRACE_EVENT1("input", "TouchActionFilter::DecreaseActiveTouches", "num",
345 num_of_active_touches_);
Xida Chene1460a2f2018-11-02 15:30:20346 num_of_active_touches_--;
Xida Chen3811c0a2018-08-29 20:01:50347}
348
calamity0c2262ad2018-05-21 03:40:16349void TouchActionFilter::ReportAndResetTouchAction() {
Michelle55a24392023-05-19 01:39:37350 if (num_of_active_touches_ <= 0) {
Xida Chene1460a2f2018-11-02 15:30:20351 ResetTouchAction();
Michelle55a24392023-05-19 01:39:37352 allow_cursor_control_ = true;
353 }
Xida Chen2eec314f2018-06-07 11:42:42354}
355
[email protected]bfd4f6e2014-02-27 16:27:55356void TouchActionFilter::ResetTouchAction() {
David Bokand0c973dd2020-04-09 19:36:36357 TRACE_EVENT0("input", "TouchActionFilter::ResetTouchAction");
[email protected]40981da2014-05-22 05:22:44358 // Note that resetting the action mid-sequence is tolerated. Gestures that had
Philip Rogersa2c73772020-06-22 14:54:13359 // their begin event(s) suppressed will be suppressed until the next sequence.
Xida Chen2eec314f2018-06-07 11:42:42360 if (has_touch_event_handler_) {
361 allowed_touch_action_.reset();
Philip Rogersa2c73772020-06-22 14:54:13362 compositor_allowed_touch_action_ = cc::TouchAction::kAuto;
Xida Chen2eec314f2018-06-07 11:42:42363 } else {
364 // Lack of a touch handler indicates that the page either has no
365 // touch-action modifiers or that all its touch-action modifiers are auto.
366 // Resetting the touch-action here allows forwarding of subsequent gestures
367 // even if the underlying touches never reach the router.
Henrique Ferreiro00e24f12019-12-17 01:14:48368 SetTouchAction(cc::TouchAction::kAuto);
Xida Chen2eec314f2018-06-07 11:42:42369 }
Hayley Ferraa29bf62017-07-14 01:40:59370}
371
Philip Rogersa2c73772020-06-22 14:54:13372void TouchActionFilter::OnSetCompositorAllowedTouchAction(
373 cc::TouchAction allowed_touch_action) {
374 TRACE_EVENT2("input", "TouchActionFilter::OnSetCompositorAllowedTouchAction",
375 "action", cc::TouchActionToString(allowed_touch_action),
376 "current", cc::TouchActionToString(allowed_touch_action));
Xida Chend7eb6362018-04-05 15:08:21377 // We use '&' here to account for the multiple-finger case, which is the same
378 // as OnSetTouchAction.
Philip Rogersa2c73772020-06-22 14:54:13379 compositor_allowed_touch_action_ =
380 compositor_allowed_touch_action_ & allowed_touch_action;
[email protected]bfd4f6e2014-02-27 16:27:55381}
382
Xida Chen06a04422018-10-30 05:35:30383bool TouchActionFilter::ShouldSuppressScrolling(
Xida Chenf164239c2018-11-13 01:59:04384 const blink::WebGestureEvent& gesture_event,
Shimi Zhang9287e2cd2020-10-31 00:40:35385 cc::TouchAction touch_action,
386 bool is_active_touch_action) {
Dave Tapuskab5a72eb2020-04-21 22:12:56387 DCHECK(gesture_event.GetType() == WebInputEvent::Type::kGestureScrollBegin);
Shimi Zhang9287e2cd2020-10-31 00:40:35388 // If kInternalPanXScrolls is true, kPanX must be true;
389 DCHECK((touch_action & cc::TouchAction::kInternalPanXScrolls) ==
390 cc::TouchAction::kNone ||
391 (touch_action & cc::TouchAction::kPanX) != cc::TouchAction::kNone);
mustaq16ce4602017-03-14 16:22:36392
Blink Reformat1c4d759e2017-04-09 16:34:54393 if (gesture_event.data.scroll_begin.pointer_count >= 2) {
mustaq16ce4602017-03-14 16:22:36394 // Any GestureScrollBegin with more than one fingers is like a pinch-zoom
395 // for touch-actions, see crbug.com/632525. Therefore, we switch to
396 // blocked-manipulation mode iff pinch-zoom is disallowed.
Henrique Ferreiro00e24f12019-12-17 01:14:48397 return (touch_action & cc::TouchAction::kPinchZoom) ==
398 cc::TouchAction::kNone;
dtapuska0e9eadf2016-09-27 15:14:10399 }
400
Blink Reformat1c4d759e2017-04-09 16:34:54401 const float& deltaXHint = gesture_event.data.scroll_begin.delta_x_hint;
402 const float& deltaYHint = gesture_event.data.scroll_begin.delta_y_hint;
mustaq4d73d6e2017-03-15 17:54:38403
404 if (deltaXHint == 0.0 && deltaYHint == 0.0)
[email protected]a18f67a2013-12-20 19:44:36405 return false;
dtapuska0e9eadf2016-09-27 15:14:10406
mustaq4d73d6e2017-03-15 17:54:38407 const float absDeltaXHint = fabs(deltaXHint);
408 const float absDeltaYHint = fabs(deltaYHint);
[email protected]a18f67a2013-12-20 19:44:36409
Mahesh Machavolu5cf127f2022-06-17 09:26:24410 // We need to wait for main-thread touch action to see if touch region is
411 // writable for stylus handwriting, and accumulate scroll events until then.
Mahesh Machavolu6cb80182022-07-22 08:09:31412 if ((gesture_event.primary_pointer_type ==
413 blink::WebPointerProperties::PointerType::kPen ||
414 gesture_event.primary_pointer_type ==
415 blink::WebPointerProperties::PointerType::kEraser) &&
Mahesh Machavolu5cf127f2022-06-17 09:26:24416 !is_active_touch_action &&
417 (touch_action & cc::TouchAction::kInternalNotWritable) !=
418 cc::TouchAction::kInternalNotWritable)
419 return true;
420
Henrique Ferreiro00e24f12019-12-17 01:14:48421 cc::TouchAction minimal_conforming_touch_action = cc::TouchAction::kNone;
Shimi Zhang9287e2cd2020-10-31 00:40:35422 if (absDeltaXHint > absDeltaYHint) {
423 // If we're performing a horizontal gesture over a region that could
424 // potentially activate cursor control, we need to wait for the real
425 // main-thread touch action before making a decision since we'll need to set
426 // the cursor control bit correctly.
427 if (!is_active_touch_action &&
428 (touch_action & cc::TouchAction::kInternalPanXScrolls) !=
429 cc::TouchAction::kInternalPanXScrolls)
430 return true;
431
mustaq4d73d6e2017-03-15 17:54:38432 if (deltaXHint > 0)
Henrique Ferreiro00e24f12019-12-17 01:14:48433 minimal_conforming_touch_action |= cc::TouchAction::kPanLeft;
mustaq4d73d6e2017-03-15 17:54:38434 else if (deltaXHint < 0)
Henrique Ferreiro00e24f12019-12-17 01:14:48435 minimal_conforming_touch_action |= cc::TouchAction::kPanRight;
Shimi Zhang9287e2cd2020-10-31 00:40:35436 } else {
mustaq4d73d6e2017-03-15 17:54:38437 if (deltaYHint > 0)
Henrique Ferreiro00e24f12019-12-17 01:14:48438 minimal_conforming_touch_action |= cc::TouchAction::kPanUp;
mustaq4d73d6e2017-03-15 17:54:38439 else if (deltaYHint < 0)
Henrique Ferreiro00e24f12019-12-17 01:14:48440 minimal_conforming_touch_action |= cc::TouchAction::kPanDown;
mustaq4d73d6e2017-03-15 17:54:38441 }
Henrique Ferreiro00e24f12019-12-17 01:14:48442 DCHECK(minimal_conforming_touch_action != cc::TouchAction::kNone);
mustaq4d73d6e2017-03-15 17:54:38443
Henrique Ferreiro00e24f12019-12-17 01:14:48444 return (touch_action & minimal_conforming_touch_action) ==
445 cc::TouchAction::kNone;
Xida Chen2eec314f2018-06-07 11:42:42446}
447
448void TouchActionFilter::OnHasTouchEventHandlers(bool has_handlers) {
David Bokand0c973dd2020-04-09 19:36:36449 TRACE_EVENT1("input", "TouchActionFilter::OnHasTouchEventHandlers",
450 "has handlers", has_handlers);
Xida Chen2eec314f2018-06-07 11:42:42451 // The has_touch_event_handler_ is default to false which is why we have the
452 // "&&" condition here, to ensure that touch actions will be set if there is
Sahir Vellani0e6d85552020-08-25 19:35:30453 // no touch event consumers.
Xida Chen2eec314f2018-06-07 11:42:42454 if (has_handlers && has_touch_event_handler_ == has_handlers)
455 return;
456 has_touch_event_handler_ = has_handlers;
Xida Chen3811c0a2018-08-29 20:01:50457 // We have set the associated touch action if the touch start already happened
458 // or there is a gesture in progress. In these cases, we should not reset the
459 // associated touch action.
Xida Chene1460a2f2018-11-02 15:30:20460 if (!gesture_sequence_in_progress_ && num_of_active_touches_ <= 0) {
Xida Chen3811c0a2018-08-29 20:01:50461 ResetTouchAction();
Xida Chenf164239c2018-11-13 01:59:04462 if (has_touch_event_handler_) {
Xida Chen06a04422018-10-30 05:35:30463 active_touch_action_.reset();
Xida Chenf164239c2018-11-13 01:59:04464 }
Xida Chen3811c0a2018-08-29 20:01:50465 }
Xida Chen2eec314f2018-06-07 11:42:42466}
467
Kartar Singhd084e582024-06-12 19:22:24468} // namespace input