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_frame_host_impl.h"
18 #include "content/browser/frame_host/render_widget_host_view_guest.h"
19 #include "content/browser/loader/resource_dispatcher_host_impl.h"
20 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
21 #include "content/browser/renderer_host/render_view_host_impl.h"
22 #include "content/browser/renderer_host/render_widget_host_impl.h"
23 #include "content/browser/renderer_host/render_widget_host_view_base.h"
24 #include "content/browser/web_contents/web_contents_impl.h"
25 #include "content/browser/web_contents/web_contents_view_guest.h"
26 #include "content/common/browser_plugin/browser_plugin_constants.h"
27 #include "content/common/browser_plugin/browser_plugin_messages.h"
28 #include "content/common/content_constants_internal.h"
29 #include "content/common/drag_messages.h"
30 #include "content/common/input_messages.h"
31 #include "content/common/view_messages.h"
32 #include "content/public/browser/browser_context.h"
33 #include "content/public/browser/content_browser_client.h"
34 #include "content/public/browser/navigation_controller.h"
35 #include "content/public/browser/render_widget_host_view.h"
36 #include "content/public/browser/user_metrics.h"
37 #include "content/public/browser/web_contents_observer.h"
38 #include "content/public/common/context_menu_params.h"
39 #include "content/public/common/drop_data.h"
40 #include "content/public/common/media_stream_request.h"
41 #include "content/public/common/result_codes.h"
42 #include "content/public/common/url_constants.h"
43 #include "content/public/common/url_utils.h"
44 #include "net/url_request/url_request.h"
45 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
46 #include "ui/events/keycodes/keyboard_codes.h"
47 #include "webkit/common/resource_type.h"
49 #if defined(OS_MACOSX)
50 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
56 BrowserPluginHostFactory* BrowserPluginGuest::factory_ = NULL;
58 // Parent class for the various types of permission requests, each of which
59 // should be able to handle the response to their permission request.
60 class BrowserPluginGuest::PermissionRequest :
61 public base::RefCounted<BrowserPluginGuest::PermissionRequest> {
63 void Respond(bool should_allow, const std::string& user_input) {
66 RespondImpl(should_allow, user_input);
68 virtual bool AllowedByDefault() const {
72 explicit PermissionRequest(const base::WeakPtr<BrowserPluginGuest>& guest)
75 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest"));
77 virtual ~PermissionRequest() {}
79 virtual void RespondImpl(bool should_allow,
80 const std::string& user_input) = 0;
81 // Friend RefCounted so that the dtor can be non-public.
82 friend class base::RefCounted<BrowserPluginGuest::PermissionRequest>;
84 base::WeakPtr<BrowserPluginGuest> guest_;
87 class BrowserPluginGuest::NewWindowRequest : public PermissionRequest {
89 NewWindowRequest(const base::WeakPtr<BrowserPluginGuest>& guest,
91 : PermissionRequest(guest),
92 instance_id_(instance_id) {
94 base::UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.NewWindow"));
97 virtual void RespondImpl(bool should_allow,
98 const std::string& user_input) OVERRIDE {
99 int embedder_render_process_id =
100 guest_->embedder_web_contents()->GetRenderProcessHost()->GetID();
101 guest_->GetBrowserPluginGuestManager()->
102 MaybeGetGuestByInstanceIDOrKill(
104 embedder_render_process_id,
105 base::Bind(&BrowserPluginGuest::NewWindowRequest::RespondInternal,
106 base::Unretained(this),
111 virtual ~NewWindowRequest() {}
113 void RespondInternal(bool should_allow,
114 BrowserPluginGuest* guest) {
116 VLOG(0) << "Guest not found. Instance ID: " << instance_id_;
120 // If we do not destroy the guest then we allow the new window.
129 std::string WindowOpenDispositionToString(
130 WindowOpenDisposition window_open_disposition) {
131 switch (window_open_disposition) {
135 return "save_to_disk";
137 return "current_tab";
138 case NEW_BACKGROUND_TAB:
139 return "new_background_tab";
140 case NEW_FOREGROUND_TAB:
141 return "new_foreground_tab";
147 NOTREACHED() << "Unknown Window Open Disposition";
152 // Called on IO thread.
153 static GURL RetrieveDownloadURLFromRequestId(
154 int render_process_id,
155 int url_request_id) {
156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
158 GlobalRequestID global_id(render_process_id, url_request_id);
159 net::URLRequest* url_request =
160 ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id);
162 return url_request->url();
168 class BrowserPluginGuest::EmbedderWebContentsObserver
169 : public WebContentsObserver {
171 explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest)
172 : WebContentsObserver(guest->embedder_web_contents()),
173 browser_plugin_guest_(guest) {
176 virtual ~EmbedderWebContentsObserver() {
179 // WebContentsObserver:
180 virtual void WebContentsDestroyed() OVERRIDE {
181 browser_plugin_guest_->EmbedderDestroyed();
184 virtual void WasShown() OVERRIDE {
185 browser_plugin_guest_->EmbedderVisibilityChanged(true);
188 virtual void WasHidden() OVERRIDE {
189 browser_plugin_guest_->EmbedderVisibilityChanged(false);
193 BrowserPluginGuest* browser_plugin_guest_;
195 DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
198 BrowserPluginGuest::BrowserPluginGuest(
200 bool has_render_view,
201 WebContentsImpl* web_contents)
202 : WebContentsObserver(web_contents),
203 embedder_web_contents_(NULL),
204 instance_id_(instance_id),
205 guest_device_scale_factor_(1.0f),
207 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
209 mouse_locked_(false),
210 pending_lock_request_(false),
211 embedder_visible_(true),
212 auto_size_enabled_(false),
214 next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID),
215 has_render_view_(has_render_view),
216 last_seen_auto_size_enabled_(false),
217 is_in_destruction_(false),
218 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
219 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
220 last_can_compose_inline_(true),
221 weak_ptr_factory_(this) {
222 DCHECK(web_contents);
223 web_contents->SetDelegate(this);
224 GetBrowserPluginGuestManager()->AddGuest(instance_id_, GetWebContents());
227 bool BrowserPluginGuest::AddMessageToConsole(WebContents* source,
229 const base::string16& message,
231 const base::string16& source_id) {
235 delegate_->AddMessageToConsole(level, message, line_no, source_id);
239 void BrowserPluginGuest::DestroyUnattachedWindows() {
240 // Destroy() reaches in and removes the BrowserPluginGuest from its opener's
241 // pending_new_windows_ set. To avoid mutating the set while iterating, we
242 // create a copy of the pending new windows set and iterate over the copy.
243 PendingWindowMap pending_new_windows(pending_new_windows_);
244 // Clean up unattached new windows opened by this guest.
245 for (PendingWindowMap::const_iterator it = pending_new_windows.begin();
246 it != pending_new_windows.end(); ++it) {
247 it->first->Destroy();
249 // All pending windows should be removed from the set after Destroy() is
250 // called on all of them.
251 DCHECK(pending_new_windows_.empty());
254 void BrowserPluginGuest::LoadURLWithParams(const GURL& url,
255 const Referrer& referrer,
256 PageTransition transition_type,
257 WebContents* web_contents) {
258 NavigationController::LoadURLParams load_url_params(url);
259 load_url_params.referrer = referrer;
260 load_url_params.transition_type = transition_type;
261 load_url_params.extra_headers = std::string();
262 if (delegate_ && delegate_->IsOverridingUserAgent()) {
263 load_url_params.override_user_agent =
264 NavigationController::UA_OVERRIDE_TRUE;
266 web_contents->GetController().LoadURLWithParams(load_url_params);
269 void BrowserPluginGuest::RespondToPermissionRequest(
272 const std::string& user_input) {
273 RequestMap::iterator request_itr = permission_request_map_.find(request_id);
274 if (request_itr == permission_request_map_.end()) {
275 VLOG(0) << "Not a valid request ID.";
278 request_itr->second->Respond(should_allow, user_input);
279 permission_request_map_.erase(request_itr);
282 void BrowserPluginGuest::RequestPermission(
283 BrowserPluginPermissionType permission_type,
284 scoped_refptr<BrowserPluginGuest::PermissionRequest> request,
285 const base::DictionaryValue& request_info) {
287 // Let the stack unwind before we deny the permission request so that
288 // objects held by the permission request are not destroyed immediately
289 // after creation. This is to allow those same objects to be accessed again
290 // in the same scope without fear of use after freeing.
291 base::MessageLoop::current()->PostTask(
293 base::Bind(&BrowserPluginGuest::PermissionRequest::Respond,
294 request, false, ""));
297 int request_id = ++next_permission_request_id_;
298 permission_request_map_[request_id] = request;
300 BrowserPluginGuestDelegate::PermissionResponseCallback callback =
301 base::Bind(&BrowserPluginGuest::RespondToPermissionRequest,
304 delegate_->RequestPermission(
305 permission_type, request_info, callback, request->AllowedByDefault());
308 BrowserPluginGuest* BrowserPluginGuest::CreateNewGuestWindow(
309 const OpenURLParams& params) {
310 BrowserPluginGuestManager* guest_manager = GetBrowserPluginGuestManager();
312 // Allocate a new instance ID for the new guest.
313 int instance_id = guest_manager->GetNextInstanceID();
315 // Set the attach params to use the same partition as the opener.
316 // We pull the partition information from the site's URL, which is of the form
317 // guest://site/{persist}?{partition_name}.
318 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
319 BrowserPluginHostMsg_Attach_Params attach_params;
320 attach_params.storage_partition_id = site_url.query();
321 attach_params.persist_storage =
322 site_url.path().find("persist") != std::string::npos;
324 // The new guest gets a copy of this guest's extra params so that the content
325 // embedder exposes the same API for this guest as its opener.
326 scoped_ptr<base::DictionaryValue> extra_params(
327 extra_attach_params_->DeepCopy());
328 BrowserPluginGuest* new_guest =
329 guest_manager->CreateGuest(GetWebContents()->GetSiteInstance(),
332 extra_params.Pass());
333 if (new_guest->delegate_)
334 new_guest->delegate_->SetOpener(GetWebContents());
336 // Take ownership of |new_guest|.
337 pending_new_windows_.insert(
338 std::make_pair(new_guest, NewWindowInfo(params.url, std::string())));
340 // Request permission to show the new window.
341 RequestNewWindowPermission(params.disposition, gfx::Rect(),
342 params.user_gesture, new_guest->GetWebContents());
347 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
348 return weak_ptr_factory_.GetWeakPtr();
351 void BrowserPluginGuest::EmbedderDestroyed() {
352 embedder_web_contents_ = NULL;
354 delegate_->EmbedderDestroyed();
358 void BrowserPluginGuest::Destroy() {
359 is_in_destruction_ = true;
360 if (!attached() && GetOpener())
361 GetOpener()->pending_new_windows_.erase(this);
362 DestroyUnattachedWindows();
363 GetBrowserPluginGuestManager()->RemoveGuest(instance_id_);
364 delete GetWebContents();
367 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
368 const IPC::Message& message) {
370 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
371 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
372 OnCompositorFrameSwappedACK)
373 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck,
374 OnCopyFromCompositingSurfaceAck)
375 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
377 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
378 OnExecuteEditCommand)
379 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
380 OnExtendSelectionAndDelete)
381 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
383 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
384 OnImeConfirmComposition)
385 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
387 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
388 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateGuest, OnNavigateGuest)
389 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
390 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
391 OnReclaimCompositorResources)
392 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
393 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize)
394 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
395 OnSetEditCommandsForNextKeyEvent)
396 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
397 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetName, OnSetName)
398 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetContentsOpaque,
400 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
401 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
402 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
403 IPC_MESSAGE_UNHANDLED(handled = false)
404 IPC_END_MESSAGE_MAP()
408 void BrowserPluginGuest::Initialize(
409 const BrowserPluginHostMsg_Attach_Params& params,
410 WebContentsImpl* embedder_web_contents) {
411 focused_ = params.focused;
412 guest_visible_ = params.visible;
413 guest_opaque_ = params.opaque;
414 guest_window_rect_ = params.resize_guest_params.view_rect;
416 if (!params.name.empty())
418 auto_size_enabled_ = params.auto_size_params.enable;
419 max_auto_size_ = params.auto_size_params.max_size;
420 min_auto_size_ = params.auto_size_params.min_size;
422 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
424 embedder_web_contents_ = embedder_web_contents;
426 WebContentsViewGuest* new_view =
427 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
428 new_view->OnGuestInitialized(embedder_web_contents->GetView());
430 RendererPreferences* renderer_prefs =
431 GetWebContents()->GetMutableRendererPrefs();
432 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
433 // Copy renderer preferences (and nothing else) from the embedder's
434 // WebContents to the guest.
436 // For GTK and Aura this is necessary to get proper renderer configuration
437 // values for caret blinking interval, colors related to selection and
439 *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs();
440 renderer_prefs->user_agent_override = guest_user_agent_override;
442 // We would like the guest to report changes to frame names so that we can
443 // update the BrowserPlugin's corresponding 'name' attribute.
444 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
445 renderer_prefs->report_frame_name_changes = true;
446 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
447 // navigations still continue to function inside the app.
448 renderer_prefs->browser_handles_all_top_level_requests = false;
449 // Disable "client blocked" error page for browser plugin.
450 renderer_prefs->disable_client_blocked_error_page = true;
452 embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this));
454 OnSetSize(instance_id_, params.auto_size_params, params.resize_guest_params);
456 // Create a swapped out RenderView for the guest in the embedder render
457 // process, so that the embedder can access the guest's window object.
458 int guest_routing_id =
459 GetWebContents()->CreateSwappedOutRenderView(
460 embedder_web_contents_->GetSiteInstance());
461 SendMessageToEmbedder(
462 new BrowserPluginMsg_GuestContentWindowReady(instance_id_,
465 if (!params.src.empty()) {
466 // params.src will be validated in BrowserPluginGuest::OnNavigateGuest.
467 OnNavigateGuest(instance_id_, params.src);
470 has_render_view_ = true;
472 WebPreferences prefs = GetWebContents()->GetWebkitPrefs();
473 prefs.navigate_on_drag_drop = false;
474 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
476 // Enable input method for guest if it's enabled for the embedder.
477 if (static_cast<RenderViewHostImpl*>(
478 embedder_web_contents_->GetRenderViewHost())->input_method_active()) {
479 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
480 GetWebContents()->GetRenderViewHost());
481 guest_rvh->SetInputMethodActive(true);
484 // Inform the embedder of the guest's information.
485 // We pull the partition information from the site's URL, which is of the form
486 // guest://site/{persist}?{partition_name}.
487 const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
488 BrowserPluginMsg_Attach_ACK_Params ack_params;
489 ack_params.storage_partition_id = site_url.query();
490 ack_params.persist_storage =
491 site_url.path().find("persist") != std::string::npos;
492 ack_params.name = name_;
493 SendMessageToEmbedder(
494 new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
497 delegate_->DidAttach();
500 BrowserPluginGuest::~BrowserPluginGuest() {
501 while (!pending_messages_.empty()) {
502 delete pending_messages_.front();
503 pending_messages_.pop();
508 BrowserPluginGuest* BrowserPluginGuest::Create(
510 SiteInstance* guest_site_instance,
511 WebContentsImpl* web_contents,
512 scoped_ptr<base::DictionaryValue> extra_params) {
513 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
514 BrowserPluginGuest* guest = NULL;
516 guest = factory_->CreateBrowserPluginGuest(instance_id, web_contents);
518 guest = new BrowserPluginGuest(instance_id, false, web_contents);
520 guest->extra_attach_params_.reset(extra_params->DeepCopy());
521 web_contents->SetBrowserPluginGuest(guest);
522 BrowserPluginGuestDelegate* delegate = NULL;
523 GetContentClient()->browser()->GuestWebContentsCreated(
524 guest_site_instance, web_contents, NULL, &delegate, extra_params.Pass());
525 guest->SetDelegate(delegate);
530 BrowserPluginGuest* BrowserPluginGuest::CreateWithOpener(
532 bool has_render_view,
533 WebContentsImpl* web_contents,
534 BrowserPluginGuest* opener) {
535 BrowserPluginGuest* guest =
536 new BrowserPluginGuest(
537 instance_id, has_render_view, web_contents);
538 web_contents->SetBrowserPluginGuest(guest);
539 BrowserPluginGuestDelegate* delegate = NULL;
540 GetContentClient()->browser()->GuestWebContentsCreated(
541 opener->GetWebContents()->GetSiteInstance(),
542 web_contents, opener->GetWebContents(), &delegate,
543 scoped_ptr<base::DictionaryValue>());
544 guest->SetDelegate(delegate);
548 RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
551 return embedder_web_contents_->GetRenderWidgetHostView();
554 BrowserPluginGuest* BrowserPluginGuest::GetOpener() const {
558 WebContents* opener = delegate_->GetOpener();
562 return static_cast<WebContentsImpl*>(opener)->GetBrowserPluginGuest();
565 void BrowserPluginGuest::UpdateVisibility() {
566 OnSetVisibility(instance_id_, visible());
569 void BrowserPluginGuest::CopyFromCompositingSurface(
570 gfx::Rect src_subrect,
572 const base::Callback<void(bool, const SkBitmap&)>& callback) {
573 copy_request_callbacks_.insert(std::make_pair(++copy_request_id_, callback));
574 SendMessageToEmbedder(
575 new BrowserPluginMsg_CopyFromCompositingSurface(instance_id(),
576 copy_request_id_, src_subrect, dst_size));
579 BrowserPluginGuestManager*
580 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
581 return BrowserPluginGuestManager::FromBrowserContext(
582 GetWebContents()->GetBrowserContext());
586 gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) {
587 gfx::Rect guest_rect(bounds);
588 guest_rect.Offset(guest_window_rect_.OffsetFromOrigin());
592 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
593 embedder_visible_ = visible;
597 void BrowserPluginGuest::AddNewContents(WebContents* source,
598 WebContents* new_contents,
599 WindowOpenDisposition disposition,
600 const gfx::Rect& initial_pos,
604 *was_blocked = false;
605 RequestNewWindowPermission(disposition, initial_pos, user_gesture,
606 static_cast<WebContentsImpl*>(new_contents));
609 void BrowserPluginGuest::CanDownload(
610 RenderViewHost* render_view_host,
612 const std::string& request_method,
613 const base::Callback<void(bool)>& callback) {
619 BrowserThread::PostTaskAndReplyWithResult(
620 BrowserThread::IO, FROM_HERE,
621 base::Bind(&RetrieveDownloadURLFromRequestId,
622 render_view_host->GetProcess()->GetID(), request_id),
623 base::Bind(&BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId,
624 weak_ptr_factory_.GetWeakPtr(),
629 void BrowserPluginGuest::LoadProgressChanged(WebContents* contents,
632 delegate_->LoadProgressed(progress);
635 void BrowserPluginGuest::CloseContents(WebContents* source) {
642 JavaScriptDialogManager* BrowserPluginGuest::GetJavaScriptDialogManager() {
645 return delegate_->GetJavaScriptDialogManager();
648 ColorChooser* BrowserPluginGuest::OpenColorChooser(
649 WebContents* web_contents,
651 const std::vector<ColorSuggestion>& suggestions) {
652 if (!embedder_web_contents_ || !embedder_web_contents_->GetDelegate())
654 return embedder_web_contents_->GetDelegate()->OpenColorChooser(
655 web_contents, color, suggestions);
658 bool BrowserPluginGuest::HandleContextMenu(const ContextMenuParams& params) {
660 WebContentsViewGuest* view_guest =
661 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
662 ContextMenuParams context_menu_params =
663 view_guest->ConvertContextMenuParams(params);
665 return delegate_->HandleContextMenu(context_menu_params);
668 // Will be handled by WebContentsViewGuest.
672 void BrowserPluginGuest::HandleKeyboardEvent(
674 const NativeWebKeyboardEvent& event) {
678 if (UnlockMouseIfNecessary(event))
681 if (delegate_ && delegate_->HandleKeyboardEvent(event))
684 if (!embedder_web_contents_->GetDelegate())
687 // Send the unhandled keyboard events back to the embedder to reprocess them.
688 // TODO(fsamuel): This introduces the possibility of out-of-order keyboard
689 // events because the guest may be arbitrarily delayed when responding to
690 // keyboard events. In that time, the embedder may have received and processed
691 // additional key events. This needs to be fixed as soon as possible.
692 // See http://crbug.com/229882.
693 embedder_web_contents_->GetDelegate()->HandleKeyboardEvent(
694 web_contents(), event);
697 void BrowserPluginGuest::SetZoom(double zoom_factor) {
699 delegate_->SetZoom(zoom_factor);
702 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
703 SendMessageToEmbedder(
704 new BrowserPluginMsg_SetMouseLock(instance_id(), allow));
707 void BrowserPluginGuest::FindReply(WebContents* contents,
709 int number_of_matches,
710 const gfx::Rect& selection_rect,
711 int active_match_ordinal,
716 // |selection_rect| is updated to incorporate embedder coordinates.
717 delegate_->FindReply(request_id, number_of_matches,
718 ToGuestRect(selection_rect),
719 active_match_ordinal, final_update);
722 WebContents* BrowserPluginGuest::OpenURLFromTab(WebContents* source,
723 const OpenURLParams& params) {
724 // If the guest wishes to navigate away prior to attachment then we save the
725 // navigation to perform upon attachment. Navigation initializes a lot of
726 // state that assumes an embedder exists, such as RenderWidgetHostViewGuest.
727 // Navigation also resumes resource loading which we don't want to allow
730 PendingWindowMap::iterator it =
731 GetOpener()->pending_new_windows_.find(this);
732 if (it == GetOpener()->pending_new_windows_.end())
734 const NewWindowInfo& old_target_url = it->second;
735 NewWindowInfo new_window_info(params.url, old_target_url.name);
736 new_window_info.changed = new_window_info.url != old_target_url.url;
737 it->second = new_window_info;
740 if (params.disposition == CURRENT_TAB) {
741 // This can happen for cross-site redirects.
742 LoadURLWithParams(params.url, params.referrer, params.transition, source);
746 return CreateNewGuestWindow(params)->GetWebContents();
749 void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents,
750 int opener_render_frame_id,
751 const base::string16& frame_name,
752 const GURL& target_url,
753 WebContents* new_contents) {
754 WebContentsImpl* new_contents_impl =
755 static_cast<WebContentsImpl*>(new_contents);
756 BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest();
757 if (guest->delegate_)
758 guest->delegate_->SetOpener(GetWebContents());
759 std::string guest_name = base::UTF16ToUTF8(frame_name);
760 guest->name_ = guest_name;
761 // Take ownership of the new guest until it is attached to the embedder's DOM
762 // tree to avoid leaking a guest if this guest is destroyed before attaching
764 pending_new_windows_.insert(
765 std::make_pair(guest, NewWindowInfo(target_url, guest_name)));
768 void BrowserPluginGuest::RendererUnresponsive(WebContents* source) {
769 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Hung"));
772 delegate_->RendererUnresponsive();
775 void BrowserPluginGuest::RendererResponsive(WebContents* source) {
776 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Responsive"));
779 delegate_->RendererResponsive();
782 void BrowserPluginGuest::RunFileChooser(WebContents* web_contents,
783 const FileChooserParams& params) {
787 if (!embedder_web_contents_->GetDelegate())
790 embedder_web_contents_->GetDelegate()->RunFileChooser(web_contents, params);
793 bool BrowserPluginGuest::ShouldFocusPageAfterCrash() {
794 // Rather than managing focus in WebContentsImpl::RenderViewReady, we will
795 // manage the focus ourselves.
799 WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
800 return static_cast<WebContentsImpl*>(web_contents());
803 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
804 const gfx::Point& relative_position) const {
805 gfx::Point screen_pos(relative_position);
806 screen_pos += guest_window_rect_.OffsetFromOrigin();
810 bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const {
811 return size.width() <= max_auto_size_.width() &&
812 size.height() <= max_auto_size_.height();
815 void BrowserPluginGuest::RequestNewWindowPermission(
816 WindowOpenDisposition disposition,
817 const gfx::Rect& initial_bounds,
819 WebContentsImpl* new_contents) {
820 BrowserPluginGuest* guest = new_contents->GetBrowserPluginGuest();
821 PendingWindowMap::iterator it = pending_new_windows_.find(guest);
822 if (it == pending_new_windows_.end())
824 const NewWindowInfo& new_window_info = it->second;
826 base::DictionaryValue request_info;
827 request_info.Set(browser_plugin::kInitialHeight,
828 base::Value::CreateIntegerValue(initial_bounds.height()));
829 request_info.Set(browser_plugin::kInitialWidth,
830 base::Value::CreateIntegerValue(initial_bounds.width()));
831 request_info.Set(browser_plugin::kTargetURL,
832 base::Value::CreateStringValue(new_window_info.url.spec()));
833 request_info.Set(browser_plugin::kName,
834 base::Value::CreateStringValue(new_window_info.name));
835 request_info.Set(browser_plugin::kWindowID,
836 base::Value::CreateIntegerValue(guest->instance_id()));
837 request_info.Set(browser_plugin::kWindowOpenDisposition,
838 base::Value::CreateStringValue(
839 WindowOpenDispositionToString(disposition)));
841 RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW,
842 new NewWindowRequest(weak_ptr_factory_.GetWeakPtr(),
843 guest->instance_id()),
847 bool BrowserPluginGuest::UnlockMouseIfNecessary(
848 const NativeWebKeyboardEvent& event) {
852 embedder_web_contents()->GotResponseToLockMouseRequest(false);
856 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
858 // Some pages such as data URLs, javascript URLs, and about:blank
859 // do not load external resources and so they load prior to attachment.
860 // As a result, we must save all these IPCs until attachment and then
861 // forward them so that the embedder gets a chance to see and process
863 pending_messages_.push(msg);
866 msg->set_routing_id(embedder_web_contents_->GetRoutingID());
867 embedder_web_contents_->Send(msg);
870 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
871 int screen_x, int screen_y, blink::WebDragOperation operation) {
872 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
873 screen_x, screen_y, operation);
876 void BrowserPluginGuest::EndSystemDrag() {
877 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
878 GetWebContents()->GetRenderViewHost());
879 guest_rvh->DragSourceSystemDragEnded();
882 void BrowserPluginGuest::SetDelegate(BrowserPluginGuestDelegate* delegate) {
884 delegate_.reset(delegate);
887 void BrowserPluginGuest::SendQueuedMessages() {
891 while (!pending_messages_.empty()) {
892 IPC::Message* message = pending_messages_.front();
893 pending_messages_.pop();
894 SendMessageToEmbedder(message);
898 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
900 const base::string16& frame_unique_name,
903 PageTransition transition_type,
904 RenderViewHost* render_view_host) {
905 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
908 void BrowserPluginGuest::DidStopLoading(RenderViewHost* render_view_host) {
909 bool enable_dragdrop = delegate_ && delegate_->IsDragAndDropEnabled();
910 if (!enable_dragdrop) {
911 // Initiating a drag from inside a guest is currently not supported without
912 // the kEnableBrowserPluginDragDrop flag on a linux platform. So inject some
913 // JS to disable it. http://crbug.com/161112
914 const char script[] = "window.addEventListener('dragstart', function() { "
915 " window.event.preventDefault(); "
917 render_view_host->GetMainFrame()->ExecuteJavaScript(
918 base::ASCIIToUTF16(script));
922 void BrowserPluginGuest::RenderViewReady() {
923 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
924 // The guest RenderView should always live in a guest process.
925 CHECK(rvh->GetProcess()->IsGuest());
926 // TODO(fsamuel): Investigate whether it's possible to update state earlier
927 // here (see http://crbug.com/158151).
928 Send(new InputMsg_SetFocus(routing_id(), focused_));
930 if (auto_size_enabled_)
931 rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
933 rvh->DisableAutoResize(full_size_);
935 Send(new ViewMsg_SetName(routing_id(), name_));
936 OnSetContentsOpaque(instance_id_, guest_opaque_);
938 RenderWidgetHostImpl::From(rvh)->
939 set_hung_renderer_delay_ms(guest_hang_timeout_);
942 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
943 SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id()));
945 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
946 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
948 case base::TERMINATION_STATUS_PROCESS_CRASHED:
949 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
951 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
953 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
958 // TODO(fsamuel): Consider whether we should be clearing
959 // |permission_request_map_| here.
961 delegate_->GuestProcessGone(status);
965 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
966 const IPC::Message& message) {
967 switch (message.type()) {
968 case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID:
969 case BrowserPluginHostMsg_CopyFromCompositingSurfaceAck::ID:
970 case BrowserPluginHostMsg_DragStatusUpdate::ID:
971 case BrowserPluginHostMsg_ExecuteEditCommand::ID:
972 case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
973 case BrowserPluginHostMsg_HandleInputEvent::ID:
974 case BrowserPluginHostMsg_ImeConfirmComposition::ID:
975 case BrowserPluginHostMsg_ImeSetComposition::ID:
976 case BrowserPluginHostMsg_LockMouse_ACK::ID:
977 case BrowserPluginHostMsg_NavigateGuest::ID:
978 case BrowserPluginHostMsg_PluginDestroyed::ID:
979 case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
980 case BrowserPluginHostMsg_ResizeGuest::ID:
981 case BrowserPluginHostMsg_SetAutoSize::ID:
982 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
983 case BrowserPluginHostMsg_SetFocus::ID:
984 case BrowserPluginHostMsg_SetName::ID:
985 case BrowserPluginHostMsg_SetContentsOpaque::ID:
986 case BrowserPluginHostMsg_SetVisibility::ID:
987 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
988 case BrowserPluginHostMsg_UpdateGeometry::ID:
995 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
997 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
998 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
999 OnHasTouchEventHandlers)
1000 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
1001 IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor)
1002 #if defined(OS_MACOSX)
1003 // MacOSX creates and populates platform-specific select drop-down menus
1004 // whereas other platforms merely create a popup window that the guest
1005 // renderer process paints inside.
1006 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup)
1008 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
1009 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
1010 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
1011 OnTextInputTypeChanged)
1012 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition,
1013 OnImeCancelComposition)
1014 #if defined(OS_MACOSX) || defined(USE_AURA)
1015 IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged,
1016 OnImeCompositionRangeChanged)
1018 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
1019 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFrameName, OnUpdateFrameName)
1020 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
1021 IPC_MESSAGE_UNHANDLED(handled = false)
1022 IPC_END_MESSAGE_MAP()
1026 void BrowserPluginGuest::Attach(
1027 WebContentsImpl* embedder_web_contents,
1028 BrowserPluginHostMsg_Attach_Params params,
1029 const base::DictionaryValue& extra_params) {
1033 extra_attach_params_.reset(extra_params.DeepCopy());
1035 // Clear parameters that get inherited from the opener.
1036 params.storage_partition_id.clear();
1037 params.persist_storage = false;
1040 // If a RenderView has already been created for this new window, then we need
1041 // to initialize the browser-side state now so that the RenderFrameHostManager
1042 // does not create a new RenderView on navigation.
1043 if (has_render_view_) {
1044 static_cast<RenderViewHostImpl*>(
1045 GetWebContents()->GetRenderViewHost())->Init();
1046 WebContentsViewGuest* new_view =
1047 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
1048 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
1051 // We need to do a navigation here if the target URL has changed between
1052 // the time the WebContents was created and the time it was attached.
1053 // We also need to do an initial navigation if a RenderView was never
1054 // created for the new window in cases where there is no referrer.
1055 PendingWindowMap::iterator it = GetOpener()->pending_new_windows_.find(this);
1056 if (it != GetOpener()->pending_new_windows_.end()) {
1057 const NewWindowInfo& new_window_info = it->second;
1058 if (new_window_info.changed || !has_render_view_)
1059 params.src = it->second.url.spec();
1064 // Once a new guest is attached to the DOM of the embedder page, then the
1065 // lifetime of the new guest is no longer managed by the opener guest.
1066 GetOpener()->pending_new_windows_.erase(this);
1068 // The guest's frame name takes precedence over the BrowserPlugin's name.
1069 // The guest's frame name is assigned in
1070 // BrowserPluginGuest::WebContentsCreated.
1072 params.name.clear();
1074 Initialize(params, embedder_web_contents);
1076 SendQueuedMessages();
1078 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
1081 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
1083 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
1084 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
1085 params.output_surface_id,
1086 params.producing_host_id,
1090 void BrowserPluginGuest::OnDragStatusUpdate(int instance_id,
1091 blink::WebDragStatus drag_status,
1092 const DropData& drop_data,
1093 blink::WebDragOperationsMask mask,
1094 const gfx::Point& location) {
1095 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
1096 switch (drag_status) {
1097 case blink::WebDragStatusEnter:
1098 embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest(
1100 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
1102 case blink::WebDragStatusOver:
1103 host->DragTargetDragOver(location, location, mask, 0);
1105 case blink::WebDragStatusLeave:
1106 embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this);
1107 host->DragTargetDragLeave();
1109 case blink::WebDragStatusDrop:
1110 host->DragTargetDrop(location, location, 0);
1113 case blink::WebDragStatusUnknown:
1118 void BrowserPluginGuest::OnExecuteEditCommand(int instance_id,
1119 const std::string& name) {
1120 Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
1123 void BrowserPluginGuest::OnImeSetComposition(
1125 const std::string& text,
1126 const std::vector<blink::WebCompositionUnderline>& underlines,
1127 int selection_start,
1128 int selection_end) {
1129 Send(new ViewMsg_ImeSetComposition(routing_id(),
1130 base::UTF8ToUTF16(text), underlines,
1131 selection_start, selection_end));
1134 void BrowserPluginGuest::OnImeConfirmComposition(
1136 const std::string& text,
1137 bool keep_selection) {
1138 Send(new ViewMsg_ImeConfirmComposition(routing_id(),
1139 base::UTF8ToUTF16(text),
1140 gfx::Range::InvalidRange(),
1144 void BrowserPluginGuest::OnExtendSelectionAndDelete(
1148 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
1149 web_contents()->GetFocusedFrame());
1151 rfh->ExtendSelectionAndDelete(before, after);
1154 void BrowserPluginGuest::OnReclaimCompositorResources(
1156 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
1157 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
1158 params.output_surface_id,
1159 params.renderer_host_id,
1163 void BrowserPluginGuest::OnHandleInputEvent(
1165 const gfx::Rect& guest_window_rect,
1166 const blink::WebInputEvent* event) {
1167 guest_window_rect_ = guest_window_rect;
1168 // If the embedder's RWHV is destroyed then that means that the embedder's
1169 // window has been closed but the embedder's WebContents has not yet been
1170 // destroyed. Computing screen coordinates of a BrowserPlugin only makes sense
1171 // if there is a visible embedder.
1172 if (embedder_web_contents_->GetRenderWidgetHostView()) {
1173 guest_screen_rect_ = guest_window_rect;
1174 guest_screen_rect_.Offset(
1175 embedder_web_contents_->GetRenderWidgetHostView()->
1176 GetViewBounds().OffsetFromOrigin());
1178 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
1179 GetWebContents()->GetRenderViewHost());
1181 if (blink::WebInputEvent::isMouseEventType(event->type)) {
1182 guest_rvh->ForwardMouseEvent(
1183 *static_cast<const blink::WebMouseEvent*>(event));
1187 if (event->type == blink::WebInputEvent::MouseWheel) {
1188 guest_rvh->ForwardWheelEvent(
1189 *static_cast<const blink::WebMouseWheelEvent*>(event));
1193 if (blink::WebInputEvent::isKeyboardEventType(event->type)) {
1194 RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
1195 embedder_web_contents_->GetRenderViewHost());
1196 if (!embedder_rvh->GetLastKeyboardEvent())
1198 NativeWebKeyboardEvent keyboard_event(
1199 *embedder_rvh->GetLastKeyboardEvent());
1200 guest_rvh->ForwardKeyboardEvent(keyboard_event);
1204 if (blink::WebInputEvent::isTouchEventType(event->type)) {
1205 guest_rvh->ForwardTouchEventWithLatencyInfo(
1206 *static_cast<const blink::WebTouchEvent*>(event),
1211 if (blink::WebInputEvent::isGestureEventType(event->type)) {
1212 guest_rvh->ForwardGestureEvent(
1213 *static_cast<const blink::WebGestureEvent*>(event));
1218 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
1219 bool last_unlocked_by_target,
1221 if (pending_lock_request_) {
1222 // Immediately reject the lock because only one pointerLock may be active
1224 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
1231 pending_lock_request_ = true;
1233 delegate_->RequestPointerLockPermission(
1235 last_unlocked_by_target,
1236 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
1237 weak_ptr_factory_.GetWeakPtr()));
1240 void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) {
1241 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
1242 pending_lock_request_ = false;
1244 mouse_locked_ = true;
1247 void BrowserPluginGuest::OnNavigateGuest(
1249 const std::string& src) {
1250 GURL url = delegate_ ? delegate_->ResolveURL(src) : GURL(src);
1252 // Do not allow navigating a guest to schemes other than known safe schemes.
1253 // This will block the embedder trying to load unwanted schemes, e.g.
1254 // chrome://settings.
1255 bool scheme_is_blocked =
1256 (!ChildProcessSecurityPolicyImpl::GetInstance()->IsWebSafeScheme(
1258 !ChildProcessSecurityPolicyImpl::GetInstance()->IsPseudoScheme(
1260 url.SchemeIs(kJavaScriptScheme);
1261 if (scheme_is_blocked || !url.is_valid()) {
1263 std::string error_type;
1264 base::RemoveChars(net::ErrorToString(net::ERR_ABORTED), "net::",
1266 delegate_->LoadAbort(true /* is_top_level */, url, error_type);
1271 GURL validated_url(url);
1272 GetWebContents()->GetRenderProcessHost()->FilterURL(false, &validated_url);
1273 // As guests do not swap processes on navigation, only navigations to
1274 // normal web URLs are supported. No protocol handlers are installed for
1275 // other schemes (e.g., WebUI or extensions), and no permissions or bindings
1276 // can be granted to the guest process.
1277 LoadURLWithParams(validated_url, Referrer(), PAGE_TRANSITION_AUTO_TOPLEVEL,
1281 void BrowserPluginGuest::OnPluginDestroyed(int instance_id) {
1285 void BrowserPluginGuest::OnResizeGuest(
1287 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
1288 if (!params.size_changed)
1290 // BrowserPlugin manages resize flow control itself and does not depend
1291 // on RenderWidgetHost's mechanisms for flow control, so we reset those flags
1292 // here. If we are setting the size for the first time before navigating then
1293 // BrowserPluginGuest does not yet have a RenderViewHost.
1294 if (GetWebContents()->GetRenderViewHost()) {
1295 RenderWidgetHostImpl* render_widget_host =
1296 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
1297 render_widget_host->ResetSizeAndRepaintPendingFlags();
1299 if (guest_device_scale_factor_ != params.scale_factor) {
1300 guest_device_scale_factor_ = params.scale_factor;
1301 render_widget_host->NotifyScreenInfoChanged();
1304 // When autosize is turned off and as a result there is a layout change, we
1305 // send a sizechanged event.
1306 if (!auto_size_enabled_ && last_seen_auto_size_enabled_ &&
1307 !params.view_rect.size().IsEmpty() && delegate_) {
1308 delegate_->SizeChanged(last_seen_view_size_, params.view_rect.size());
1309 last_seen_auto_size_enabled_ = false;
1311 // Just resize the WebContents and repaint if needed.
1312 full_size_ = params.view_rect.size();
1313 if (!params.view_rect.size().IsEmpty())
1314 GetWebContents()->GetView()->SizeContents(params.view_rect.size());
1316 Send(new ViewMsg_Repaint(routing_id(), params.view_rect.size()));
1319 void BrowserPluginGuest::OnSetFocus(int instance_id, bool focused) {
1321 Send(new InputMsg_SetFocus(routing_id(), focused));
1322 if (!focused && mouse_locked_)
1325 // Restore the last seen state of text input to the view.
1326 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
1327 web_contents()->GetRenderWidgetHostView());
1329 rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
1330 last_can_compose_inline_);
1334 void BrowserPluginGuest::OnSetName(int instance_id, const std::string& name) {
1338 Send(new ViewMsg_SetName(routing_id(), name));
1341 void BrowserPluginGuest::OnSetSize(
1343 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1344 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1345 bool old_auto_size_enabled = auto_size_enabled_;
1346 gfx::Size old_max_size = max_auto_size_;
1347 gfx::Size old_min_size = min_auto_size_;
1348 auto_size_enabled_ = auto_size_params.enable;
1349 max_auto_size_ = auto_size_params.max_size;
1350 min_auto_size_ = auto_size_params.min_size;
1351 if (auto_size_enabled_ && (!old_auto_size_enabled ||
1352 (old_max_size != max_auto_size_) ||
1353 (old_min_size != min_auto_size_))) {
1355 base::UserMetricsAction("BrowserPlugin.Guest.EnableAutoResize"));
1356 GetWebContents()->GetRenderViewHost()->EnableAutoResize(
1357 min_auto_size_, max_auto_size_);
1358 // TODO(fsamuel): If we're changing autosize parameters, then we force
1359 // the guest to completely repaint itself.
1360 // Ideally, we shouldn't need to do this unless |max_auto_size_| has
1362 // However, even in that case, layout may not change and so we may
1363 // not get a full frame worth of pixels.
1364 Send(new ViewMsg_Repaint(routing_id(), max_auto_size_));
1365 } else if (!auto_size_enabled_ && old_auto_size_enabled) {
1366 GetWebContents()->GetRenderViewHost()->DisableAutoResize(
1367 resize_guest_params.view_rect.size());
1369 OnResizeGuest(instance_id_, resize_guest_params);
1372 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
1374 const std::vector<EditCommand>& edit_commands) {
1375 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
1379 void BrowserPluginGuest::OnSetContentsOpaque(int instance_id, bool opaque) {
1380 guest_opaque_ = opaque;
1382 SkBitmap background;
1383 if (!guest_opaque_) {
1384 background.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
1385 unsigned int color = 0;
1386 background.setPixels(&color);
1388 Send(new ViewMsg_SetBackground(routing_id(), background));
1391 void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) {
1392 guest_visible_ = visible;
1393 if (embedder_visible_ && guest_visible_)
1394 GetWebContents()->WasShown();
1396 GetWebContents()->WasHidden();
1399 void BrowserPluginGuest::OnUnlockMouse() {
1400 SendMessageToEmbedder(
1401 new BrowserPluginMsg_SetMouseLock(instance_id(), false));
1404 void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) {
1405 // mouse_locked_ could be false here if the lock attempt was cancelled due
1406 // to window focus, or for various other reasons before the guest was informed
1407 // of the lock's success.
1409 Send(new ViewMsg_MouseLockLost(routing_id()));
1410 mouse_locked_ = false;
1413 void BrowserPluginGuest::OnCopyFromCompositingSurfaceAck(
1416 const SkBitmap& bitmap) {
1417 CHECK(copy_request_callbacks_.count(request_id));
1418 if (!copy_request_callbacks_.count(request_id))
1420 const CopyRequestCallback& callback = copy_request_callbacks_[request_id];
1421 callback.Run(!bitmap.empty() && !bitmap.isNull(), bitmap);
1422 copy_request_callbacks_.erase(request_id);
1425 void BrowserPluginGuest::OnUpdateGeometry(int instance_id,
1426 const gfx::Rect& view_rect) {
1427 // The plugin has moved within the embedder without resizing or the
1428 // embedder/container's view rect changing.
1429 guest_window_rect_ = view_rect;
1430 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1431 GetWebContents()->GetRenderViewHost());
1433 rvh->SendScreenRects();
1436 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
1437 SendMessageToEmbedder(
1438 new BrowserPluginMsg_ShouldAcceptTouchEvents(instance_id(), accept));
1441 void BrowserPluginGuest::OnSetCursor(const WebCursor& cursor) {
1442 SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(instance_id(), cursor));
1445 #if defined(OS_MACOSX)
1446 void BrowserPluginGuest::OnShowPopup(
1447 const ViewHostMsg_ShowPopup_Params& params) {
1448 gfx::Rect translated_bounds(params.bounds);
1449 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
1450 BrowserPluginPopupMenuHelper popup_menu_helper(
1451 embedder_web_contents_->GetRenderViewHost(),
1452 GetWebContents()->GetRenderViewHost());
1453 popup_menu_helper.ShowPopupMenu(translated_bounds,
1455 params.item_font_size,
1456 params.selected_item,
1458 params.right_aligned,
1459 params.allow_multiple_selection);
1463 void BrowserPluginGuest::OnShowWidget(int route_id,
1464 const gfx::Rect& initial_pos) {
1465 GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
1468 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
1469 SendMessageToEmbedder(
1470 new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
1473 void BrowserPluginGuest::OnUpdateFrameName(int frame_id,
1475 const std::string& name) {
1480 SendMessageToEmbedder(new BrowserPluginMsg_UpdatedName(instance_id_, name));
1483 void BrowserPluginGuest::RequestMediaAccessPermission(
1484 WebContents* web_contents,
1485 const MediaStreamRequest& request,
1486 const MediaResponseCallback& callback) {
1488 callback.Run(MediaStreamDevices(),
1489 MEDIA_DEVICE_INVALID_STATE,
1490 scoped_ptr<MediaStreamUI>());
1494 delegate_->RequestMediaAccessPermission(request, callback);
1497 bool BrowserPluginGuest::PreHandleGestureEvent(
1498 WebContents* source, const blink::WebGestureEvent& event) {
1499 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
1500 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
1501 event.type == blink::WebGestureEvent::GesturePinchEnd;
1504 void BrowserPluginGuest::OnUpdateRect(
1505 const ViewHostMsg_UpdateRect_Params& params) {
1506 BrowserPluginMsg_UpdateRect_Params relay_params;
1507 relay_params.view_size = params.view_size;
1508 relay_params.scale_factor = params.scale_factor;
1509 relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(
1512 bool size_changed = last_seen_view_size_ != params.view_size;
1513 gfx::Size old_size = last_seen_view_size_;
1514 last_seen_view_size_ = params.view_size;
1516 if ((auto_size_enabled_ || last_seen_auto_size_enabled_) &&
1517 size_changed && delegate_) {
1518 delegate_->SizeChanged(old_size, last_seen_view_size_);
1520 last_seen_auto_size_enabled_ = auto_size_enabled_;
1522 SendMessageToEmbedder(
1523 new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1526 void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
1527 ui::TextInputMode input_mode,
1528 bool can_compose_inline) {
1529 // Save the state of text input so we can restore it on focus.
1530 last_text_input_type_ = type;
1531 last_input_mode_ = input_mode;
1532 last_can_compose_inline_ = can_compose_inline;
1534 static_cast<RenderWidgetHostViewBase*>(
1535 web_contents()->GetRenderWidgetHostView())->TextInputTypeChanged(
1536 type, input_mode, can_compose_inline);
1539 void BrowserPluginGuest::OnImeCancelComposition() {
1540 static_cast<RenderWidgetHostViewBase*>(
1541 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
1544 #if defined(OS_MACOSX) || defined(USE_AURA)
1545 void BrowserPluginGuest::OnImeCompositionRangeChanged(
1546 const gfx::Range& range,
1547 const std::vector<gfx::Rect>& character_bounds) {
1548 static_cast<RenderWidgetHostViewBase*>(
1549 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
1550 range, character_bounds);
1554 void BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId(
1555 const std::string& request_method,
1556 const base::Callback<void(bool)>& callback,
1558 if (!url.is_valid()) {
1559 callback.Run(false);
1563 delegate_->CanDownload(request_method, url, callback);
1566 } // namespace content