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

Side by Side Diff: content/browser/renderer_host/input/input_queue.cc

Issue 20356003: Provided batched input delivery with a BufferedInputRouter (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: BufferedInputRouter unit tests Created 7 years, 4 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 unified diff | Download patch
OLDNEW
(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 "content/browser/renderer_host/input/event_ack_handler.h"
9 #include "content/browser/renderer_host/input/input_queue_client.h"
10 #include "content/common/input/event_packet.h"
11 #include "content/common/input/input_event.h"
12
13 namespace content {
14 namespace {
15
16 // TODO(jdduke):
17 // INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP: Delay flush, hold future packets.
18 // INPUT_EVENT_NEEDS_ACK: Signal flush immediately, dispatch ack in-order.
19 // INPUT_EVENT_ONE_WAY: Signal flush immediately, ignore ack.
20 InputEventType RestrictingEventType(const EventPacket& packet) {
21 InputEventType restricting_type = INPUT_EVENT_INVALID;
22 for (std::vector<InputEvent>::const_iterator event_it = packet.events.begin();
23 event_it != packet.events.end();
24 ++event_it) {
25 if (event_it->type > restricting_type)
26 restricting_type = event_it->type;
27 }
28 return restricting_type;
29 }
30
31 bool HasFollowupEvents(const EventPacket& packet) {
32 return RestrictingEventType(packet) == INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP;
33 }
34
35 bool HasAckEvents(const EventPacket& packet) {
36 return RestrictingEventType(packet) >= INPUT_EVENT_NEEDS_ACK;
37 }
38
39 bool IsOneWay(const EventPacket& packet) {
40 return RestrictingEventType(packet) <= INPUT_EVENT_ONE_WAY;
41 }
42
43 }
44
45 // Utilty class for storing input events and their ack handlers, and dispatching
46 // input event responses.
47 class InputQueue::EventFrame : EventAckHandler::EventInjector {
48 public:
49 EventFrame() : weak_factory_(this) {}
50 virtual ~EventFrame() {}
51
52 void DeliverTo(InputQueueClient* client, int64 id) {
53 packet_.id = id;
54 client->Deliver(packet_);
55 }
56
57 void QueueEvent(const InputEvent& event, EventAckHandler* handler) {
58 packet_.events.push_back(event);
59 handlers_.push_back(handler);
60 }
61
62 // Validate |acked_packet| and dispatch the acked events upon successful
63 // validation. Returns |false| if the validation failed.
64 AckResult ValidateAndDispatchAcks(const EventPacket& acked_packet) {
65 if (!Validate(acked_packet))
66 return ACK_INVALID;
67
68 std::vector<InputEvent> events;
69 std::swap(events, packet_.events);
70
71 std::vector<EventAckHandler*> handlers;
72 std::swap(handlers, handlers_);
73
74 // The EventFrame could be deleted as a result of the event ack; use a local
75 // weak ref to ensure proper shutdown.
76 base::WeakPtr<EventFrame> weak_ref_this = weak_factory_.GetWeakPtr();
77
78 const std::vector<InputEvent>& acked_events = acked_packet.events;
79 for (size_t event_idx = 0; event_idx < acked_events.size(); ++event_idx) {
80 const InputEvent& acked_event = acked_events[event_idx];
81
82 // All events marked undeliverable should be re-enqueued.
83 switch (acked_event.state) {
84 case INPUT_EVENT_IMPL_THREAD_COULD_NOT_DELIVER:
85 case INPUT_EVENT_MAIN_THREAD_COULD_NOT_DELIVER:
86 QueueEvent(events[event_idx], handlers[event_idx]);
87 continue;
88 default:
89 break;
90 }
91
92 // NULL handlers are acceptable.
93 if (!handlers[event_idx])
94 continue;
95
96 // Update the original event's state, and use it for the ack.
97 InputEvent& event = events[event_idx];
98 event.state = acked_event.state;
99
100 switch (acked_events[event_idx].type) {
101 case INPUT_EVENT_NEEDS_ACK_AND_HAS_FOLLOWUP:
102 handlers[event_idx]->OnInputEventAck(event, this);
103 break;
104 case INPUT_EVENT_NEEDS_ACK:
105 handlers[event_idx]->OnInputEventAck(event);
106 break;
107 default:
108 break;
109 }
110
111 // Exit immediately if the ack handler triggered an early shutdown.
112 if (!weak_ref_this.get())
113 return ACK_SHUTDOWN;
114 }
115 return ACK_OK;
116 }
117
118 bool IsEmpty() const { return packet_.events.empty(); }
119 size_t Size() const { return packet_.events.size(); }
120
121 protected:
122
123 // EventInjector
124 virtual void InjectEvent(const InputEvent& event,
125 EventAckHandler* handler) OVERRIDE {
126 QueueEvent(event, handler);
127 }
128
129 // Perform a sanity check of |acked_packet| against the queued events.
130 // The packet should contain the same number of events, and all events and
131 // the event messages should be of the same general type.
132 bool Validate(const EventPacket& acked_packet) {
133 if (acked_packet.id != packet_.id)
134 return false;
135
136 const std::vector<InputEvent>& source_events = packet_.events;
137 const std::vector<InputEvent>& acked_events = acked_packet.events;
138 if (source_events.size() != acked_events.size())
139 return false;
140
141 for (size_t event_idx = 0; event_idx < acked_events.size(); ++event_idx) {
142 const InputEvent& source_event = source_events[event_idx];
143 const InputEvent& acked_event = acked_events[event_idx];
144
145 if (acked_event.type != source_event.type)
146 return false;
147
148 if (acked_event.message.type() != source_event.message.type())
149 return false;
150 }
151
152 return true;
153 }
154
155 private:
156 EventPacket packet_;
157 std::vector<EventAckHandler*> handlers_;
158 base::WeakPtrFactory<EventFrame> weak_factory_;
159 };
160
161 InputQueue::InputQueue(InputQueueClient* client)
162 : client_(client),
163 last_packet_id_(0),
164 flush_requested_(false),
165 flush_signalled_(false),
166 current_frame_(new EventFrame()),
167 pending_frame_(new EventFrame()) {
168 DCHECK(client_);
169 }
170
171 InputQueue::~InputQueue() {}
172
173 void InputQueue::QueueEvent(const InputEvent& event,
174 EventAckHandler* ack_handler) {
175 pending_frame_->QueueEvent(event, ack_handler);
176 RequestFlushIfNecessary();
177 }
178
179 void InputQueue::FlushEventsInCurrentFrame() {
180 // Ignore repeated flush attempts.
181 if (!flush_requested_)
182 return;
183
184 if (IsFlushing()) {
185 NOTREACHED() << "InputQueue::Flush() - A flush is already in-progress.";
186 return;
187 }
188
189 flush_requested_ = false;
190 flush_signalled_ = false;
191 current_frame_.swap(pending_frame_);
192
193 TryFinishFlush();
194 }
195
196 InputQueue::AckResult InputQueue::OnEventPacketAck(
197 const EventPacket& acked_packet) {
198 if (!IsFlushing())
199 return ACK_UNEXPECTED;
200
201 AckResult ack_result = current_frame_->ValidateAndDispatchAcks(acked_packet);
202 if (ack_result == ACK_OK)
203 TryFinishFlush();
204
205 return ack_result;
206 }
207
208 void InputQueue::OnEventPacketAckDelayed() {
209 if (!IsFlushing())
210 return;
211
212 SignalFlushedIfNecessary();
213 // Don't request another flush until the ack is received.
214 }
215
216 size_t InputQueue::QueuedEventCount() const {
217 return current_frame_->Size() + pending_frame_->Size();
218 }
219
220 void InputQueue::TryFinishFlush() {
221 if (!IsFlushing()) {
222 SignalFlushedIfNecessary();
223 RequestFlushIfNecessary();
224 return;
225 }
226
227 // Provide a unique id for every delivered packet.
228 current_frame_->DeliverTo(client_, ++last_packet_id_);
229 }
230
231 void InputQueue::RequestFlushIfNecessary() {
232 if (flush_requested_)
233 return;
234
235 // No events to flush.
236 if (pending_frame_->IsEmpty())
237 return;
238
239 // We're still flushing; wait until it finishes before an additional request.
240 if (IsFlushing())
241 return;
242
243 flush_requested_ = true;
244 client_->SetNeedsFlush();
245 }
246
247 void InputQueue::SignalFlushedIfNecessary() {
248 if (flush_signalled_)
249 return;
250
251 flush_signalled_ = true;
252 client_->DidFlush();
253 }
254
255 bool InputQueue::IsFlushing() const {
256 return !current_frame_->IsEmpty();
257 }
258
259 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698