OLD | NEW |
| (Empty) |
1 // Copyright 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 // TODO(jdduke): http://crbug.com/274029 | |
57 if (!weak_ref_this.get()) | |
58 return ACK_SHUTDOWN; | |
59 | |
60 AddAll(&followup_events); | |
61 } | |
62 return ACK_OK; | |
63 } | |
64 | |
65 protected: | |
66 // Add and take ownership of events in |followup_events|. | |
67 void AddAll(BrowserInputEvents* followup_events) { | |
68 for (BrowserInputEvents::iterator iter = followup_events->begin(); | |
69 iter != followup_events->end(); | |
70 ++iter) { | |
71 Add(scoped_ptr<InputEvent>(*iter)); | |
72 } | |
73 followup_events->weak_clear(); | |
74 } | |
75 | |
76 // Perform a sanity check of the ack against the current packet. | |
77 // |packet_id| should match that of this packet, and |dispositions| should | |
78 // be of size equal to the number of events in this packet. | |
79 bool Validate(int64 packet_id, | |
80 const InputEventDispositions& dispositions) const { | |
81 if (packet_id != id()) | |
82 return false; | |
83 | |
84 if (dispositions.size() != size()) | |
85 return false; | |
86 | |
87 return true; | |
88 } | |
89 | |
90 private: | |
91 base::WeakPtrFactory<EventPacket> weak_factory_; | |
92 }; | |
93 | |
94 InputQueue::InputQueue(InputQueueClient* client) | |
95 : client_(client), | |
96 next_packet_id_(1), | |
97 flush_requested_(false), | |
98 in_flush_packet_(new BrowserEventPacket()), | |
99 pending_flush_packet_(new BrowserEventPacket()) { | |
100 DCHECK(client_); | |
101 } | |
102 | |
103 InputQueue::~InputQueue() {} | |
104 | |
105 void InputQueue::QueueEvent(scoped_ptr<BrowserInputEvent> event) { | |
106 DCHECK(event); | |
107 DCHECK(event->valid()); | |
108 pending_flush_packet_->Add(event.PassAs<InputEvent>()); | |
109 RequestFlushIfNecessary(); | |
110 } | |
111 | |
112 void InputQueue::BeginFlush() { | |
113 // Ignore repeated flush attempts. | |
114 if (!flush_requested_) | |
115 return; | |
116 | |
117 DCHECK(!FlushInProgress()); | |
118 DCHECK(!pending_flush_packet_->empty()); | |
119 | |
120 flush_requested_ = false; | |
121 in_flush_packet_.swap(pending_flush_packet_); | |
122 DeliverInFlushPacket(); | |
123 } | |
124 | |
125 InputQueue::AckResult InputQueue::OnEventPacketAck( | |
126 int64 packet_id, | |
127 const InputEventDispositions& dispositions) { | |
128 if (!FlushInProgress()) | |
129 return ACK_UNEXPECTED; | |
130 | |
131 TRACE_EVENT_ASYNC_STEP1("input", "InputQueueFlush", this, "AckPacket", | |
132 "id", packet_id); | |
133 | |
134 AckResult ack_result = | |
135 in_flush_packet_->ValidateAndDispatchAck(packet_id, dispositions); | |
136 | |
137 if (ack_result != ACK_OK) | |
138 return ack_result; | |
139 | |
140 if (FlushInProgress()) { | |
141 DeliverInFlushPacket(); | |
142 } else { | |
143 TRACE_EVENT_ASYNC_END0("input", "InputQueueFlush", this); | |
144 client_->DidFinishFlush(); | |
145 RequestFlushIfNecessary(); | |
146 } | |
147 | |
148 return ACK_OK; | |
149 } | |
150 | |
151 size_t InputQueue::QueuedEventCount() const { | |
152 return in_flush_packet_->size() + pending_flush_packet_->size(); | |
153 } | |
154 | |
155 void InputQueue::DeliverInFlushPacket() { | |
156 DCHECK(FlushInProgress()); | |
157 TRACE_EVENT_ASYNC_STEP1("input", "InputQueueFlush", this, "DeliverPacket", | |
158 "id", next_packet_id_); | |
159 in_flush_packet_->set_id(next_packet_id_++); | |
160 client_->Deliver(*in_flush_packet_); | |
161 } | |
162 | |
163 void InputQueue::RequestFlushIfNecessary() { | |
164 if (flush_requested_) | |
165 return; | |
166 | |
167 // Defer flush requests until the current flush has finished. | |
168 if (FlushInProgress()) | |
169 return; | |
170 | |
171 // No additional events to flush. | |
172 if (pending_flush_packet_->empty()) | |
173 return; | |
174 | |
175 TRACE_EVENT_ASYNC_BEGIN0("input", "InputQueueFlush", this); | |
176 TRACE_EVENT_ASYNC_STEP0("input", "InputQueueFlush", this, "Request"); | |
177 flush_requested_ = true; | |
178 client_->SetNeedsFlush(); | |
179 } | |
180 | |
181 bool InputQueue::FlushInProgress() const { return !in_flush_packet_->empty(); } | |
182 | |
183 } // namespace content | |
OLD | NEW |