Chromium Code Reviews| 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/input_queue.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/debug/trace_event.h" | |
| 9 #include "content/browser/renderer_host/input/browser_input_event.h" | |
| 10 #include "content/browser/renderer_host/input/input_queue_client.h" | |
| 11 #include "content/common/input/event_packet.h" | |
| 12 #include "content/common/input/input_event.h" | |
| 13 | |
| 14 namespace content { | |
| 15 | |
| 16 // A specialized EventPacket with utility methods for dispatched event handling. | |
| 17 class InputQueue::BrowserEventPacket : public EventPacket { | |
| 18 public: | |
| 19 typedef ScopedVector<BrowserInputEvent> BrowserInputEvents; | |
| 20 | |
| 21 BrowserEventPacket() : weak_factory_(this) {} | |
| 22 virtual ~BrowserEventPacket() {} | |
| 23 | |
| 24 // Validate the response and signal dispatch to the processed events. | |
| 25 // Undelivered events will be re-enqueued, and any generated followup events | |
| 26 // will be inserted at the same relative order as their generating event. | |
| 27 AckResult ValidateAndDispatchAck(int64 packet_id, | |
| 28 const InputEventDispositions& dispositions) { | |
| 29 if (!Validate(packet_id, dispositions)) | |
| 30 return ACK_INVALID; | |
| 31 | |
| 32 // Empty the packet; events will be re-enqueued as necessary. | |
| 33 InputEvents dispatched_events; | |
| 34 events_.swap(dispatched_events); | |
| 35 | |
| 36 // The packet could be deleted as a result of event dispatch; use a local | |
| 37 // weak ref to ensure proper shutdown. | |
| 38 base::WeakPtr<EventPacket> weak_ref_this = weak_factory_.GetWeakPtr(); | |
| 39 | |
| 40 BrowserInputEvents followup_events; | |
| 41 for (size_t i = 0; i < dispatched_events.size(); ++i) { | |
| 42 // Take ownership of the event. | |
| 43 scoped_ptr<BrowserInputEvent> event( | |
| 44 static_cast<BrowserInputEvent*>(dispatched_events[i])); | |
| 45 dispatched_events[i] = NULL; | |
| 46 | |
| 47 // Re-enqueue undelivered events. | |
| 48 InputEventDisposition disposition = dispositions[i]; | |
| 49 if (disposition == INPUT_EVENT_COULD_NOT_DELIVER) { | |
| 50 Add(event.PassAs<InputEvent>()); | |
| 51 continue; | |
| 52 } | |
| 53 | |
| 54 event->OnDispatched(disposition, &followup_events); | |
| 55 | |
| 56 if (!weak_ref_this.get()) | |
| 
 
aelias_OOO_until_Jul13
2013/09/09 22:31:14
Please add a comment // TODO(jdduke): http://crbug
 
jdduke (slow)
2013/09/10 19:41:16
Done.
 
 | |
| 57 return ACK_SHUTDOWN; | |
| 58 | |
| 59 AddAll(&followup_events); | |
| 60 } | |
| 61 return ACK_OK; | |
| 62 }; | |
| 63 | |
| 64 protected: | |
| 65 // Add and take ownership of events in |followup_events|. | |
| 66 void AddAll(BrowserInputEvents* followup_events) { | |
| 67 for (BrowserInputEvents::iterator iter = followup_events->begin(); | |
| 68 iter != followup_events->end(); | |
| 69 ++iter) { | |
| 70 Add(scoped_ptr<InputEvent>(*iter)); | |
| 71 } | |
| 72 followup_events->weak_clear(); | |
| 73 } | |
| 74 | |
| 75 // Perform a sanity check of the ack against the current packet. | |
| 76 // |packet_id| should match that of this packet, and |dispositions| should | |
| 77 // be of size equal to the number of events in this packet. | |
| 78 bool Validate(int64 packet_id, | |
| 79 const InputEventDispositions& dispositions) const { | |
| 80 if (packet_id != id()) | |
| 81 return false; | |
| 82 | |
| 83 if (dispositions.size() != size()) | |
| 84 return false; | |
| 85 | |
| 86 return true; | |
| 87 } | |
| 88 | |
| 89 private: | |
| 90 base::WeakPtrFactory<EventPacket> weak_factory_; | |
| 91 }; | |
| 92 | |
| 93 InputQueue::InputQueue(InputQueueClient* client) | |
| 94 : client_(client), | |
| 95 next_packet_id_(1), | |
| 96 flush_requested_(false), | |
| 97 in_flush_packet_(new BrowserEventPacket()), | |
| 98 pending_flush_packet_(new BrowserEventPacket()) { | |
| 99 DCHECK(client_); | |
| 100 } | |
| 101 | |
| 102 InputQueue::~InputQueue() {} | |
| 103 | |
| 104 void InputQueue::QueueEvent(scoped_ptr<BrowserInputEvent> event) { | |
| 105 DCHECK(event); | |
| 106 DCHECK(event->valid()); | |
| 107 pending_flush_packet_->Add(event.PassAs<InputEvent>()); | |
| 108 RequestFlushIfNecessary(); | |
| 109 } | |
| 110 | |
| 111 void InputQueue::BeginFlush() { | |
| 112 // Ignore repeated flush attempts. | |
| 113 if (!flush_requested_) | |
| 114 return; | |
| 115 | |
| 116 DCHECK(!FlushInProgress()); | |
| 117 DCHECK(!pending_flush_packet_->empty()); | |
| 118 | |
| 119 flush_requested_ = false; | |
| 120 in_flush_packet_.swap(pending_flush_packet_); | |
| 121 DeliverInFlushPacket(); | |
| 122 } | |
| 123 | |
| 124 InputQueue::AckResult InputQueue::OnEventPacketAck( | |
| 125 int64 packet_id, const InputEventDispositions& dispositions) { | |
| 126 if (!FlushInProgress()) | |
| 127 return ACK_UNEXPECTED; | |
| 128 | |
| 129 TRACE_EVENT_ASYNC_STEP1("input", "InputQueueFlush", this, "AckPacket", | |
| 130 "id", packet_id); | |
| 131 | |
| 132 AckResult ack_result = | |
| 133 in_flush_packet_->ValidateAndDispatchAck(packet_id, dispositions); | |
| 134 | |
| 135 if (ack_result != ACK_OK) | |
| 136 return ack_result; | |
| 137 | |
| 138 if (FlushInProgress()) { | |
| 139 DeliverInFlushPacket(); | |
| 140 } else { | |
| 141 TRACE_EVENT_ASYNC_END0("input", "InputQueueFlush", this); | |
| 142 client_->DidFinishFlush(); | |
| 143 RequestFlushIfNecessary(); | |
| 144 } | |
| 145 | |
| 146 return ACK_OK; | |
| 147 } | |
| 148 | |
| 149 size_t InputQueue::QueuedEventCount() const { | |
| 150 return in_flush_packet_->size() + pending_flush_packet_->size(); | |
| 151 } | |
| 152 | |
| 153 void InputQueue::DeliverInFlushPacket() { | |
| 154 DCHECK(FlushInProgress()); | |
| 155 TRACE_EVENT_ASYNC_STEP1("input", "InputQueueFlush", this, "DeliverPacket", | |
| 156 "id", next_packet_id_); | |
| 157 in_flush_packet_->set_id(next_packet_id_++); | |
| 158 client_->Deliver(*in_flush_packet_); | |
| 159 } | |
| 160 | |
| 161 void InputQueue::RequestFlushIfNecessary() { | |
| 162 if (flush_requested_) | |
| 163 return; | |
| 164 | |
| 165 // Defer flush requests until the current flush has finished. | |
| 166 if (FlushInProgress()) | |
| 167 return; | |
| 168 | |
| 169 // No additional events to flush. | |
| 170 if (pending_flush_packet_->empty()) | |
| 171 return; | |
| 172 | |
| 173 TRACE_EVENT_ASYNC_BEGIN0("input", "InputQueueFlush", this); | |
| 174 TRACE_EVENT_ASYNC_STEP0("input", "InputQueueFlush", this, "Request"); | |
| 175 flush_requested_ = true; | |
| 176 client_->SetNeedsFlush(); | |
| 177 } | |
| 178 | |
| 179 bool InputQueue::FlushInProgress() const { | |
| 180 return !in_flush_packet_->empty(); | |
| 181 } | |
| 182 | |
| 183 } // namespace content | |
| OLD | NEW |