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/pickle.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
13 #include "content/browser/browser_thread_impl.h"
14 #include "content/browser/child_process_security_policy_impl.h"
15 #include "content/browser/frame_host/render_frame_host_impl.h"
16 #include "content/browser/frame_host/render_widget_host_view_guest.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/renderer_host/render_widget_host_view_base.h"
21 #include "content/browser/web_contents/web_contents_impl.h"
22 #include "content/browser/web_contents/web_contents_view_guest.h"
23 #include "content/common/browser_plugin/browser_plugin_constants.h"
24 #include "content/common/browser_plugin/browser_plugin_messages.h"
25 #include "content/common/content_constants_internal.h"
26 #include "content/common/drag_messages.h"
27 #include "content/common/frame_messages.h"
28 #include "content/common/host_shared_bitmap_manager.h"
29 #include "content/common/input_messages.h"
30 #include "content/common/view_messages.h"
31 #include "content/public/browser/browser_context.h"
32 #include "content/public/browser/browser_plugin_guest_manager.h"
33 #include "content/public/browser/content_browser_client.h"
34 #include "content/public/browser/guest_host.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/drop_data.h"
39 #include "ui/gfx/geometry/size_conversions.h"
41 #if defined(OS_MACOSX)
42 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
47 class BrowserPluginGuest::EmbedderVisibilityObserver
48 : public WebContentsObserver
{
50 explicit EmbedderVisibilityObserver(BrowserPluginGuest
* guest
)
51 : WebContentsObserver(guest
->embedder_web_contents()),
52 browser_plugin_guest_(guest
) {
55 ~EmbedderVisibilityObserver() override
{}
57 // WebContentsObserver implementation.
58 void WasShown() override
{
59 browser_plugin_guest_
->EmbedderVisibilityChanged(true);
62 void WasHidden() override
{
63 browser_plugin_guest_
->EmbedderVisibilityChanged(false);
67 BrowserPluginGuest
* browser_plugin_guest_
;
69 DISALLOW_COPY_AND_ASSIGN(EmbedderVisibilityObserver
);
72 BrowserPluginGuest::BrowserPluginGuest(bool has_render_view
,
73 WebContentsImpl
* web_contents
,
74 BrowserPluginGuestDelegate
* delegate
)
75 : WebContentsObserver(web_contents
),
76 owner_web_contents_(nullptr),
78 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone
),
81 pending_lock_request_(false),
82 guest_visible_(false),
83 embedder_visible_(true),
84 is_full_page_plugin_(false),
85 has_render_view_(has_render_view
),
86 is_in_destruction_(false),
88 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE
),
89 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT
),
91 last_can_compose_inline_(true),
92 guest_proxy_routing_id_(MSG_ROUTING_NONE
),
93 last_drag_status_(blink::WebDragStatusUnknown
),
94 seen_embedder_system_drag_ended_(false),
95 seen_embedder_drag_source_ended_at_(false),
97 weak_ptr_factory_(this) {
100 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
101 web_contents
->SetBrowserPluginGuest(this);
102 delegate
->SetGuestHost(this);
105 int BrowserPluginGuest::GetGuestProxyRoutingID() {
106 if (guest_proxy_routing_id_
!= MSG_ROUTING_NONE
)
107 return guest_proxy_routing_id_
;
109 // Create a swapped out RenderView for the guest in the embedder renderer
110 // process, so that the embedder can access the guest's window object.
111 // On reattachment, we can reuse the same swapped out RenderView because
112 // the embedder process will always be the same even if the embedder
113 // WebContents changes.
115 // TODO(fsamuel): Make sure this works for transferring guests across
116 // owners in different processes. We probably need to clear the
117 // |guest_proxy_routing_id_| and perform any necessary cleanup on Detach
119 SiteInstance
* owner_site_instance
= owner_web_contents_
->GetSiteInstance();
120 guest_proxy_routing_id_
=
121 GetWebContents()->CreateSwappedOutRenderView(owner_site_instance
);
123 return guest_proxy_routing_id_
;
126 int BrowserPluginGuest::LoadURLWithParams(
127 const NavigationController::LoadURLParams
& load_params
) {
128 GetWebContents()->GetController().LoadURLWithParams(load_params
);
129 return GetGuestProxyRoutingID();
132 void BrowserPluginGuest::SizeContents(const gfx::Size
& new_size
) {
133 GetWebContents()->GetView()->SizeContents(new_size
);
136 void BrowserPluginGuest::WillDestroy() {
137 is_in_destruction_
= true;
138 owner_web_contents_
= nullptr;
142 void BrowserPluginGuest::Init() {
147 // TODO(fsamuel): Initiailization prior to attachment should be behind a
148 // command line flag once we introduce experimental guest types that rely on
149 // this functionality.
150 if (!delegate_
->CanRunInDetachedState())
153 WebContentsImpl
* owner_web_contents
= static_cast<WebContentsImpl
*>(
154 delegate_
->GetOwnerWebContents());
155 owner_web_contents
->CreateBrowserPluginEmbedderIfNecessary();
156 InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents
);
159 base::WeakPtr
<BrowserPluginGuest
> BrowserPluginGuest::AsWeakPtr() {
160 return weak_ptr_factory_
.GetWeakPtr();
163 void BrowserPluginGuest::SetFocus(RenderWidgetHost
* rwh
,
165 blink::WebFocusType focus_type
) {
170 if ((focus_type
== blink::WebFocusTypeForward
) ||
171 (focus_type
== blink::WebFocusTypeBackward
)) {
172 static_cast<RenderViewHostImpl
*>(RenderViewHost::From(rwh
))->
173 SetInitialFocus(focus_type
== blink::WebFocusTypeBackward
);
175 rwh
->Send(new InputMsg_SetFocus(rwh
->GetRoutingID(), focused
));
176 if (!focused
&& mouse_locked_
)
179 // Restore the last seen state of text input to the view.
180 RenderWidgetHostViewBase
* rwhv
= static_cast<RenderWidgetHostViewBase
*>(
182 SendTextInputTypeChangedToView(rwhv
);
185 void BrowserPluginGuest::SetTooltipText(const base::string16
& tooltip_text
) {
186 if (tooltip_text
== current_tooltip_text_
)
188 current_tooltip_text_
= tooltip_text
;
190 SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
191 browser_plugin_instance_id_
, tooltip_text
));
194 bool BrowserPluginGuest::LockMouse(bool allowed
) {
195 if (!attached() || (mouse_locked_
== allowed
))
198 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed
);
201 WebContentsImpl
* BrowserPluginGuest::CreateNewGuestWindow(
202 const WebContents::CreateParams
& params
) {
203 WebContentsImpl
* new_contents
=
204 static_cast<WebContentsImpl
*>(delegate_
->CreateNewGuestWindow(params
));
205 DCHECK(new_contents
);
209 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
210 const IPC::Message
& message
) {
211 RenderWidgetHostViewGuest
* rwhv
= static_cast<RenderWidgetHostViewGuest
*>(
212 web_contents()->GetRenderWidgetHostView());
214 rwhv
->OnMessageReceivedFromEmbedder(
216 static_cast<RenderViewHostImpl
*>(
217 embedder_web_contents()->GetRenderViewHost()))) {
222 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest
, message
)
223 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK
,
224 OnCompositorFrameSwappedACK
)
225 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach
, OnDetach
)
226 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate
,
228 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand
,
229 OnExecuteEditCommand
)
230 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete
,
231 OnExtendSelectionAndDelete
)
232 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition
,
233 OnImeConfirmComposition
)
234 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition
,
236 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK
, OnLockMouseAck
)
237 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources
,
238 OnReclaimCompositorResources
)
239 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent
,
240 OnSetEditCommandsForNextKeyEvent
)
241 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus
, OnSetFocus
)
242 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility
, OnSetVisibility
)
243 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK
, OnUnlockMouseAck
)
244 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry
, OnUpdateGeometry
)
245 IPC_MESSAGE_UNHANDLED(handled
= false)
246 IPC_END_MESSAGE_MAP()
250 void BrowserPluginGuest::InitInternal(
251 const BrowserPluginHostMsg_Attach_Params
& params
,
252 WebContentsImpl
* owner_web_contents
) {
253 focused_
= params
.focused
;
254 OnSetFocus(browser_plugin::kInstanceIDNone
,
256 blink::WebFocusTypeNone
);
258 guest_visible_
= params
.visible
;
261 is_full_page_plugin_
= params
.is_full_page_plugin
;
262 guest_window_rect_
= params
.view_rect
;
264 if (owner_web_contents_
!= owner_web_contents
) {
265 WebContentsViewGuest
* new_view
=
266 static_cast<WebContentsViewGuest
*>(GetWebContents()->GetView());
267 if (owner_web_contents_
)
268 new_view
->OnGuestDetached(owner_web_contents_
->GetView());
270 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
272 owner_web_contents_
= owner_web_contents
;
273 new_view
->OnGuestAttached(owner_web_contents_
->GetView());
276 RendererPreferences
* renderer_prefs
=
277 GetWebContents()->GetMutableRendererPrefs();
278 std::string guest_user_agent_override
= renderer_prefs
->user_agent_override
;
279 // Copy renderer preferences (and nothing else) from the embedder's
280 // WebContents to the guest.
282 // For GTK and Aura this is necessary to get proper renderer configuration
283 // values for caret blinking interval, colors related to selection and
285 *renderer_prefs
= *owner_web_contents_
->GetMutableRendererPrefs();
286 renderer_prefs
->user_agent_override
= guest_user_agent_override
;
288 // We would like the guest to report changes to frame names so that we can
289 // update the BrowserPlugin's corresponding 'name' attribute.
290 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
291 renderer_prefs
->report_frame_name_changes
= true;
292 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
293 // navigations still continue to function inside the app.
294 renderer_prefs
->browser_handles_all_top_level_requests
= false;
295 // Disable "client blocked" error page for browser plugin.
296 renderer_prefs
->disable_client_blocked_error_page
= true;
298 embedder_visibility_observer_
.reset(new EmbedderVisibilityObserver(this));
300 DCHECK(GetWebContents()->GetRenderViewHost());
302 // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
303 auto render_widget_host
=
304 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
305 render_widget_host
->NotifyScreenInfoChanged();
307 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
308 // be reset again the next time preferences are updated.
309 WebPreferences prefs
=
310 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
311 prefs
.navigate_on_drag_drop
= false;
312 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs
);
315 BrowserPluginGuest::~BrowserPluginGuest() {
319 BrowserPluginGuest
* BrowserPluginGuest::Create(
320 WebContentsImpl
* web_contents
,
321 BrowserPluginGuestDelegate
* delegate
) {
322 return new BrowserPluginGuest(
323 web_contents
->opener() != nullptr, web_contents
, delegate
);
327 bool BrowserPluginGuest::IsGuest(WebContentsImpl
* web_contents
) {
328 return web_contents
&& web_contents
->GetBrowserPluginGuest();
332 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl
* render_view_host
) {
333 return render_view_host
&& IsGuest(
334 static_cast<WebContentsImpl
*>(WebContents::FromRenderViewHost(
338 RenderWidgetHostView
* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
339 if (!owner_web_contents_
)
341 return owner_web_contents_
->GetRenderWidgetHostView();
344 void BrowserPluginGuest::UpdateVisibility() {
345 OnSetVisibility(browser_plugin_instance_id(), visible());
348 BrowserPluginGuestManager
*
349 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
350 return GetWebContents()->GetBrowserContext()->GetGuestManager();
353 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible
) {
354 embedder_visible_
= visible
;
358 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow
) {
359 SendMessageToEmbedder(
360 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow
));
363 void BrowserPluginGuest::SwapCompositorFrame(
364 uint32 output_surface_id
,
367 scoped_ptr
<cc::CompositorFrame
> frame
) {
368 cc::RenderPass
* root_pass
=
369 frame
->delegated_frame_data
->render_pass_list
.back();
370 gfx::Size
view_size(gfx::ToFlooredSize(gfx::ScaleSize(
371 root_pass
->output_rect
.size(),
372 1.0f
/ frame
->metadata
.device_scale_factor
)));
374 if (last_seen_view_size_
!= view_size
) {
375 delegate_
->GuestSizeChanged(view_size
);
376 last_seen_view_size_
= view_size
;
379 last_pending_frame_
.reset(new FrameMsg_CompositorFrameSwapped_Params());
380 frame
->AssignTo(&last_pending_frame_
->frame
);
381 last_pending_frame_
->output_surface_id
= output_surface_id
;
382 last_pending_frame_
->producing_route_id
= host_routing_id
;
383 last_pending_frame_
->producing_host_id
= host_process_id
;
385 SendMessageToEmbedder(
386 new BrowserPluginMsg_CompositorFrameSwapped(
387 browser_plugin_instance_id(), *last_pending_frame_
));
390 void BrowserPluginGuest::SetContentsOpaque(bool opaque
) {
391 SendMessageToEmbedder(
392 new BrowserPluginMsg_SetContentsOpaque(
393 browser_plugin_instance_id(), opaque
));
396 bool BrowserPluginGuest::Find(int request_id
,
397 const base::string16
& search_text
,
398 const blink::WebFindOptions
& options
) {
399 return delegate_
->Find(request_id
, search_text
, options
);
402 bool BrowserPluginGuest::StopFinding(StopFindAction action
) {
403 return delegate_
->StopFinding(action
);
406 WebContentsImpl
* BrowserPluginGuest::GetWebContents() const {
407 return static_cast<WebContentsImpl
*>(web_contents());
410 gfx::Point
BrowserPluginGuest::GetScreenCoordinates(
411 const gfx::Point
& relative_position
) const {
413 return relative_position
;
415 gfx::Point
screen_pos(relative_position
);
416 screen_pos
+= guest_window_rect_
.OffsetFromOrigin();
417 if (embedder_web_contents()->GetBrowserPluginGuest()) {
418 BrowserPluginGuest
* embedder_guest
=
419 embedder_web_contents()->GetBrowserPluginGuest();
420 screen_pos
+= embedder_guest
->guest_window_rect_
.OffsetFromOrigin();
425 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message
* msg
) {
427 // Some pages such as data URLs, javascript URLs, and about:blank
428 // do not load external resources and so they load prior to attachment.
429 // As a result, we must save all these IPCs until attachment and then
430 // forward them so that the embedder gets a chance to see and process
432 pending_messages_
.push_back(linked_ptr
<IPC::Message
>(msg
));
435 owner_web_contents_
->Send(msg
);
438 void BrowserPluginGuest::DragSourceEndedAt(int client_x
, int client_y
,
439 int screen_x
, int screen_y
, blink::WebDragOperation operation
) {
440 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x
, client_y
,
441 screen_x
, screen_y
, operation
);
442 seen_embedder_drag_source_ended_at_
= true;
443 EndSystemDragIfApplicable();
446 void BrowserPluginGuest::EndSystemDragIfApplicable() {
447 // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
448 // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
449 // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
450 // means we call it in all cases and also make sure we only call it once.
451 // This ensures that the input state of the guest stays correct, otherwise
452 // it will go stale and won't accept any further input events.
454 // The strategy used here to call DragSourceSystemDragEnded() on the RVH
455 // is when the following conditions are met:
456 // a. Embedder has seen SystemDragEnded()
457 // b. Embedder has seen DragSourceEndedAt()
458 // c. The guest has seen some drag status update other than
459 // WebDragStatusUnknown. Note that this step should ideally be done
460 // differently: The guest has seen at least one of
461 // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
462 // a source quickly outside of <webview> bounds, then the
463 // BrowserPluginGuest never sees any of these drag status updates,
464 // there we just check whether we've seen any drag status update or
466 if (last_drag_status_
!= blink::WebDragStatusOver
&&
467 seen_embedder_drag_source_ended_at_
&& seen_embedder_system_drag_ended_
) {
468 RenderViewHostImpl
* guest_rvh
= static_cast<RenderViewHostImpl
*>(
469 GetWebContents()->GetRenderViewHost());
470 guest_rvh
->DragSourceSystemDragEnded();
471 last_drag_status_
= blink::WebDragStatusUnknown
;
472 seen_embedder_system_drag_ended_
= false;
473 seen_embedder_drag_source_ended_at_
= false;
474 dragged_url_
= GURL();
478 void BrowserPluginGuest::EmbedderSystemDragEnded() {
479 seen_embedder_system_drag_ended_
= true;
480 EndSystemDragIfApplicable();
483 void BrowserPluginGuest::SendQueuedMessages() {
487 while (!pending_messages_
.empty()) {
488 linked_ptr
<IPC::Message
> message_ptr
= pending_messages_
.front();
489 pending_messages_
.pop_front();
490 SendMessageToEmbedder(message_ptr
.release());
494 void BrowserPluginGuest::SendTextInputTypeChangedToView(
495 RenderWidgetHostViewBase
* guest_rwhv
) {
499 if (!owner_web_contents_
) {
500 // If we were showing an interstitial, then we can end up here during
501 // embedder shutdown or when the embedder navigates to a different page.
502 // The call stack is roughly:
503 // BrowserPluginGuest::SetFocus()
504 // content::InterstitialPageImpl::Hide()
505 // content::InterstitialPageImpl::DontProceed().
507 // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed.
511 guest_rwhv
->TextInputTypeChanged(last_text_input_type_
, last_input_mode_
,
512 last_can_compose_inline_
, last_input_flags_
);
513 // Enable input method for guest if it's enabled for the embedder.
514 if (!static_cast<RenderViewHostImpl
*>(
515 owner_web_contents_
->GetRenderViewHost())->input_method_active()) {
518 RenderViewHostImpl
* guest_rvh
=
519 static_cast<RenderViewHostImpl
*>(GetWebContents()->GetRenderViewHost());
520 guest_rvh
->SetInputMethodActive(true);
523 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
524 RenderFrameHost
* render_frame_host
,
526 ui::PageTransition transition_type
) {
527 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
530 void BrowserPluginGuest::RenderViewReady() {
531 RenderViewHost
* rvh
= GetWebContents()->GetRenderViewHost();
532 // TODO(fsamuel): Investigate whether it's possible to update state earlier
533 // here (see http://crbug.com/158151).
534 Send(new InputMsg_SetFocus(routing_id(), focused_
));
537 RenderWidgetHostImpl::From(rvh
)->set_hung_renderer_delay(
538 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs
));
541 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status
) {
542 SendMessageToEmbedder(
543 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
545 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED
:
546 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
548 case base::TERMINATION_STATUS_PROCESS_CRASHED
:
549 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
551 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION
:
553 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
561 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
562 const IPC::Message
& message
) {
563 return (message
.type() != BrowserPluginHostMsg_Attach::ID
) &&
564 (IPC_MESSAGE_CLASS(message
) == BrowserPluginMsgStart
);
567 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message
& message
) {
569 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest
, message
)
570 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition
,
571 OnImeCancelComposition
)
572 #if defined(OS_MACOSX) || defined(USE_AURA)
573 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged
,
574 OnImeCompositionRangeChanged
)
576 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers
,
577 OnHasTouchEventHandlers
)
578 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse
, OnLockMouse
)
579 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget
, OnShowWidget
)
580 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus
, OnTakeFocus
)
581 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged
,
582 OnTextInputTypeChanged
)
583 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse
, OnUnlockMouse
)
584 IPC_MESSAGE_UNHANDLED(handled
= false)
585 IPC_END_MESSAGE_MAP()
589 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message
& message
,
590 RenderFrameHost
* render_frame_host
) {
591 // This will eventually be the home for more IPC handlers that depend on
592 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
593 // compile if there are no handlers for a platform. So we have both #if guards
594 // around the whole thing (unfortunate but temporary), and #if guards where
595 // they belong, only around the one IPC handler. TODO(avi): Move more of the
596 // frame-based handlers to this function and remove the outer #if layer.
597 #if defined(OS_MACOSX)
599 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest
, message
,
601 #if defined(OS_MACOSX)
602 // MacOS X creates and populates platform-specific select drop-down menus
603 // whereas other platforms merely create a popup window that the guest
604 // renderer process paints inside.
605 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup
, OnShowPopup
)
607 IPC_MESSAGE_UNHANDLED(handled
= false)
608 IPC_END_MESSAGE_MAP()
615 void BrowserPluginGuest::Attach(
616 int browser_plugin_instance_id
,
617 WebContentsImpl
* embedder_web_contents
,
618 const BrowserPluginHostMsg_Attach_Params
& params
) {
619 browser_plugin_instance_id_
= browser_plugin_instance_id
;
620 // If a guest is detaching from one container and attaching to another
621 // container, then late arriving ACKs may be lost if the mapping from
622 // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
623 // ensure that we always get new frames on attachment by ACKing the pending
624 // frame if it's still waiting on the ACK.
625 if (last_pending_frame_
) {
626 cc::CompositorFrameAck ack
;
627 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
628 last_pending_frame_
->producing_route_id
,
629 last_pending_frame_
->output_surface_id
,
630 last_pending_frame_
->producing_host_id
,
632 last_pending_frame_
.reset();
635 // The guest is owned by the embedder. Attach is queued up so we cannot
636 // change embedders before attach completes. If the embedder goes away,
637 // so does the guest and so we will never call WillAttachComplete because
638 // we have a weak ptr.
639 delegate_
->WillAttach(embedder_web_contents
, browser_plugin_instance_id
,
640 params
.is_full_page_plugin
,
641 base::Bind(&BrowserPluginGuest::OnWillAttachComplete
,
642 weak_ptr_factory_
.GetWeakPtr(),
643 embedder_web_contents
, params
));
646 void BrowserPluginGuest::OnWillAttachComplete(
647 WebContentsImpl
* embedder_web_contents
,
648 const BrowserPluginHostMsg_Attach_Params
& params
) {
649 // If a RenderView has already been created for this new window, then we need
650 // to initialize the browser-side state now so that the RenderFrameHostManager
651 // does not create a new RenderView on navigation.
652 if (has_render_view_
) {
653 // This will trigger a callback to RenderViewReady after a round-trip IPC.
654 static_cast<RenderViewHostImpl
*>(
655 GetWebContents()->GetRenderViewHost())->Init();
656 WebContentsViewGuest
* web_contents_view
=
657 static_cast<WebContentsViewGuest
*>(GetWebContents()->GetView());
658 if (!web_contents()->GetRenderViewHost()->GetView()) {
659 web_contents_view
->CreateViewForWidget(
660 web_contents()->GetRenderViewHost(), true);
664 InitInternal(params
, embedder_web_contents
);
667 SendQueuedMessages();
669 delegate_
->DidAttach(GetGuestProxyRoutingID());
671 has_render_view_
= true;
673 // Enable input method for guest if it's enabled for the embedder.
674 if (static_cast<RenderViewHostImpl
*>(
675 owner_web_contents_
->GetRenderViewHost())->input_method_active()) {
676 RenderViewHostImpl
* guest_rvh
= static_cast<RenderViewHostImpl
*>(
677 GetWebContents()->GetRenderViewHost());
678 guest_rvh
->SetInputMethodActive(true);
681 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
684 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
685 int browser_plugin_instance_id
,
686 const FrameHostMsg_CompositorFrameSwappedACK_Params
& params
) {
687 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params
.producing_route_id
,
688 params
.output_surface_id
,
689 params
.producing_host_id
,
691 last_pending_frame_
.reset();
694 void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id
) {
698 // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
699 // it's attached again.
702 delegate_
->DidDetach();
705 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id
,
706 blink::WebDragStatus drag_status
,
707 const DropData
& drop_data
,
708 blink::WebDragOperationsMask mask
,
709 const gfx::Point
& location
) {
710 RenderViewHost
* host
= GetWebContents()->GetRenderViewHost();
711 auto embedder
= owner_web_contents_
->GetBrowserPluginEmbedder();
712 switch (drag_status
) {
713 case blink::WebDragStatusEnter
:
714 // Only track the URL being dragged over the guest if the link isn't
715 // coming from the guest.
716 if (!embedder
->DragEnteredGuest(this))
717 dragged_url_
= drop_data
.url
;
718 host
->DragTargetDragEnter(drop_data
, location
, location
, mask
, 0);
720 case blink::WebDragStatusOver
:
721 host
->DragTargetDragOver(location
, location
, mask
, 0);
723 case blink::WebDragStatusLeave
:
724 embedder
->DragLeftGuest(this);
725 host
->DragTargetDragLeave();
727 case blink::WebDragStatusDrop
:
728 host
->DragTargetDrop(location
, location
, 0);
729 if (dragged_url_
.is_valid()) {
730 delegate_
->DidDropLink(dragged_url_
);
731 dragged_url_
= GURL();
734 case blink::WebDragStatusUnknown
:
737 last_drag_status_
= drag_status
;
738 EndSystemDragIfApplicable();
741 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id
,
742 const std::string
& name
) {
743 RenderFrameHost
* focused_frame
= web_contents()->GetFocusedFrame();
747 focused_frame
->Send(new InputMsg_ExecuteNoValueEditCommand(
748 focused_frame
->GetRoutingID(), name
));
751 void BrowserPluginGuest::OnImeSetComposition(
752 int browser_plugin_instance_id
,
753 const std::string
& text
,
754 const std::vector
<blink::WebCompositionUnderline
>& underlines
,
757 Send(new InputMsg_ImeSetComposition(routing_id(),
758 base::UTF8ToUTF16(text
), underlines
,
759 selection_start
, selection_end
));
762 void BrowserPluginGuest::OnImeConfirmComposition(
763 int browser_plugin_instance_id
,
764 const std::string
& text
,
765 bool keep_selection
) {
766 Send(new InputMsg_ImeConfirmComposition(routing_id(),
767 base::UTF8ToUTF16(text
),
768 gfx::Range::InvalidRange(),
772 void BrowserPluginGuest::OnExtendSelectionAndDelete(
773 int browser_plugin_instance_id
,
776 RenderFrameHostImpl
* rfh
= static_cast<RenderFrameHostImpl
*>(
777 web_contents()->GetFocusedFrame());
779 rfh
->ExtendSelectionAndDelete(before
, after
);
782 void BrowserPluginGuest::OnReclaimCompositorResources(
783 int browser_plugin_instance_id
,
784 const FrameHostMsg_ReclaimCompositorResources_Params
& params
) {
785 RenderWidgetHostImpl::SendReclaimCompositorResources(params
.route_id
,
786 params
.output_surface_id
,
787 params
.renderer_host_id
,
791 void BrowserPluginGuest::OnLockMouse(bool user_gesture
,
792 bool last_unlocked_by_target
,
794 if (pending_lock_request_
) {
795 // Immediately reject the lock because only one pointerLock may be active
797 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
801 pending_lock_request_
= true;
803 delegate_
->RequestPointerLockPermission(
805 last_unlocked_by_target
,
806 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse
,
807 weak_ptr_factory_
.GetWeakPtr()));
810 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id
,
812 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded
));
813 pending_lock_request_
= false;
815 mouse_locked_
= true;
818 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id
,
820 blink::WebFocusType focus_type
) {
821 RenderWidgetHostView
* rwhv
= web_contents()->GetRenderWidgetHostView();
822 RenderWidgetHost
* rwh
= rwhv
? rwhv
->GetRenderWidgetHost() : nullptr;
823 SetFocus(rwh
, focused
, focus_type
);
826 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
827 int browser_plugin_instance_id
,
828 const std::vector
<EditCommand
>& edit_commands
) {
829 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
833 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id
,
835 guest_visible_
= visible
;
836 if (embedder_visible_
&& guest_visible_
)
837 GetWebContents()->WasShown();
839 GetWebContents()->WasHidden();
842 void BrowserPluginGuest::OnUnlockMouse() {
843 SendMessageToEmbedder(
844 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
847 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id
) {
848 // mouse_locked_ could be false here if the lock attempt was cancelled due
849 // to window focus, or for various other reasons before the guest was informed
850 // of the lock's success.
852 Send(new ViewMsg_MouseLockLost(routing_id()));
853 mouse_locked_
= false;
856 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id
,
857 const gfx::Rect
& view_rect
) {
858 // The plugin has moved within the embedder without resizing or the
859 // embedder/container's view rect changing.
860 guest_window_rect_
= view_rect
;
861 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
862 GetWebContents()->GetRenderViewHost());
864 rvh
->SendScreenRects();
867 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept
) {
868 SendMessageToEmbedder(
869 new BrowserPluginMsg_ShouldAcceptTouchEvents(
870 browser_plugin_instance_id(), accept
));
873 #if defined(OS_MACOSX)
874 void BrowserPluginGuest::OnShowPopup(
875 RenderFrameHost
* render_frame_host
,
876 const FrameHostMsg_ShowPopup_Params
& params
) {
877 gfx::Rect
translated_bounds(params
.bounds
);
878 translated_bounds
.Offset(guest_window_rect_
.OffsetFromOrigin());
879 BrowserPluginPopupMenuHelper
popup_menu_helper(
880 owner_web_contents_
->GetRenderViewHost(), render_frame_host
);
881 popup_menu_helper
.ShowPopupMenu(translated_bounds
,
883 params
.item_font_size
,
884 params
.selected_item
,
886 params
.right_aligned
,
887 params
.allow_multiple_selection
);
891 void BrowserPluginGuest::OnShowWidget(int route_id
,
892 const gfx::Rect
& initial_rect
) {
893 GetWebContents()->ShowCreatedWidget(route_id
, initial_rect
);
896 void BrowserPluginGuest::OnTakeFocus(bool reverse
) {
897 SendMessageToEmbedder(
898 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse
));
901 void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type
,
902 ui::TextInputMode input_mode
,
903 bool can_compose_inline
,
905 // Save the state of text input so we can restore it on focus.
906 last_text_input_type_
= type
;
907 last_input_mode_
= input_mode
;
908 last_input_flags_
= flags
;
909 last_can_compose_inline_
= can_compose_inline
;
911 SendTextInputTypeChangedToView(
912 static_cast<RenderWidgetHostViewBase
*>(
913 web_contents()->GetRenderWidgetHostView()));
916 void BrowserPluginGuest::OnImeCancelComposition() {
917 static_cast<RenderWidgetHostViewBase
*>(
918 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
921 #if defined(OS_MACOSX) || defined(USE_AURA)
922 void BrowserPluginGuest::OnImeCompositionRangeChanged(
923 const gfx::Range
& range
,
924 const std::vector
<gfx::Rect
>& character_bounds
) {
925 static_cast<RenderWidgetHostViewBase
*>(
926 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
927 range
, character_bounds
);
931 } // namespace content