Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1011)

Unified Diff: content/browser/renderer_host/input/touch_event_queue.cc

Issue 23856016: Send touch cancel to renderer when scrolling starts (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fix the issue that TouchCancel may never be sent Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/input/touch_event_queue.cc
diff --git a/content/browser/renderer_host/input/touch_event_queue.cc b/content/browser/renderer_host/input/touch_event_queue.cc
index 9d0394ef162d034a0f43ebe90cb34969011867de..dfa4916d92ca88d0f54cdfe8f76b13c72e168eba 100644
--- a/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/content/browser/renderer_host/input/touch_event_queue.cc
@@ -20,7 +20,9 @@ typedef std::vector<TouchEventWithLatencyInfo> WebTouchEventWithLatencyList;
class CoalescedWebTouchEvent {
public:
explicit CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event)
- : coalesced_event_(event) {
+ : coalesced_event_(event),
+ ignore_ack_(false),
+ has_been_sent_to_renderer_(false) {
events_.push_back(event);
TRACE_EVENT_ASYNC_BEGIN0(
"input", "TouchEventQueue::QueueEvent", this);
@@ -79,6 +81,14 @@ class CoalescedWebTouchEvent {
size_t size() const { return events_.size(); }
+ bool ignore_ack() const { return ignore_ack_; }
+ void set_ignore_ack(bool value) { ignore_ack_ = value; }
+
+ bool has_been_sent_to_renderer() const { return has_been_sent_to_renderer_; }
+ void set_has_been_sent_to_renderer(bool value) {
+ has_been_sent_to_renderer_ = value;
+ }
+
private:
// This is the event that is forwarded to the renderer.
TouchEventWithLatencyInfo coalesced_event_;
@@ -86,13 +96,20 @@ class CoalescedWebTouchEvent {
// This is the list of the original events that were coalesced.
WebTouchEventWithLatencyList events_;
+ // If |ignore_ack_| is true, don't send this touch event to client
+ // when the event is acked.
+ bool ignore_ack_;
+
+ // Whether the touch event has been sent to renderer.
+ bool has_been_sent_to_renderer_;
+
DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent);
};
TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client)
: client_(client),
- dispatching_touch_ack_(false),
- no_touch_move_to_renderer_(false) {
+ dispatching_touch_ack_(NULL),
+ no_touch_to_renderer_(false) {
DCHECK(client);
}
@@ -158,8 +175,11 @@ void TouchEventQueue::TryForwardNextEventToRenderer() {
while (!touch_queue_.empty()) {
const TouchEventWithLatencyInfo& touch =
touch_queue_.front()->coalesced_event();
+ if (touch_queue_.front()->has_been_sent_to_renderer())
jdduke (slow) 2013/09/30 19:21:51 You can remove this flag (or make it a DCHECK(!...
Yufeng Shen (Slow to review) 2013/09/30 20:43:14 removed.
+ break;
if (ShouldForwardToRenderer(touch.event)) {
client_->SendTouchEventImmediately(touch);
+ touch_queue_.front()->set_has_been_sent_to_renderer(true);
break;
}
PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
@@ -167,6 +187,50 @@ void TouchEventQueue::TryForwardNextEventToRenderer() {
}
}
+void TouchEventQueue::OnGestureScrollEvent(
+ const GestureEventWithLatencyInfo& gesture_event) {
+ WebKit::WebInputEvent::Type type = gesture_event.event.type;
+ if (type == WebKit::WebInputEvent::GestureScrollBegin) {
+ // We assume the scroll event are generated synchronously from
+ // dispatching a touch event ack, so that we can fake a cancel
+ // event that has the correct touch ids as the touch event that
+ // is being acked. If not, we don't do the touch-cancel optimization.
+ if (no_touch_to_renderer_ || !dispatching_touch_ack_)
+ return;
+ no_touch_to_renderer_ = true;
+ // Fake a TouchCancel to cancel the touch points of the touch event
+ // that is currently being acked.
+ TouchEventWithLatencyInfo cancel_event =
+ dispatching_touch_ack_->coalesced_event();
+ cancel_event.event.type = WebKit::WebInputEvent::TouchCancel;
+ for (size_t i = 0; i < cancel_event.event.touchesLength; i++)
+ cancel_event.event.touches[i].state =
+ WebKit::WebTouchPoint::StateCancelled;
+ CoalescedWebTouchEvent* coalesced_cancel_event =
+ new CoalescedWebTouchEvent(cancel_event);
+ // Ignore the ack of the touch cancel so when it is acked, it won't get
+ // sent to gesture recognizer.
+ coalesced_cancel_event->set_ignore_ack(true);
+ // If the touch event queue is empty, or the first touch event in the queue
+ // has not been sent to renderer (i.e. not waiting for ack), we insert the
+ // touch cancel at the beginning of the queue to be the first to send.
+ if (touch_queue_.empty() ||
+ !touch_queue_.front()->has_been_sent_to_renderer()) {
+ touch_queue_.push_front(coalesced_cancel_event);
+ } else {
+ // If there there is touch event already sent to the renderer and waiting
+ // for ack, we insert the touch cancel after that touch event.
sadrul 2013/09/27 15:13:51 + "This cancel event will be dispatched to the ren
Yufeng Shen (Slow to review) 2013/09/30 20:43:14 see the comments below.
+ TouchQueue::iterator it = touch_queue_.begin();
+ it++;
+ touch_queue_.insert(it, coalesced_cancel_event);
+ }
+ TryForwardNextEventToRenderer();
jdduke (slow) 2013/09/30 19:21:51 I believe you can remove this call. |dispatching_
sadrul 2013/09/30 20:33:24 Client::OnTouchEventAck can cause another touch-ev
Yufeng Shen (Slow to review) 2013/09/30 20:43:14 Right. So all the complication comes from that I w
sadrul 2013/10/01 11:32:45 Thanks for the detailed explanation. This makes se
+ } else if (type == WebKit::WebInputEvent::GestureScrollEnd ||
+ type == WebKit::WebInputEvent::GestureFlingStart) {
+ no_touch_to_renderer_ = false;
+ }
+}
+
void TouchEventQueue::FlushQueue() {
DCHECK(!dispatching_touch_ack_);
while (!touch_queue_.empty())
@@ -190,9 +254,13 @@ void TouchEventQueue::PopTouchEventToClient(
scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front());
touch_queue_.pop_front();
+ if (acked_event->ignore_ack())
+ return;
+
// Note that acking the touch-event may result in multiple gestures being sent
// to the renderer, or touch-events being queued.
- base::AutoReset<bool> dispatching_touch_ack(&dispatching_touch_ack_, true);
+ base::AutoReset<CoalescedWebTouchEvent*>
+ dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get());
sadrul 2013/09/27 15:13:51 Hm, this would only work if the acked touch-event
jdduke (slow) 2013/09/30 19:21:51 Yup, that's generally the case on Android, and oth
base::TimeTicks now = base::TimeTicks::HighResNow();
for (WebTouchEventWithLatencyList::const_iterator iter = acked_event->begin(),
@@ -208,14 +276,14 @@ void TouchEventQueue::PopTouchEventToClient(
bool TouchEventQueue::ShouldForwardToRenderer(
const WebKit::WebTouchEvent& event) const {
+ if (no_touch_to_renderer_ &&
+ event.type != WebKit::WebInputEvent::TouchCancel)
+ return false;
+
// Touch press events should always be forwarded to the renderer.
if (event.type == WebKit::WebInputEvent::TouchStart)
return true;
- if (event.type == WebKit::WebInputEvent::TouchMove &&
- no_touch_move_to_renderer_)
- return false;
-
for (unsigned int i = 0; i < event.touchesLength; ++i) {
const WebKit::WebTouchPoint& point = event.touches[i];
// If a point has been stationary, then don't take it into account.

Powered by Google App Engine
This is Rietveld 408576698