// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/browser_plugin/browser_plugin_guest.h" #include #include "base/message_loop/message_loop.h" #include "base/pickle.h" #include "base/strings/utf_string_conversions.h" #include "content/browser/browser_plugin/browser_plugin_embedder.h" #include "content/browser/browser_thread_impl.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/frame_host/render_widget_host_view_guest.h" #include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_view_guest.h" #include "content/common/browser_plugin/browser_plugin_constants.h" #include "content/common/browser_plugin/browser_plugin_messages.h" #include "content/common/content_constants_internal.h" #include "content/common/drag_messages.h" #include "content/common/frame_messages.h" #include "content/common/host_shared_bitmap_manager.h" #include "content/common/input_messages.h" #include "content/common/view_messages.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_plugin_guest_manager.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/guest_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/drop_data.h" #include "ui/gfx/geometry/size_conversions.h" #if defined(OS_MACOSX) #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h" #endif namespace content { class BrowserPluginGuest::EmbedderVisibilityObserver : public WebContentsObserver { public: explicit EmbedderVisibilityObserver(BrowserPluginGuest* guest) : WebContentsObserver(guest->embedder_web_contents()), browser_plugin_guest_(guest) { } ~EmbedderVisibilityObserver() override {} // WebContentsObserver implementation. void WasShown() override { browser_plugin_guest_->EmbedderVisibilityChanged(true); } void WasHidden() override { browser_plugin_guest_->EmbedderVisibilityChanged(false); } private: BrowserPluginGuest* browser_plugin_guest_; DISALLOW_COPY_AND_ASSIGN(EmbedderVisibilityObserver); }; BrowserPluginGuest::BrowserPluginGuest(bool has_render_view, WebContentsImpl* web_contents, BrowserPluginGuestDelegate* delegate) : WebContentsObserver(web_contents), owner_web_contents_(nullptr), attached_(false), browser_plugin_instance_id_(browser_plugin::kInstanceIDNone), focused_(false), mouse_locked_(false), pending_lock_request_(false), guest_visible_(false), embedder_visible_(true), is_full_page_plugin_(false), has_render_view_(has_render_view), is_in_destruction_(false), initialized_(false), last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE), last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT), last_input_flags_(0), last_can_compose_inline_(true), guest_proxy_routing_id_(MSG_ROUTING_NONE), last_drag_status_(blink::WebDragStatusUnknown), seen_embedder_system_drag_ended_(false), seen_embedder_drag_source_ended_at_(false), delegate_(delegate), weak_ptr_factory_(this) { DCHECK(web_contents); DCHECK(delegate); RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create")); web_contents->SetBrowserPluginGuest(this); delegate->SetGuestHost(this); } int BrowserPluginGuest::GetGuestProxyRoutingID() { if (guest_proxy_routing_id_ != MSG_ROUTING_NONE) return guest_proxy_routing_id_; // Create a swapped out RenderView for the guest in the embedder renderer // process, so that the embedder can access the guest's window object. // On reattachment, we can reuse the same swapped out RenderView because // the embedder process will always be the same even if the embedder // WebContents changes. // // TODO(fsamuel): Make sure this works for transferring guests across // owners in different processes. We probably need to clear the // |guest_proxy_routing_id_| and perform any necessary cleanup on Detach // to enable this. SiteInstance* owner_site_instance = owner_web_contents_->GetSiteInstance(); guest_proxy_routing_id_ = GetWebContents()->CreateSwappedOutRenderView(owner_site_instance); return guest_proxy_routing_id_; } int BrowserPluginGuest::LoadURLWithParams( const NavigationController::LoadURLParams& load_params) { GetWebContents()->GetController().LoadURLWithParams(load_params); return GetGuestProxyRoutingID(); } void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) { GetWebContents()->GetView()->SizeContents(new_size); } void BrowserPluginGuest::WillDestroy() { is_in_destruction_ = true; owner_web_contents_ = nullptr; attached_ = false; } void BrowserPluginGuest::Init() { if (initialized_) return; initialized_ = true; // TODO(fsamuel): Initiailization prior to attachment should be behind a // command line flag once we introduce experimental guest types that rely on // this functionality. if (!delegate_->CanRunInDetachedState()) return; WebContentsImpl* owner_web_contents = static_cast( delegate_->GetOwnerWebContents()); owner_web_contents->CreateBrowserPluginEmbedderIfNecessary(); InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents); } base::WeakPtr BrowserPluginGuest::AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh, bool focused, blink::WebFocusType focus_type) { focused_ = focused; if (!rwh) return; if ((focus_type == blink::WebFocusTypeForward) || (focus_type == blink::WebFocusTypeBackward)) { static_cast(RenderViewHost::From(rwh))-> SetInitialFocus(focus_type == blink::WebFocusTypeBackward); } rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused)); if (!focused && mouse_locked_) OnUnlockMouse(); // Restore the last seen state of text input to the view. RenderWidgetHostViewBase* rwhv = static_cast( rwh->GetView()); SendTextInputTypeChangedToView(rwhv); } void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) { if (tooltip_text == current_tooltip_text_) return; current_tooltip_text_ = tooltip_text; SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText( browser_plugin_instance_id_, tooltip_text)); } bool BrowserPluginGuest::LockMouse(bool allowed) { if (!attached() || (mouse_locked_ == allowed)) return false; return embedder_web_contents()->GotResponseToLockMouseRequest(allowed); } WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow( const WebContents::CreateParams& params) { WebContentsImpl* new_contents = static_cast(delegate_->CreateNewGuestWindow(params)); DCHECK(new_contents); return new_contents; } bool BrowserPluginGuest::OnMessageReceivedFromEmbedder( const IPC::Message& message) { RenderWidgetHostViewGuest* rwhv = static_cast( web_contents()->GetRenderWidgetHostView()); // Until the guest is attached, it should not be handling input events. if (attached() && rwhv && rwhv->OnMessageReceivedFromEmbedder( message, static_cast( embedder_web_contents()->GetRenderViewHost()))) { return true; } bool handled = true; IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK, OnCompositorFrameSwappedACK) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate, OnDragStatusUpdate) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand, OnExecuteEditCommand) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete, OnExtendSelectionAndDelete) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition, OnImeConfirmComposition) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition, OnImeSetComposition) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources, OnReclaimCompositorResources) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent, OnSetEditCommandsForNextKeyEvent) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck) IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void BrowserPluginGuest::InitInternal( const BrowserPluginHostMsg_Attach_Params& params, WebContentsImpl* owner_web_contents) { focused_ = params.focused; OnSetFocus(browser_plugin::kInstanceIDNone, focused_, blink::WebFocusTypeNone); guest_visible_ = params.visible; UpdateVisibility(); is_full_page_plugin_ = params.is_full_page_plugin; guest_window_rect_ = params.view_rect; if (owner_web_contents_ != owner_web_contents) { WebContentsViewGuest* new_view = static_cast(GetWebContents()->GetView()); if (owner_web_contents_) new_view->OnGuestDetached(owner_web_contents_->GetView()); // Once a BrowserPluginGuest has an embedder WebContents, it's considered to // be attached. owner_web_contents_ = owner_web_contents; new_view->OnGuestAttached(owner_web_contents_->GetView()); } RendererPreferences* renderer_prefs = GetWebContents()->GetMutableRendererPrefs(); std::string guest_user_agent_override = renderer_prefs->user_agent_override; // Copy renderer preferences (and nothing else) from the embedder's // WebContents to the guest. // // For GTK and Aura this is necessary to get proper renderer configuration // values for caret blinking interval, colors related to selection and // focus. *renderer_prefs = *owner_web_contents_->GetMutableRendererPrefs(); renderer_prefs->user_agent_override = guest_user_agent_override; // We would like the guest to report changes to frame names so that we can // update the BrowserPlugin's corresponding 'name' attribute. // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed. renderer_prefs->report_frame_name_changes = true; // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated // navigations still continue to function inside the app. renderer_prefs->browser_handles_all_top_level_requests = false; // Disable "client blocked" error page for browser plugin. renderer_prefs->disable_client_blocked_error_page = true; embedder_visibility_observer_.reset(new EmbedderVisibilityObserver(this)); DCHECK(GetWebContents()->GetRenderViewHost()); // Initialize the device scale factor by calling |NotifyScreenInfoChanged|. auto render_widget_host = RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost()); render_widget_host->NotifyScreenInfoChanged(); // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will // be reset again the next time preferences are updated. WebPreferences prefs = GetWebContents()->GetRenderViewHost()->GetWebkitPreferences(); prefs.navigate_on_drag_drop = false; GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs); } BrowserPluginGuest::~BrowserPluginGuest() { } // static BrowserPluginGuest* BrowserPluginGuest::Create( WebContentsImpl* web_contents, BrowserPluginGuestDelegate* delegate) { return new BrowserPluginGuest( web_contents->opener() != nullptr, web_contents, delegate); } // static bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) { return web_contents && web_contents->GetBrowserPluginGuest(); } // static bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) { return render_view_host && IsGuest( static_cast(WebContents::FromRenderViewHost( render_view_host))); } RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() { if (!owner_web_contents_) return nullptr; return owner_web_contents_->GetRenderWidgetHostView(); } void BrowserPluginGuest::UpdateVisibility() { OnSetVisibility(browser_plugin_instance_id(), visible()); } BrowserPluginGuestManager* BrowserPluginGuest::GetBrowserPluginGuestManager() const { return GetWebContents()->GetBrowserContext()->GetGuestManager(); } void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) { embedder_visible_ = visible; UpdateVisibility(); } void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) { SendMessageToEmbedder( new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow)); } void BrowserPluginGuest::SwapCompositorFrame( uint32 output_surface_id, int host_process_id, int host_routing_id, scoped_ptr frame) { cc::RenderPass* root_pass = frame->delegated_frame_data->render_pass_list.back(); gfx::Size view_size(gfx::ToFlooredSize(gfx::ScaleSize( root_pass->output_rect.size(), 1.0f / frame->metadata.device_scale_factor))); if (last_seen_view_size_ != view_size) { delegate_->GuestSizeChanged(view_size); last_seen_view_size_ = view_size; } last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params()); frame->AssignTo(&last_pending_frame_->frame); last_pending_frame_->output_surface_id = output_surface_id; last_pending_frame_->producing_route_id = host_routing_id; last_pending_frame_->producing_host_id = host_process_id; SendMessageToEmbedder( new BrowserPluginMsg_CompositorFrameSwapped( browser_plugin_instance_id(), *last_pending_frame_)); } void BrowserPluginGuest::SetContentsOpaque(bool opaque) { SendMessageToEmbedder( new BrowserPluginMsg_SetContentsOpaque( browser_plugin_instance_id(), opaque)); } bool BrowserPluginGuest::Find(int request_id, const base::string16& search_text, const blink::WebFindOptions& options) { return delegate_->Find(request_id, search_text, options); } bool BrowserPluginGuest::StopFinding(StopFindAction action) { return delegate_->StopFinding(action); } WebContentsImpl* BrowserPluginGuest::GetWebContents() const { return static_cast(web_contents()); } gfx::Point BrowserPluginGuest::GetScreenCoordinates( const gfx::Point& relative_position) const { if (!attached()) return relative_position; gfx::Point screen_pos(relative_position); screen_pos += guest_window_rect_.OffsetFromOrigin(); if (embedder_web_contents()->GetBrowserPluginGuest()) { BrowserPluginGuest* embedder_guest = embedder_web_contents()->GetBrowserPluginGuest(); screen_pos += embedder_guest->guest_window_rect_.OffsetFromOrigin(); } return screen_pos; } void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) { if (!attached()) { // Some pages such as data URLs, javascript URLs, and about:blank // do not load external resources and so they load prior to attachment. // As a result, we must save all these IPCs until attachment and then // forward them so that the embedder gets a chance to see and process // the load events. pending_messages_.push_back(linked_ptr(msg)); return; } owner_web_contents_->Send(msg); } void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y, int screen_x, int screen_y, blink::WebDragOperation operation) { web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y, screen_x, screen_y, operation); seen_embedder_drag_source_ended_at_ = true; EndSystemDragIfApplicable(); } void BrowserPluginGuest::EndSystemDragIfApplicable() { // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave... // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where // the drag was initiated. Calling DragSourceSystemDragEnded() correctly // means we call it in all cases and also make sure we only call it once. // This ensures that the input state of the guest stays correct, otherwise // it will go stale and won't accept any further input events. // // The strategy used here to call DragSourceSystemDragEnded() on the RVH // is when the following conditions are met: // a. Embedder has seen SystemDragEnded() // b. Embedder has seen DragSourceEndedAt() // c. The guest has seen some drag status update other than // WebDragStatusUnknown. Note that this step should ideally be done // differently: The guest has seen at least one of // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags // a source quickly outside of bounds, then the // BrowserPluginGuest never sees any of these drag status updates, // there we just check whether we've seen any drag status update or // not. if (last_drag_status_ != blink::WebDragStatusOver && seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) { RenderViewHostImpl* guest_rvh = static_cast( GetWebContents()->GetRenderViewHost()); guest_rvh->DragSourceSystemDragEnded(); last_drag_status_ = blink::WebDragStatusUnknown; seen_embedder_system_drag_ended_ = false; seen_embedder_drag_source_ended_at_ = false; dragged_url_ = GURL(); } } void BrowserPluginGuest::EmbedderSystemDragEnded() { seen_embedder_system_drag_ended_ = true; EndSystemDragIfApplicable(); } void BrowserPluginGuest::SendQueuedMessages() { if (!attached()) return; while (!pending_messages_.empty()) { linked_ptr message_ptr = pending_messages_.front(); pending_messages_.pop_front(); SendMessageToEmbedder(message_ptr.release()); } } void BrowserPluginGuest::SendTextInputTypeChangedToView( RenderWidgetHostViewBase* guest_rwhv) { if (!guest_rwhv) return; if (!owner_web_contents_) { // If we were showing an interstitial, then we can end up here during // embedder shutdown or when the embedder navigates to a different page. // The call stack is roughly: // BrowserPluginGuest::SetFocus() // content::InterstitialPageImpl::Hide() // content::InterstitialPageImpl::DontProceed(). // // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed. return; } guest_rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_, last_can_compose_inline_, last_input_flags_); // Enable input method for guest if it's enabled for the embedder. if (!static_cast( owner_web_contents_->GetRenderViewHost())->input_method_active()) { return; } RenderViewHostImpl* guest_rvh = static_cast(GetWebContents()->GetRenderViewHost()); guest_rvh->SetInputMethodActive(true); } void BrowserPluginGuest::DidCommitProvisionalLoadForFrame( RenderFrameHost* render_frame_host, const GURL& url, ui::PageTransition transition_type) { RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate")); } void BrowserPluginGuest::RenderViewReady() { RenderViewHost* rvh = GetWebContents()->GetRenderViewHost(); // TODO(fsamuel): Investigate whether it's possible to update state earlier // here (see http://crbug.com/158151). Send(new InputMsg_SetFocus(routing_id(), focused_)); UpdateVisibility(); RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay( base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)); } void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) { SendMessageToEmbedder( new BrowserPluginMsg_GuestGone(browser_plugin_instance_id())); switch (status) { case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed")); break; case base::TERMINATION_STATUS_PROCESS_CRASHED: RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed")); break; case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: RecordAction( base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath")); break; default: break; } } // static bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest( const IPC::Message& message) { return (message.type() != BrowserPluginHostMsg_Attach::ID) && (IPC_MESSAGE_CLASS(message) == BrowserPluginMsgStart); } bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message) IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition, OnImeCancelComposition) #if defined(OS_MACOSX) || defined(USE_AURA) IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged, OnImeCompositionRangeChanged) #endif IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers, OnHasTouchEventHandlers) IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse) IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget) IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus) IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged, OnTextInputTypeChanged) IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message, RenderFrameHost* render_frame_host) { // This will eventually be the home for more IPC handlers that depend on // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't // compile if there are no handlers for a platform. So we have both #if guards // around the whole thing (unfortunate but temporary), and #if guards where // they belong, only around the one IPC handler. TODO(avi): Move more of the // frame-based handlers to this function and remove the outer #if layer. #if defined(OS_MACOSX) bool handled = true; IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message, render_frame_host) #if defined(OS_MACOSX) // MacOS X creates and populates platform-specific select drop-down menus // whereas other platforms merely create a popup window that the guest // renderer process paints inside. IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup) #endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; #else return false; #endif } void BrowserPluginGuest::Attach( int browser_plugin_instance_id, WebContentsImpl* embedder_web_contents, const BrowserPluginHostMsg_Attach_Params& params) { browser_plugin_instance_id_ = browser_plugin_instance_id; // If a guest is detaching from one container and attaching to another // container, then late arriving ACKs may be lost if the mapping from // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we // ensure that we always get new frames on attachment by ACKing the pending // frame if it's still waiting on the ACK. if (last_pending_frame_) { cc::CompositorFrameAck ack; RenderWidgetHostImpl::SendSwapCompositorFrameAck( last_pending_frame_->producing_route_id, last_pending_frame_->output_surface_id, last_pending_frame_->producing_host_id, ack); last_pending_frame_.reset(); } // The guest is owned by the embedder. Attach is queued up so we cannot // change embedders before attach completes. If the embedder goes away, // so does the guest and so we will never call WillAttachComplete because // we have a weak ptr. delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id, params.is_full_page_plugin, base::Bind(&BrowserPluginGuest::OnWillAttachComplete, weak_ptr_factory_.GetWeakPtr(), embedder_web_contents, params)); } void BrowserPluginGuest::OnWillAttachComplete( WebContentsImpl* embedder_web_contents, const BrowserPluginHostMsg_Attach_Params& params) { // If a RenderView has already been created for this new window, then we need // to initialize the browser-side state now so that the RenderFrameHostManager // does not create a new RenderView on navigation. if (has_render_view_) { // This will trigger a callback to RenderViewReady after a round-trip IPC. static_cast( GetWebContents()->GetRenderViewHost())->Init(); WebContentsViewGuest* web_contents_view = static_cast(GetWebContents()->GetView()); if (!web_contents()->GetRenderViewHost()->GetView()) { web_contents_view->CreateViewForWidget( web_contents()->GetRenderViewHost(), true); } } InitInternal(params, embedder_web_contents); attached_ = true; SendQueuedMessages(); delegate_->DidAttach(GetGuestProxyRoutingID()); has_render_view_ = true; // Enable input method for guest if it's enabled for the embedder. if (static_cast( owner_web_contents_->GetRenderViewHost())->input_method_active()) { RenderViewHostImpl* guest_rvh = static_cast( GetWebContents()->GetRenderViewHost()); guest_rvh->SetInputMethodActive(true); } RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached")); } void BrowserPluginGuest::OnCompositorFrameSwappedACK( int browser_plugin_instance_id, const FrameHostMsg_CompositorFrameSwappedACK_Params& params) { RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id, params.output_surface_id, params.producing_host_id, params.ack); last_pending_frame_.reset(); } void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) { if (!attached()) return; // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until // it's attached again. attached_ = false; delegate_->DidDetach(); } void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id, blink::WebDragStatus drag_status, const DropData& drop_data, blink::WebDragOperationsMask mask, const gfx::Point& location) { RenderViewHost* host = GetWebContents()->GetRenderViewHost(); auto embedder = owner_web_contents_->GetBrowserPluginEmbedder(); switch (drag_status) { case blink::WebDragStatusEnter: // Only track the URL being dragged over the guest if the link isn't // coming from the guest. if (!embedder->DragEnteredGuest(this)) dragged_url_ = drop_data.url; host->DragTargetDragEnter(drop_data, location, location, mask, 0); break; case blink::WebDragStatusOver: host->DragTargetDragOver(location, location, mask, 0); break; case blink::WebDragStatusLeave: embedder->DragLeftGuest(this); host->DragTargetDragLeave(); break; case blink::WebDragStatusDrop: host->DragTargetDrop(location, location, 0); if (dragged_url_.is_valid()) { delegate_->DidDropLink(dragged_url_); dragged_url_ = GURL(); } break; case blink::WebDragStatusUnknown: NOTREACHED(); } last_drag_status_ = drag_status; EndSystemDragIfApplicable(); } void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id, const std::string& name) { RenderFrameHost* focused_frame = web_contents()->GetFocusedFrame(); if (!focused_frame) return; focused_frame->Send(new InputMsg_ExecuteNoValueEditCommand( focused_frame->GetRoutingID(), name)); } void BrowserPluginGuest::OnImeSetComposition( int browser_plugin_instance_id, const std::string& text, const std::vector& underlines, int selection_start, int selection_end) { Send(new InputMsg_ImeSetComposition(routing_id(), base::UTF8ToUTF16(text), underlines, selection_start, selection_end)); } void BrowserPluginGuest::OnImeConfirmComposition( int browser_plugin_instance_id, const std::string& text, bool keep_selection) { Send(new InputMsg_ImeConfirmComposition(routing_id(), base::UTF8ToUTF16(text), gfx::Range::InvalidRange(), keep_selection)); } void BrowserPluginGuest::OnExtendSelectionAndDelete( int browser_plugin_instance_id, int before, int after) { RenderFrameHostImpl* rfh = static_cast( web_contents()->GetFocusedFrame()); if (rfh) rfh->ExtendSelectionAndDelete(before, after); } void BrowserPluginGuest::OnReclaimCompositorResources( int browser_plugin_instance_id, const FrameHostMsg_ReclaimCompositorResources_Params& params) { RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id, params.output_surface_id, params.renderer_host_id, params.ack); } void BrowserPluginGuest::OnLockMouse(bool user_gesture, bool last_unlocked_by_target, bool privileged) { if (pending_lock_request_) { // Immediately reject the lock because only one pointerLock may be active // at a time. Send(new ViewMsg_LockMouse_ACK(routing_id(), false)); return; } pending_lock_request_ = true; delegate_->RequestPointerLockPermission( user_gesture, last_unlocked_by_target, base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse, weak_ptr_factory_.GetWeakPtr())); } void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id, bool succeeded) { Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded)); pending_lock_request_ = false; if (succeeded) mouse_locked_ = true; } void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id, bool focused, blink::WebFocusType focus_type) { RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView(); RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : nullptr; SetFocus(rwh, focused, focus_type); } void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent( int browser_plugin_instance_id, const std::vector& edit_commands) { Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(), edit_commands)); } void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id, bool visible) { guest_visible_ = visible; if (embedder_visible_ && guest_visible_) GetWebContents()->WasShown(); else GetWebContents()->WasHidden(); } void BrowserPluginGuest::OnUnlockMouse() { SendMessageToEmbedder( new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false)); } void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) { // mouse_locked_ could be false here if the lock attempt was cancelled due // to window focus, or for various other reasons before the guest was informed // of the lock's success. if (mouse_locked_) Send(new ViewMsg_MouseLockLost(routing_id())); mouse_locked_ = false; } void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id, const gfx::Rect& view_rect) { // The plugin has moved within the embedder without resizing or the // embedder/container's view rect changing. guest_window_rect_ = view_rect; RenderViewHostImpl* rvh = static_cast( GetWebContents()->GetRenderViewHost()); if (rvh) rvh->SendScreenRects(); } void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) { SendMessageToEmbedder( new BrowserPluginMsg_ShouldAcceptTouchEvents( browser_plugin_instance_id(), accept)); } #if defined(OS_MACOSX) void BrowserPluginGuest::OnShowPopup( RenderFrameHost* render_frame_host, const FrameHostMsg_ShowPopup_Params& params) { gfx::Rect translated_bounds(params.bounds); translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin()); BrowserPluginPopupMenuHelper popup_menu_helper( owner_web_contents_->GetRenderViewHost(), render_frame_host); popup_menu_helper.ShowPopupMenu(translated_bounds, params.item_height, params.item_font_size, params.selected_item, params.popup_items, params.right_aligned, params.allow_multiple_selection); } #endif void BrowserPluginGuest::OnShowWidget(int route_id, const gfx::Rect& initial_rect) { GetWebContents()->ShowCreatedWidget(route_id, initial_rect); } void BrowserPluginGuest::OnTakeFocus(bool reverse) { SendMessageToEmbedder( new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse)); } void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type, ui::TextInputMode input_mode, bool can_compose_inline, int flags) { // Save the state of text input so we can restore it on focus. last_text_input_type_ = type; last_input_mode_ = input_mode; last_input_flags_ = flags; last_can_compose_inline_ = can_compose_inline; SendTextInputTypeChangedToView( static_cast( web_contents()->GetRenderWidgetHostView())); } void BrowserPluginGuest::OnImeCancelComposition() { static_cast( web_contents()->GetRenderWidgetHostView())->ImeCancelComposition(); } #if defined(OS_MACOSX) || defined(USE_AURA) void BrowserPluginGuest::OnImeCompositionRangeChanged( const gfx::Range& range, const std::vector& character_bounds) { static_cast( web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged( range, character_bounds); } #endif } // namespace content