Index: content/browser/renderer_host/input/input_queue.cc |
diff --git a/content/browser/renderer_host/input/input_queue.cc b/content/browser/renderer_host/input/input_queue.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9e7bf654df5671d736cdf907cf78c2d25524a76f |
--- /dev/null |
+++ b/content/browser/renderer_host/input/input_queue.cc |
@@ -0,0 +1,183 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/renderer_host/input/input_queue.h" |
+ |
+#include "base/bind.h" |
+#include "base/debug/trace_event.h" |
+#include "content/browser/renderer_host/input/browser_input_event.h" |
+#include "content/browser/renderer_host/input/input_queue_client.h" |
+#include "content/common/input/event_packet.h" |
+#include "content/common/input/input_event.h" |
+ |
+namespace content { |
+ |
+// A specialized EventPacket with utility methods for dispatched event handling. |
+class InputQueue::BrowserEventPacket : public EventPacket { |
+ public: |
+ typedef ScopedVector<BrowserInputEvent> BrowserInputEvents; |
+ |
+ BrowserEventPacket() : weak_factory_(this) {} |
+ virtual ~BrowserEventPacket() {} |
+ |
+ // Validate the response and signal dispatch to the processed events. |
+ // Undelivered events will be re-enqueued, and any generated followup events |
+ // will be inserted at the same relative order as their generating event. |
+ AckResult ValidateAndDispatchAck(int64 packet_id, |
+ const InputEventDispositions& dispositions) { |
+ if (!Validate(packet_id, dispositions)) |
+ return ACK_INVALID; |
+ |
+ // Empty the packet; events will be re-enqueued as necessary. |
+ InputEvents dispatched_events; |
+ events_.swap(dispatched_events); |
+ |
+ // The packet could be deleted as a result of event dispatch; use a local |
+ // weak ref to ensure proper shutdown. |
+ base::WeakPtr<EventPacket> weak_ref_this = weak_factory_.GetWeakPtr(); |
+ |
+ BrowserInputEvents followup_events; |
+ for (size_t i = 0; i < dispatched_events.size(); ++i) { |
+ // Take ownership of the event. |
+ scoped_ptr<BrowserInputEvent> event( |
+ static_cast<BrowserInputEvent*>(dispatched_events[i])); |
+ dispatched_events[i] = NULL; |
+ |
+ // Re-enqueue undelivered events. |
+ InputEventDisposition disposition = dispositions[i]; |
+ if (disposition == INPUT_EVENT_COULD_NOT_DELIVER) { |
+ Add(event.PassAs<InputEvent>()); |
+ continue; |
+ } |
+ |
+ event->OnDispatched(disposition, &followup_events); |
+ |
+ // TODO(jdduke): http://crbug.com/274029 |
+ if (!weak_ref_this.get()) |
+ return ACK_SHUTDOWN; |
+ |
+ AddAll(&followup_events); |
+ } |
+ return ACK_OK; |
+ } |
+ |
+ protected: |
+ // Add and take ownership of events in |followup_events|. |
+ void AddAll(BrowserInputEvents* followup_events) { |
+ for (BrowserInputEvents::iterator iter = followup_events->begin(); |
+ iter != followup_events->end(); |
+ ++iter) { |
+ Add(scoped_ptr<InputEvent>(*iter)); |
+ } |
+ followup_events->weak_clear(); |
+ } |
+ |
+ // Perform a sanity check of the ack against the current packet. |
+ // |packet_id| should match that of this packet, and |dispositions| should |
+ // be of size equal to the number of events in this packet. |
+ bool Validate(int64 packet_id, |
+ const InputEventDispositions& dispositions) const { |
+ if (packet_id != id()) |
+ return false; |
+ |
+ if (dispositions.size() != size()) |
+ return false; |
+ |
+ return true; |
+ } |
+ |
+ private: |
+ base::WeakPtrFactory<EventPacket> weak_factory_; |
+}; |
+ |
+InputQueue::InputQueue(InputQueueClient* client) |
+ : client_(client), |
+ next_packet_id_(1), |
+ flush_requested_(false), |
+ in_flush_packet_(new BrowserEventPacket()), |
+ pending_flush_packet_(new BrowserEventPacket()) { |
+ DCHECK(client_); |
+} |
+ |
+InputQueue::~InputQueue() {} |
+ |
+void InputQueue::QueueEvent(scoped_ptr<BrowserInputEvent> event) { |
+ DCHECK(event); |
+ DCHECK(event->valid()); |
+ pending_flush_packet_->Add(event.PassAs<InputEvent>()); |
+ RequestFlushIfNecessary(); |
+} |
+ |
+void InputQueue::BeginFlush() { |
+ // Ignore repeated flush attempts. |
+ if (!flush_requested_) |
+ return; |
+ |
+ DCHECK(!FlushInProgress()); |
+ DCHECK(!pending_flush_packet_->empty()); |
+ |
+ flush_requested_ = false; |
+ in_flush_packet_.swap(pending_flush_packet_); |
+ DeliverInFlushPacket(); |
+} |
+ |
+InputQueue::AckResult InputQueue::OnEventPacketAck( |
+ int64 packet_id, |
+ const InputEventDispositions& dispositions) { |
+ if (!FlushInProgress()) |
+ return ACK_UNEXPECTED; |
+ |
+ TRACE_EVENT_ASYNC_STEP1("input", "InputQueueFlush", this, "AckPacket", |
+ "id", packet_id); |
+ |
+ AckResult ack_result = |
+ in_flush_packet_->ValidateAndDispatchAck(packet_id, dispositions); |
+ |
+ if (ack_result != ACK_OK) |
+ return ack_result; |
+ |
+ if (FlushInProgress()) { |
+ DeliverInFlushPacket(); |
+ } else { |
+ TRACE_EVENT_ASYNC_END0("input", "InputQueueFlush", this); |
+ client_->DidFinishFlush(); |
+ RequestFlushIfNecessary(); |
+ } |
+ |
+ return ACK_OK; |
+} |
+ |
+size_t InputQueue::QueuedEventCount() const { |
+ return in_flush_packet_->size() + pending_flush_packet_->size(); |
+} |
+ |
+void InputQueue::DeliverInFlushPacket() { |
+ DCHECK(FlushInProgress()); |
+ TRACE_EVENT_ASYNC_STEP1("input", "InputQueueFlush", this, "DeliverPacket", |
+ "id", next_packet_id_); |
+ in_flush_packet_->set_id(next_packet_id_++); |
+ client_->Deliver(*in_flush_packet_); |
+} |
+ |
+void InputQueue::RequestFlushIfNecessary() { |
+ if (flush_requested_) |
+ return; |
+ |
+ // Defer flush requests until the current flush has finished. |
+ if (FlushInProgress()) |
+ return; |
+ |
+ // No additional events to flush. |
+ if (pending_flush_packet_->empty()) |
+ return; |
+ |
+ TRACE_EVENT_ASYNC_BEGIN0("input", "InputQueueFlush", this); |
+ TRACE_EVENT_ASYNC_STEP0("input", "InputQueueFlush", this, "Request"); |
+ flush_requested_ = true; |
+ client_->SetNeedsFlush(); |
+} |
+ |
+bool InputQueue::FlushInProgress() const { return !in_flush_packet_->empty(); } |
+ |
+} // namespace content |