1 // Copyright (c) 2012 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.
5 #include "content/browser/browser_plugin/browser_plugin_guest.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
13 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
14 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
15 #include "content/browser/browser_thread_impl.h"
16 #include "content/browser/child_process_security_policy_impl.h"
17 #include "content/browser/frame_host/render_widget_host_view_guest.h"
18 #include "content/browser/loader/resource_dispatcher_host_impl.h"
19 #include "content/browser/renderer_host/render_view_host_impl.h"
20 #include "content/browser/renderer_host/render_widget_host_impl.h"
21 #include "content/browser/web_contents/web_contents_impl.h"
22 #include "content/browser/web_contents/web_contents_view_guest.h"
23 #include "content/common/browser_plugin/browser_plugin_constants.h"
24 #include "content/common/browser_plugin/browser_plugin_messages.h"
25 #include "content/common/content_constants_internal.h"
26 #include "content/common/drag_messages.h"
27 #include "content/common/gpu/gpu_messages.h"
28 #include "content/common/input_messages.h"
29 #include "content/common/view_messages.h"
30 #include "content/port/browser/render_view_host_delegate_view.h"
31 #include "content/port/browser/render_widget_host_view_port.h"
32 #include "content/public/browser/browser_context.h"
33 #include "content/public/browser/content_browser_client.h"
34 #include "content/public/browser/geolocation_permission_context.h"
35 #include "content/public/browser/navigation_controller.h"
36 #include "content/public/browser/render_process_host.h"
37 #include "content/public/browser/render_widget_host_view.h"
38 #include "content/public/browser/resource_request_details.h"
39 #include "content/public/browser/user_metrics.h"
40 #include "content/public/browser/web_contents_observer.h"
41 #include "content/public/browser/web_contents_view.h"
42 #include "content/public/common/drop_data.h"
43 #include "content/public/common/media_stream_request.h"
44 #include "content/public/common/result_codes.h"
45 #include "content/public/common/url_constants.h"
46 #include "content/public/common/url_utils.h"
47 #include "net/url_request/url_request.h"
48 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
49 #include "ui/events/keycodes/keyboard_codes.h"
50 #include "ui/surface/transport_dib.h"
51 #include "webkit/common/resource_type.h"
53 #if defined(OS_MACOSX)
54 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
60 BrowserPluginHostFactory* BrowserPluginGuest::factory_ = NULL;
62 // Parent class for the various types of permission requests, each of which
63 // should be able to handle the response to their permission request.
64 class BrowserPluginGuest::PermissionRequest :
65 public base::RefCounted<BrowserPluginGuest::PermissionRequest> {
67 void Respond(bool should_allow, const std::string& user_input) {
70 RespondImpl(should_allow, user_input);
72 virtual bool AllowedByDefault() const {
76 explicit PermissionRequest(const base::WeakPtr<BrowserPluginGuest>& guest)
79 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest"));
81 virtual ~PermissionRequest() {}
83 virtual void RespondImpl(bool should_allow,
84 const std::string& user_input) = 0;
85 // Friend RefCounted so that the dtor can be non-public.
86 friend class base::RefCounted<BrowserPluginGuest::PermissionRequest>;
88 base::WeakPtr<BrowserPluginGuest> guest_;
91 class BrowserPluginGuest::DownloadRequest : public PermissionRequest {
93 DownloadRequest(const base::WeakPtr<BrowserPluginGuest>& guest,
94 const base::Callback<void(bool)>& callback)
95 : PermissionRequest(guest),
98 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Download"));
100 virtual void RespondImpl(bool should_allow,
101 const std::string& user_input) OVERRIDE {
102 callback_.Run(should_allow);
106 virtual ~DownloadRequest() {}
107 base::Callback<void(bool)> callback_;
110 class BrowserPluginGuest::GeolocationRequest : public PermissionRequest {
112 GeolocationRequest(const base::WeakPtr<BrowserPluginGuest>& guest,
113 GeolocationCallback callback,
115 : PermissionRequest(guest),
117 bridge_id_(bridge_id) {
119 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Geolocation"));
122 virtual void RespondImpl(bool should_allow,
123 const std::string& user_input) OVERRIDE {
124 WebContents* web_contents = guest_->embedder_web_contents();
125 if (should_allow && web_contents) {
126 // If renderer side embedder decides to allow gelocation, we need to check
127 // if the app/embedder itself has geolocation access.
128 BrowserContext* browser_context = web_contents->GetBrowserContext();
129 if (browser_context) {
130 GeolocationPermissionContext* geolocation_context =
131 browser_context->GetGeolocationPermissionContext();
132 if (geolocation_context) {
133 base::Callback<void(bool)> geolocation_callback = base::Bind(
134 &BrowserPluginGuest::SetGeolocationPermission,
138 geolocation_context->RequestGeolocationPermission(
139 web_contents->GetRenderProcessHost()->GetID(),
140 web_contents->GetRoutingID(),
141 // The geolocation permission request here is not initiated
142 // through WebGeolocationPermissionRequest. We are only interested
143 // in the fact whether the embedder/app has geolocation
144 // permission. Therefore we use an invalid |bridge_id|.
146 web_contents->GetLastCommittedURL(),
147 geolocation_callback);
152 guest_->SetGeolocationPermission(callback_, bridge_id_, false);
156 virtual ~GeolocationRequest() {}
157 base::Callback<void(bool)> callback_;
161 class BrowserPluginGuest::MediaRequest : public PermissionRequest {
163 MediaRequest(const base::WeakPtr<BrowserPluginGuest>& guest,
164 const MediaStreamRequest& request,
165 const MediaResponseCallback& callback)
166 : PermissionRequest(guest),
168 callback_(callback) {
170 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Media"));
173 virtual void RespondImpl(bool should_allow,
174 const std::string& user_input) OVERRIDE {
175 WebContentsImpl* web_contents = guest_->embedder_web_contents();
176 if (should_allow && web_contents) {
177 // Re-route the request to the embedder's WebContents; the guest gets the
178 // permission this way.
179 web_contents->RequestMediaAccessPermission(request_, callback_);
182 callback_.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
187 virtual ~MediaRequest() {}
188 MediaStreamRequest request_;
189 MediaResponseCallback callback_;
192 class BrowserPluginGuest::NewWindowRequest : public PermissionRequest {
194 NewWindowRequest(const base::WeakPtr<BrowserPluginGuest>& guest,
196 : PermissionRequest(guest),
197 instance_id_(instance_id) {
199 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.NewWindow"));
202 virtual void RespondImpl(bool should_allow,
203 const std::string& user_input) OVERRIDE {
204 int embedder_render_process_id =
205 guest_->embedder_web_contents()->GetRenderProcessHost()->GetID();
206 BrowserPluginGuest* guest =
207 guest_->GetWebContents()->GetBrowserPluginGuestManager()->
208 GetGuestByInstanceID(instance_id_, embedder_render_process_id);
210 VLOG(0) << "Guest not found. Instance ID: " << instance_id_;
214 // If we do not destroy the guest then we allow the new window.
220 virtual ~NewWindowRequest() {}
224 class BrowserPluginGuest::JavaScriptDialogRequest : public PermissionRequest {
226 JavaScriptDialogRequest(const base::WeakPtr<BrowserPluginGuest>& guest,
227 const DialogClosedCallback& callback)
228 : PermissionRequest(guest),
229 callback_(callback) {
231 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.JSDialog"));
234 virtual void RespondImpl(bool should_allow,
235 const std::string& user_input) OVERRIDE {
236 callback_.Run(should_allow, base::UTF8ToUTF16(user_input));
240 virtual ~JavaScriptDialogRequest() {}
241 DialogClosedCallback callback_;
244 class BrowserPluginGuest::PointerLockRequest : public PermissionRequest {
246 explicit PointerLockRequest(const base::WeakPtr<BrowserPluginGuest>& guest)
247 : PermissionRequest(guest) {
249 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.PointerLock"));
252 virtual void RespondImpl(bool should_allow,
253 const std::string& user_input) OVERRIDE {
254 guest_->SendMessageToEmbedder(
255 new BrowserPluginMsg_SetMouseLock(guest_->instance_id(), should_allow));
259 virtual ~PointerLockRequest() {}
263 std::string WindowOpenDispositionToString(
264 WindowOpenDisposition window_open_disposition) {
265 switch (window_open_disposition) {
269 return "save_to_disk";
271 return "current_tab";
272 case NEW_BACKGROUND_TAB:
273 return "new_background_tab";
274 case NEW_FOREGROUND_TAB:
275 return "new_foreground_tab";
281 NOTREACHED() << "Unknown Window Open Disposition";
286 std::string JavaScriptMessageTypeToString(JavaScriptMessageType message_type) {
287 switch (message_type) {
288 case JAVASCRIPT_MESSAGE_TYPE_ALERT:
290 case JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
292 case JAVASCRIPT_MESSAGE_TYPE_PROMPT:
295 NOTREACHED() << "Unknown JavaScript Message Type.";
300 // Called on IO thread.
301 static std::string RetrieveDownloadURLFromRequestId(
302 RenderViewHost* render_view_host,
303 int url_request_id) {
304 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
306 int render_process_id = render_view_host->GetProcess()->GetID();
307 GlobalRequestID global_id(render_process_id, url_request_id);
308 net::URLRequest* url_request =
309 ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id);
311 return url_request->url().possibly_invalid_spec();
317 class BrowserPluginGuest::EmbedderWebContentsObserver
318 : public WebContentsObserver {
320 explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest)
321 : WebContentsObserver(guest->embedder_web_contents()),
322 browser_plugin_guest_(guest) {
325 virtual ~EmbedderWebContentsObserver() {
328 // WebContentsObserver:
329 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
330 browser_plugin_guest_->EmbedderDestroyed();
333 virtual void WasShown() OVERRIDE {
334 browser_plugin_guest_->EmbedderVisibilityChanged(true);
337 virtual void WasHidden() OVERRIDE {
338 browser_plugin_guest_->EmbedderVisibilityChanged(false);
342 BrowserPluginGuest* browser_plugin_guest_;
344 DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
347 BrowserPluginGuest::BrowserPluginGuest(
349 bool has_render_view,
350 WebContentsImpl* web_contents,
351 BrowserPluginGuest* opener)
352 : WebContentsObserver(web_contents),
353 embedder_web_contents_(NULL),
354 instance_id_(instance_id),
355 damage_buffer_sequence_id_(0),
356 damage_buffer_size_(0),
357 damage_buffer_scale_factor_(1.0f),
358 guest_device_scale_factor_(1.0f),
360 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
362 mouse_locked_(false),
363 pending_lock_request_(false),
364 embedder_visible_(true),
366 next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID),
367 has_render_view_(has_render_view),
368 last_seen_auto_size_enabled_(false),
369 is_in_destruction_(false),
370 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
371 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
372 last_can_compose_inline_(true),
373 weak_ptr_factory_(this) {
374 DCHECK(web_contents);
375 web_contents->SetDelegate(this);
377 opener_ = opener->AsWeakPtr();
378 GetWebContents()->GetBrowserPluginGuestManager()->AddGuest(instance_id_,
382 bool BrowserPluginGuest::AddMessageToConsole(WebContents* source,
384 const base::string16& message,
386 const base::string16& source_id) {
390 delegate_->AddMessageToConsole(level, message, line_no, source_id);
394 void BrowserPluginGuest::DestroyUnattachedWindows() {
395 // Destroy() reaches in and removes the BrowserPluginGuest from its opener's
396 // pending_new_windows_ set. To avoid mutating the set while iterating, we
397 // create a copy of the pending new windows set and iterate over the copy.
398 PendingWindowMap pending_new_windows(pending_new_windows_);
399 // Clean up unattached new windows opened by this guest.
400 for (PendingWindowMap::const_iterator it = pending_new_windows.begin();
401 it != pending_new_windows.end(); ++it) {
402 it->first->Destroy();
404 // All pending windows should be removed from the set after Destroy() is
405 // called on all of them.
406 DCHECK(pending_new_windows_.empty());
409 void BrowserPluginGuest::LoadURLWithParams(const GURL& url,
410 const Referrer& referrer,
411 PageTransition transition_type,
412 WebContents* web_contents) {
413 NavigationController::LoadURLParams load_url_params(url);
414 load_url_params.referrer = referrer;
415 load_url_params.transition_type = transition_type;
416 load_url_params.extra_headers = std::string();
417 if (delegate_ && delegate_->IsOverridingUserAgent()) {
418 load_url_params.override_user_agent =
419 NavigationController::UA_OVERRIDE_TRUE;
421 web_contents->GetController().LoadURLWithParams(load_url_params);
424 void BrowserPluginGuest::RespondToPermissionRequest(
427 const std::string& user_input) {
428 RequestMap::iterator request_itr = permission_request_map_.find(request_id);
429 if (request_itr == permission_request_map_.end()) {
430 VLOG(0) << "Not a valid request ID.";
433 request_itr->second->Respond(should_allow, user_input);
434 permission_request_map_.erase(request_itr);
437 int BrowserPluginGuest::RequestPermission(
438 BrowserPluginPermissionType permission_type,
439 scoped_refptr<BrowserPluginGuest::PermissionRequest> request,
440 const base::DictionaryValue& request_info) {
442 // Let the stack unwind before we deny the permission request so that
443 // objects held by the permission request are not destroyed immediately
444 // after creation. This is to allow those same objects to be accessed again
445 // in the same scope without fear of use after freeing.
446 base::MessageLoop::current()->PostTask(
448 base::Bind(&BrowserPluginGuest::PermissionRequest::Respond,
449 request, false, ""));
450 return browser_plugin::kInvalidPermissionRequestID;
453 int request_id = ++next_permission_request_id_;
454 permission_request_map_[request_id] = request;
456 BrowserPluginGuestDelegate::PermissionResponseCallback callback =
457 base::Bind(&BrowserPluginGuest::RespondToPermissionRequest,
460 // If BrowserPluginGuestDelegate hasn't handled the permission then we simply
461 // perform the default action (which is one of allow or reject) immediately.
462 if (!delegate_->RequestPermission(
463 permission_type, request_info, callback, request->AllowedByDefault())) {
464 callback.Run(request->AllowedByDefault(), "");
465 return browser_plugin::kInvalidPermissionRequestID;
471 BrowserPluginGuest* BrowserPluginGuest::CreateNewGuestWindow(
472 const OpenURLParams& params) {
473 BrowserPluginGuestManager* guest_manager =
474 GetWebContents()->GetBrowserPluginGuestManager();
476 // Allocate a new instance ID for the new guest.
477 int instance_id = guest_manager->get_next_instance_id();
479 // Set the attach params to use the same partition as the opener.
480 // We pull the partition information from the site's URL, which is of the form
481 // guest://site/{persist}?{partition_name}.
482 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
483 BrowserPluginHostMsg_Attach_Params attach_params;
484 attach_params.storage_partition_id = site_url.query();
485 attach_params.persist_storage =
486 site_url.path().find("persist") != std::string::npos;
488 // The new guest gets a copy of this guest's extra params so that the content
489 // embedder exposes the same API for this guest as its opener.
490 scoped_ptr<base::DictionaryValue> extra_params(
491 extra_attach_params_->DeepCopy());
492 BrowserPluginGuest* new_guest =
493 GetWebContents()->GetBrowserPluginGuestManager()->CreateGuest(
494 GetWebContents()->GetSiteInstance(), instance_id,
495 attach_params, extra_params.Pass());
496 new_guest->opener_ = AsWeakPtr();
498 // Take ownership of |new_guest|.
499 pending_new_windows_.insert(
500 std::make_pair(new_guest, NewWindowInfo(params.url, std::string())));
502 // Request permission to show the new window.
503 RequestNewWindowPermission(params.disposition, gfx::Rect(),
504 params.user_gesture, new_guest->GetWebContents());
509 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
510 return weak_ptr_factory_.GetWeakPtr();
513 void BrowserPluginGuest::EmbedderDestroyed() {
514 embedder_web_contents_ = NULL;
516 delegate_->EmbedderDestroyed();
520 void BrowserPluginGuest::Destroy() {
521 is_in_destruction_ = true;
522 if (!attached() && opener())
523 opener()->pending_new_windows_.erase(this);
524 DestroyUnattachedWindows();
525 GetWebContents()->GetBrowserPluginGuestManager()->RemoveGuest(instance_id_);
526 delete GetWebContents();
529 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
530 const IPC::Message& message) {
532 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
533 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_BuffersSwappedACK,
535 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
536 OnCompositorFrameSwappedACK)
537 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck,
538 OnCopyFromCompositingSurfaceAck)
539 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
541 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
542 OnExecuteEditCommand)
543 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
544 OnExtendSelectionAndDelete)
545 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
547 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
548 OnImeConfirmComposition)
549 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
551 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
552 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateGuest, OnNavigateGuest)
553 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
554 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
555 OnReclaimCompositorResources)
556 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
557 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize)
558 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
559 OnSetEditCommandsForNextKeyEvent)
560 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
561 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetName, OnSetName)
562 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetContentsOpaque,
564 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
565 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
566 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
567 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateRect_ACK, OnUpdateRectACK)
568 IPC_MESSAGE_UNHANDLED(handled = false)
569 IPC_END_MESSAGE_MAP()
573 void BrowserPluginGuest::Initialize(
574 const BrowserPluginHostMsg_Attach_Params& params,
575 WebContentsImpl* embedder_web_contents) {
576 focused_ = params.focused;
577 guest_visible_ = params.visible;
578 guest_opaque_ = params.opaque;
579 guest_window_rect_ = params.resize_guest_params.view_rect;
581 if (!params.name.empty())
583 auto_size_enabled_ = params.auto_size_params.enable;
584 max_auto_size_ = params.auto_size_params.max_size;
585 min_auto_size_ = params.auto_size_params.min_size;
587 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
589 embedder_web_contents_ = embedder_web_contents;
591 WebContentsViewGuest* new_view =
592 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
593 new_view->OnGuestInitialized(embedder_web_contents->GetView());
595 RendererPreferences* renderer_prefs =
596 GetWebContents()->GetMutableRendererPrefs();
597 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
598 // Copy renderer preferences (and nothing else) from the embedder's
599 // WebContents to the guest.
601 // For GTK and Aura this is necessary to get proper renderer configuration
602 // values for caret blinking interval, colors related to selection and
604 *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs();
605 renderer_prefs->user_agent_override = guest_user_agent_override;
607 // We would like the guest to report changes to frame names so that we can
608 // update the BrowserPlugin's corresponding 'name' attribute.
609 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
610 renderer_prefs->report_frame_name_changes = true;
611 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
612 // navigations still continue to function inside the app.
613 renderer_prefs->browser_handles_all_top_level_requests = false;
614 // Disable "client blocked" error page for browser plugin.
615 renderer_prefs->disable_client_blocked_error_page = true;
617 embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this));
619 OnSetSize(instance_id_, params.auto_size_params, params.resize_guest_params);
621 // Create a swapped out RenderView for the guest in the embedder render
622 // process, so that the embedder can access the guest's window object.
623 int guest_routing_id =
624 GetWebContents()->CreateSwappedOutRenderView(
625 embedder_web_contents_->GetSiteInstance());
626 SendMessageToEmbedder(
627 new BrowserPluginMsg_GuestContentWindowReady(instance_id_,
630 if (!params.src.empty()) {
631 // params.src will be validated in BrowserPluginGuest::OnNavigateGuest.
632 OnNavigateGuest(instance_id_, params.src);
635 has_render_view_ = true;
637 if (!embedder_web_contents_->
638 GetWebkitPrefs().accelerated_compositing_enabled) {
639 WebPreferences prefs = GetWebContents()->GetWebkitPrefs();
640 prefs.accelerated_compositing_enabled = false;
641 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
644 // Enable input method for guest if it's enabled for the embedder.
645 if (static_cast<RenderViewHostImpl*>(
646 embedder_web_contents_->GetRenderViewHost())->input_method_active()) {
647 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
648 GetWebContents()->GetRenderViewHost());
649 guest_rvh->SetInputMethodActive(true);
652 // Inform the embedder of the guest's information.
653 // We pull the partition information from the site's URL, which is of the form
654 // guest://site/{persist}?{partition_name}.
655 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
656 BrowserPluginMsg_Attach_ACK_Params ack_params;
657 ack_params.storage_partition_id = site_url.query();
658 ack_params.persist_storage =
659 site_url.path().find("persist") != std::string::npos;
660 ack_params.name = name_;
661 SendMessageToEmbedder(
662 new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
665 delegate_->DidAttach();
668 BrowserPluginGuest::~BrowserPluginGuest() {
669 while (!pending_messages_.empty()) {
670 delete pending_messages_.front();
671 pending_messages_.pop();
676 BrowserPluginGuest* BrowserPluginGuest::Create(
678 SiteInstance* guest_site_instance,
679 WebContentsImpl* web_contents,
680 scoped_ptr<base::DictionaryValue> extra_params) {
681 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
682 BrowserPluginGuest* guest = NULL;
684 guest = factory_->CreateBrowserPluginGuest(instance_id, web_contents);
686 guest = new BrowserPluginGuest(instance_id, false, web_contents, NULL);
688 guest->extra_attach_params_.reset(extra_params->DeepCopy());
689 web_contents->SetBrowserPluginGuest(guest);
690 BrowserPluginGuestDelegate* delegate = NULL;
691 GetContentClient()->browser()->GuestWebContentsCreated(
692 guest_site_instance, web_contents, NULL, &delegate, extra_params.Pass());
693 guest->SetDelegate(delegate);
698 BrowserPluginGuest* BrowserPluginGuest::CreateWithOpener(
700 bool has_render_view,
701 WebContentsImpl* web_contents,
702 BrowserPluginGuest* opener) {
703 BrowserPluginGuest* guest =
704 new BrowserPluginGuest(
705 instance_id, has_render_view, web_contents, opener);
706 web_contents->SetBrowserPluginGuest(guest);
707 BrowserPluginGuestDelegate* delegate = NULL;
708 GetContentClient()->browser()->GuestWebContentsCreated(
709 opener->GetWebContents()->GetSiteInstance(),
710 web_contents, opener->GetWebContents(), &delegate,
711 scoped_ptr<base::DictionaryValue>());
712 guest->SetDelegate(delegate);
716 RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
719 return embedder_web_contents_->GetRenderWidgetHostView();
722 void BrowserPluginGuest::UpdateVisibility() {
723 OnSetVisibility(instance_id_, visible());
726 void BrowserPluginGuest::CopyFromCompositingSurface(
727 gfx::Rect src_subrect,
729 const base::Callback<void(bool, const SkBitmap&)>& callback) {
730 copy_request_callbacks_.insert(std::make_pair(++copy_request_id_, callback));
731 SendMessageToEmbedder(
732 new BrowserPluginMsg_CopyFromCompositingSurface(instance_id(),
733 copy_request_id_, src_subrect, dst_size));
737 gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) {
738 gfx::Rect guest_rect(bounds);
739 guest_rect.Offset(guest_window_rect_.OffsetFromOrigin());
743 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
744 embedder_visible_ = visible;
748 void BrowserPluginGuest::AddNewContents(WebContents* source,
749 WebContents* new_contents,
750 WindowOpenDisposition disposition,
751 const gfx::Rect& initial_pos,
755 *was_blocked = false;
756 RequestNewWindowPermission(disposition, initial_pos, user_gesture,
757 static_cast<WebContentsImpl*>(new_contents));
760 void BrowserPluginGuest::CanDownload(
761 RenderViewHost* render_view_host,
763 const std::string& request_method,
764 const base::Callback<void(bool)>& callback) {
765 BrowserThread::PostTaskAndReplyWithResult(
766 BrowserThread::IO, FROM_HERE,
767 base::Bind(&RetrieveDownloadURLFromRequestId,
768 render_view_host, request_id),
769 base::Bind(&BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId,
770 weak_ptr_factory_.GetWeakPtr(),
775 void BrowserPluginGuest::LoadProgressChanged(WebContents* contents,
778 delegate_->LoadProgressed(progress);
781 void BrowserPluginGuest::CloseContents(WebContents* source) {
788 JavaScriptDialogManager* BrowserPluginGuest::GetJavaScriptDialogManager() {
792 bool BrowserPluginGuest::HandleContextMenu(const ContextMenuParams& params) {
793 // TODO(fsamuel): We show the regular page context menu handler for now until
794 // we implement the Apps Context Menu API for Browser Plugin (see
795 // http://crbug.com/140315).
796 return false; // Will be handled by WebContentsViewGuest.
799 void BrowserPluginGuest::HandleKeyboardEvent(
801 const NativeWebKeyboardEvent& event) {
805 if (UnlockMouseIfNecessary(event))
808 if (delegate_ && delegate_->HandleKeyboardEvent(event))
811 if (!embedder_web_contents_->GetDelegate())
814 // Send the unhandled keyboard events back to the embedder to reprocess them.
815 // TODO(fsamuel): This introduces the possibility of out-of-order keyboard
816 // events because the guest may be arbitrarily delayed when responding to
817 // keyboard events. In that time, the embedder may have received and processed
818 // additional key events. This needs to be fixed as soon as possible.
819 // See http://crbug.com/229882.
820 embedder_web_contents_->GetDelegate()->HandleKeyboardEvent(
821 web_contents(), event);
824 void BrowserPluginGuest::SetZoom(double zoom_factor) {
826 delegate_->SetZoom(zoom_factor);
829 WebContents* BrowserPluginGuest::OpenURLFromTab(WebContents* source,
830 const OpenURLParams& params) {
831 // If the guest wishes to navigate away prior to attachment then we save the
832 // navigation to perform upon attachment. Navigation initializes a lot of
833 // state that assumes an embedder exists, such as RenderWidgetHostViewGuest.
834 // Navigation also resumes resource loading which we don't want to allow
837 PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
838 if (it == opener()->pending_new_windows_.end())
840 const NewWindowInfo& old_target_url = it->second;
841 NewWindowInfo new_window_info(params.url, old_target_url.name);
842 new_window_info.changed = new_window_info.url != old_target_url.url;
843 it->second = new_window_info;
846 if (params.disposition == CURRENT_TAB) {
847 // This can happen for cross-site redirects.
848 LoadURLWithParams(params.url, params.referrer, params.transition, source);
852 return CreateNewGuestWindow(params)->GetWebContents();
855 void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents,
856 int64 source_frame_id,
857 const base::string16& frame_name,
858 const GURL& target_url,
859 WebContents* new_contents) {
860 WebContentsImpl* new_contents_impl =
861 static_cast<WebContentsImpl*>(new_contents);
862 BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest();
863 guest->opener_ = AsWeakPtr();
864 std::string guest_name = base::UTF16ToUTF8(frame_name);
865 guest->name_ = guest_name;
866 // Take ownership of the new guest until it is attached to the embedder's DOM
867 // tree to avoid leaking a guest if this guest is destroyed before attaching
869 pending_new_windows_.insert(
870 std::make_pair(guest, NewWindowInfo(target_url, guest_name)));
873 void BrowserPluginGuest::RendererUnresponsive(WebContents* source) {
874 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Hung"));
877 delegate_->RendererUnresponsive();
880 void BrowserPluginGuest::RendererResponsive(WebContents* source) {
881 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Responsive"));
884 delegate_->RendererResponsive();
887 void BrowserPluginGuest::RunFileChooser(WebContents* web_contents,
888 const FileChooserParams& params) {
892 if (!embedder_web_contents_->GetDelegate())
895 embedder_web_contents_->GetDelegate()->RunFileChooser(web_contents, params);
898 bool BrowserPluginGuest::ShouldFocusPageAfterCrash() {
899 // Rather than managing focus in WebContentsImpl::RenderViewReady, we will
900 // manage the focus ourselves.
904 WebContentsImpl* BrowserPluginGuest::GetWebContents() {
905 return static_cast<WebContentsImpl*>(web_contents());
908 base::SharedMemory* BrowserPluginGuest::GetDamageBufferFromEmbedder(
909 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
911 LOG(WARNING) << "Attempting to map a damage buffer prior to attachment.";
915 base::ProcessHandle handle =
916 embedder_web_contents_->GetRenderProcessHost()->GetHandle();
917 scoped_ptr<base::SharedMemory> shared_buf(
918 new base::SharedMemory(params.damage_buffer_handle, false, handle));
919 #elif defined(OS_POSIX)
920 scoped_ptr<base::SharedMemory> shared_buf(
921 new base::SharedMemory(params.damage_buffer_handle, false));
923 if (!shared_buf->Map(params.damage_buffer_size)) {
924 LOG(WARNING) << "Unable to map the embedder's damage buffer.";
927 return shared_buf.release();
930 void BrowserPluginGuest::SetDamageBuffer(
931 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
932 damage_buffer_.reset(GetDamageBufferFromEmbedder(params));
933 // Sanity check: Verify that we've correctly shared the damage buffer memory
934 // between the embedder and browser processes.
935 DCHECK(!damage_buffer_ ||
936 *static_cast<unsigned int*>(damage_buffer_->memory()) == 0xdeadbeef);
937 damage_buffer_sequence_id_ = params.damage_buffer_sequence_id;
938 damage_buffer_size_ = params.damage_buffer_size;
939 damage_view_size_ = params.view_rect.size();
940 damage_buffer_scale_factor_ = params.scale_factor;
943 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
944 const gfx::Point& relative_position) const {
945 gfx::Point screen_pos(relative_position);
946 screen_pos += guest_window_rect_.OffsetFromOrigin();
950 bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const {
951 return size.width() <= max_auto_size_.width() &&
952 size.height() <= max_auto_size_.height();
955 void BrowserPluginGuest::RequestNewWindowPermission(
956 WindowOpenDisposition disposition,
957 const gfx::Rect& initial_bounds,
959 WebContentsImpl* new_contents) {
960 BrowserPluginGuest* guest = new_contents->GetBrowserPluginGuest();
961 PendingWindowMap::iterator it = pending_new_windows_.find(guest);
962 if (it == pending_new_windows_.end())
964 const NewWindowInfo& new_window_info = it->second;
966 base::DictionaryValue request_info;
967 request_info.Set(browser_plugin::kInitialHeight,
968 base::Value::CreateIntegerValue(initial_bounds.height()));
969 request_info.Set(browser_plugin::kInitialWidth,
970 base::Value::CreateIntegerValue(initial_bounds.width()));
971 request_info.Set(browser_plugin::kTargetURL,
972 base::Value::CreateStringValue(new_window_info.url.spec()));
973 request_info.Set(browser_plugin::kName,
974 base::Value::CreateStringValue(new_window_info.name));
975 request_info.Set(browser_plugin::kWindowID,
976 base::Value::CreateIntegerValue(guest->instance_id()));
977 request_info.Set(browser_plugin::kWindowOpenDisposition,
978 base::Value::CreateStringValue(
979 WindowOpenDispositionToString(disposition)));
981 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW,
982 new NewWindowRequest(weak_ptr_factory_.GetWeakPtr(),
983 guest->instance_id()),
987 bool BrowserPluginGuest::UnlockMouseIfNecessary(
988 const NativeWebKeyboardEvent& event) {
992 embedder_web_contents()->GotResponseToLockMouseRequest(false);
996 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
998 // Some pages such as data URLs, javascript URLs, and about:blank
999 // do not load external resources and so they load prior to attachment.
1000 // As a result, we must save all these IPCs until attachment and then
1001 // forward them so that the embedder gets a chance to see and process
1003 pending_messages_.push(msg);
1006 msg->set_routing_id(embedder_web_contents_->GetRoutingID());
1007 embedder_web_contents_->Send(msg);
1010 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
1011 int screen_x, int screen_y, blink::WebDragOperation operation) {
1012 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
1013 screen_x, screen_y, operation);
1016 void BrowserPluginGuest::DragSourceMovedTo(int client_x, int client_y,
1017 int screen_x, int screen_y) {
1018 web_contents()->GetRenderViewHost()->DragSourceMovedTo(client_x, client_y,
1019 screen_x, screen_y);
1022 void BrowserPluginGuest::EndSystemDrag() {
1023 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
1024 GetWebContents()->GetRenderViewHost());
1025 guest_rvh->DragSourceSystemDragEnded();
1028 void BrowserPluginGuest::SetDelegate(BrowserPluginGuestDelegate* delegate) {
1030 delegate_.reset(delegate);
1033 void BrowserPluginGuest::AskEmbedderForGeolocationPermission(
1035 const GURL& requesting_frame,
1036 const GeolocationCallback& callback) {
1037 base::DictionaryValue request_info;
1038 request_info.Set(browser_plugin::kURL,
1039 base::Value::CreateStringValue(requesting_frame.spec()));
1042 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_GEOLOCATION,
1043 new GeolocationRequest(weak_ptr_factory_.GetWeakPtr(),
1048 DCHECK(bridge_id_to_request_id_map_.find(bridge_id) ==
1049 bridge_id_to_request_id_map_.end());
1050 bridge_id_to_request_id_map_[bridge_id] = request_id;
1053 int BrowserPluginGuest::RemoveBridgeID(int bridge_id) {
1054 std::map<int, int>::iterator bridge_itr =
1055 bridge_id_to_request_id_map_.find(bridge_id);
1056 if (bridge_itr == bridge_id_to_request_id_map_.end())
1057 return browser_plugin::kInvalidPermissionRequestID;
1059 int request_id = bridge_itr->second;
1060 bridge_id_to_request_id_map_.erase(bridge_itr);
1064 void BrowserPluginGuest::CancelGeolocationRequest(int bridge_id) {
1065 int request_id = RemoveBridgeID(bridge_id);
1066 RequestMap::iterator request_itr = permission_request_map_.find(request_id);
1067 if (request_itr == permission_request_map_.end())
1069 permission_request_map_.erase(request_itr);
1072 void BrowserPluginGuest::SetGeolocationPermission(GeolocationCallback callback,
1075 callback.Run(allowed);
1076 RemoveBridgeID(bridge_id);
1079 void BrowserPluginGuest::SendQueuedMessages() {
1083 while (!pending_messages_.empty()) {
1084 IPC::Message* message = pending_messages_.front();
1085 pending_messages_.pop();
1086 SendMessageToEmbedder(message);
1090 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
1092 const base::string16& frame_unique_name,
1095 PageTransition transition_type,
1096 RenderViewHost* render_view_host) {
1097 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
1100 void BrowserPluginGuest::DidStopLoading(RenderViewHost* render_view_host) {
1101 bool enable_dragdrop = delegate_ && delegate_->IsDragAndDropEnabled();
1102 if (!enable_dragdrop) {
1103 // Initiating a drag from inside a guest is currently not supported without
1104 // the kEnableBrowserPluginDragDrop flag on a linux platform. So inject some
1105 // JS to disable it. http://crbug.com/161112
1106 const char script[] = "window.addEventListener('dragstart', function() { "
1107 " window.event.preventDefault(); "
1109 render_view_host->ExecuteJavascriptInWebFrame(base::string16(),
1110 base::ASCIIToUTF16(script));
1114 void BrowserPluginGuest::RenderViewReady() {
1115 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
1116 // The guest RenderView should always live in a guest process.
1117 CHECK(rvh->GetProcess()->IsGuest());
1118 // TODO(fsamuel): Investigate whether it's possible to update state earlier
1119 // here (see http://crbug.com/158151).
1120 Send(new InputMsg_SetFocus(routing_id(), focused_));
1122 if (auto_size_enabled_)
1123 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
1125 rvh->DisableAutoResize(damage_view_size_);
1127 Send(new ViewMsg_SetName(routing_id(), name_));
1128 OnSetContentsOpaque(instance_id_, guest_opaque_);
1130 RenderWidgetHostImpl::From(rvh)->
1131 set_hung_renderer_delay_ms(guest_hang_timeout_);
1134 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
1135 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id()));
1137 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
1138 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
1140 case base::TERMINATION_STATUS_PROCESS_CRASHED:
1141 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
1143 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
1145 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
1150 // TODO(fsamuel): Consider whether we should be clearing
1151 // |permission_request_map_| here.
1153 delegate_->GuestProcessGone(status);
1157 void BrowserPluginGuest::AcknowledgeBufferPresent(
1160 const gpu::Mailbox& mailbox,
1161 uint32 sync_point) {
1162 AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
1163 ack_params.mailbox = mailbox;
1164 ack_params.sync_point = sync_point;
1165 RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id,
1171 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
1172 const IPC::Message& message) {
1173 switch (message.type()) {
1174 case BrowserPluginHostMsg_BuffersSwappedACK::ID:
1175 case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID:
1176 case BrowserPluginHostMsg_CopyFromCompositingSurfaceAck::ID:
1177 case BrowserPluginHostMsg_DragStatusUpdate::ID:
1178 case BrowserPluginHostMsg_ExecuteEditCommand::ID:
1179 case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
1180 case BrowserPluginHostMsg_HandleInputEvent::ID:
1181 case BrowserPluginHostMsg_ImeConfirmComposition::ID:
1182 case BrowserPluginHostMsg_ImeSetComposition::ID:
1183 case BrowserPluginHostMsg_LockMouse_ACK::ID:
1184 case BrowserPluginHostMsg_NavigateGuest::ID:
1185 case BrowserPluginHostMsg_PluginDestroyed::ID:
1186 case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
1187 case BrowserPluginHostMsg_ResizeGuest::ID:
1188 case BrowserPluginHostMsg_SetAutoSize::ID:
1189 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
1190 case BrowserPluginHostMsg_SetFocus::ID:
1191 case BrowserPluginHostMsg_SetName::ID:
1192 case BrowserPluginHostMsg_SetContentsOpaque::ID:
1193 case BrowserPluginHostMsg_SetVisibility::ID:
1194 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
1195 case BrowserPluginHostMsg_UpdateGeometry::ID:
1196 case BrowserPluginHostMsg_UpdateRect_ACK::ID:
1203 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
1204 bool handled = true;
1205 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
1206 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
1207 OnHasTouchEventHandlers)
1208 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
1209 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor)
1210 #if defined(OS_MACOSX)
1211 // MacOSX creates and populates platform-specific select drop-down menus
1212 // whereas other platforms merely create a popup window that the guest
1213 // renderer process paints inside.
1214 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup)
1216 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
1217 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
1218 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
1219 OnTextInputTypeChanged)
1220 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition,
1221 OnImeCancelComposition)
1222 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
1223 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged,
1224 OnImeCompositionRangeChanged)
1226 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
1227 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFrameName, OnUpdateFrameName)
1228 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
1229 IPC_MESSAGE_UNHANDLED(handled = false)
1230 IPC_END_MESSAGE_MAP()
1234 void BrowserPluginGuest::Attach(
1235 WebContentsImpl* embedder_web_contents,
1236 BrowserPluginHostMsg_Attach_Params params,
1237 const base::DictionaryValue& extra_params) {
1241 extra_attach_params_.reset(extra_params.DeepCopy());
1243 // Clear parameters that get inherited from the opener.
1244 params.storage_partition_id.clear();
1245 params.persist_storage = false;
1248 // If a RenderView has already been created for this new window, then we need
1249 // to initialize the browser-side state now so that the RenderFrameHostManager
1250 // does not create a new RenderView on navigation.
1251 if (has_render_view_) {
1252 static_cast<RenderViewHostImpl*>(
1253 GetWebContents()->GetRenderViewHost())->Init();
1254 WebContentsViewGuest* new_view =
1255 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
1256 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
1259 // We need to do a navigation here if the target URL has changed between
1260 // the time the WebContents was created and the time it was attached.
1261 // We also need to do an initial navigation if a RenderView was never
1262 // created for the new window in cases where there is no referrer.
1263 PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
1264 if (it != opener()->pending_new_windows_.end()) {
1265 const NewWindowInfo& new_window_info = it->second;
1266 if (new_window_info.changed || !has_render_view_)
1267 params.src = it->second.url.spec();
1272 // Once a new guest is attached to the DOM of the embedder page, then the
1273 // lifetime of the new guest is no longer managed by the opener guest.
1274 opener()->pending_new_windows_.erase(this);
1276 // The guest's frame name takes precedence over the BrowserPlugin's name.
1277 // The guest's frame name is assigned in
1278 // BrowserPluginGuest::WebContentsCreated.
1280 params.name.clear();
1282 Initialize(params, embedder_web_contents);
1284 SendQueuedMessages();
1286 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
1289 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
1291 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
1292 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
1293 params.output_surface_id,
1294 params.producing_host_id,
1298 void BrowserPluginGuest::OnDragStatusUpdate(int instance_id,
1299 blink::WebDragStatus drag_status,
1300 const DropData& drop_data,
1301 blink::WebDragOperationsMask mask,
1302 const gfx::Point& location) {
1303 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
1304 switch (drag_status) {
1305 case blink::WebDragStatusEnter:
1306 embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest(
1308 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
1310 case blink::WebDragStatusOver:
1311 host->DragTargetDragOver(location, location, mask, 0);
1313 case blink::WebDragStatusLeave:
1314 embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this);
1315 host->DragTargetDragLeave();
1317 case blink::WebDragStatusDrop:
1318 host->DragTargetDrop(location, location, 0);
1321 case blink::WebDragStatusUnknown:
1326 void BrowserPluginGuest::OnExecuteEditCommand(int instance_id,
1327 const std::string& name) {
1328 Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
1331 void BrowserPluginGuest::OnImeSetComposition(
1333 const std::string& text,
1334 const std::vector<blink::WebCompositionUnderline>& underlines,
1335 int selection_start,
1336 int selection_end) {
1337 Send(new ViewMsg_ImeSetComposition(routing_id(),
1338 base::UTF8ToUTF16(text), underlines,
1339 selection_start, selection_end));
1342 void BrowserPluginGuest::OnImeConfirmComposition(
1344 const std::string& text,
1345 bool keep_selection) {
1346 Send(new ViewMsg_ImeConfirmComposition(routing_id(),
1347 base::UTF8ToUTF16(text),
1348 gfx::Range::InvalidRange(),
1352 void BrowserPluginGuest::OnExtendSelectionAndDelete(
1356 Send(new ViewMsg_ExtendSelectionAndDelete(routing_id(), before, after));
1359 void BrowserPluginGuest::OnReclaimCompositorResources(
1361 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
1362 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
1363 params.output_surface_id,
1364 params.renderer_host_id,
1368 void BrowserPluginGuest::OnHandleInputEvent(
1370 const gfx::Rect& guest_window_rect,
1371 const blink::WebInputEvent* event) {
1372 guest_window_rect_ = guest_window_rect;
1373 // If the embedder's RWHV is destroyed then that means that the embedder's
1374 // window has been closed but the embedder's WebContents has not yet been
1375 // destroyed. Computing screen coordinates of a BrowserPlugin only makes sense
1376 // if there is a visible embedder.
1377 if (embedder_web_contents_->GetRenderWidgetHostView()) {
1378 guest_screen_rect_ = guest_window_rect;
1379 guest_screen_rect_.Offset(
1380 embedder_web_contents_->GetRenderWidgetHostView()->
1381 GetViewBounds().OffsetFromOrigin());
1383 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
1384 GetWebContents()->GetRenderViewHost());
1386 if (blink::WebInputEvent::isMouseEventType(event->type)) {
1387 guest_rvh->ForwardMouseEvent(
1388 *static_cast<const blink::WebMouseEvent*>(event));
1392 if (event->type == blink::WebInputEvent::MouseWheel) {
1393 guest_rvh->ForwardWheelEvent(
1394 *static_cast<const blink::WebMouseWheelEvent*>(event));
1398 if (blink::WebInputEvent::isKeyboardEventType(event->type)) {
1399 RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
1400 embedder_web_contents_->GetRenderViewHost());
1401 if (!embedder_rvh->GetLastKeyboardEvent())
1403 NativeWebKeyboardEvent keyboard_event(
1404 *embedder_rvh->GetLastKeyboardEvent());
1405 guest_rvh->ForwardKeyboardEvent(keyboard_event);
1409 if (blink::WebInputEvent::isTouchEventType(event->type)) {
1410 guest_rvh->ForwardTouchEventWithLatencyInfo(
1411 *static_cast<const blink::WebTouchEvent*>(event),
1416 if (blink::WebInputEvent::isGestureEventType(event->type)) {
1417 guest_rvh->ForwardGestureEvent(
1418 *static_cast<const blink::WebGestureEvent*>(event));
1423 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
1424 bool last_unlocked_by_target,
1426 if (pending_lock_request_) {
1427 // Immediately reject the lock because only one pointerLock may be active
1429 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
1432 pending_lock_request_ = true;
1433 base::DictionaryValue request_info;
1434 request_info.Set(browser_plugin::kUserGesture,
1435 base::Value::CreateBooleanValue(user_gesture));
1436 request_info.Set(browser_plugin::kLastUnlockedBySelf,
1437 base::Value::CreateBooleanValue(last_unlocked_by_target));
1438 request_info.Set(browser_plugin::kURL,
1439 base::Value::CreateStringValue(
1440 web_contents()->GetLastCommittedURL().spec()));
1442 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK,
1443 new PointerLockRequest(weak_ptr_factory_.GetWeakPtr()),
1447 void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) {
1448 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
1449 pending_lock_request_ = false;
1451 mouse_locked_ = true;
1454 void BrowserPluginGuest::OnNavigateGuest(
1456 const std::string& src) {
1457 GURL url = delegate_ ? delegate_->ResolveURL(src) : GURL(src);
1459 // Do not allow navigating a guest to schemes other than known safe schemes.
1460 // This will block the embedder trying to load unwanted schemes, e.g.
1461 // chrome://settings.
1462 bool scheme_is_blocked =
1463 (!ChildProcessSecurityPolicyImpl::GetInstance()->IsWebSafeScheme(
1465 !ChildProcessSecurityPolicyImpl::GetInstance()->IsPseudoScheme(
1467 url.SchemeIs(kJavaScriptScheme);
1468 if (scheme_is_blocked || !url.is_valid()) {
1470 std::string error_type;
1471 base::RemoveChars(net::ErrorToString(net::ERR_ABORTED), "net::",
1473 delegate_->LoadAbort(true /* is_top_level */, url, error_type);
1478 GURL validated_url(url);
1479 GetWebContents()->GetRenderProcessHost()->FilterURL(false, &validated_url);
1480 // As guests do not swap processes on navigation, only navigations to
1481 // normal web URLs are supported. No protocol handlers are installed for
1482 // other schemes (e.g., WebUI or extensions), and no permissions or bindings
1483 // can be granted to the guest process.
1484 LoadURLWithParams(validated_url, Referrer(), PAGE_TRANSITION_AUTO_TOPLEVEL,
1488 void BrowserPluginGuest::OnPluginDestroyed(int instance_id) {
1492 void BrowserPluginGuest::OnResizeGuest(
1494 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
1495 if (!params.size_changed)
1497 // BrowserPlugin manages resize flow control itself and does not depend
1498 // on RenderWidgetHost's mechanisms for flow control, so we reset those flags
1499 // here. If we are setting the size for the first time before navigating then
1500 // BrowserPluginGuest does not yet have a RenderViewHost.
1501 if (GetWebContents()->GetRenderViewHost()) {
1502 RenderWidgetHostImpl* render_widget_host =
1503 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
1504 render_widget_host->ResetSizeAndRepaintPendingFlags();
1506 if (guest_device_scale_factor_ != params.scale_factor) {
1507 guest_device_scale_factor_ = params.scale_factor;
1508 render_widget_host->NotifyScreenInfoChanged();
1511 // When autosize is turned off and as a result there is a layout change, we
1512 // send a sizechanged event.
1513 if (!auto_size_enabled_ && last_seen_auto_size_enabled_ &&
1514 !params.view_rect.size().IsEmpty() && delegate_) {
1515 delegate_->SizeChanged(last_seen_view_size_, params.view_rect.size());
1516 last_seen_auto_size_enabled_ = false;
1518 // Invalid damage buffer means we are in HW compositing mode,
1519 // so just resize the WebContents and repaint if needed.
1520 if (base::SharedMemory::IsHandleValid(params.damage_buffer_handle))
1521 SetDamageBuffer(params);
1522 if (!params.view_rect.size().IsEmpty())
1523 GetWebContents()->GetView()->SizeContents(params.view_rect.size());
1525 Send(new ViewMsg_Repaint(routing_id(), params.view_rect.size()));
1528 void BrowserPluginGuest::OnSetFocus(int instance_id, bool focused) {
1530 Send(new InputMsg_SetFocus(routing_id(), focused));
1531 if (!focused && mouse_locked_)
1534 // Restore the last seen state of text input to the view.
1535 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV(
1536 web_contents()->GetRenderWidgetHostView());
1538 rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
1539 last_can_compose_inline_);
1543 void BrowserPluginGuest::OnSetName(int instance_id, const std::string& name) {
1547 Send(new ViewMsg_SetName(routing_id(), name));
1550 void BrowserPluginGuest::OnSetSize(
1552 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1553 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1554 bool old_auto_size_enabled = auto_size_enabled_;
1555 gfx::Size old_max_size = max_auto_size_;
1556 gfx::Size old_min_size = min_auto_size_;
1557 auto_size_enabled_ = auto_size_params.enable;
1558 max_auto_size_ = auto_size_params.max_size;
1559 min_auto_size_ = auto_size_params.min_size;
1560 if (auto_size_enabled_ && (!old_auto_size_enabled ||
1561 (old_max_size != max_auto_size_) ||
1562 (old_min_size != min_auto_size_))) {
1564 base::UserMetricsAction("BrowserPlugin.Guest.EnableAutoResize"));
1565 GetWebContents()->GetRenderViewHost()->EnableAutoResize(
1566 min_auto_size_, max_auto_size_);
1567 // TODO(fsamuel): If we're changing autosize parameters, then we force
1568 // the guest to completely repaint itself, because BrowserPlugin has
1569 // allocated a new damage buffer and expects a full frame of pixels.
1570 // Ideally, we shouldn't need to do this because we shouldn't need to
1571 // allocate a new damage buffer unless |max_auto_size_| has changed.
1572 // However, even in that case, layout may not change and so we may
1573 // not get a full frame worth of pixels.
1574 Send(new ViewMsg_Repaint(routing_id(), max_auto_size_));
1575 } else if (!auto_size_enabled_ && old_auto_size_enabled) {
1576 GetWebContents()->GetRenderViewHost()->DisableAutoResize(
1577 resize_guest_params.view_rect.size());
1579 OnResizeGuest(instance_id_, resize_guest_params);
1582 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
1584 const std::vector<EditCommand>& edit_commands) {
1585 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
1589 void BrowserPluginGuest::OnSetContentsOpaque(int instance_id, bool opaque) {
1590 guest_opaque_ = opaque;
1592 SkBitmap background;
1593 if (!guest_opaque_) {
1594 background.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
1595 unsigned int color = 0;
1596 background.setPixels(&color);
1598 Send(new ViewMsg_SetBackground(routing_id(), background));
1601 void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) {
1602 guest_visible_ = visible;
1603 if (embedder_visible_ && guest_visible_)
1604 GetWebContents()->WasShown();
1606 GetWebContents()->WasHidden();
1609 void BrowserPluginGuest::OnSwapBuffersACK(
1611 const FrameHostMsg_BuffersSwappedACK_Params& params) {
1612 AcknowledgeBufferPresent(params.gpu_route_id, params.gpu_host_id,
1613 params.mailbox, params.sync_point);
1615 // This is only relevant on MACOSX and WIN when threaded compositing
1616 // is not enabled. In threaded mode, above ACK is sufficient.
1617 #if defined(OS_MACOSX) || defined(OS_WIN)
1618 RenderWidgetHostImpl* render_widget_host =
1619 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
1620 render_widget_host->AcknowledgeSwapBuffersToRenderer();
1621 #endif // defined(OS_MACOSX) || defined(OS_WIN)
1624 void BrowserPluginGuest::OnUnlockMouse() {
1625 SendMessageToEmbedder(
1626 new BrowserPluginMsg_SetMouseLock(instance_id(), false));
1629 void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) {
1630 // mouse_locked_ could be false here if the lock attempt was cancelled due
1631 // to window focus, or for various other reasons before the guest was informed
1632 // of the lock's success.
1634 Send(new ViewMsg_MouseLockLost(routing_id()));
1635 mouse_locked_ = false;
1638 void BrowserPluginGuest::OnUpdateRectACK(
1641 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1642 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1643 // Only the software path expects an ACK.
1645 Send(new ViewMsg_UpdateRect_ACK(routing_id()));
1646 OnSetSize(instance_id_, auto_size_params, resize_guest_params);
1649 void BrowserPluginGuest::OnCopyFromCompositingSurfaceAck(
1652 const SkBitmap& bitmap) {
1653 CHECK(copy_request_callbacks_.count(request_id));
1654 if (!copy_request_callbacks_.count(request_id))
1656 const CopyRequestCallback& callback = copy_request_callbacks_[request_id];
1657 callback.Run(!bitmap.empty() && !bitmap.isNull(), bitmap);
1658 copy_request_callbacks_.erase(request_id);
1661 void BrowserPluginGuest::OnUpdateGeometry(int instance_id,
1662 const gfx::Rect& view_rect) {
1663 // The plugin has moved within the embedder without resizing or the
1664 // embedder/container's view rect changing.
1665 guest_window_rect_ = view_rect;
1666 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1667 GetWebContents()->GetRenderViewHost());
1669 rvh->SendScreenRects();
1672 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
1673 SendMessageToEmbedder(
1674 new BrowserPluginMsg_ShouldAcceptTouchEvents(instance_id(), accept));
1677 void BrowserPluginGuest::OnSetCursor(const WebCursor& cursor) {
1678 SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(instance_id(), cursor));
1681 #if defined(OS_MACOSX)
1682 void BrowserPluginGuest::OnShowPopup(
1683 const ViewHostMsg_ShowPopup_Params& params) {
1684 gfx::Rect translated_bounds(params.bounds);
1685 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
1686 BrowserPluginPopupMenuHelper popup_menu_helper(
1687 embedder_web_contents_->GetRenderViewHost(),
1688 GetWebContents()->GetRenderViewHost());
1689 popup_menu_helper.ShowPopupMenu(translated_bounds,
1691 params.item_font_size,
1692 params.selected_item,
1694 params.right_aligned,
1695 params.allow_multiple_selection);
1699 void BrowserPluginGuest::OnShowWidget(int route_id,
1700 const gfx::Rect& initial_pos) {
1701 GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
1704 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
1705 SendMessageToEmbedder(
1706 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
1709 void BrowserPluginGuest::OnUpdateFrameName(int frame_id,
1711 const std::string& name) {
1716 SendMessageToEmbedder(new BrowserPluginMsg_UpdatedName(instance_id_, name));
1719 void BrowserPluginGuest::RequestMediaAccessPermission(
1720 WebContents* web_contents,
1721 const MediaStreamRequest& request,
1722 const MediaResponseCallback& callback) {
1723 base::DictionaryValue request_info;
1725 browser_plugin::kURL,
1726 base::Value::CreateStringValue(request.security_origin.spec()));
1728 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_MEDIA,
1729 new MediaRequest(weak_ptr_factory_.GetWeakPtr(),
1735 bool BrowserPluginGuest::PreHandleGestureEvent(
1736 WebContents* source, const blink::WebGestureEvent& event) {
1737 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
1738 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
1739 event.type == blink::WebGestureEvent::GesturePinchEnd;
1742 void BrowserPluginGuest::RunJavaScriptDialog(
1743 WebContents* web_contents,
1744 const GURL& origin_url,
1745 const std::string& accept_lang,
1746 JavaScriptMessageType javascript_message_type,
1747 const base::string16& message_text,
1748 const base::string16& default_prompt_text,
1749 const DialogClosedCallback& callback,
1750 bool* did_suppress_message) {
1751 base::DictionaryValue request_info;
1753 browser_plugin::kDefaultPromptText,
1754 base::Value::CreateStringValue(base::UTF16ToUTF8(default_prompt_text)));
1756 browser_plugin::kMessageText,
1757 base::Value::CreateStringValue(base::UTF16ToUTF8(message_text)));
1759 browser_plugin::kMessageType,
1760 base::Value::CreateStringValue(
1761 JavaScriptMessageTypeToString(javascript_message_type)));
1763 browser_plugin::kURL,
1764 base::Value::CreateStringValue(origin_url.spec()));
1766 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG,
1767 new JavaScriptDialogRequest(weak_ptr_factory_.GetWeakPtr(),
1772 void BrowserPluginGuest::RunBeforeUnloadDialog(
1773 WebContents* web_contents,
1774 const base::string16& message_text,
1776 const DialogClosedCallback& callback) {
1777 // This is called if the guest has a beforeunload event handler.
1778 // This callback allows navigation to proceed.
1779 callback.Run(true, base::string16());
1782 bool BrowserPluginGuest::HandleJavaScriptDialog(
1783 WebContents* web_contents,
1785 const base::string16* prompt_override) {
1789 void BrowserPluginGuest::CancelActiveAndPendingDialogs(
1790 WebContents* web_contents) {
1793 void BrowserPluginGuest::WebContentsDestroyed(WebContents* web_contents) {
1796 void BrowserPluginGuest::OnUpdateRect(
1797 const ViewHostMsg_UpdateRect_Params& params) {
1798 BrowserPluginMsg_UpdateRect_Params relay_params;
1799 relay_params.view_size = params.view_size;
1800 relay_params.scale_factor = params.scale_factor;
1801 relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(
1803 relay_params.needs_ack = params.needs_ack;
1805 bool size_changed = last_seen_view_size_ != params.view_size;
1806 gfx::Size old_size = last_seen_view_size_;
1807 last_seen_view_size_ = params.view_size;
1809 if ((auto_size_enabled_ || last_seen_auto_size_enabled_) &&
1810 size_changed && delegate_) {
1811 delegate_->SizeChanged(old_size, last_seen_view_size_);
1813 last_seen_auto_size_enabled_ = auto_size_enabled_;
1815 // HW accelerated case, acknowledge resize only
1816 if (!params.needs_ack || !damage_buffer_) {
1817 relay_params.damage_buffer_sequence_id = 0;
1818 SendMessageToEmbedder(
1819 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1823 // Only copy damage if the guest is in autosize mode and the guest's view size
1824 // is less than the maximum size or the guest's view size is equal to the
1825 // damage buffer's size and the guest's scale factor is equal to the damage
1826 // buffer's scale factor.
1827 // The scaling change can happen due to asynchronous updates of the DPI on a
1828 // resolution change.
1829 if (((auto_size_enabled_ && InAutoSizeBounds(params.view_size)) ||
1830 (params.view_size == damage_view_size())) &&
1831 params.scale_factor == damage_buffer_scale_factor()) {
1832 TransportDIB* dib = GetWebContents()->GetRenderProcessHost()->
1833 GetTransportDIB(params.bitmap);
1835 size_t guest_damage_buffer_size =
1837 params.bitmap_rect.width() *
1838 params.bitmap_rect.height() * 4;
1842 size_t embedder_damage_buffer_size = damage_buffer_size_;
1843 void* guest_memory = dib->memory();
1844 void* embedder_memory = damage_buffer_->memory();
1845 size_t size = std::min(guest_damage_buffer_size,
1846 embedder_damage_buffer_size);
1847 memcpy(embedder_memory, guest_memory, size);
1850 relay_params.damage_buffer_sequence_id = damage_buffer_sequence_id_;
1851 relay_params.bitmap_rect = params.bitmap_rect;
1852 relay_params.scroll_delta = params.scroll_delta;
1853 relay_params.scroll_rect = params.scroll_rect;
1854 relay_params.copy_rects = params.copy_rects;
1856 SendMessageToEmbedder(
1857 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1860 void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
1861 ui::TextInputMode input_mode,
1862 bool can_compose_inline) {
1863 // Save the state of text input so we can restore it on focus.
1864 last_text_input_type_ = type;
1865 last_input_mode_ = input_mode;
1866 last_can_compose_inline_ = can_compose_inline;
1868 RenderWidgetHostViewPort::FromRWHV(
1869 web_contents()->GetRenderWidgetHostView())->TextInputTypeChanged(
1870 type, input_mode, can_compose_inline);
1873 void BrowserPluginGuest::OnImeCancelComposition() {
1874 RenderWidgetHostViewPort::FromRWHV(
1875 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
1878 #if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
1879 void BrowserPluginGuest::OnImeCompositionRangeChanged(
1880 const gfx::Range& range,
1881 const std::vector<gfx::Rect>& character_bounds) {
1882 RenderWidgetHostViewPort::FromRWHV(
1883 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
1884 range, character_bounds);
1888 void BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId(
1889 const std::string& request_method,
1890 const base::Callback<void(bool)>& callback,
1891 const std::string& url) {
1893 callback.Run(false);
1897 base::DictionaryValue request_info;
1898 request_info.Set(browser_plugin::kRequestMethod,
1899 base::Value::CreateStringValue(request_method));
1900 request_info.Set(browser_plugin::kURL, base::Value::CreateStringValue(url));
1902 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_DOWNLOAD,
1903 new DownloadRequest(weak_ptr_factory_.GetWeakPtr(),
1908 } // namespace content