summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/renderer_host/input/touch_action_filter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/renderer_host/input/touch_action_filter.cc')
-rw-r--r--chromium/content/browser/renderer_host/input/touch_action_filter.cc172
1 files changed, 153 insertions, 19 deletions
diff --git a/chromium/content/browser/renderer_host/input/touch_action_filter.cc b/chromium/content/browser/renderer_host/input/touch_action_filter.cc
index 665ff15bd30..53d47c4234c 100644
--- a/chromium/content/browser/renderer_host/input/touch_action_filter.cc
+++ b/chromium/content/browser/renderer_host/input/touch_action_filter.cc
@@ -4,6 +4,9 @@
#include "content/browser/renderer_host/input/touch_action_filter.h"
+#include <math.h>
+
+#include "base/logging.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
using blink::WebInputEvent;
@@ -13,31 +16,108 @@ namespace content {
TouchActionFilter::TouchActionFilter() :
drop_scroll_gesture_events_(false),
+ drop_pinch_gesture_events_(false),
+ drop_current_tap_ending_event_(false),
+ allow_current_double_tap_event_(true),
allowed_touch_action_(TOUCH_ACTION_AUTO) {
}
-bool TouchActionFilter::FilterGestureEvent(
- const WebGestureEvent& gesture_event) {
+bool TouchActionFilter::FilterGestureEvent(WebGestureEvent* gesture_event) {
// Filter for allowable touch actions first (eg. before the TouchEventQueue
// can decide to send a touch cancel event).
- // TODO(rbyers): Add touch-action control over for pinch. crbug.com/247566.
- switch(gesture_event.type) {
+ switch(gesture_event->type) {
case WebInputEvent::GestureScrollBegin:
- if (allowed_touch_action_ == TOUCH_ACTION_NONE)
- drop_scroll_gesture_events_ = true;
- // FALL THROUGH
+ DCHECK(!drop_scroll_gesture_events_);
+ drop_scroll_gesture_events_ = ShouldSuppressScroll(*gesture_event);
+ return drop_scroll_gesture_events_;
+
case WebInputEvent::GestureScrollUpdate:
if (drop_scroll_gesture_events_)
return true;
+ else {
+ if (allowed_touch_action_ == TOUCH_ACTION_PAN_X) {
+ gesture_event->data.scrollUpdate.deltaY = 0;
+ gesture_event->data.scrollUpdate.velocityY = 0;
+ } else if (allowed_touch_action_ == TOUCH_ACTION_PAN_Y) {
+ gesture_event->data.scrollUpdate.deltaX = 0;
+ gesture_event->data.scrollUpdate.velocityX = 0;
+ }
+ }
break;
- case WebInputEvent::GestureScrollEnd:
case WebInputEvent::GestureFlingStart:
- allowed_touch_action_ = content::TOUCH_ACTION_AUTO;
- if (drop_scroll_gesture_events_) {
- drop_scroll_gesture_events_ = false;
+ if (gesture_event->sourceDevice != blink::WebGestureDeviceTouchscreen)
+ break;
+ if (!drop_scroll_gesture_events_) {
+ if (allowed_touch_action_ == TOUCH_ACTION_PAN_X)
+ gesture_event->data.flingStart.velocityY = 0;
+ if (allowed_touch_action_ == TOUCH_ACTION_PAN_Y)
+ gesture_event->data.flingStart.velocityX = 0;
+ }
+ return FilterScrollEndingGesture();
+
+ case WebInputEvent::GestureScrollEnd:
+ return FilterScrollEndingGesture();
+
+ case WebInputEvent::GesturePinchBegin:
+ DCHECK(!drop_pinch_gesture_events_);
+ if (allowed_touch_action_ == TOUCH_ACTION_AUTO ||
+ allowed_touch_action_ & TOUCH_ACTION_PINCH_ZOOM) {
+ // Pinch events are always bracketed by scroll events, and the W3C
+ // standard touch-action provides no way to disable scrolling without
+ // also disabling pinching (validated by the IPC ENUM traits).
+ DCHECK(allowed_touch_action_ == TOUCH_ACTION_AUTO ||
+ allowed_touch_action_ == TOUCH_ACTION_MANIPULATION);
+ DCHECK(!drop_scroll_gesture_events_);
+ } else {
+ drop_pinch_gesture_events_ = true;
+ }
+ return drop_pinch_gesture_events_;
+
+ case WebInputEvent::GesturePinchUpdate:
+ return drop_pinch_gesture_events_;
+
+ case WebInputEvent::GesturePinchEnd:
+ if (drop_pinch_gesture_events_) {
+ drop_pinch_gesture_events_ = false;
return true;
}
+ DCHECK(!drop_scroll_gesture_events_);
+ break;
+
+ // The double tap gesture is a tap ending event. If a double tap gesture is
+ // filtered out, replace it with a tap event.
+ case WebInputEvent::GestureDoubleTap:
+ DCHECK_EQ(1, gesture_event->data.tap.tapCount);
+ if (!allow_current_double_tap_event_)
+ gesture_event->type = WebInputEvent::GestureTap;
+ allow_current_double_tap_event_ = true;
+ break;
+
+ // If double tap is disabled, there's no reason for the tap delay.
+ case WebInputEvent::GestureTapUnconfirmed:
+ DCHECK_EQ(1, gesture_event->data.tap.tapCount);
+ allow_current_double_tap_event_ =
+ allowed_touch_action_ == TOUCH_ACTION_AUTO;
+ if (!allow_current_double_tap_event_) {
+ gesture_event->type = WebInputEvent::GestureTap;
+ drop_current_tap_ending_event_ = true;
+ }
+ break;
+
+ case WebInputEvent::GestureTap:
+ allow_current_double_tap_event_ =
+ allowed_touch_action_ == TOUCH_ACTION_AUTO;
+ // Fall through.
+ case WebInputEvent::GestureTapCancel:
+ if (drop_current_tap_ending_event_) {
+ drop_current_tap_ending_event_ = false;
+ return true;
+ }
+ break;
+
+ case WebInputEvent::GestureTapDown:
+ DCHECK(!drop_current_tap_ending_event_);
break;
default:
@@ -49,15 +129,69 @@ bool TouchActionFilter::FilterGestureEvent(
return false;
}
-void TouchActionFilter::OnSetTouchAction(
- content::TouchAction touch_action) {
+bool TouchActionFilter::FilterScrollEndingGesture() {
+ DCHECK(!drop_pinch_gesture_events_);
+ if (drop_scroll_gesture_events_) {
+ drop_scroll_gesture_events_ = false;
+ return true;
+ }
+ return false;
+}
+
+void TouchActionFilter::OnSetTouchAction(TouchAction touch_action) {
// For multiple fingers, we take the intersection of the touch actions for
- // all fingers that have gone down during this action.
- // TODO(rbyers): What exact multi-finger semantic do we want? This is left
- // as implementation-defined in the pointer events specification.
- // crbug.com/247566.
- if (touch_action == content::TOUCH_ACTION_NONE)
- allowed_touch_action_ = content::TOUCH_ACTION_NONE;
+ // all fingers that have gone down during this action. In the majority of
+ // real-world scenarios the touch action for all fingers will be the same.
+ // This is left as implementation-defined in the pointer events
+ // specification because of the relationship to gestures (which are off
+ // limits for the spec). I believe the following are desirable properties
+ // of this choice:
+ // 1. Not sensitive to finger touch order. Behavior of putting two fingers
+ // down "at once" will be deterministic.
+ // 2. Only subtractive - eg. can't trigger scrolling on a element that
+ // otherwise has scrolling disabling by the addition of a finger.
+ allowed_touch_action_ = Intersect(allowed_touch_action_, touch_action);
+}
+
+void TouchActionFilter::ResetTouchAction() {
+ // Note that resetting the action mid-sequence is tolerated. Gestures that had
+ // their begin event(s) suppressed will be suppressed until the next sequence.
+ allowed_touch_action_ = TOUCH_ACTION_AUTO;
+}
+
+bool TouchActionFilter::ShouldSuppressScroll(
+ const blink::WebGestureEvent& gesture_event) {
+ DCHECK_EQ(gesture_event.type, WebInputEvent::GestureScrollBegin);
+ if (allowed_touch_action_ == TOUCH_ACTION_AUTO)
+ return false;
+ if (allowed_touch_action_ == TOUCH_ACTION_NONE)
+ return true;
+
+ // If there's no hint or it's perfectly diagonal, then allow the scroll.
+ if (fabs(gesture_event.data.scrollBegin.deltaXHint) ==
+ fabs(gesture_event.data.scrollBegin.deltaYHint))
+ return false;
+
+ // Determine the primary initial axis of the scroll, and check whether
+ // panning along that axis is permitted.
+ if (fabs(gesture_event.data.scrollBegin.deltaXHint) >
+ fabs(gesture_event.data.scrollBegin.deltaYHint))
+ return !(allowed_touch_action_ & TOUCH_ACTION_PAN_X);
+ return !(allowed_touch_action_ & TOUCH_ACTION_PAN_Y);
+}
+
+TouchAction TouchActionFilter::Intersect(TouchAction ta1, TouchAction ta2) {
+ if (ta1 == TOUCH_ACTION_NONE || ta2 == TOUCH_ACTION_NONE)
+ return TOUCH_ACTION_NONE;
+ if (ta1 == TOUCH_ACTION_AUTO)
+ return ta2;
+ if (ta2 == TOUCH_ACTION_AUTO)
+ return ta1;
+
+ // Only the true flags are left - take their intersection.
+ if (!(ta1 & ta2))
+ return TOUCH_ACTION_NONE;
+ return static_cast<TouchAction>(ta1 & ta2);
}
}