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

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: Code review 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/input_ack_observer.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;
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Please avoid <=/>= on enums. Please delete Restri
jdduke (slow) 2013/08/15 23:22:26 Yeah this was a speculative addition. I'll remove
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 observers, and
aelias_OOO_until_Jul13 2013/08/15 00:52:15 typo: "Utilty"
jdduke (slow) 2013/08/15 23:22:26 Done.
46 // dispatching input event responses.
47 class InputQueue::EventFrame {
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, InputAckObserver* observer) {
58 packet_.events.push_back(event);
59 observers_.push_back(observer);
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 InputQueueClient* client) {
66 if (!Validate(acked_packet))
67 return ACK_INVALID;
68
69 std::vector<InputEvent> events;
70 std::swap(events, packet_.events);
71
72 std::vector<InputAckObserver*> observers;
73 std::swap(observers, observers_);
74
75 // The EventFrame could be deleted as a result of the event ack; use a local
76 // weak ref to ensure proper shutdown.
77 base::WeakPtr<EventFrame> weak_ref_this = weak_factory_.GetWeakPtr();
78
79 const std::vector<InputEvent>& acked_events = acked_packet.events;
80 for (size_t event_idx = 0; event_idx < acked_events.size(); ++event_idx) {
81 const InputEvent& acked_event = acked_events[event_idx];
82
83 // All events marked undeliverable should be re-enqueued.
84 switch (acked_event.state) {
85 case INPUT_EVENT_IMPL_THREAD_COULD_NOT_DELIVER:
86 case INPUT_EVENT_MAIN_THREAD_COULD_NOT_DELIVER:
87 QueueEvent(events[event_idx], observers[event_idx]);
88 continue;
89 default:
90 break;
91 }
92
93 // Update the original event's state, and use it for the ack.
94 InputEvent& event = events[event_idx];
95 event.state = acked_event.state;
96
97 std::vector<InputEvent> followup_events = client->OnInputEventAck(event);
98
99 // Exit immediately if the client ack triggered an early shutdown.
100 // TODO(jdduke): Look into making ack-triggered shutdown async.
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Please file a bug for this.
jdduke (slow) 2013/08/15 23:53:30 Done.
101 if (!weak_ref_this.get())
102 return ACK_SHUTDOWN;
103
104 for (std::vector<InputEvent>::iterator iter = followup_events.begin();
105 iter != followup_events.end();
106 ++iter) {
107 QueueEvent(*iter, NULL);
108 }
109
110 if (observers[event_idx])
111 observers[event_idx]->OnInputEventAck(event);
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Please DCHECK the size of "observers".
jdduke (slow) 2013/08/15 23:22:26 Done.
112 }
113 return ACK_OK;
114 };
115
116 bool IsEmpty() const { return packet_.events.empty(); }
117 size_t Size() const { return packet_.events.size(); }
118
119 protected:
120
121 // Perform a sanity check of |acked_packet| against the queued events.
122 // The packet should contain the same number of events, and all events and
123 // the event messages should be of the same general type.
124 bool Validate(const EventPacket& acked_packet) {
125 if (acked_packet.id != packet_.id)
126 return false;
127
128 const std::vector<InputEvent>& source_events = packet_.events;
129 const std::vector<InputEvent>& acked_events = acked_packet.events;
130 if (source_events.size() != acked_events.size())
131 return false;
132
133 for (size_t event_idx = 0; event_idx < acked_events.size(); ++event_idx) {
134 const InputEvent& source_event = source_events[event_idx];
135 const InputEvent& acked_event = acked_events[event_idx];
136
137 if (acked_event.type != source_event.type)
138 return false;
139
140 if (acked_event.message.type() != source_event.message.type())
141 return false;
142 }
143
144 return true;
145 }
146
147 private:
148 EventPacket packet_;
149 std::vector<InputAckObserver*> observers_;
150 base::WeakPtrFactory<EventFrame> weak_factory_;
151 };
152
153 InputQueue::InputQueue(InputQueueClient* client)
154 : client_(client),
155 last_packet_id_(0),
156 flush_requested_(false),
157 flush_signalled_(false),
158 current_frame_(new EventFrame()),
159 pending_frame_(new EventFrame()) {
160 DCHECK(client_);
161 }
162
163 InputQueue::~InputQueue() {}
164
165 void InputQueue::QueueEvent(const InputEvent& event,
166 InputAckObserver* ack_observer) {
167 pending_frame_->QueueEvent(event, ack_observer);
168 RequestFlushIfNecessary();
169 }
170
171 void InputQueue::FlushEventsInCurrentFrame() {
172 // Ignore repeated flush attempts.
173 if (!flush_requested_)
174 return;
175
176 if (IsFlushing()) {
177 NOTREACHED() << "InputQueue::Flush() - A flush is already in-progress.";
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Another place that should just have a DCHECK, not
jdduke (slow) 2013/08/15 23:22:26 Done.
178 return;
179 }
180
181 flush_requested_ = false;
182 flush_signalled_ = false;
183 current_frame_.swap(pending_frame_);
184
185 TryFinishFlush();
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Do you ever want the request-flush behavior of Try
jdduke (slow) 2013/08/15 23:22:26 Yeah, I added this to allow a bit of flexibility i
186 }
187
188 InputQueue::AckResult InputQueue::OnEventPacketAck(
189 const EventPacket& acked_packet) {
190 if (!IsFlushing())
191 return ACK_UNEXPECTED;
192
193 AckResult ack_result =
194 current_frame_->ValidateAndDispatchAcks(acked_packet, client_);
195 if (ack_result == ACK_OK)
196 TryFinishFlush();
197
198 return ack_result;
199 }
200
201 size_t InputQueue::QueuedEventCount() const {
202 return current_frame_->Size() + pending_frame_->Size();
203 }
204
205 void InputQueue::TryFinishFlush() {
206 if (!IsFlushing()) {
207 SignalFlushedIfNecessary();
208 RequestFlushIfNecessary();
209 return;
210 }
211
212 // Provide a unique id for every delivered packet.
213 current_frame_->DeliverTo(client_, ++last_packet_id_);
214 }
215
216 void InputQueue::RequestFlushIfNecessary() {
217 if (flush_requested_)
218 return;
219
220 // No events to flush.
221 if (pending_frame_->IsEmpty())
aelias_OOO_until_Jul13 2013/08/15 00:52:15 Is it correct to check pending_frame_ here? TryFi
jdduke (slow) 2013/08/15 23:22:26 Well, I think I should clear up the expectations:
222 return;
223
224 // We're still flushing; wait until it finishes before an additional request.
225 if (IsFlushing())
226 return;
227
228 flush_requested_ = true;
229 client_->SetNeedsFlush();
230 }
231
232 void InputQueue::SignalFlushedIfNecessary() {
aelias_OOO_until_Jul13 2013/08/15 00:52:15 I don't think this method (nor the field flush_sig
jdduke (slow) 2013/08/15 23:22:26 Right, deleting.
233 if (flush_signalled_)
234 return;
235
236 flush_signalled_ = true;
237 client_->DidFlush();
238 }
239
240 bool InputQueue::IsFlushing() const {
241 return !current_frame_->IsEmpty();
242 }
243
244 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698