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

Side by Side Diff: content/renderer/presentation/presentation_dispatcher.cc

Issue 1259073004: [Presentation API] Change ListenForSessionMessages API to client-style. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: update comments Created 5 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/presentation/presentation_dispatcher.h" 5 #include "content/renderer/presentation/presentation_dispatcher.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 case presentation::PRESENTATION_SESSION_STATE_CONNECTED: 43 case presentation::PRESENTATION_SESSION_STATE_CONNECTED:
44 return blink::WebPresentationSessionState::Connected; 44 return blink::WebPresentationSessionState::Connected;
45 case presentation::PRESENTATION_SESSION_STATE_DISCONNECTED: 45 case presentation::PRESENTATION_SESSION_STATE_DISCONNECTED:
46 return blink::WebPresentationSessionState::Disconnected; 46 return blink::WebPresentationSessionState::Disconnected;
47 } 47 }
48 48
49 NOTREACHED(); 49 NOTREACHED();
50 return blink::WebPresentationSessionState::Disconnected; 50 return blink::WebPresentationSessionState::Disconnected;
51 } 51 }
52 52
53 presentation::SessionMessage* GetMojoSessionMessage(
54 const blink::WebString& presentationUrl,
55 const blink::WebString& presentationId,
56 presentation::PresentationMessageType type,
57 const uint8* data,
58 size_t length) {
59 presentation::SessionMessage* session_message =
60 new presentation::SessionMessage();
61 session_message->presentation_url = presentationUrl.utf8();
62 session_message->presentation_id = presentationId.utf8();
63 session_message->type = type;
64 const std::vector<uint8> vector(data, data + length);
65 session_message->data = mojo::Array<uint8>::From(vector);
66 return session_message;
67 }
68
69 } // namespace 53 } // namespace
70 54
71 namespace content { 55 namespace content {
72 56
73 PresentationDispatcher::PresentationDispatcher(RenderFrame* render_frame) 57 PresentationDispatcher::PresentationDispatcher(RenderFrame* render_frame)
74 : RenderFrameObserver(render_frame), 58 : RenderFrameObserver(render_frame),
75 controller_(nullptr), 59 controller_(nullptr),
76 binding_(this), 60 binding_(this),
77 listening_state_(ListeningState::Inactive), 61 listening_state_(ListeningState::Inactive),
78 last_known_availability_(false), 62 last_known_availability_(false) {}
79 listening_for_messages_(false) {
80 }
81 63
82 PresentationDispatcher::~PresentationDispatcher() { 64 PresentationDispatcher::~PresentationDispatcher() {
83 // Controller should be destroyed before the dispatcher when frame is 65 // Controller should be destroyed before the dispatcher when frame is
84 // destroyed. 66 // destroyed.
85 DCHECK(!controller_); 67 DCHECK(!controller_);
86 } 68 }
87 69
88 void PresentationDispatcher::setController( 70 void PresentationDispatcher::setController(
89 blink::WebPresentationController* controller) { 71 blink::WebPresentationController* controller) {
90 // There shouldn't be any swapping from one non-null controller to another. 72 // There shouldn't be any swapping from one non-null controller to another.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 const blink::WebString& presentationId, 124 const blink::WebString& presentationId,
143 const blink::WebString& message) { 125 const blink::WebString& message) {
144 if (message.utf8().size() > kMaxPresentationSessionMessageSize) { 126 if (message.utf8().size() > kMaxPresentationSessionMessageSize) {
145 // TODO(crbug.com/459008): Limit the size of individual messages to 64k 127 // TODO(crbug.com/459008): Limit the size of individual messages to 64k
146 // for now. Consider throwing DOMException or splitting bigger messages 128 // for now. Consider throwing DOMException or splitting bigger messages
147 // into smaller chunks later. 129 // into smaller chunks later.
148 LOG(WARNING) << "message size exceeded limit!"; 130 LOG(WARNING) << "message size exceeded limit!";
149 return; 131 return;
150 } 132 }
151 133
152 presentation::SessionMessage* session_message = 134 message_request_queue_.push(make_linked_ptr(
153 new presentation::SessionMessage(); 135 CreateSendTextMessageRequest(presentationUrl, presentationId, message)));
154 session_message->presentation_url = presentationUrl.utf8();
155 session_message->presentation_id = presentationId.utf8();
156 session_message->type = presentation::PresentationMessageType::
157 PRESENTATION_MESSAGE_TYPE_TEXT;
158 session_message->message = message.utf8();
159
160 message_request_queue_.push(make_linked_ptr(session_message));
161 // Start processing request if only one in the queue. 136 // Start processing request if only one in the queue.
162 if (message_request_queue_.size() == 1) { 137 if (message_request_queue_.size() == 1)
163 const linked_ptr<presentation::SessionMessage>& request = 138 DoSendMessage(message_request_queue_.front().get());
164 message_request_queue_.front();
165 DoSendMessage(*request);
166 }
167 } 139 }
168 140
169 void PresentationDispatcher::sendArrayBuffer( 141 void PresentationDispatcher::sendArrayBuffer(
170 const blink::WebString& presentationUrl, 142 const blink::WebString& presentationUrl,
171 const blink::WebString& presentationId, 143 const blink::WebString& presentationId,
172 const uint8* data, 144 const uint8* data,
173 size_t length) { 145 size_t length) {
174 DCHECK(data); 146 DCHECK(data);
175 if (length > kMaxPresentationSessionMessageSize) { 147 if (length > kMaxPresentationSessionMessageSize) {
176 // TODO(crbug.com/459008): Same as in sendString(). 148 // TODO(crbug.com/459008): Same as in sendString().
177 LOG(WARNING) << "data size exceeded limit!"; 149 LOG(WARNING) << "data size exceeded limit!";
178 return; 150 return;
179 } 151 }
180 152
181 presentation::SessionMessage* session_message = 153 message_request_queue_.push(make_linked_ptr(
182 GetMojoSessionMessage(presentationUrl, presentationId, 154 CreateSendBinaryMessageRequest(presentationUrl, presentationId,
183 presentation::PresentationMessageType:: 155 presentation::PresentationMessageType::
184 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER, 156 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER,
185 data, length); 157 data, length)));
186 message_request_queue_.push(make_linked_ptr(session_message));
187 // Start processing request if only one in the queue. 158 // Start processing request if only one in the queue.
188 if (message_request_queue_.size() == 1) { 159 if (message_request_queue_.size() == 1)
189 const linked_ptr<presentation::SessionMessage>& request = 160 DoSendMessage(message_request_queue_.front().get());
190 message_request_queue_.front();
191 DoSendMessage(*request);
192 }
193 } 161 }
194 162
195 void PresentationDispatcher::sendBlobData( 163 void PresentationDispatcher::sendBlobData(
196 const blink::WebString& presentationUrl, 164 const blink::WebString& presentationUrl,
197 const blink::WebString& presentationId, 165 const blink::WebString& presentationId,
198 const uint8* data, 166 const uint8* data,
199 size_t length) { 167 size_t length) {
200 DCHECK(data); 168 DCHECK(data);
201 if (length > kMaxPresentationSessionMessageSize) { 169 if (length > kMaxPresentationSessionMessageSize) {
202 // TODO(crbug.com/459008): Same as in sendString(). 170 // TODO(crbug.com/459008): Same as in sendString().
203 LOG(WARNING) << "data size exceeded limit!"; 171 LOG(WARNING) << "data size exceeded limit!";
204 return; 172 return;
205 } 173 }
206 174
207 presentation::SessionMessage* session_message = GetMojoSessionMessage( 175 message_request_queue_.push(make_linked_ptr(CreateSendBinaryMessageRequest(
208 presentationUrl, presentationId, 176 presentationUrl, presentationId,
209 presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_BLOB, 177 presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_BLOB,
210 data, length); 178 data, length)));
211 message_request_queue_.push(make_linked_ptr(session_message)); 179 // Start processing request if only one in the queue.
212 if (message_request_queue_.size() == 1) { 180 if (message_request_queue_.size() == 1)
213 const linked_ptr<presentation::SessionMessage>& request = 181 DoSendMessage(message_request_queue_.front().get());
214 message_request_queue_.front();
215 DoSendMessage(*request);
216 }
217 } 182 }
218 183
219 void PresentationDispatcher::DoSendMessage( 184 void PresentationDispatcher::DoSendMessage(SendMessageRequest* request) {
220 const presentation::SessionMessage& session_message) {
221 ConnectToPresentationServiceIfNeeded(); 185 ConnectToPresentationServiceIfNeeded();
222 presentation::SessionMessagePtr message_request(
223 presentation::SessionMessage::New());
224 message_request->presentation_url = session_message.presentation_url;
225 message_request->presentation_id = session_message.presentation_id;
226 message_request->type = session_message.type;
227 switch (session_message.type) {
228 case presentation::PresentationMessageType::
229 PRESENTATION_MESSAGE_TYPE_TEXT: {
230 message_request->message = session_message.message;
231 break;
232 }
233 case presentation::PresentationMessageType::
234 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER:
235 case presentation::PresentationMessageType::
236 PRESENTATION_MESSAGE_TYPE_BLOB: {
237 message_request->data =
238 mojo::Array<uint8>::From(session_message.data.storage());
239 break;
240 }
241 default: {
242 NOTREACHED() << "Invalid presentation message type "
243 << session_message.type;
244 break;
245 }
246 }
247 186
248 presentation_service_->SendSessionMessage( 187 presentation_service_->SendSessionMessage(
249 message_request.Pass(), 188 request->session_info.Pass(), request->message.Pass(),
250 base::Bind(&PresentationDispatcher::HandleSendMessageRequests, 189 base::Bind(&PresentationDispatcher::HandleSendMessageRequests,
251 base::Unretained(this))); 190 base::Unretained(this)));
252 } 191 }
253 192
254 void PresentationDispatcher::HandleSendMessageRequests(bool success) { 193 void PresentationDispatcher::HandleSendMessageRequests(bool success) {
255 // In normal cases, message_request_queue_ should not be empty at this point 194 // In normal cases, message_request_queue_ should not be empty at this point
256 // of time, but when DidCommitProvisionalLoad() is invoked before receiving 195 // of time, but when DidCommitProvisionalLoad() is invoked before receiving
257 // the callback for previous send mojo call, queue would have been emptied. 196 // the callback for previous send mojo call, queue would have been emptied.
258 if (message_request_queue_.empty()) 197 if (message_request_queue_.empty())
259 return; 198 return;
260 199
261 if (!success) { 200 if (!success) {
262 // PresentationServiceImpl is informing that Frame has been detached or 201 // PresentationServiceImpl is informing that Frame has been detached or
263 // navigated away. Invalidate all pending requests. 202 // navigated away. Invalidate all pending requests.
264 MessageRequestQueue empty; 203 MessageRequestQueue empty;
265 std::swap(message_request_queue_, empty); 204 std::swap(message_request_queue_, empty);
266 return; 205 return;
267 } 206 }
268 207
269 message_request_queue_.pop(); 208 message_request_queue_.pop();
270 if (!message_request_queue_.empty()) { 209 if (!message_request_queue_.empty()) {
271 const linked_ptr<presentation::SessionMessage>& request = 210 DoSendMessage(message_request_queue_.front().get());
272 message_request_queue_.front();
273 DoSendMessage(*request);
274 } 211 }
275 } 212 }
276 213
277 void PresentationDispatcher::closeSession( 214 void PresentationDispatcher::closeSession(
278 const blink::WebString& presentationUrl, 215 const blink::WebString& presentationUrl,
279 const blink::WebString& presentationId) { 216 const blink::WebString& presentationId) {
280 ConnectToPresentationServiceIfNeeded(); 217 ConnectToPresentationServiceIfNeeded();
281 218
282 presentation_service_->CloseSession( 219 presentation_service_->CloseSession(
283 presentationUrl.utf8(), 220 presentationUrl.utf8(),
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 bool is_new_navigation, 257 bool is_new_navigation,
321 bool is_same_page_navigation) { 258 bool is_same_page_navigation) {
322 blink::WebFrame* frame = render_frame()->GetWebFrame(); 259 blink::WebFrame* frame = render_frame()->GetWebFrame();
323 // If not top-level navigation. 260 // If not top-level navigation.
324 if (frame->parent() || is_same_page_navigation) 261 if (frame->parent() || is_same_page_navigation)
325 return; 262 return;
326 263
327 // Remove all pending send message requests. 264 // Remove all pending send message requests.
328 MessageRequestQueue empty; 265 MessageRequestQueue empty;
329 std::swap(message_request_queue_, empty); 266 std::swap(message_request_queue_, empty);
330
331 listening_for_messages_ = false;
332 } 267 }
333 268
334 void PresentationDispatcher::OnScreenAvailabilityUpdated(bool available) { 269 void PresentationDispatcher::OnScreenAvailabilityUpdated(bool available) {
335 last_known_availability_ = available; 270 last_known_availability_ = available;
336 271
337 if (listening_state_ == ListeningState::Waiting) 272 if (listening_state_ == ListeningState::Waiting)
338 listening_state_ = ListeningState::Active; 273 listening_state_ = ListeningState::Active;
339 274
340 for (auto observer : availability_observers_) 275 for (auto observer : availability_observers_)
341 observer->availabilityChanged(available); 276 observer->availabilityChanged(available);
(...skipping 29 matching lines...) Expand all
371 if (!controller_) 306 if (!controller_)
372 return; 307 return;
373 308
374 // Reset the callback to get the next event. 309 // Reset the callback to get the next event.
375 presentation_service_->ListenForDefaultSessionStart(base::Bind( 310 presentation_service_->ListenForDefaultSessionStart(base::Bind(
376 &PresentationDispatcher::OnDefaultSessionStarted, 311 &PresentationDispatcher::OnDefaultSessionStarted,
377 base::Unretained(this))); 312 base::Unretained(this)));
378 313
379 if (!session_info.is_null()) { 314 if (!session_info.is_null()) {
380 controller_->didStartDefaultSession( 315 controller_->didStartDefaultSession(
381 new PresentationSessionClient(session_info.Pass())); 316 new PresentationSessionClient(session_info.Clone()));
382 StartListenForMessages(); 317 presentation_service_->ListenForSessionMessages(session_info.Pass());
383 } 318 }
384 } 319 }
385 320
386 void PresentationDispatcher::OnSessionCreated( 321 void PresentationDispatcher::OnSessionCreated(
387 blink::WebPresentationSessionClientCallbacks* callback, 322 blink::WebPresentationSessionClientCallbacks* callback,
388 presentation::PresentationSessionInfoPtr session_info, 323 presentation::PresentationSessionInfoPtr session_info,
389 presentation::PresentationErrorPtr error) { 324 presentation::PresentationErrorPtr error) {
390 DCHECK(callback); 325 DCHECK(callback);
391 if (!error.is_null()) { 326 if (!error.is_null()) {
392 DCHECK(session_info.is_null()); 327 DCHECK(session_info.is_null());
393 callback->onError(new blink::WebPresentationError( 328 callback->onError(new blink::WebPresentationError(
394 GetWebPresentationErrorTypeFromMojo(error->error_type), 329 GetWebPresentationErrorTypeFromMojo(error->error_type),
395 blink::WebString::fromUTF8(error->message))); 330 blink::WebString::fromUTF8(error->message)));
396 return; 331 return;
397 } 332 }
398 333
399 DCHECK(!session_info.is_null()); 334 DCHECK(!session_info.is_null());
400 callback->onSuccess(new PresentationSessionClient(session_info.Pass())); 335 callback->onSuccess(new PresentationSessionClient(session_info.Clone()));
401 StartListenForMessages(); 336 presentation_service_->ListenForSessionMessages(session_info.Pass());
402 }
403
404 void PresentationDispatcher::StartListenForMessages() {
405 if (listening_for_messages_)
406 return;
407
408 listening_for_messages_ = true;
409 presentation_service_->ListenForSessionMessages(
410 base::Bind(&PresentationDispatcher::OnSessionMessagesReceived,
411 base::Unretained(this)));
412 } 337 }
413 338
414 void PresentationDispatcher::OnSessionStateChanged( 339 void PresentationDispatcher::OnSessionStateChanged(
415 presentation::PresentationSessionInfoPtr session_info, 340 presentation::PresentationSessionInfoPtr session_info,
416 presentation::PresentationSessionState session_state) { 341 presentation::PresentationSessionState session_state) {
417 if (!controller_) 342 if (!controller_)
418 return; 343 return;
419 344
420 DCHECK(!session_info.is_null()); 345 DCHECK(!session_info.is_null());
421 controller_->didChangeSessionState( 346 controller_->didChangeSessionState(
422 new PresentationSessionClient(session_info.Pass()), 347 new PresentationSessionClient(session_info.Pass()),
423 GetWebPresentationSessionStateFromMojo(session_state)); 348 GetWebPresentationSessionStateFromMojo(session_state));
424 } 349 }
425 350
426 void PresentationDispatcher::OnSessionMessagesReceived( 351 void PresentationDispatcher::OnSessionMessagesReceived(
352 presentation::PresentationSessionInfoPtr session_info,
427 mojo::Array<presentation::SessionMessagePtr> messages) { 353 mojo::Array<presentation::SessionMessagePtr> messages) {
428 if (!listening_for_messages_) 354 if (!controller_)
429 return; // messages may come after the frame navigated.
430
431 // When messages is null, there is an error at presentation service side.
432 if (!controller_ || messages.is_null()) {
433 listening_for_messages_ = false;
434 return; 355 return;
435 }
436 356
437 for (size_t i = 0; i < messages.size(); ++i) { 357 for (size_t i = 0; i < messages.size(); ++i) {
438 // Note: Passing batches of messages to the Blink layer would be more 358 // Note: Passing batches of messages to the Blink layer would be more
439 // efficient. 359 // efficient.
440 scoped_ptr<PresentationSessionClient> session_client( 360 scoped_ptr<PresentationSessionClient> session_client(
441 new PresentationSessionClient(messages[i]->presentation_url, 361 new PresentationSessionClient(session_info->url, session_info->id));
442 messages[i]->presentation_id));
443 switch (messages[i]->type) { 362 switch (messages[i]->type) {
444 case presentation::PresentationMessageType:: 363 case presentation::PresentationMessageType::
445 PRESENTATION_MESSAGE_TYPE_TEXT: { 364 PRESENTATION_MESSAGE_TYPE_TEXT: {
446 controller_->didReceiveSessionTextMessage( 365 controller_->didReceiveSessionTextMessage(
447 session_client.release(), 366 session_client.release(),
448 blink::WebString::fromUTF8(messages[i]->message)); 367 blink::WebString::fromUTF8(messages[i]->message));
449 break; 368 break;
450 } 369 }
451 case presentation::PresentationMessageType:: 370 case presentation::PresentationMessageType::
452 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER: 371 PRESENTATION_MESSAGE_TYPE_ARRAY_BUFFER:
453 case presentation::PresentationMessageType:: 372 case presentation::PresentationMessageType::
454 PRESENTATION_MESSAGE_TYPE_BLOB: { 373 PRESENTATION_MESSAGE_TYPE_BLOB: {
455 controller_->didReceiveSessionBinaryMessage( 374 controller_->didReceiveSessionBinaryMessage(
456 session_client.release(), &(messages[i]->data.front()), 375 session_client.release(), &(messages[i]->data.front()),
457 messages[i]->data.size()); 376 messages[i]->data.size());
458 break; 377 break;
459 } 378 }
460 default: { 379 default: {
461 NOTREACHED(); 380 NOTREACHED();
462 break; 381 break;
463 } 382 }
464 } 383 }
465 } 384 }
466
467 presentation_service_->ListenForSessionMessages(
468 base::Bind(&PresentationDispatcher::OnSessionMessagesReceived,
469 base::Unretained(this)));
470 } 385 }
471 386
472 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() { 387 void PresentationDispatcher::ConnectToPresentationServiceIfNeeded() {
473 if (presentation_service_.get()) 388 if (presentation_service_.get())
474 return; 389 return;
475 390
476 render_frame()->GetServiceRegistry()->ConnectToRemoteService( 391 render_frame()->GetServiceRegistry()->ConnectToRemoteService(
477 mojo::GetProxy(&presentation_service_)); 392 mojo::GetProxy(&presentation_service_));
478 presentation::PresentationServiceClientPtr client_ptr; 393 presentation::PresentationServiceClientPtr client_ptr;
479 binding_.Bind(GetProxy(&client_ptr)); 394 binding_.Bind(GetProxy(&client_ptr));
(...skipping 16 matching lines...) Expand all
496 ConnectToPresentationServiceIfNeeded(); 411 ConnectToPresentationServiceIfNeeded();
497 if (should_listen) { 412 if (should_listen) {
498 listening_state_ = ListeningState::Waiting; 413 listening_state_ = ListeningState::Waiting;
499 presentation_service_->ListenForScreenAvailability(); 414 presentation_service_->ListenForScreenAvailability();
500 } else { 415 } else {
501 listening_state_ = ListeningState::Inactive; 416 listening_state_ = ListeningState::Inactive;
502 presentation_service_->StopListeningForScreenAvailability(); 417 presentation_service_->StopListeningForScreenAvailability();
503 } 418 }
504 } 419 }
505 420
421 PresentationDispatcher::SendMessageRequest::SendMessageRequest(
422 presentation::PresentationSessionInfoPtr session_info,
423 presentation::SessionMessagePtr message)
424 : session_info(session_info.Pass()), message(message.Pass()) {}
425
426 PresentationDispatcher::SendMessageRequest::~SendMessageRequest() {}
427
428 // static
429 PresentationDispatcher::SendMessageRequest*
430 PresentationDispatcher::CreateSendTextMessageRequest(
431 const blink::WebString& presentationUrl,
432 const blink::WebString& presentationId,
433 const blink::WebString& message) {
434 presentation::PresentationSessionInfoPtr session_info =
435 presentation::PresentationSessionInfo::New();
436 session_info->url = presentationUrl.utf8();
437 session_info->id = presentationId.utf8();
438
439 presentation::SessionMessagePtr session_message =
440 presentation::SessionMessage::New();
441 session_message->type =
442 presentation::PresentationMessageType::PRESENTATION_MESSAGE_TYPE_TEXT;
443 session_message->message = message.utf8();
444 return new SendMessageRequest(session_info.Pass(), session_message.Pass());
445 }
446
447 // static
448 PresentationDispatcher::SendMessageRequest*
449 PresentationDispatcher::CreateSendBinaryMessageRequest(
450 const blink::WebString& presentationUrl,
451 const blink::WebString& presentationId,
452 presentation::PresentationMessageType type,
453 const uint8* data,
454 size_t length) {
455 presentation::PresentationSessionInfoPtr session_info =
456 presentation::PresentationSessionInfo::New();
457 session_info->url = presentationUrl.utf8();
458 session_info->id = presentationId.utf8();
459
460 presentation::SessionMessagePtr session_message =
461 presentation::SessionMessage::New();
462 session_message->type = type;
463 std::vector<uint8> tmp_data_vector(data, data + length);
464 session_message->data.Swap(&tmp_data_vector);
465 return new SendMessageRequest(session_info.Pass(), session_message.Pass());
466 }
467
506 } // namespace content 468 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/presentation/presentation_dispatcher.h ('k') | extensions/renderer/resources/media_router_bindings.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698