1 // Copyright 2014 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 "ui/events/gesture_detection/touch_disposition_gesture_filter.h" 6 7 #include "base/auto_reset.h" 8 #include "base/logging.h" 9 #include "ui/events/gesture_event_details.h" 10 11 namespace ui { 12 namespace { 13 14 // A BitSet32 is used for tracking dropped gesture types. 15 COMPILE_ASSERT(ET_GESTURE_TYPE_END - ET_GESTURE_TYPE_START < 32, 16 gesture_type_count_too_large); 17 18 GestureEventData CreateGesture(EventType type, 19 int motion_event_id, 20 MotionEvent::ToolType primary_tool_type, 21 const GestureEventDataPacket& packet) { 22 // As the event is purely synthetic, we needn't be strict with event flags. 23 int flags = EF_NONE; 24 return GestureEventData(GestureEventDetails(type), 25 motion_event_id, 26 primary_tool_type, 27 packet.timestamp(), 28 packet.touch_location().x(), 29 packet.touch_location().y(), 30 packet.raw_touch_location().x(), 31 packet.raw_touch_location().y(), 32 1, 33 gfx::RectF(packet.touch_location(), gfx::SizeF()), 34 flags); 35 } 36 37 enum RequiredTouches { 38 RT_NONE = 0, 39 RT_START = 1 << 0, 40 RT_CURRENT = 1 << 1, 41 }; 42 43 struct DispositionHandlingInfo { 44 // A bitwise-OR of |RequiredTouches|. 45 int required_touches; 46 EventType antecedent_event_type; 47 48 explicit DispositionHandlingInfo(int required_touches) 49 : required_touches(required_touches), antecedent_event_type(ET_UNKNOWN) {} 50 51 DispositionHandlingInfo(int required_touches, 52 EventType antecedent_event_type) 53 : required_touches(required_touches), 54 antecedent_event_type(antecedent_event_type) {} 55 }; 56 57 DispositionHandlingInfo Info(int required_touches) { 58 return DispositionHandlingInfo(required_touches); 59 } 60 61 DispositionHandlingInfo Info(int required_touches, 62 EventType antecedent_event_type) { 63 return DispositionHandlingInfo(required_touches, antecedent_event_type); 64 } 65 66 // This approach to disposition handling is described at http://goo.gl/5G8PWJ. 67 DispositionHandlingInfo GetDispositionHandlingInfo(EventType type) { 68 switch (type) { 69 case ET_GESTURE_TAP_DOWN: 70 return Info(RT_START); 71 case ET_GESTURE_TAP_CANCEL: 72 return Info(RT_START); 73 case ET_GESTURE_SHOW_PRESS: 74 return Info(RT_START); 75 case ET_GESTURE_LONG_PRESS: 76 return Info(RT_START); 77 case ET_GESTURE_LONG_TAP: 78 return Info(RT_START | RT_CURRENT); 79 case ET_GESTURE_TAP: 80 return Info(RT_START | RT_CURRENT, ET_GESTURE_TAP_UNCONFIRMED); 81 case ET_GESTURE_TAP_UNCONFIRMED: 82 return Info(RT_START | RT_CURRENT); 83 case ET_GESTURE_DOUBLE_TAP: 84 return Info(RT_START | RT_CURRENT, ET_GESTURE_TAP_UNCONFIRMED); 85 case ET_GESTURE_SCROLL_BEGIN: 86 return Info(RT_START); 87 case ET_GESTURE_SCROLL_UPDATE: 88 return Info(RT_CURRENT, ET_GESTURE_SCROLL_BEGIN); 89 case ET_GESTURE_SCROLL_END: 90 return Info(RT_NONE, ET_GESTURE_SCROLL_BEGIN); 91 case ET_SCROLL_FLING_START: 92 // We rely on |EndScrollGestureIfNecessary| to end the scroll if the fling 93 // start is prevented. 94 return Info(RT_NONE, ET_GESTURE_SCROLL_UPDATE); 95 case ET_SCROLL_FLING_CANCEL: 96 return Info(RT_NONE, ET_SCROLL_FLING_START); 97 case ET_GESTURE_PINCH_BEGIN: 98 return Info(RT_START, ET_GESTURE_SCROLL_BEGIN); 99 case ET_GESTURE_PINCH_UPDATE: 100 return Info(RT_CURRENT, ET_GESTURE_PINCH_BEGIN); 101 case ET_GESTURE_PINCH_END: 102 return Info(RT_NONE, ET_GESTURE_PINCH_BEGIN); 103 case ET_GESTURE_BEGIN: 104 return Info(RT_START); 105 case ET_GESTURE_END: 106 return Info(RT_NONE, ET_GESTURE_BEGIN); 107 case ET_GESTURE_SWIPE: 108 return Info(RT_START, ET_GESTURE_SCROLL_BEGIN); 109 case ET_GESTURE_TWO_FINGER_TAP: 110 return Info(RT_START); 111 default: 112 break; 113 } 114 NOTREACHED(); 115 return Info(RT_NONE); 116 } 117 118 int GetGestureTypeIndex(EventType type) { 119 DCHECK_GE(type, ET_GESTURE_TYPE_START); 120 DCHECK_LE(type, ET_GESTURE_TYPE_END); 121 return type - ET_GESTURE_TYPE_START; 122 } 123 124 bool IsTouchStartEvent(GestureEventDataPacket::GestureSource gesture_source) { 125 return gesture_source == GestureEventDataPacket::TOUCH_SEQUENCE_START || 126 gesture_source == GestureEventDataPacket::TOUCH_START; 127 } 128 129 } // namespace 130 131 // TouchDispositionGestureFilter 132 133 TouchDispositionGestureFilter::TouchDispositionGestureFilter( 134 TouchDispositionGestureFilterClient* client) 135 : client_(client), 136 ending_event_motion_event_id_(0), 137 ending_event_primary_tool_type_(MotionEvent::TOOL_TYPE_UNKNOWN), 138 needs_tap_ending_event_(false), 139 needs_show_press_event_(false), 140 needs_fling_ending_event_(false), 141 needs_scroll_ending_event_(false) { 142 DCHECK(client_); 143 } 144 145 TouchDispositionGestureFilter::~TouchDispositionGestureFilter() { 146 } 147 148 TouchDispositionGestureFilter::PacketResult 149 TouchDispositionGestureFilter::OnGesturePacket( 150 const GestureEventDataPacket& packet) { 151 if (packet.gesture_source() == GestureEventDataPacket::UNDEFINED || 152 packet.gesture_source() == GestureEventDataPacket::INVALID) 153 return INVALID_PACKET_TYPE; 154 155 if (packet.gesture_source() == GestureEventDataPacket::TOUCH_SEQUENCE_START) 156 sequences_.push(GestureSequence()); 157 158 if (IsEmpty()) 159 return INVALID_PACKET_ORDER; 160 161 if (packet.gesture_source() == GestureEventDataPacket::TOUCH_TIMEOUT && 162 Tail().empty()) { 163 // Handle the timeout packet immediately if the packet preceding the timeout 164 // has already been dispatched. 165 FilterAndSendPacket(packet); 166 return SUCCESS; 167 } 168 169 Tail().push(packet); 170 return SUCCESS; 171 } 172 173 void TouchDispositionGestureFilter::OnTouchEventAck(bool event_consumed) { 174 // Spurious touch acks from the renderer should not trigger a crash. 175 if (IsEmpty() || (Head().empty() && sequences_.size() == 1)) 176 return; 177 178 if (Head().empty()) 179 PopGestureSequence(); 180 181 GestureSequence& sequence = Head(); 182 183 // Dispatch the packet corresponding to the ack'ed touch, as well as any 184 // additional timeout-based packets queued before the ack was received. 185 bool touch_packet_for_current_ack_handled = false; 186 while (!sequence.empty()) { 187 DCHECK_NE(sequence.front().gesture_source(), 188 GestureEventDataPacket::UNDEFINED); 189 DCHECK_NE(sequence.front().gesture_source(), 190 GestureEventDataPacket::INVALID); 191 192 GestureEventDataPacket::GestureSource source = 193 sequence.front().gesture_source(); 194 if (source != GestureEventDataPacket::TOUCH_TIMEOUT) { 195 // We should handle at most one non-timeout based packet. 196 if (touch_packet_for_current_ack_handled) 197 break; 198 state_.OnTouchEventAck(event_consumed, IsTouchStartEvent(source)); 199 touch_packet_for_current_ack_handled = true; 200 } 201 // We need to pop the current sequence before sending the packet, because 202 // sending the packet could result in this method being re-entered (e.g. on 203 // Aura, we could trigger a touch-cancel). As popping the sequence destroys 204 // the packet, we copy the packet before popping it. 205 const GestureEventDataPacket packet = sequence.front(); 206 sequence.pop(); 207 FilterAndSendPacket(packet); 208 } 209 DCHECK(touch_packet_for_current_ack_handled); 210 } 211 212 bool TouchDispositionGestureFilter::IsEmpty() const { 213 return sequences_.empty(); 214 } 215 216 void TouchDispositionGestureFilter::FilterAndSendPacket( 217 const GestureEventDataPacket& packet) { 218 if (packet.gesture_source() == GestureEventDataPacket::TOUCH_SEQUENCE_START) { 219 CancelTapIfNecessary(packet); 220 EndScrollIfNecessary(packet); 221 CancelFlingIfNecessary(packet); 222 } else if (packet.gesture_source() == GestureEventDataPacket::TOUCH_START) { 223 CancelTapIfNecessary(packet); 224 } 225 int gesture_end_index = -1; 226 for (size_t i = 0; i < packet.gesture_count(); ++i) { 227 const GestureEventData& gesture = packet.gesture(i); 228 DCHECK_GE(gesture.details.type(), ET_GESTURE_TYPE_START); 229 DCHECK_LE(gesture.details.type(), ET_GESTURE_TYPE_END); 230 if (state_.Filter(gesture.details.type())) { 231 CancelTapIfNecessary(packet); 232 continue; 233 } 234 if (packet.gesture_source() == GestureEventDataPacket::TOUCH_TIMEOUT) { 235 // Sending a timed gesture could delete |this|, so we need to return 236 // directly after the |SendGesture| call. 237 SendGesture(gesture, packet); 238 // We should not have a timeout gesture and other gestures in the same 239 // packet. 240 DCHECK_EQ(1U, packet.gesture_count()); 241 return; 242 } 243 // Occasionally scroll or tap cancel events are synthesized when a touch 244 // sequence has been canceled or terminated, we want to make sure that 245 // ET_GESTURE_END always happens after them. 246 if (gesture.type() == ET_GESTURE_END) { 247 // Make sure there is at most one ET_GESTURE_END event in each packet. 248 DCHECK_EQ(-1, gesture_end_index); 249 gesture_end_index = static_cast<int>(i); 250 continue; 251 } 252 SendGesture(gesture, packet); 253 } 254 255 if (packet.gesture_source() == 256 GestureEventDataPacket::TOUCH_SEQUENCE_CANCEL) { 257 EndScrollIfNecessary(packet); 258 CancelTapIfNecessary(packet); 259 } else if (packet.gesture_source() == 260 GestureEventDataPacket::TOUCH_SEQUENCE_END) { 261 EndScrollIfNecessary(packet); 262 } 263 // Always send the ET_GESTURE_END event as the last one for every touch event. 264 if (gesture_end_index >= 0) 265 SendGesture(packet.gesture(gesture_end_index), packet); 266 } 267 268 void TouchDispositionGestureFilter::SendGesture( 269 const GestureEventData& event, 270 const GestureEventDataPacket& packet_being_sent) { 271 // TODO(jdduke): Factor out gesture stream reparation code into a standalone 272 // utility class. 273 switch (event.type()) { 274 case ET_GESTURE_LONG_TAP: 275 if (!needs_tap_ending_event_) 276 return; 277 CancelTapIfNecessary(packet_being_sent); 278 CancelFlingIfNecessary(packet_being_sent); 279 break; 280 case ET_GESTURE_TAP_DOWN: 281 DCHECK(!needs_tap_ending_event_); 282 ending_event_motion_event_id_ = event.motion_event_id; 283 ending_event_primary_tool_type_ = event.primary_tool_type; 284 needs_show_press_event_ = true; 285 needs_tap_ending_event_ = true; 286 break; 287 case ET_GESTURE_SHOW_PRESS: 288 if (!needs_show_press_event_) 289 return; 290 needs_show_press_event_ = false; 291 break; 292 case ET_GESTURE_DOUBLE_TAP: 293 CancelTapIfNecessary(packet_being_sent); 294 needs_show_press_event_ = false; 295 break; 296 case ET_GESTURE_TAP: 297 DCHECK(needs_tap_ending_event_); 298 if (needs_show_press_event_) { 299 SendGesture(GestureEventData(ET_GESTURE_SHOW_PRESS, event), 300 packet_being_sent); 301 DCHECK(!needs_show_press_event_); 302 } 303 needs_tap_ending_event_ = false; 304 break; 305 case ET_GESTURE_TAP_CANCEL: 306 needs_show_press_event_ = false; 307 needs_tap_ending_event_ = false; 308 break; 309 case ET_GESTURE_SCROLL_BEGIN: 310 CancelTapIfNecessary(packet_being_sent); 311 CancelFlingIfNecessary(packet_being_sent); 312 EndScrollIfNecessary(packet_being_sent); 313 ending_event_motion_event_id_ = event.motion_event_id; 314 ending_event_primary_tool_type_ = event.primary_tool_type; 315 needs_scroll_ending_event_ = true; 316 break; 317 case ET_GESTURE_SCROLL_END: 318 needs_scroll_ending_event_ = false; 319 break; 320 case ET_SCROLL_FLING_START: 321 CancelFlingIfNecessary(packet_being_sent); 322 ending_event_motion_event_id_ = event.motion_event_id; 323 ending_event_primary_tool_type_ = event.primary_tool_type; 324 needs_fling_ending_event_ = true; 325 needs_scroll_ending_event_ = false; 326 break; 327 case ET_SCROLL_FLING_CANCEL: 328 needs_fling_ending_event_ = false; 329 break; 330 default: 331 break; 332 } 333 client_->ForwardGestureEvent(event); 334 } 335 336 void TouchDispositionGestureFilter::CancelTapIfNecessary( 337 const GestureEventDataPacket& packet_being_sent) { 338 if (!needs_tap_ending_event_) 339 return; 340 341 SendGesture(CreateGesture(ET_GESTURE_TAP_CANCEL, 342 ending_event_motion_event_id_, 343 ending_event_primary_tool_type_, 344 packet_being_sent), 345 packet_being_sent); 346 DCHECK(!needs_tap_ending_event_); 347 } 348 349 void TouchDispositionGestureFilter::CancelFlingIfNecessary( 350 const GestureEventDataPacket& packet_being_sent) { 351 if (!needs_fling_ending_event_) 352 return; 353 354 SendGesture(CreateGesture(ET_SCROLL_FLING_CANCEL, 355 ending_event_motion_event_id_, 356 ending_event_primary_tool_type_, 357 packet_being_sent), 358 packet_being_sent); 359 DCHECK(!needs_fling_ending_event_); 360 } 361 362 void TouchDispositionGestureFilter::EndScrollIfNecessary( 363 const GestureEventDataPacket& packet_being_sent) { 364 if (!needs_scroll_ending_event_) 365 return; 366 367 SendGesture(CreateGesture(ET_GESTURE_SCROLL_END, 368 ending_event_motion_event_id_, 369 ending_event_primary_tool_type_, 370 packet_being_sent), 371 packet_being_sent); 372 DCHECK(!needs_scroll_ending_event_); 373 } 374 375 void TouchDispositionGestureFilter::PopGestureSequence() { 376 DCHECK(Head().empty()); 377 state_ = GestureHandlingState(); 378 sequences_.pop(); 379 } 380 381 TouchDispositionGestureFilter::GestureSequence& 382 TouchDispositionGestureFilter::Head() { 383 DCHECK(!sequences_.empty()); 384 return sequences_.front(); 385 } 386 387 TouchDispositionGestureFilter::GestureSequence& 388 TouchDispositionGestureFilter::Tail() { 389 DCHECK(!sequences_.empty()); 390 return sequences_.back(); 391 } 392 393 // TouchDispositionGestureFilter::GestureHandlingState 394 395 TouchDispositionGestureFilter::GestureHandlingState::GestureHandlingState() 396 : start_touch_consumed_(false), 397 current_touch_consumed_(false) {} 398 399 void TouchDispositionGestureFilter::GestureHandlingState::OnTouchEventAck( 400 bool event_consumed, 401 bool is_touch_start_event) { 402 current_touch_consumed_ = event_consumed; 403 if (event_consumed && is_touch_start_event) 404 start_touch_consumed_ = true; 405 } 406 407 bool TouchDispositionGestureFilter::GestureHandlingState::Filter( 408 EventType gesture_type) { 409 DispositionHandlingInfo disposition_handling_info = 410 GetDispositionHandlingInfo(gesture_type); 411 412 int required_touches = disposition_handling_info.required_touches; 413 EventType antecedent_event_type = 414 disposition_handling_info.antecedent_event_type; 415 if ((required_touches & RT_START && start_touch_consumed_) || 416 (required_touches & RT_CURRENT && current_touch_consumed_) || 417 (antecedent_event_type != ET_UNKNOWN && 418 last_gesture_of_type_dropped_.has_bit( 419 GetGestureTypeIndex(antecedent_event_type)))) { 420 last_gesture_of_type_dropped_.mark_bit(GetGestureTypeIndex(gesture_type)); 421 return true; 422 } 423 last_gesture_of_type_dropped_.clear_bit(GetGestureTypeIndex(gesture_type)); 424 return false; 425 } 426 427 } // namespace content 428