| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013 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/input/buffered_input_router.h" |
| 6 |
| 7 #include "base/auto_reset.h" |
| 8 #include "content/browser/renderer_host/input/browser_input_event.h" |
| 9 #include "content/browser/renderer_host/input/input_ack_handler.h" |
| 10 #include "content/browser/renderer_host/input/input_queue.h" |
| 11 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| 12 #include "content/common/input_messages.h" |
| 13 #include "content/common/view_messages.h" |
| 14 #include "content/public/browser/native_web_keyboard_event.h" |
| 15 #include "content/public/browser/user_metrics.h" |
| 16 |
| 17 using WebKit::WebGestureEvent; |
| 18 using WebKit::WebInputEvent; |
| 19 using WebKit::WebKeyboardEvent; |
| 20 using WebKit::WebMouseEvent; |
| 21 using WebKit::WebMouseWheelEvent; |
| 22 using WebKit::WebTouchEvent; |
| 23 |
| 24 namespace content { |
| 25 |
| 26 BufferedInputRouter::BufferedInputRouter(IPC::Sender* sender, |
| 27 InputRouterClient* client, |
| 28 InputAckHandler* ack_handler, |
| 29 int routing_id) |
| 30 : client_(client), |
| 31 ack_handler_(ack_handler), |
| 32 sender_(sender), |
| 33 routing_id_(routing_id), |
| 34 queued_gesture_count_(0), |
| 35 has_touch_handler_(false), |
| 36 queued_touch_count_(0), |
| 37 input_queue_override_(NULL), |
| 38 next_input_id_(1), |
| 39 in_flight_packet_id_(0) { |
| 40 input_queue_.reset(new InputQueue(this)); |
| 41 } |
| 42 |
| 43 BufferedInputRouter::~BufferedInputRouter() {} |
| 44 |
| 45 void BufferedInputRouter::Flush() { |
| 46 TRACE_EVENT0("input", "BufferedInputRouter::Flush"); |
| 47 DCHECK_EQ(0, in_flight_packet_id_); |
| 48 input_queue_->BeginFlush(); |
| 49 } |
| 50 |
| 51 bool BufferedInputRouter::SendInput(scoped_ptr<IPC::Message> message) { |
| 52 DCHECK_EQ(InputMsgStart, IPC_MESSAGE_ID_CLASS(message->type())); |
| 53 DCHECK_NE(InputMsg_HandleEventPacket::ID, message->type()); |
| 54 input_queue_->QueueEvent( |
| 55 BrowserInputEvent::Create(NextInputID(), |
| 56 IPCInputEventPayload::Create(message.Pass()), |
| 57 NULL)); |
| 58 return true; |
| 59 } |
| 60 |
| 61 void BufferedInputRouter::SendMouseEvent( |
| 62 const MouseEventWithLatencyInfo& mouse_event) { |
| 63 if (!client_->OnSendMouseEvent(mouse_event)) |
| 64 return; |
| 65 QueueWebEvent(mouse_event.event, mouse_event.latency, false, false); |
| 66 } |
| 67 |
| 68 void BufferedInputRouter::SendWheelEvent( |
| 69 const MouseWheelEventWithLatencyInfo& wheel_event) { |
| 70 if (!client_->OnSendWheelEvent(wheel_event)) |
| 71 return; |
| 72 QueueWebEvent(wheel_event.event, wheel_event.latency, false, false); |
| 73 } |
| 74 |
| 75 void BufferedInputRouter::SendKeyboardEvent( |
| 76 const NativeWebKeyboardEvent& key_event, |
| 77 const ui::LatencyInfo& latency_info) { |
| 78 bool is_shortcut = false; |
| 79 if (!client_->OnSendKeyboardEvent(key_event, latency_info, &is_shortcut)) |
| 80 return; |
| 81 int64 event_id = QueueWebEvent(key_event, latency_info, is_shortcut, false); |
| 82 if (event_id) { |
| 83 DCHECK(queued_key_map_.find(event_id) == queued_key_map_.end()); |
| 84 queued_key_map_[event_id] = key_event; |
| 85 } |
| 86 } |
| 87 |
| 88 void BufferedInputRouter::SendGestureEvent( |
| 89 const GestureEventWithLatencyInfo& gesture_event) { |
| 90 if (!client_->OnSendGestureEvent(gesture_event)) |
| 91 return; |
| 92 if (QueueWebEvent(gesture_event.event, gesture_event.latency, false, false)) |
| 93 ++queued_gesture_count_; |
| 94 } |
| 95 |
| 96 void BufferedInputRouter::SendTouchEvent( |
| 97 const TouchEventWithLatencyInfo& touch_event) { |
| 98 if (!client_->OnSendTouchEvent(touch_event)) |
| 99 return; |
| 100 if (QueueWebEvent(touch_event.event, touch_event.latency, false, true)) |
| 101 ++queued_touch_count_; |
| 102 } |
| 103 |
| 104 void BufferedInputRouter::SendMouseEventImmediately( |
| 105 const MouseEventWithLatencyInfo& mouse_event) { |
| 106 if (!client_->OnSendMouseEventImmediately(mouse_event)) |
| 107 return; |
| 108 QueueWebEvent(mouse_event.event, mouse_event.latency, false, false); |
| 109 } |
| 110 |
| 111 void BufferedInputRouter::SendTouchEventImmediately( |
| 112 const TouchEventWithLatencyInfo& touch_event) { |
| 113 if (!client_->OnSendTouchEventImmediately(touch_event)) |
| 114 return; |
| 115 QueueWebEvent(touch_event.event, touch_event.latency, false, false); |
| 116 } |
| 117 |
| 118 void BufferedInputRouter::SendGestureEventImmediately( |
| 119 const GestureEventWithLatencyInfo& gesture_event) { |
| 120 if (!client_->OnSendGestureEventImmediately(gesture_event)) |
| 121 return; |
| 122 QueueWebEvent(gesture_event.event, gesture_event.latency, false, false); |
| 123 } |
| 124 |
| 125 void BufferedInputRouter::Deliver(const EventPacket& packet) { |
| 126 TRACE_EVENT2("input", "BufferedInputRouter::DeliverPacket", |
| 127 "id", packet.id(), |
| 128 "events", packet.size()); |
| 129 DCHECK(packet.id()); |
| 130 DCHECK(!in_flight_packet_id_); |
| 131 if (!sender_->Send( |
| 132 new InputMsg_HandleEventPacket(routing_id_, |
| 133 packet, |
| 134 InputEventDispositions()))) { |
| 135 return; |
| 136 } |
| 137 |
| 138 in_flight_packet_id_ = packet.id(); |
| 139 client_->IncrementInFlightEventCount(); |
| 140 } |
| 141 |
| 142 void BufferedInputRouter::DidFinishFlush() { |
| 143 TRACE_EVENT0("input", "BufferedInputRouter::DidFinishFlush"); |
| 144 client_->DidFlush(); |
| 145 } |
| 146 |
| 147 void BufferedInputRouter::SetNeedsFlush() { |
| 148 TRACE_EVENT0("input", "BufferedInputRouter::SetNeedsFlush"); |
| 149 client_->SetNeedsFlush(); |
| 150 } |
| 151 |
| 152 void BufferedInputRouter::OnDispatched(const BrowserInputEvent& event, |
| 153 InputEventDisposition disposition) { |
| 154 // Only WebInputEvents currently have ack response. |
| 155 if (event.payload()->GetType() != InputEvent::Payload::WEB_INPUT_EVENT) |
| 156 return; |
| 157 |
| 158 const WebInputEventPayload* web_payload = |
| 159 WebInputEventPayload::Cast(event.payload()); |
| 160 |
| 161 OnWebInputEventAck(event.id(), |
| 162 *web_payload->web_event(), |
| 163 web_payload->latency_info(), |
| 164 ToAckState(disposition), |
| 165 true); |
| 166 } |
| 167 |
| 168 void BufferedInputRouter::OnDispatched( |
| 169 const BrowserInputEvent& event, |
| 170 InputEventDisposition disposition, |
| 171 ScopedVector<BrowserInputEvent>* followup) { |
| 172 DCHECK(followup); |
| 173 DCHECK_NE(INPUT_EVENT_ACK_STATE_CONSUMED, ToAckState(disposition)); |
| 174 |
| 175 // Events sent to the router within this scope will be added to |followup|. |
| 176 base::AutoReset<ScopedVector<BrowserInputEvent>*> input_queue_override( |
| 177 &input_queue_override_, followup); |
| 178 |
| 179 OnDispatched(event, disposition); |
| 180 } |
| 181 |
| 182 bool BufferedInputRouter::OnMessageReceived(const IPC::Message& message) { |
| 183 bool handled = true; |
| 184 bool message_is_ok = true; |
| 185 IPC_BEGIN_MESSAGE_MAP_EX(BufferedInputRouter, message, message_is_ok) |
| 186 IPC_MESSAGE_HANDLER(InputHostMsg_HandleEventPacket_ACK, OnEventPacketAck) |
| 187 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers, |
| 188 OnHasTouchEventHandlers) |
| 189 IPC_MESSAGE_UNHANDLED(handled = false) |
| 190 IPC_END_MESSAGE_MAP() |
| 191 |
| 192 if (!message_is_ok) |
| 193 ack_handler_->OnUnexpectedEventAck(true); |
| 194 |
| 195 return handled; |
| 196 } |
| 197 |
| 198 const NativeWebKeyboardEvent* |
| 199 BufferedInputRouter::GetLastKeyboardEvent() const { |
| 200 return queued_key_map_.empty() ? NULL : &queued_key_map_.begin()->second; |
| 201 } |
| 202 |
| 203 bool BufferedInputRouter::ShouldForwardTouchEvent() const { |
| 204 return has_touch_handler_ && queued_touch_count_ > 0; |
| 205 } |
| 206 |
| 207 bool BufferedInputRouter::ShouldForwardGestureEvent( |
| 208 const GestureEventWithLatencyInfo& touch_event) const { |
| 209 return true; |
| 210 } |
| 211 |
| 212 bool BufferedInputRouter::HasQueuedGestureEvents() const { |
| 213 return queued_gesture_count_ > 0; |
| 214 } |
| 215 |
| 216 void BufferedInputRouter::OnWebInputEventAck( |
| 217 int64 event_id, |
| 218 const WebKit::WebInputEvent& web_event, |
| 219 const ui::LatencyInfo& latency_info, |
| 220 InputEventAckState acked_result, |
| 221 bool ack_from_input_queue) { |
| 222 if (WebInputEvent::isKeyboardEventType(web_event.type)) { |
| 223 if (ack_from_input_queue) { |
| 224 KeyMap::iterator key_it = queued_key_map_.find(event_id); |
| 225 DCHECK(key_it != queued_key_map_.end()); |
| 226 NativeWebKeyboardEvent key_event = key_it->second; |
| 227 queued_key_map_.erase(key_it); |
| 228 ack_handler_->OnKeyboardEventAck(key_event, acked_result); |
| 229 } else { |
| 230 DCHECK_EQ(0, event_id); |
| 231 ack_handler_->OnKeyboardEventAck( |
| 232 static_cast<const NativeWebKeyboardEvent&>(web_event), acked_result); |
| 233 } |
| 234 // WARNING: This BufferedInputRouter can be deallocated at this point |
| 235 // (i.e. in the case of Ctrl+W, where the call to |
| 236 // HandleKeyboardEvent destroys this BufferedInputRouter). |
| 237 } else if (web_event.type == WebInputEvent::MouseWheel) { |
| 238 ack_handler_->OnWheelEventAck( |
| 239 static_cast<const WebMouseWheelEvent&>(web_event), acked_result); |
| 240 } else if (WebInputEvent::isTouchEventType(web_event.type)) { |
| 241 if (ack_from_input_queue) { |
| 242 DCHECK_GT(queued_touch_count_, 0); |
| 243 --queued_touch_count_; |
| 244 } |
| 245 ack_handler_->OnTouchEventAck( |
| 246 TouchEventWithLatencyInfo(static_cast<const WebTouchEvent&>(web_event), |
| 247 latency_info), acked_result); |
| 248 } else if (WebInputEvent::isGestureEventType(web_event.type)) { |
| 249 if (ack_from_input_queue) { |
| 250 DCHECK_GT(queued_gesture_count_, 0); |
| 251 --queued_gesture_count_; |
| 252 } |
| 253 ack_handler_->OnGestureEventAck( |
| 254 static_cast<const WebGestureEvent&>(web_event), acked_result); |
| 255 } else |
| 256 NOTREACHED() << "Unexpected WebInputEvent in OnWebInputEventAck"; |
| 257 } |
| 258 |
| 259 void BufferedInputRouter::OnEventPacketAck( |
| 260 int64 packet_id, |
| 261 const InputEventDispositions& dispositions) { |
| 262 TRACE_EVENT2("input", "BufferedInputRouter::OnEventPacketAck", |
| 263 "id", packet_id, |
| 264 "dispositions", dispositions.size()); |
| 265 if (!in_flight_packet_id_ || packet_id != in_flight_packet_id_) { |
| 266 ack_handler_->OnUnexpectedEventAck(false); |
| 267 return; |
| 268 } |
| 269 |
| 270 in_flight_packet_id_ = 0; |
| 271 client_->DecrementInFlightEventCount(); |
| 272 |
| 273 InputQueue::AckResult ack_result = |
| 274 input_queue_->OnEventPacketAck(packet_id, dispositions); |
| 275 if (ack_result == InputQueue::ACK_UNEXPECTED) |
| 276 ack_handler_->OnUnexpectedEventAck(false); |
| 277 else if (ack_result == InputQueue::ACK_INVALID) |
| 278 ack_handler_->OnUnexpectedEventAck(true); |
| 279 } |
| 280 |
| 281 void BufferedInputRouter::OnHasTouchEventHandlers(bool has_handlers) { |
| 282 if (has_touch_handler_ == has_handlers) |
| 283 return; |
| 284 has_touch_handler_ = has_handlers; |
| 285 client_->OnHasTouchEventHandlers(has_handlers); |
| 286 } |
| 287 |
| 288 int64 BufferedInputRouter::QueueWebEvent(const WebKit::WebInputEvent& web_event, |
| 289 const ui::LatencyInfo& latency_info, |
| 290 bool is_key_shortcut, |
| 291 bool creates_followup_events) { |
| 292 TRACE_EVENT0("input", "BufferedInputRouter::QueueWebEvent"); |
| 293 |
| 294 if (FilterWebEvent(web_event, latency_info)) { |
| 295 TRACE_EVENT_INSTANT0("input", |
| 296 "BufferedInputRouter::QueueWebEvent::Filtered", |
| 297 TRACE_EVENT_SCOPE_THREAD); |
| 298 return 0; |
| 299 } |
| 300 |
| 301 int64 event_id = NextInputID(); |
| 302 scoped_ptr<BrowserInputEvent> event = |
| 303 BrowserInputEvent::Create(event_id, |
| 304 WebInputEventPayload::Create(web_event, |
| 305 latency_info, |
| 306 is_key_shortcut), |
| 307 this); |
| 308 |
| 309 // The presence of |input_queue_override_| implies that we are in the |
| 310 // scope of |OnInputEventDispatched()| with an event can create followup. |
| 311 if (input_queue_override_) |
| 312 input_queue_override_->push_back(event.release()); |
| 313 else |
| 314 input_queue_->QueueEvent(event.Pass()); |
| 315 |
| 316 return event_id; |
| 317 } |
| 318 |
| 319 bool BufferedInputRouter::FilterWebEvent(const WebKit::WebInputEvent& web_event, |
| 320 const ui::LatencyInfo& latency_info) { |
| 321 // Perform optional, synchronous event handling, sending ACK messages for |
| 322 // processed events, or proceeding as usual. |
| 323 InputEventAckState filter_ack = client_->FilterInputEvent(web_event, |
| 324 latency_info); |
| 325 switch (filter_ack) { |
| 326 // Send the ACK and early exit. |
| 327 case INPUT_EVENT_ACK_STATE_CONSUMED: |
| 328 case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS: |
| 329 OnWebInputEventAck(0, web_event, latency_info, filter_ack, false); |
| 330 // WARNING: |this| may be deleted at this point. |
| 331 return true; |
| 332 |
| 333 // Drop the event. |
| 334 case INPUT_EVENT_ACK_STATE_UNKNOWN: |
| 335 return true; |
| 336 |
| 337 // Proceed as normal. |
| 338 case INPUT_EVENT_ACK_STATE_NOT_CONSUMED: |
| 339 default: |
| 340 break; |
| 341 }; |
| 342 |
| 343 return false; |
| 344 } |
| 345 |
| 346 int64 BufferedInputRouter::NextInputID() { |
| 347 return next_input_id_++; |
| 348 } |
| 349 |
| 350 } // namespace content |
| OLD | NEW |