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/loader/resource_dispatcher_host_impl.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/renderer_host/render_widget_host_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/browser/web_contents/web_contents_view_guest.h"
22 #include "content/common/browser_plugin/browser_plugin_constants.h"
23 #include "content/common/browser_plugin/browser_plugin_messages.h"
24 #include "content/common/content_constants_internal.h"
25 #include "content/common/drag_messages.h"
26 #include "content/common/gpu/gpu_messages.h"
27 #include "content/common/input_messages.h"
28 #include "content/common/view_messages.h"
29 #include "content/port/browser/render_view_host_delegate_view.h"
30 #include "content/public/browser/browser_context.h"
31 #include "content/public/browser/content_browser_client.h"
32 #include "content/public/browser/geolocation_permission_context.h"
33 #include "content/public/browser/navigation_controller.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/render_widget_host_view.h"
36 #include "content/public/browser/resource_request_details.h"
37 #include "content/public/browser/user_metrics.h"
38 #include "content/public/browser/web_contents_observer.h"
39 #include "content/public/browser/web_contents_view.h"
40 #include "content/public/common/drop_data.h"
41 #include "content/public/common/media_stream_request.h"
42 #include "content/public/common/result_codes.h"
43 #include "content/public/common/url_constants.h"
44 #include "content/public/common/url_utils.h"
45 #include "net/url_request/url_request.h"
46 #include "third_party/WebKit/public/web/WebCursorInfo.h"
47 #include "ui/events/keycodes/keyboard_codes.h"
48 #include "ui/surface/transport_dib.h"
49 #include "webkit/common/resource_type.h"
51 #if defined(OS_MACOSX)
52 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
58 BrowserPluginHostFactory* BrowserPluginGuest::factory_ = NULL;
60 // Parent class for the various types of permission requests, each of which
61 // should be able to handle the response to their permission request.
62 class BrowserPluginGuest::PermissionRequest :
63 public base::RefCounted<BrowserPluginGuest::PermissionRequest> {
65 virtual void Respond(bool should_allow, const std::string& user_input) = 0;
66 virtual bool AllowedByDefault() const {
71 RecordAction(UserMetricsAction("BrowserPlugin.Guest.PermissionRequest"));
73 virtual ~PermissionRequest() {}
74 // Friend RefCounted so that the dtor can be non-public.
75 friend class base::RefCounted<BrowserPluginGuest::PermissionRequest>;
78 class BrowserPluginGuest::DownloadRequest : public PermissionRequest {
80 explicit DownloadRequest(base::Callback<void(bool)> callback)
81 : callback_(callback) {
83 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Download"));
85 virtual void Respond(bool should_allow,
86 const std::string& user_input) OVERRIDE {
87 callback_.Run(should_allow);
91 virtual ~DownloadRequest() {}
92 base::Callback<void(bool)> callback_;
95 class BrowserPluginGuest::GeolocationRequest : public PermissionRequest {
97 GeolocationRequest(GeolocationCallback callback,
99 base::WeakPtrFactory<BrowserPluginGuest>* weak_ptr_factory)
100 : callback_(callback),
101 bridge_id_(bridge_id),
102 weak_ptr_factory_(weak_ptr_factory) {
104 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Geolocation"));
107 virtual void Respond(bool should_allow,
108 const std::string& user_input) OVERRIDE {
109 base::WeakPtr<BrowserPluginGuest> guest(weak_ptr_factory_->GetWeakPtr());
111 WebContents* web_contents = guest->embedder_web_contents();
112 if (should_allow && web_contents) {
113 // If renderer side embedder decides to allow gelocation, we need to check
114 // if the app/embedder itself has geolocation access.
115 BrowserContext* browser_context = web_contents->GetBrowserContext();
116 if (browser_context) {
117 GeolocationPermissionContext* geolocation_context =
118 browser_context->GetGeolocationPermissionContext();
119 if (geolocation_context) {
120 base::Callback<void(bool)> geolocation_callback = base::Bind(
121 &BrowserPluginGuest::SetGeolocationPermission,
125 geolocation_context->RequestGeolocationPermission(
126 web_contents->GetRenderProcessHost()->GetID(),
127 web_contents->GetRoutingID(),
128 // The geolocation permission request here is not initiated
129 // through WebGeolocationPermissionRequest. We are only interested
130 // in the fact whether the embedder/app has geolocation
131 // permission. Therefore we use an invalid |bridge_id|.
133 web_contents->GetLastCommittedURL(),
134 geolocation_callback);
139 guest->SetGeolocationPermission(callback_, bridge_id_, false);
143 virtual ~GeolocationRequest() {}
144 base::Callback<void(bool)> callback_;
146 base::WeakPtrFactory<BrowserPluginGuest>* weak_ptr_factory_;
149 class BrowserPluginGuest::MediaRequest : public PermissionRequest {
151 MediaRequest(const MediaStreamRequest& request,
152 const MediaResponseCallback& callback,
153 BrowserPluginGuest* guest)
158 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Media"));
161 virtual void Respond(bool should_allow,
162 const std::string& user_input) OVERRIDE {
163 WebContentsImpl* web_contents = guest_->embedder_web_contents();
164 if (should_allow && web_contents) {
165 // Re-route the request to the embedder's WebContents; the guest gets the
166 // permission this way.
167 web_contents->RequestMediaAccessPermission(request_, callback_);
170 callback_.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
175 virtual ~MediaRequest() {}
176 MediaStreamRequest request_;
177 MediaResponseCallback callback_;
178 BrowserPluginGuest* guest_;
181 class BrowserPluginGuest::NewWindowRequest : public PermissionRequest {
183 NewWindowRequest(int instance_id, BrowserPluginGuest* guest)
184 : instance_id_(instance_id),
187 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.NewWindow"));
190 virtual void Respond(bool should_allow,
191 const std::string& user_input) OVERRIDE {
192 int embedder_render_process_id =
193 guest_->embedder_web_contents()->GetRenderProcessHost()->GetID();
194 BrowserPluginGuest* guest =
195 guest_->GetWebContents()->GetBrowserPluginGuestManager()->
196 GetGuestByInstanceID(instance_id_, embedder_render_process_id);
198 LOG(INFO) << "Guest not found. Instance ID: " << instance_id_;
202 // If we do not destroy the guest then we allow the new window.
208 virtual ~NewWindowRequest() {}
210 BrowserPluginGuest* guest_;
213 class BrowserPluginGuest::JavaScriptDialogRequest : public PermissionRequest {
215 JavaScriptDialogRequest(const DialogClosedCallback& callback)
216 : callback_(callback) {
219 "BrowserPlugin.Guest.PermissionRequest.JavaScriptDialog"));
222 virtual void Respond(bool should_allow,
223 const std::string& user_input) OVERRIDE {
224 callback_.Run(should_allow, UTF8ToUTF16(user_input));
228 virtual ~JavaScriptDialogRequest() {}
229 DialogClosedCallback callback_;
232 class BrowserPluginGuest::PointerLockRequest : public PermissionRequest {
234 PointerLockRequest(BrowserPluginGuest* guest)
237 UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.PointerLock"));
240 virtual void Respond(bool should_allow,
241 const std::string& user_input) OVERRIDE {
242 guest_->SendMessageToEmbedder(
243 new BrowserPluginMsg_SetMouseLock(guest_->instance_id(), should_allow));
247 virtual ~PointerLockRequest() {}
248 BrowserPluginGuest* guest_;
252 std::string WindowOpenDispositionToString(
253 WindowOpenDisposition window_open_disposition) {
254 switch (window_open_disposition) {
258 return "save_to_disk";
260 return "current_tab";
261 case NEW_BACKGROUND_TAB:
262 return "new_background_tab";
263 case NEW_FOREGROUND_TAB:
264 return "new_foreground_tab";
270 NOTREACHED() << "Unknown Window Open Disposition";
275 std::string JavaScriptMessageTypeToString(JavaScriptMessageType message_type) {
276 switch (message_type) {
277 case JAVASCRIPT_MESSAGE_TYPE_ALERT:
279 case JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
281 case JAVASCRIPT_MESSAGE_TYPE_PROMPT:
284 NOTREACHED() << "Unknown JavaScript Message Type.";
289 // Called on IO thread.
290 static std::string RetrieveDownloadURLFromRequestId(
291 RenderViewHost* render_view_host,
292 int url_request_id) {
293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
295 int render_process_id = render_view_host->GetProcess()->GetID();
296 GlobalRequestID global_id(render_process_id, url_request_id);
297 net::URLRequest* url_request =
298 ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id);
300 return url_request->url().possibly_invalid_spec();
301 return std::string();
306 class BrowserPluginGuest::EmbedderWebContentsObserver
307 : public WebContentsObserver {
309 explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest)
310 : WebContentsObserver(guest->embedder_web_contents()),
311 browser_plugin_guest_(guest) {
314 virtual ~EmbedderWebContentsObserver() {
317 // WebContentsObserver:
318 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
319 browser_plugin_guest_->EmbedderDestroyed();
322 virtual void WasShown() OVERRIDE {
323 browser_plugin_guest_->EmbedderVisibilityChanged(true);
326 virtual void WasHidden() OVERRIDE {
327 browser_plugin_guest_->EmbedderVisibilityChanged(false);
331 BrowserPluginGuest* browser_plugin_guest_;
333 DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
336 BrowserPluginGuest::BrowserPluginGuest(
338 WebContentsImpl* web_contents,
339 BrowserPluginGuest* opener,
340 bool has_render_view)
341 : WebContentsObserver(web_contents),
342 weak_ptr_factory_(this),
343 embedder_web_contents_(NULL),
344 instance_id_(instance_id),
345 damage_buffer_sequence_id_(0),
346 damage_buffer_size_(0),
347 damage_buffer_scale_factor_(1.0f),
348 guest_device_scale_factor_(1.0f),
350 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
352 mouse_locked_(false),
353 pending_lock_request_(false),
354 embedder_visible_(true),
355 next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID),
356 has_render_view_(has_render_view),
357 last_seen_auto_size_enabled_(false),
358 is_in_destruction_(false) {
359 DCHECK(web_contents);
360 web_contents->SetDelegate(this);
362 opener_ = opener->AsWeakPtr();
363 GetWebContents()->GetBrowserPluginGuestManager()->AddGuest(instance_id_,
367 bool BrowserPluginGuest::AddMessageToConsole(WebContents* source,
369 const string16& message,
371 const string16& source_id) {
375 delegate_->AddMessageToConsole(level, message, line_no, source_id);
379 void BrowserPluginGuest::DestroyUnattachedWindows() {
380 // Destroy() reaches in and removes the BrowserPluginGuest from its opener's
381 // pending_new_windows_ set. To avoid mutating the set while iterating, we
382 // create a copy of the pending new windows set and iterate over the copy.
383 PendingWindowMap pending_new_windows(pending_new_windows_);
384 // Clean up unattached new windows opened by this guest.
385 for (PendingWindowMap::const_iterator it = pending_new_windows.begin();
386 it != pending_new_windows.end(); ++it) {
387 it->first->Destroy();
389 // All pending windows should be removed from the set after Destroy() is
390 // called on all of them.
391 DCHECK_EQ(0ul, pending_new_windows_.size());
394 void BrowserPluginGuest::LoadURLWithParams(WebContents* web_contents,
396 const Referrer& referrer,
397 PageTransition transition_type) {
398 NavigationController::LoadURLParams load_url_params(url);
399 load_url_params.referrer = referrer;
400 load_url_params.transition_type = transition_type;
401 load_url_params.extra_headers = std::string();
402 if (delegate_ && delegate_->IsOverridingUserAgent()) {
403 load_url_params.override_user_agent =
404 NavigationController::UA_OVERRIDE_TRUE;
406 web_contents->GetController().LoadURLWithParams(load_url_params);
409 void BrowserPluginGuest::RespondToPermissionRequest(
412 const std::string& user_input) {
413 RequestMap::iterator request_itr = permission_request_map_.find(request_id);
414 if (request_itr == permission_request_map_.end()) {
415 LOG(INFO) << "Not a valid request ID.";
418 request_itr->second->Respond(should_allow, user_input);
419 permission_request_map_.erase(request_itr);
422 int BrowserPluginGuest::RequestPermission(
423 BrowserPluginPermissionType permission_type,
424 scoped_refptr<BrowserPluginGuest::PermissionRequest> request,
425 const base::DictionaryValue& request_info) {
427 request->Respond(false, "");
428 return browser_plugin::kInvalidPermissionRequestID;
431 int request_id = ++next_permission_request_id_;
432 permission_request_map_[request_id] = request;
434 BrowserPluginGuestDelegate::PermissionResponseCallback callback =
435 base::Bind(&BrowserPluginGuest::RespondToPermissionRequest,
438 // If BrowserPluginGuestDelegate hasn't handled the permission then we simply
439 // reject it immediately.
440 if (!delegate_->RequestPermission(
441 permission_type, request_info, callback, request->AllowedByDefault())) {
442 callback.Run(request->AllowedByDefault(), "");
443 return browser_plugin::kInvalidPermissionRequestID;
449 BrowserPluginGuest* BrowserPluginGuest::CreateNewGuestWindow(
450 const OpenURLParams& params) {
451 BrowserPluginGuestManager* guest_manager =
452 GetWebContents()->GetBrowserPluginGuestManager();
454 // Allocate a new instance ID for the new guest.
455 int instance_id = guest_manager->get_next_instance_id();
457 // Set the attach params to use the same partition as the opener.
458 // We pull the partition information from the site's URL, which is of the form
459 // guest://site/{persist}?{partition_name}.
460 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
461 BrowserPluginHostMsg_Attach_Params attach_params;
462 attach_params.storage_partition_id = site_url.query();
463 attach_params.persist_storage =
464 site_url.path().find("persist") != std::string::npos;
466 // The new guest gets a copy of this guest's extra params so that the content
467 // embedder exposes the same API for this guest as its opener.
468 scoped_ptr<base::DictionaryValue> extra_params(
469 extra_attach_params_->DeepCopy());
470 BrowserPluginGuest* new_guest =
471 GetWebContents()->GetBrowserPluginGuestManager()->CreateGuest(
472 GetWebContents()->GetSiteInstance(), instance_id,
473 attach_params, extra_params.Pass());
474 new_guest->opener_ = AsWeakPtr();
476 // Take ownership of |new_guest|.
477 pending_new_windows_.insert(
478 std::make_pair(new_guest, NewWindowInfo(params.url, std::string())));
480 // Request permission to show the new window.
481 RequestNewWindowPermission(
482 new_guest->GetWebContents(),
485 params.user_gesture);
490 void BrowserPluginGuest::EmbedderDestroyed() {
491 embedder_web_contents_ = NULL;
493 delegate_->EmbedderDestroyed();
497 void BrowserPluginGuest::Destroy() {
498 is_in_destruction_ = true;
499 if (!attached() && opener())
500 opener()->pending_new_windows_.erase(this);
501 DestroyUnattachedWindows();
502 GetWebContents()->GetBrowserPluginGuestManager()->RemoveGuest(instance_id_);
503 delete GetWebContents();
506 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
507 const IPC::Message& message) {
509 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
510 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_BuffersSwappedACK,
512 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameACK,
513 OnCompositorFrameACK)
514 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
516 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
517 OnExecuteEditCommand)
518 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
520 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
521 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateGuest, OnNavigateGuest)
522 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
523 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
524 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize)
525 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
526 OnSetEditCommandsForNextKeyEvent)
527 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
528 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetName, OnSetName)
529 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
530 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
531 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
532 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateRect_ACK, OnUpdateRectACK)
533 IPC_MESSAGE_UNHANDLED(handled = false)
534 IPC_END_MESSAGE_MAP()
538 void BrowserPluginGuest::Initialize(
539 WebContentsImpl* embedder_web_contents,
540 const BrowserPluginHostMsg_Attach_Params& params) {
541 focused_ = params.focused;
542 guest_visible_ = params.visible;
543 guest_window_rect_ = params.resize_guest_params.view_rect;
545 if (!params.name.empty())
547 auto_size_enabled_ = params.auto_size_params.enable;
548 max_auto_size_ = params.auto_size_params.max_size;
549 min_auto_size_ = params.auto_size_params.min_size;
551 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
553 embedder_web_contents_ = embedder_web_contents;
555 WebContentsViewGuest* new_view =
556 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
557 new_view->OnGuestInitialized(embedder_web_contents->GetView());
559 RendererPreferences* renderer_prefs =
560 GetWebContents()->GetMutableRendererPrefs();
561 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
562 // Copy renderer preferences (and nothing else) from the embedder's
563 // WebContents to the guest.
565 // For GTK and Aura this is necessary to get proper renderer configuration
566 // values for caret blinking interval, colors related to selection and
568 *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs();
569 renderer_prefs->user_agent_override = guest_user_agent_override;
571 // We would like the guest to report changes to frame names so that we can
572 // update the BrowserPlugin's corresponding 'name' attribute.
573 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
574 renderer_prefs->report_frame_name_changes = true;
575 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
576 // navigations still continue to function inside the app.
577 renderer_prefs->browser_handles_all_top_level_requests = false;
578 // Disable "client blocked" error page for browser plugin.
579 renderer_prefs->disable_client_blocked_error_page = true;
581 embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this));
583 OnSetSize(instance_id_, params.auto_size_params, params.resize_guest_params);
585 // Create a swapped out RenderView for the guest in the embedder render
586 // process, so that the embedder can access the guest's window object.
587 int guest_routing_id =
588 GetWebContents()->CreateSwappedOutRenderView(
589 embedder_web_contents_->GetSiteInstance());
590 SendMessageToEmbedder(
591 new BrowserPluginMsg_GuestContentWindowReady(instance_id_,
594 if (!params.src.empty()) {
595 // params.src will be validated in BrowserPluginGuest::OnNavigateGuest.
596 OnNavigateGuest(instance_id_, params.src);
599 has_render_view_ = true;
601 if (!embedder_web_contents_->
602 GetWebkitPrefs().accelerated_compositing_enabled) {
603 WebPreferences prefs = GetWebContents()->GetWebkitPrefs();
604 prefs.accelerated_compositing_enabled = false;
605 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
608 // Enable input method for guest if it's enabled for the embedder.
609 if (static_cast<RenderViewHostImpl*>(
610 embedder_web_contents_->GetRenderViewHost())->input_method_active()) {
611 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
612 GetWebContents()->GetRenderViewHost());
613 guest_rvh->SetInputMethodActive(true);
616 // Inform the embedder of the guest's information.
617 // We pull the partition information from the site's URL, which is of the form
618 // guest://site/{persist}?{partition_name}.
619 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
620 BrowserPluginMsg_Attach_ACK_Params ack_params;
621 ack_params.storage_partition_id = site_url.query();
622 ack_params.persist_storage =
623 site_url.path().find("persist") != std::string::npos;
624 ack_params.name = name_;
625 SendMessageToEmbedder(
626 new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
629 BrowserPluginGuest::~BrowserPluginGuest() {
630 while (!pending_messages_.empty()) {
631 delete pending_messages_.front();
632 pending_messages_.pop();
637 BrowserPluginGuest* BrowserPluginGuest::Create(
639 SiteInstance* guest_site_instance,
640 WebContentsImpl* web_contents,
641 scoped_ptr<base::DictionaryValue> extra_params) {
642 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Create"));
643 BrowserPluginGuest* guest = NULL;
645 guest = factory_->CreateBrowserPluginGuest(instance_id, web_contents);
647 guest = new BrowserPluginGuest(instance_id, web_contents, NULL, false);
649 guest->extra_attach_params_.reset(extra_params->DeepCopy());
650 web_contents->SetBrowserPluginGuest(guest);
651 BrowserPluginGuestDelegate* delegate = NULL;
652 GetContentClient()->browser()->GuestWebContentsCreated(
653 guest_site_instance, web_contents, NULL, &delegate, extra_params.Pass());
654 guest->SetDelegate(delegate);
659 BrowserPluginGuest* BrowserPluginGuest::CreateWithOpener(
661 WebContentsImpl* web_contents,
662 BrowserPluginGuest* opener,
663 bool has_render_view) {
664 BrowserPluginGuest* guest =
665 new BrowserPluginGuest(
666 instance_id, web_contents, opener, has_render_view);
667 web_contents->SetBrowserPluginGuest(guest);
668 BrowserPluginGuestDelegate* delegate = NULL;
669 GetContentClient()->browser()->GuestWebContentsCreated(
670 opener->GetWebContents()->GetSiteInstance(),
671 web_contents, opener->GetWebContents(), &delegate,
672 scoped_ptr<base::DictionaryValue>());
673 guest->SetDelegate(delegate);
677 RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
678 return embedder_web_contents_->GetRenderWidgetHostView();
681 void BrowserPluginGuest::UpdateVisibility() {
682 OnSetVisibility(instance_id_, visible());
686 gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) {
687 gfx::Rect guest_rect(bounds);
688 guest_rect.Offset(guest_window_rect_.OffsetFromOrigin());
692 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
693 embedder_visible_ = visible;
697 void BrowserPluginGuest::AddNewContents(WebContents* source,
698 WebContents* new_contents,
699 WindowOpenDisposition disposition,
700 const gfx::Rect& initial_pos,
704 *was_blocked = false;
705 RequestNewWindowPermission(static_cast<WebContentsImpl*>(new_contents),
706 disposition, initial_pos, user_gesture);
709 void BrowserPluginGuest::CanDownload(
710 RenderViewHost* render_view_host,
712 const std::string& request_method,
713 const base::Callback<void(bool)>& callback) {
714 BrowserThread::PostTaskAndReplyWithResult(
715 BrowserThread::IO, FROM_HERE,
716 base::Bind(&RetrieveDownloadURLFromRequestId,
717 render_view_host, request_id),
718 base::Bind(&BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId,
719 weak_ptr_factory_.GetWeakPtr(),
724 void BrowserPluginGuest::LoadProgressChanged(WebContents* contents,
727 delegate_->LoadProgressed(progress);
730 void BrowserPluginGuest::CloseContents(WebContents* source) {
737 JavaScriptDialogManager* BrowserPluginGuest::GetJavaScriptDialogManager() {
741 bool BrowserPluginGuest::HandleContextMenu(const ContextMenuParams& params) {
742 // TODO(fsamuel): We show the regular page context menu handler for now until
743 // we implement the Apps Context Menu API for Browser Plugin (see
744 // http://crbug.com/140315).
745 return false; // Will be handled by WebContentsViewGuest.
748 void BrowserPluginGuest::HandleKeyboardEvent(
750 const NativeWebKeyboardEvent& event) {
754 if (UnlockMouseIfNecessary(event))
757 if (delegate_ && delegate_->HandleKeyboardEvent(event))
760 // Send the unhandled keyboard events back to the embedder to reprocess them.
761 // TODO(fsamuel): This introduces the possibility of out-of-order keyboard
762 // events because the guest may be arbitrarily delayed when responding to
763 // keyboard events. In that time, the embedder may have received and processed
764 // additional key events. This needs to be fixed as soon as possible.
765 // See http://crbug.com/229882.
766 embedder_web_contents_->GetDelegate()->HandleKeyboardEvent(
767 web_contents(), event);
770 WebContents* BrowserPluginGuest::OpenURLFromTab(WebContents* source,
771 const OpenURLParams& params) {
772 // If the guest wishes to navigate away prior to attachment then we save the
773 // navigation to perform upon attachment. Navigation initializes a lot of
774 // state that assumes an embedder exists, such as RenderWidgetHostViewGuest.
775 // Navigation also resumes resource loading which we don't want to allow
778 PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
779 if (it == opener()->pending_new_windows_.end())
781 const NewWindowInfo& old_target_url = it->second;
782 NewWindowInfo new_window_info(params.url, old_target_url.name);
783 new_window_info.changed = new_window_info.url != old_target_url.url;
784 it->second = new_window_info;
787 if (params.disposition == CURRENT_TAB) {
788 // This can happen for cross-site redirects.
789 LoadURLWithParams(source, params.url, params.referrer, params.transition);
793 return CreateNewGuestWindow(params)->GetWebContents();
796 void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents,
797 int64 source_frame_id,
798 const string16& frame_name,
799 const GURL& target_url,
800 WebContents* new_contents) {
801 WebContentsImpl* new_contents_impl =
802 static_cast<WebContentsImpl*>(new_contents);
803 BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest();
804 guest->opener_ = AsWeakPtr();
805 std::string guest_name = UTF16ToUTF8(frame_name);
806 guest->name_ = guest_name;
807 // Take ownership of the new guest until it is attached to the embedder's DOM
808 // tree to avoid leaking a guest if this guest is destroyed before attaching
810 pending_new_windows_.insert(
811 std::make_pair(guest, NewWindowInfo(target_url, guest_name)));
814 void BrowserPluginGuest::RendererUnresponsive(WebContents* source) {
815 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Hung"));
818 delegate_->RendererUnresponsive();
821 void BrowserPluginGuest::RendererResponsive(WebContents* source) {
822 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Responsive"));
825 delegate_->RendererResponsive();
828 void BrowserPluginGuest::RunFileChooser(WebContents* web_contents,
829 const FileChooserParams& params) {
830 embedder_web_contents_->GetDelegate()->RunFileChooser(web_contents, params);
833 bool BrowserPluginGuest::ShouldFocusPageAfterCrash() {
834 // Rather than managing focus in WebContentsImpl::RenderViewReady, we will
835 // manage the focus ourselves.
839 WebContentsImpl* BrowserPluginGuest::GetWebContents() {
840 return static_cast<WebContentsImpl*>(web_contents());
843 base::SharedMemory* BrowserPluginGuest::GetDamageBufferFromEmbedder(
844 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
846 LOG(WARNING) << "Attempting to map a damage buffer prior to attachment.";
850 base::ProcessHandle handle =
851 embedder_web_contents_->GetRenderProcessHost()->GetHandle();
852 scoped_ptr<base::SharedMemory> shared_buf(
853 new base::SharedMemory(params.damage_buffer_handle, false, handle));
854 #elif defined(OS_POSIX)
855 scoped_ptr<base::SharedMemory> shared_buf(
856 new base::SharedMemory(params.damage_buffer_handle, false));
858 if (!shared_buf->Map(params.damage_buffer_size)) {
859 LOG(WARNING) << "Unable to map the embedder's damage buffer.";
862 return shared_buf.release();
865 void BrowserPluginGuest::SetDamageBuffer(
866 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
867 damage_buffer_.reset(GetDamageBufferFromEmbedder(params));
868 // Sanity check: Verify that we've correctly shared the damage buffer memory
869 // between the embedder and browser processes.
870 DCHECK(!damage_buffer_ ||
871 *static_cast<unsigned int*>(damage_buffer_->memory()) == 0xdeadbeef);
872 damage_buffer_sequence_id_ = params.damage_buffer_sequence_id;
873 damage_buffer_size_ = params.damage_buffer_size;
874 damage_view_size_ = params.view_rect.size();
875 damage_buffer_scale_factor_ = params.scale_factor;
878 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
879 const gfx::Point& relative_position) const {
880 gfx::Point screen_pos(relative_position);
881 screen_pos += guest_window_rect_.OffsetFromOrigin();
885 bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const {
886 return size.width() <= max_auto_size_.width() &&
887 size.height() <= max_auto_size_.height();
890 void BrowserPluginGuest::RequestNewWindowPermission(
891 WebContentsImpl* new_contents,
892 WindowOpenDisposition disposition,
893 const gfx::Rect& initial_bounds,
895 BrowserPluginGuest* guest = new_contents->GetBrowserPluginGuest();
896 PendingWindowMap::iterator it = pending_new_windows_.find(guest);
897 if (it == pending_new_windows_.end())
899 const NewWindowInfo& new_window_info = it->second;
901 base::DictionaryValue request_info;
902 request_info.Set(browser_plugin::kInitialHeight,
903 base::Value::CreateIntegerValue(initial_bounds.height()));
904 request_info.Set(browser_plugin::kInitialWidth,
905 base::Value::CreateIntegerValue(initial_bounds.width()));
906 request_info.Set(browser_plugin::kTargetURL,
907 base::Value::CreateStringValue(new_window_info.url.spec()));
908 request_info.Set(browser_plugin::kName,
909 base::Value::CreateStringValue(new_window_info.name));
910 request_info.Set(browser_plugin::kWindowID,
911 base::Value::CreateIntegerValue(guest->instance_id()));
912 request_info.Set(browser_plugin::kWindowOpenDisposition,
913 base::Value::CreateStringValue(
914 WindowOpenDispositionToString(disposition)));
916 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW,
917 new NewWindowRequest(guest->instance_id(), this),
921 bool BrowserPluginGuest::UnlockMouseIfNecessary(
922 const NativeWebKeyboardEvent& event) {
926 embedder_web_contents()->GotResponseToLockMouseRequest(false);
930 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
932 // Some pages such as data URLs, javascript URLs, and about:blank
933 // do not load external resources and so they load prior to attachment.
934 // As a result, we must save all these IPCs until attachment and then
935 // forward them so that the embedder gets a chance to see and process
937 pending_messages_.push(msg);
940 msg->set_routing_id(embedder_web_contents_->GetRoutingID());
941 embedder_web_contents_->Send(msg);
944 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
945 int screen_x, int screen_y, WebKit::WebDragOperation operation) {
946 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
947 screen_x, screen_y, operation);
950 void BrowserPluginGuest::DragSourceMovedTo(int client_x, int client_y,
951 int screen_x, int screen_y) {
952 web_contents()->GetRenderViewHost()->DragSourceMovedTo(client_x, client_y,
956 void BrowserPluginGuest::EndSystemDrag() {
957 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
958 GetWebContents()->GetRenderViewHost());
959 guest_rvh->DragSourceSystemDragEnded();
960 // Issue a MouseUp event to get out of a selection state.
961 WebKit::WebMouseEvent mouse_event;
962 mouse_event.type = WebKit::WebInputEvent::MouseUp;
963 mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
964 guest_rvh->ForwardMouseEvent(mouse_event);
967 void BrowserPluginGuest::SetDelegate(BrowserPluginGuestDelegate* delegate) {
969 delegate_.reset(delegate);
972 void BrowserPluginGuest::AskEmbedderForGeolocationPermission(
974 const GURL& requesting_frame,
975 const GeolocationCallback& callback) {
976 base::DictionaryValue request_info;
977 request_info.Set(browser_plugin::kURL,
978 base::Value::CreateStringValue(requesting_frame.spec()));
981 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_GEOLOCATION,
982 new GeolocationRequest(
983 callback, bridge_id, &weak_ptr_factory_),
986 DCHECK(bridge_id_to_request_id_map_.find(bridge_id) ==
987 bridge_id_to_request_id_map_.end());
988 bridge_id_to_request_id_map_[bridge_id] = request_id;
991 int BrowserPluginGuest::RemoveBridgeID(int bridge_id) {
992 std::map<int, int>::iterator bridge_itr =
993 bridge_id_to_request_id_map_.find(bridge_id);
994 if (bridge_itr == bridge_id_to_request_id_map_.end())
995 return browser_plugin::kInvalidPermissionRequestID;
997 int request_id = bridge_itr->second;
998 bridge_id_to_request_id_map_.erase(bridge_itr);
1002 void BrowserPluginGuest::CancelGeolocationRequest(int bridge_id) {
1003 int request_id = RemoveBridgeID(bridge_id);
1004 RequestMap::iterator request_itr = permission_request_map_.find(request_id);
1005 if (request_itr == permission_request_map_.end())
1007 permission_request_map_.erase(request_itr);
1010 void BrowserPluginGuest::SetGeolocationPermission(GeolocationCallback callback,
1013 callback.Run(allowed);
1014 RemoveBridgeID(bridge_id);
1017 void BrowserPluginGuest::SendQueuedMessages() {
1021 while (!pending_messages_.empty()) {
1022 IPC::Message* message = pending_messages_.front();
1023 pending_messages_.pop();
1024 SendMessageToEmbedder(message);
1028 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
1030 const string16& frame_unique_name,
1033 PageTransition transition_type,
1034 RenderViewHost* render_view_host) {
1035 RecordAction(UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
1038 void BrowserPluginGuest::DidStopLoading(RenderViewHost* render_view_host) {
1039 bool enable_dragdrop = delegate_ && delegate_->IsDragAndDropEnabled();
1040 if (!enable_dragdrop) {
1041 // Initiating a drag from inside a guest is currently not supported without
1042 // the kEnableBrowserPluginDragDrop flag on a linux platform. So inject some
1043 // JS to disable it. http://crbug.com/161112
1044 const char script[] = "window.addEventListener('dragstart', function() { "
1045 " window.event.preventDefault(); "
1047 render_view_host->ExecuteJavascriptInWebFrame(string16(),
1048 ASCIIToUTF16(script));
1052 void BrowserPluginGuest::RenderViewReady() {
1053 // TODO(fsamuel): Investigate whether it's possible to update state earlier
1054 // here (see http://crbug.com/158151).
1055 Send(new InputMsg_SetFocus(routing_id(), focused_));
1057 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
1058 if (auto_size_enabled_)
1059 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
1061 rvh->DisableAutoResize(damage_view_size_);
1063 Send(new ViewMsg_SetName(routing_id(), name_));
1065 RenderWidgetHostImpl::From(rvh)->
1066 set_hung_renderer_delay_ms(guest_hang_timeout_);
1069 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
1070 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id()));
1072 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
1073 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Killed"));
1075 case base::TERMINATION_STATUS_PROCESS_CRASHED:
1076 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Crashed"));
1078 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
1079 RecordAction(UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
1084 // TODO(fsamuel): Consider whether we should be clearing
1085 // |permission_request_map_| here.
1087 delegate_->GuestProcessGone(status);
1091 void BrowserPluginGuest::AcknowledgeBufferPresent(
1094 const std::string& mailbox_name,
1095 uint32 sync_point) {
1096 AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
1097 ack_params.mailbox_name = mailbox_name;
1098 ack_params.sync_point = sync_point;
1099 RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id,
1105 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
1106 const IPC::Message& message) {
1107 switch (message.type()) {
1108 case BrowserPluginHostMsg_BuffersSwappedACK::ID:
1109 case BrowserPluginHostMsg_CompositorFrameACK::ID:
1110 case BrowserPluginHostMsg_DragStatusUpdate::ID:
1111 case BrowserPluginHostMsg_ExecuteEditCommand::ID:
1112 case BrowserPluginHostMsg_HandleInputEvent::ID:
1113 case BrowserPluginHostMsg_LockMouse_ACK::ID:
1114 case BrowserPluginHostMsg_NavigateGuest::ID:
1115 case BrowserPluginHostMsg_PluginDestroyed::ID:
1116 case BrowserPluginHostMsg_ResizeGuest::ID:
1117 case BrowserPluginHostMsg_SetAutoSize::ID:
1118 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
1119 case BrowserPluginHostMsg_SetFocus::ID:
1120 case BrowserPluginHostMsg_SetName::ID:
1121 case BrowserPluginHostMsg_SetVisibility::ID:
1122 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
1123 case BrowserPluginHostMsg_UpdateGeometry::ID:
1124 case BrowserPluginHostMsg_UpdateRect_ACK::ID:
1132 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
1133 bool handled = true;
1134 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
1135 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
1136 OnHasTouchEventHandlers)
1137 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
1138 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor)
1139 #if defined(OS_MACOSX)
1140 // MacOSX creates and populates platform-specific select drop-down menus
1141 // whereas other platforms merely create a popup window that the guest
1142 // renderer process paints inside.
1143 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup)
1145 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
1146 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
1147 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
1148 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFrameName, OnUpdateFrameName)
1149 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
1150 IPC_MESSAGE_UNHANDLED(handled = false)
1151 IPC_END_MESSAGE_MAP()
1155 void BrowserPluginGuest::Attach(
1156 WebContentsImpl* embedder_web_contents,
1157 BrowserPluginHostMsg_Attach_Params params,
1158 const base::DictionaryValue& extra_params) {
1162 extra_attach_params_.reset(extra_params.DeepCopy());
1164 // Clear parameters that get inherited from the opener.
1165 params.storage_partition_id.clear();
1166 params.persist_storage = false;
1169 // If a RenderView has already been created for this new window, then we need
1170 // to initialize the browser-side state now so that the RenderViewHostManager
1171 // does not create a new RenderView on navigation.
1172 if (has_render_view_) {
1173 static_cast<RenderViewHostImpl*>(
1174 GetWebContents()->GetRenderViewHost())->Init();
1175 WebContentsViewGuest* new_view =
1176 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
1177 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
1180 // We need to do a navigation here if the target URL has changed between
1181 // the time the WebContents was created and the time it was attached.
1182 // We also need to do an initial navigation if a RenderView was never
1183 // created for the new window in cases where there is no referrer.
1184 PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
1185 if (it != opener()->pending_new_windows_.end()) {
1186 const NewWindowInfo& new_window_info = it->second;
1187 if (new_window_info.changed || !has_render_view_)
1188 params.src = it->second.url.spec();
1193 // Once a new guest is attached to the DOM of the embedder page, then the
1194 // lifetime of the new guest is no longer managed by the opener guest.
1195 opener()->pending_new_windows_.erase(this);
1197 // The guest's frame name takes precedence over the BrowserPlugin's name.
1198 // The guest's frame name is assigned in
1199 // BrowserPluginGuest::WebContentsCreated.
1201 params.name.clear();
1203 Initialize(embedder_web_contents, params);
1205 SendQueuedMessages();
1207 RecordAction(UserMetricsAction("BrowserPlugin.Guest.Attached"));
1210 void BrowserPluginGuest::OnCompositorFrameACK(
1213 uint32 output_surface_id,
1214 int renderer_host_id,
1215 const cc::CompositorFrameAck& ack) {
1216 RenderWidgetHostImpl::SendSwapCompositorFrameAck(route_id,
1222 void BrowserPluginGuest::OnDragStatusUpdate(int instance_id,
1223 WebKit::WebDragStatus drag_status,
1224 const DropData& drop_data,
1225 WebKit::WebDragOperationsMask mask,
1226 const gfx::Point& location) {
1227 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
1228 switch (drag_status) {
1229 case WebKit::WebDragStatusEnter:
1230 embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest(
1232 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
1234 case WebKit::WebDragStatusOver:
1235 host->DragTargetDragOver(location, location, mask, 0);
1237 case WebKit::WebDragStatusLeave:
1238 embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this);
1239 host->DragTargetDragLeave();
1241 case WebKit::WebDragStatusDrop:
1242 host->DragTargetDrop(location, location, 0);
1245 case WebKit::WebDragStatusUnknown:
1250 void BrowserPluginGuest::OnExecuteEditCommand(int instance_id,
1251 const std::string& name) {
1252 Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
1255 void BrowserPluginGuest::OnHandleInputEvent(
1257 const gfx::Rect& guest_window_rect,
1258 const WebKit::WebInputEvent* event) {
1259 guest_window_rect_ = guest_window_rect;
1260 // If the embedder's RWHV is destroyed then that means that the embedder's
1261 // window has been closed but the embedder's WebContents has not yet been
1262 // destroyed. Computing screen coordinates of a BrowserPlugin only makes sense
1263 // if there is a visible embedder.
1264 if (embedder_web_contents_->GetRenderWidgetHostView()) {
1265 guest_screen_rect_ = guest_window_rect;
1266 guest_screen_rect_.Offset(
1267 embedder_web_contents_->GetRenderWidgetHostView()->
1268 GetViewBounds().OffsetFromOrigin());
1270 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
1271 GetWebContents()->GetRenderViewHost());
1273 if (WebKit::WebInputEvent::isMouseEventType(event->type)) {
1274 guest_rvh->ForwardMouseEvent(
1275 *static_cast<const WebKit::WebMouseEvent*>(event));
1279 if (event->type == WebKit::WebInputEvent::MouseWheel) {
1280 guest_rvh->ForwardWheelEvent(
1281 *static_cast<const WebKit::WebMouseWheelEvent*>(event));
1285 if (WebKit::WebInputEvent::isKeyboardEventType(event->type)) {
1286 RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
1287 embedder_web_contents_->GetRenderViewHost());
1288 if (!embedder_rvh->GetLastKeyboardEvent())
1290 NativeWebKeyboardEvent keyboard_event(
1291 *embedder_rvh->GetLastKeyboardEvent());
1292 guest_rvh->ForwardKeyboardEvent(keyboard_event);
1296 if (WebKit::WebInputEvent::isTouchEventType(event->type)) {
1297 guest_rvh->ForwardTouchEventWithLatencyInfo(
1298 *static_cast<const WebKit::WebTouchEvent*>(event),
1303 if (WebKit::WebInputEvent::isGestureEventType(event->type)) {
1304 guest_rvh->ForwardGestureEvent(
1305 *static_cast<const WebKit::WebGestureEvent*>(event));
1310 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
1311 bool last_unlocked_by_target,
1313 if (pending_lock_request_) {
1314 // Immediately reject the lock because only one pointerLock may be active
1316 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
1319 pending_lock_request_ = true;
1320 base::DictionaryValue request_info;
1321 request_info.Set(browser_plugin::kUserGesture,
1322 base::Value::CreateBooleanValue(user_gesture));
1323 request_info.Set(browser_plugin::kLastUnlockedBySelf,
1324 base::Value::CreateBooleanValue(last_unlocked_by_target));
1325 request_info.Set(browser_plugin::kURL,
1326 base::Value::CreateStringValue(
1327 web_contents()->GetLastCommittedURL().spec()));
1329 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK,
1330 new PointerLockRequest(this),
1334 void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) {
1335 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
1336 pending_lock_request_ = false;
1338 mouse_locked_ = true;
1341 void BrowserPluginGuest::OnNavigateGuest(
1343 const std::string& src) {
1344 GURL url = delegate_ ? delegate_->ResolveURL(src) : GURL(src);
1345 // We do not load empty urls in web_contents.
1346 // If a guest sets empty src attribute after it has navigated to some
1347 // non-empty page, the action is considered no-op. This empty src navigation
1348 // should never be sent to BrowserPluginGuest (browser process).
1349 DCHECK(!src.empty());
1353 // Do not allow navigating a guest to schemes other than known safe schemes.
1354 // This will block the embedder trying to load unwanted schemes, e.g.
1355 // chrome://settings.
1356 bool scheme_is_blocked =
1357 (!ChildProcessSecurityPolicyImpl::GetInstance()->IsWebSafeScheme(
1359 !ChildProcessSecurityPolicyImpl::GetInstance()->IsPseudoScheme(
1361 url.SchemeIs(kJavaScriptScheme);
1362 if (scheme_is_blocked || !url.is_valid()) {
1364 std::string error_type;
1365 RemoveChars(net::ErrorToString(net::ERR_ABORTED), "net::", &error_type);
1366 delegate_->LoadAbort(true /* is_top_level */, url, error_type);
1371 GURL validated_url(url);
1372 RenderViewHost::FilterURL(
1373 GetWebContents()->GetRenderProcessHost(),
1376 // As guests do not swap processes on navigation, only navigations to
1377 // normal web URLs are supported. No protocol handlers are installed for
1378 // other schemes (e.g., WebUI or extensions), and no permissions or bindings
1379 // can be granted to the guest process.
1380 LoadURLWithParams(GetWebContents(), validated_url, Referrer(),
1381 PAGE_TRANSITION_AUTO_TOPLEVEL);
1384 void BrowserPluginGuest::OnPluginDestroyed(int instance_id) {
1388 void BrowserPluginGuest::OnResizeGuest(
1390 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
1391 if (!params.size_changed)
1393 // BrowserPlugin manages resize flow control itself and does not depend
1394 // on RenderWidgetHost's mechanisms for flow control, so we reset those flags
1395 // here. If we are setting the size for the first time before navigating then
1396 // BrowserPluginGuest does not yet have a RenderViewHost.
1397 if (GetWebContents()->GetRenderViewHost()) {
1398 RenderWidgetHostImpl* render_widget_host =
1399 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
1400 render_widget_host->ResetSizeAndRepaintPendingFlags();
1402 if (guest_device_scale_factor_ != params.scale_factor) {
1403 guest_device_scale_factor_ = params.scale_factor;
1404 render_widget_host->NotifyScreenInfoChanged();
1407 // When autosize is turned off and as a result there is a layout change, we
1408 // send a sizechanged event.
1409 if (!auto_size_enabled_ && last_seen_auto_size_enabled_ &&
1410 !params.view_rect.size().IsEmpty() && delegate_) {
1411 delegate_->SizeChanged(last_seen_view_size_, params.view_rect.size());
1412 last_seen_auto_size_enabled_ = false;
1414 // Invalid damage buffer means we are in HW compositing mode,
1415 // so just resize the WebContents and repaint if needed.
1416 if (!base::SharedMemory::IsHandleValid(params.damage_buffer_handle)) {
1417 if (!params.view_rect.size().IsEmpty())
1418 GetWebContents()->GetView()->SizeContents(params.view_rect.size());
1420 Send(new ViewMsg_Repaint(routing_id(), params.view_rect.size()));
1423 SetDamageBuffer(params);
1424 GetWebContents()->GetView()->SizeContents(params.view_rect.size());
1426 Send(new ViewMsg_Repaint(routing_id(), params.view_rect.size()));
1429 void BrowserPluginGuest::OnSetFocus(int instance_id, bool focused) {
1430 if (focused_ == focused)
1433 Send(new InputMsg_SetFocus(routing_id(), focused));
1434 if (!focused && mouse_locked_)
1438 void BrowserPluginGuest::OnSetName(int instance_id, const std::string& name) {
1442 Send(new ViewMsg_SetName(routing_id(), name));
1445 void BrowserPluginGuest::OnSetSize(
1447 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1448 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1449 bool old_auto_size_enabled = auto_size_enabled_;
1450 gfx::Size old_max_size = max_auto_size_;
1451 gfx::Size old_min_size = min_auto_size_;
1452 auto_size_enabled_ = auto_size_params.enable;
1453 max_auto_size_ = auto_size_params.max_size;
1454 min_auto_size_ = auto_size_params.min_size;
1455 if (auto_size_enabled_ && (!old_auto_size_enabled ||
1456 (old_max_size != max_auto_size_) ||
1457 (old_min_size != min_auto_size_))) {
1458 RecordAction(UserMetricsAction("BrowserPlugin.Guest.EnableAutoResize"));
1459 GetWebContents()->GetRenderViewHost()->EnableAutoResize(
1460 min_auto_size_, max_auto_size_);
1461 // TODO(fsamuel): If we're changing autosize parameters, then we force
1462 // the guest to completely repaint itself, because BrowserPlugin has
1463 // allocated a new damage buffer and expects a full frame of pixels.
1464 // Ideally, we shouldn't need to do this because we shouldn't need to
1465 // allocate a new damage buffer unless |max_auto_size_| has changed.
1466 // However, even in that case, layout may not change and so we may
1467 // not get a full frame worth of pixels.
1468 Send(new ViewMsg_Repaint(routing_id(), max_auto_size_));
1469 } else if (!auto_size_enabled_ && old_auto_size_enabled) {
1470 GetWebContents()->GetRenderViewHost()->DisableAutoResize(
1471 resize_guest_params.view_rect.size());
1473 OnResizeGuest(instance_id_, resize_guest_params);
1476 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
1478 const std::vector<EditCommand>& edit_commands) {
1479 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
1483 void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) {
1484 guest_visible_ = visible;
1485 if (embedder_visible_ && guest_visible_)
1486 GetWebContents()->WasShown();
1488 GetWebContents()->WasHidden();
1491 void BrowserPluginGuest::OnSwapBuffersACK(int instance_id,
1494 const std::string& mailbox_name,
1495 uint32 sync_point) {
1496 AcknowledgeBufferPresent(route_id, gpu_host_id, mailbox_name, sync_point);
1498 // This is only relevant on MACOSX and WIN when threaded compositing
1499 // is not enabled. In threaded mode, above ACK is sufficient.
1500 #if defined(OS_MACOSX) || defined(OS_WIN)
1501 RenderWidgetHostImpl* render_widget_host =
1502 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
1503 render_widget_host->AcknowledgeSwapBuffersToRenderer();
1504 #endif // defined(OS_MACOSX) || defined(OS_WIN)
1507 void BrowserPluginGuest::OnUnlockMouse() {
1508 SendMessageToEmbedder(
1509 new BrowserPluginMsg_SetMouseLock(instance_id(), false));
1512 void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) {
1513 // mouse_locked_ could be false here if the lock attempt was cancelled due
1514 // to window focus, or for various other reasons before the guest was informed
1515 // of the lock's success.
1517 Send(new ViewMsg_MouseLockLost(routing_id()));
1518 mouse_locked_ = false;
1521 void BrowserPluginGuest::OnUpdateRectACK(
1524 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1525 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1526 // Only the software path expects an ACK.
1528 Send(new ViewMsg_UpdateRect_ACK(routing_id()));
1529 OnSetSize(instance_id_, auto_size_params, resize_guest_params);
1532 void BrowserPluginGuest::OnUpdateGeometry(int instance_id,
1533 const gfx::Rect& view_rect) {
1534 // The plugin has moved within the embedder without resizing or the
1535 // embedder/container's view rect changing.
1536 guest_window_rect_ = view_rect;
1537 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1538 GetWebContents()->GetRenderViewHost());
1540 rvh->SendScreenRects();
1543 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
1544 SendMessageToEmbedder(
1545 new BrowserPluginMsg_ShouldAcceptTouchEvents(instance_id(), accept));
1548 void BrowserPluginGuest::OnSetCursor(const WebCursor& cursor) {
1549 SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(instance_id(), cursor));
1552 #if defined(OS_MACOSX)
1553 void BrowserPluginGuest::OnShowPopup(
1554 const ViewHostMsg_ShowPopup_Params& params) {
1555 gfx::Rect translated_bounds(params.bounds);
1556 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
1557 BrowserPluginPopupMenuHelper popup_menu_helper(
1558 embedder_web_contents_->GetRenderViewHost(),
1559 GetWebContents()->GetRenderViewHost());
1560 popup_menu_helper.ShowPopupMenu(translated_bounds,
1562 params.item_font_size,
1563 params.selected_item,
1565 params.right_aligned,
1566 params.allow_multiple_selection);
1570 void BrowserPluginGuest::OnShowWidget(int route_id,
1571 const gfx::Rect& initial_pos) {
1572 GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
1575 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
1576 SendMessageToEmbedder(
1577 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
1580 void BrowserPluginGuest::OnUpdateFrameName(int frame_id,
1582 const std::string& name) {
1587 SendMessageToEmbedder(new BrowserPluginMsg_UpdatedName(instance_id_, name));
1590 void BrowserPluginGuest::RequestMediaAccessPermission(
1591 WebContents* web_contents,
1592 const MediaStreamRequest& request,
1593 const MediaResponseCallback& callback) {
1594 base::DictionaryValue request_info;
1596 browser_plugin::kURL,
1597 base::Value::CreateStringValue(request.security_origin.spec()));
1599 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_MEDIA,
1600 new MediaRequest(request, callback, this),
1604 void BrowserPluginGuest::RunJavaScriptDialog(
1605 WebContents* web_contents,
1606 const GURL& origin_url,
1607 const std::string& accept_lang,
1608 JavaScriptMessageType javascript_message_type,
1609 const string16& message_text,
1610 const string16& default_prompt_text,
1611 const DialogClosedCallback& callback,
1612 bool* did_suppress_message) {
1613 base::DictionaryValue request_info;
1615 browser_plugin::kDefaultPromptText,
1616 base::Value::CreateStringValue(UTF16ToUTF8(default_prompt_text)));
1618 browser_plugin::kMessageText,
1619 base::Value::CreateStringValue(UTF16ToUTF8(message_text)));
1621 browser_plugin::kMessageType,
1622 base::Value::CreateStringValue(
1623 JavaScriptMessageTypeToString(javascript_message_type)));
1625 browser_plugin::kURL,
1626 base::Value::CreateStringValue(origin_url.spec()));
1628 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG,
1629 new JavaScriptDialogRequest(callback),
1633 void BrowserPluginGuest::RunBeforeUnloadDialog(
1634 WebContents* web_contents,
1635 const string16& message_text,
1637 const DialogClosedCallback& callback) {
1638 // This is called if the guest has a beforeunload event handler.
1639 // This callback allows navigation to proceed.
1640 callback.Run(true, string16());
1643 bool BrowserPluginGuest::HandleJavaScriptDialog(
1644 WebContents* web_contents,
1646 const string16* prompt_override) {
1650 void BrowserPluginGuest::CancelActiveAndPendingDialogs(
1651 WebContents* web_contents) {
1654 void BrowserPluginGuest::WebContentsDestroyed(WebContents* web_contents) {
1657 void BrowserPluginGuest::OnUpdateRect(
1658 const ViewHostMsg_UpdateRect_Params& params) {
1659 BrowserPluginMsg_UpdateRect_Params relay_params;
1660 relay_params.view_size = params.view_size;
1661 relay_params.scale_factor = params.scale_factor;
1662 relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(
1664 relay_params.needs_ack = params.needs_ack;
1666 bool size_changed = last_seen_view_size_ != params.view_size;
1667 gfx::Size old_size = last_seen_view_size_;
1668 last_seen_view_size_ = params.view_size;
1670 if ((auto_size_enabled_ || last_seen_auto_size_enabled_) &&
1671 size_changed && delegate_) {
1672 delegate_->SizeChanged(old_size, last_seen_view_size_);
1674 last_seen_auto_size_enabled_ = auto_size_enabled_;
1676 // HW accelerated case, acknowledge resize only
1677 if (!params.needs_ack || !damage_buffer_) {
1678 relay_params.damage_buffer_sequence_id = 0;
1679 SendMessageToEmbedder(
1680 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1684 // Only copy damage if the guest is in autosize mode and the guest's view size
1685 // is less than the maximum size or the guest's view size is equal to the
1686 // damage buffer's size and the guest's scale factor is equal to the damage
1687 // buffer's scale factor.
1688 // The scaling change can happen due to asynchronous updates of the DPI on a
1689 // resolution change.
1690 if (((auto_size_enabled_ && InAutoSizeBounds(params.view_size)) ||
1691 (params.view_size == damage_view_size())) &&
1692 params.scale_factor == damage_buffer_scale_factor()) {
1693 TransportDIB* dib = GetWebContents()->GetRenderProcessHost()->
1694 GetTransportDIB(params.bitmap);
1696 size_t guest_damage_buffer_size =
1698 params.bitmap_rect.width() *
1699 params.bitmap_rect.height() * 4;
1703 size_t embedder_damage_buffer_size = damage_buffer_size_;
1704 void* guest_memory = dib->memory();
1705 void* embedder_memory = damage_buffer_->memory();
1706 size_t size = std::min(guest_damage_buffer_size,
1707 embedder_damage_buffer_size);
1708 memcpy(embedder_memory, guest_memory, size);
1711 relay_params.damage_buffer_sequence_id = damage_buffer_sequence_id_;
1712 relay_params.bitmap_rect = params.bitmap_rect;
1713 relay_params.scroll_delta = params.scroll_delta;
1714 relay_params.scroll_rect = params.scroll_rect;
1715 relay_params.copy_rects = params.copy_rects;
1717 SendMessageToEmbedder(
1718 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1721 void BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId(
1722 const std::string& request_method,
1723 const base::Callback<void(bool)>& callback,
1724 const std::string& url) {
1726 callback.Run(false);
1730 base::DictionaryValue request_info;
1731 request_info.Set(browser_plugin::kRequestMethod,
1732 base::Value::CreateStringValue(request_method));
1733 request_info.Set(browser_plugin::kURL, base::Value::CreateStringValue(url));
1735 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_DOWNLOAD,
1736 new DownloadRequest(callback),
1740 } // namespace content