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 "cc/surfaces/surface.h"
13 #include "cc/surfaces/surface_manager.h"
14 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
15 #include "content/browser/browser_thread_impl.h"
16 #include "content/browser/child_process_security_policy_impl.h"
17 #include "content/browser/compositor/surface_utils.h"
18 #include "content/browser/frame_host/render_frame_host_impl.h"
19 #include "content/browser/frame_host/render_widget_host_view_guest.h"
20 #include "content/browser/loader/resource_dispatcher_host_impl.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/host_shared_bitmap_manager.h"
31 #include "content/common/input_messages.h"
32 #include "content/common/view_messages.h"
33 #include "content/public/browser/browser_context.h"
34 #include "content/public/browser/browser_plugin_guest_manager.h"
35 #include "content/public/browser/content_browser_client.h"
36 #include "content/public/browser/guest_host.h"
37 #include "content/public/browser/render_widget_host_view.h"
38 #include "content/public/browser/user_metrics.h"
39 #include "content/public/browser/web_contents_observer.h"
40 #include "content/public/common/browser_plugin_guest_mode.h"
41 #include "content/public/common/drop_data.h"
42 #include "ui/gfx/geometry/size_conversions.h"
44 #if defined(OS_MACOSX)
45 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
46 #include "content/common/frame_messages.h"
51 class BrowserPluginGuest::EmbedderVisibilityObserver
52 : public WebContentsObserver
{
54 explicit EmbedderVisibilityObserver(BrowserPluginGuest
* guest
)
55 : WebContentsObserver(guest
->embedder_web_contents()),
56 browser_plugin_guest_(guest
) {
59 ~EmbedderVisibilityObserver() override
{}
61 // WebContentsObserver implementation.
62 void WasShown() override
{
63 browser_plugin_guest_
->EmbedderVisibilityChanged(true);
66 void WasHidden() override
{
67 browser_plugin_guest_
->EmbedderVisibilityChanged(false);
71 BrowserPluginGuest
* browser_plugin_guest_
;
73 DISALLOW_COPY_AND_ASSIGN(EmbedderVisibilityObserver
);
76 BrowserPluginGuest::BrowserPluginGuest(bool has_render_view
,
77 WebContentsImpl
* web_contents
,
78 BrowserPluginGuestDelegate
* delegate
)
79 : WebContentsObserver(web_contents
),
80 owner_web_contents_(nullptr),
82 has_attached_since_surface_set_(false),
83 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone
),
86 pending_lock_request_(false),
87 guest_visible_(false),
88 embedder_visible_(true),
89 is_full_page_plugin_(false),
90 has_render_view_(has_render_view
),
91 is_in_destruction_(false),
93 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE
),
94 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT
),
96 last_can_compose_inline_(true),
97 guest_proxy_routing_id_(MSG_ROUTING_NONE
),
98 last_drag_status_(blink::WebDragStatusUnknown
),
99 seen_embedder_system_drag_ended_(false),
100 seen_embedder_drag_source_ended_at_(false),
102 weak_ptr_factory_(this) {
103 DCHECK(web_contents
);
105 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
106 web_contents
->SetBrowserPluginGuest(this);
107 delegate
->SetGuestHost(this);
110 int BrowserPluginGuest::GetGuestProxyRoutingID() {
111 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
112 // We don't use the proxy to send postMessage in --site-per-process, since
113 // we use the contentWindow directly from the frame element instead.
114 return MSG_ROUTING_NONE
;
117 if (guest_proxy_routing_id_
!= MSG_ROUTING_NONE
)
118 return guest_proxy_routing_id_
;
120 // Create a swapped out RenderView for the guest in the embedder renderer
121 // process, so that the embedder can access the guest's window object.
122 // On reattachment, we can reuse the same swapped out RenderView because
123 // the embedder process will always be the same even if the embedder
124 // WebContents changes.
126 // TODO(fsamuel): Make sure this works for transferring guests across
127 // owners in different processes. We probably need to clear the
128 // |guest_proxy_routing_id_| and perform any necessary cleanup on Detach
130 SiteInstance
* owner_site_instance
= owner_web_contents_
->GetSiteInstance();
131 guest_proxy_routing_id_
=
132 GetWebContents()->CreateSwappedOutRenderView(owner_site_instance
);
134 return guest_proxy_routing_id_
;
137 int BrowserPluginGuest::LoadURLWithParams(
138 const NavigationController::LoadURLParams
& load_params
) {
139 GetWebContents()->GetController().LoadURLWithParams(load_params
);
140 return GetGuestProxyRoutingID();
143 void BrowserPluginGuest::SizeContents(const gfx::Size
& new_size
) {
144 GetWebContents()->GetView()->SizeContents(new_size
);
147 void BrowserPluginGuest::WillDestroy() {
148 is_in_destruction_
= true;
149 owner_web_contents_
= nullptr;
153 void BrowserPluginGuest::Init() {
158 // TODO(fsamuel): Initiailization prior to attachment should be behind a
159 // command line flag once we introduce experimental guest types that rely on
160 // this functionality.
161 if (!delegate_
->CanRunInDetachedState())
164 WebContentsImpl
* owner_web_contents
= static_cast<WebContentsImpl
*>(
165 delegate_
->GetOwnerWebContents());
166 owner_web_contents
->CreateBrowserPluginEmbedderIfNecessary();
167 InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents
);
170 base::WeakPtr
<BrowserPluginGuest
> BrowserPluginGuest::AsWeakPtr() {
171 return weak_ptr_factory_
.GetWeakPtr();
174 void BrowserPluginGuest::SetFocus(RenderWidgetHost
* rwh
,
176 blink::WebFocusType focus_type
) {
181 if ((focus_type
== blink::WebFocusTypeForward
) ||
182 (focus_type
== blink::WebFocusTypeBackward
)) {
183 static_cast<RenderViewHostImpl
*>(RenderViewHost::From(rwh
))->
184 SetInitialFocus(focus_type
== blink::WebFocusTypeBackward
);
186 rwh
->Send(new InputMsg_SetFocus(rwh
->GetRoutingID(), focused
));
187 if (!focused
&& mouse_locked_
)
190 // Restore the last seen state of text input to the view.
191 RenderWidgetHostViewBase
* rwhv
= static_cast<RenderWidgetHostViewBase
*>(
193 SendTextInputTypeChangedToView(rwhv
);
196 void BrowserPluginGuest::SetTooltipText(const base::string16
& tooltip_text
) {
197 if (tooltip_text
== current_tooltip_text_
)
199 current_tooltip_text_
= tooltip_text
;
201 SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
202 browser_plugin_instance_id_
, tooltip_text
));
205 bool BrowserPluginGuest::LockMouse(bool allowed
) {
206 if (!attached() || (mouse_locked_
== allowed
))
209 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed
);
212 WebContentsImpl
* BrowserPluginGuest::CreateNewGuestWindow(
213 const WebContents::CreateParams
& params
) {
214 WebContentsImpl
* new_contents
=
215 static_cast<WebContentsImpl
*>(delegate_
->CreateNewGuestWindow(params
));
216 DCHECK(new_contents
);
220 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
221 const IPC::Message
& message
) {
222 RenderWidgetHostViewGuest
* rwhv
= static_cast<RenderWidgetHostViewGuest
*>(
223 web_contents()->GetRenderWidgetHostView());
224 // Until the guest is attached, it should not be handling input events.
225 if (attached() && rwhv
&& rwhv
->OnMessageReceivedFromEmbedder(
227 static_cast<RenderViewHostImpl
*>(
228 embedder_web_contents()->GetRenderViewHost()))) {
233 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest
, message
)
234 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK
,
235 OnCompositorFrameSwappedACK
)
236 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach
, OnDetach
)
237 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate
,
239 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand
,
240 OnExecuteEditCommand
)
241 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete
,
242 OnExtendSelectionAndDelete
)
243 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition
,
244 OnImeConfirmComposition
)
245 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition
,
247 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK
, OnLockMouseAck
)
248 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources
,
249 OnReclaimCompositorResources
)
250 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent
,
251 OnSetEditCommandsForNextKeyEvent
)
252 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus
, OnSetFocus
)
253 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility
, OnSetVisibility
)
254 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK
, OnUnlockMouseAck
)
255 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry
, OnUpdateGeometry
)
256 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SatisfySequence
, OnSatisfySequence
)
257 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_RequireSequence
, OnRequireSequence
)
258 IPC_MESSAGE_UNHANDLED(handled
= false)
259 IPC_END_MESSAGE_MAP()
263 void BrowserPluginGuest::InitInternal(
264 const BrowserPluginHostMsg_Attach_Params
& params
,
265 WebContentsImpl
* owner_web_contents
) {
266 focused_
= params
.focused
;
267 OnSetFocus(browser_plugin::kInstanceIDNone
,
269 blink::WebFocusTypeNone
);
271 guest_visible_
= params
.visible
;
274 is_full_page_plugin_
= params
.is_full_page_plugin
;
275 guest_window_rect_
= params
.view_rect
;
277 if (owner_web_contents_
!= owner_web_contents
) {
278 WebContentsViewGuest
* new_view
= nullptr;
279 if (!BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
281 static_cast<WebContentsViewGuest
*>(GetWebContents()->GetView());
284 if (owner_web_contents_
&& new_view
)
285 new_view
->OnGuestDetached(owner_web_contents_
->GetView());
287 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
289 owner_web_contents_
= owner_web_contents
;
291 new_view
->OnGuestAttached(owner_web_contents_
->GetView());
294 RendererPreferences
* renderer_prefs
=
295 GetWebContents()->GetMutableRendererPrefs();
296 std::string guest_user_agent_override
= renderer_prefs
->user_agent_override
;
297 // Copy renderer preferences (and nothing else) from the embedder's
298 // WebContents to the guest.
300 // For GTK and Aura this is necessary to get proper renderer configuration
301 // values for caret blinking interval, colors related to selection and
303 *renderer_prefs
= *owner_web_contents_
->GetMutableRendererPrefs();
304 renderer_prefs
->user_agent_override
= guest_user_agent_override
;
306 // We would like the guest to report changes to frame names so that we can
307 // update the BrowserPlugin's corresponding 'name' attribute.
308 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
309 renderer_prefs
->report_frame_name_changes
= true;
310 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
311 // navigations still continue to function inside the app.
312 renderer_prefs
->browser_handles_all_top_level_requests
= false;
313 // Disable "client blocked" error page for browser plugin.
314 renderer_prefs
->disable_client_blocked_error_page
= true;
316 embedder_visibility_observer_
.reset(new EmbedderVisibilityObserver(this));
318 DCHECK(GetWebContents()->GetRenderViewHost());
320 // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
321 auto render_widget_host
=
322 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
323 render_widget_host
->NotifyScreenInfoChanged();
325 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
326 // be reset again the next time preferences are updated.
327 WebPreferences prefs
=
328 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
329 prefs
.navigate_on_drag_drop
= false;
330 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs
);
333 BrowserPluginGuest::~BrowserPluginGuest() {
337 BrowserPluginGuest
* BrowserPluginGuest::Create(
338 WebContentsImpl
* web_contents
,
339 BrowserPluginGuestDelegate
* delegate
) {
340 return new BrowserPluginGuest(
341 web_contents
->HasOpener(), web_contents
, delegate
);
345 bool BrowserPluginGuest::IsGuest(WebContentsImpl
* web_contents
) {
346 return web_contents
&& web_contents
->GetBrowserPluginGuest();
350 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl
* render_view_host
) {
351 return render_view_host
&& IsGuest(
352 static_cast<WebContentsImpl
*>(WebContents::FromRenderViewHost(
356 RenderWidgetHostView
* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
357 if (!owner_web_contents_
)
359 return owner_web_contents_
->GetRenderWidgetHostView();
362 void BrowserPluginGuest::UpdateVisibility() {
363 OnSetVisibility(browser_plugin_instance_id(), visible());
366 BrowserPluginGuestManager
*
367 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
368 return GetWebContents()->GetBrowserContext()->GetGuestManager();
371 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible
) {
372 embedder_visible_
= visible
;
376 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow
) {
377 SendMessageToEmbedder(
378 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow
));
381 void BrowserPluginGuest::UpdateGuestSizeIfNecessary(
382 const gfx::Size
& frame_size
, float scale_factor
) {
384 gfx::ToFlooredSize(gfx::ScaleSize(frame_size
, 1.0f
/ scale_factor
)));
386 if (last_seen_view_size_
!= view_size
) {
387 delegate_
->GuestSizeChanged(view_size
);
388 last_seen_view_size_
= view_size
;
392 // TODO(wjmaclean): Remove this once any remaining users of this pathway
394 void BrowserPluginGuest::SwapCompositorFrame(
395 uint32 output_surface_id
,
398 scoped_ptr
<cc::CompositorFrame
> frame
) {
399 cc::RenderPass
* root_pass
=
400 frame
->delegated_frame_data
->render_pass_list
.back();
401 UpdateGuestSizeIfNecessary(root_pass
->output_rect
.size(),
402 frame
->metadata
.device_scale_factor
);
404 last_pending_frame_
.reset(new FrameMsg_CompositorFrameSwapped_Params());
405 frame
->AssignTo(&last_pending_frame_
->frame
);
406 last_pending_frame_
->output_surface_id
= output_surface_id
;
407 last_pending_frame_
->producing_route_id
= host_routing_id
;
408 last_pending_frame_
->producing_host_id
= host_process_id
;
410 SendMessageToEmbedder(
411 new BrowserPluginMsg_CompositorFrameSwapped(
412 browser_plugin_instance_id(), *last_pending_frame_
));
415 void BrowserPluginGuest::SetChildFrameSurface(
416 const cc::SurfaceId
& surface_id
,
417 const gfx::Size
& frame_size
,
419 const cc::SurfaceSequence
& sequence
) {
420 has_attached_since_surface_set_
= false;
421 SendMessageToEmbedder(new BrowserPluginMsg_SetChildFrameSurface(
422 browser_plugin_instance_id(), surface_id
, frame_size
, scale_factor
,
426 void BrowserPluginGuest::OnSatisfySequence(
428 const cc::SurfaceSequence
& sequence
) {
429 std::vector
<uint32_t> sequences
;
430 sequences
.push_back(sequence
.sequence
);
431 cc::SurfaceManager
* manager
= GetSurfaceManager();
432 manager
->DidSatisfySequences(sequence
.id_namespace
, &sequences
);
435 void BrowserPluginGuest::OnRequireSequence(
437 const cc::SurfaceId
& id
,
438 const cc::SurfaceSequence
& sequence
) {
439 cc::SurfaceManager
* manager
= GetSurfaceManager();
440 cc::Surface
* surface
= manager
->GetSurfaceForId(id
);
442 LOG(ERROR
) << "Attempting to require callback on nonexistent surface";
445 surface
->AddDestructionDependency(sequence
);
448 void BrowserPluginGuest::SetContentsOpaque(bool opaque
) {
449 SendMessageToEmbedder(
450 new BrowserPluginMsg_SetContentsOpaque(
451 browser_plugin_instance_id(), opaque
));
454 bool BrowserPluginGuest::Find(int request_id
,
455 const base::string16
& search_text
,
456 const blink::WebFindOptions
& options
) {
457 return delegate_
->Find(request_id
, search_text
, options
);
460 bool BrowserPluginGuest::StopFinding(StopFindAction action
) {
461 return delegate_
->StopFinding(action
);
464 WebContentsImpl
* BrowserPluginGuest::GetWebContents() const {
465 return static_cast<WebContentsImpl
*>(web_contents());
468 gfx::Point
BrowserPluginGuest::GetScreenCoordinates(
469 const gfx::Point
& relative_position
) const {
471 return relative_position
;
473 gfx::Point
screen_pos(relative_position
);
474 screen_pos
+= guest_window_rect_
.OffsetFromOrigin();
478 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message
* msg
) {
479 // During tests, attache() may be true when there is no owner_web_contents_;
480 // in this case just queue any messages we receive.
481 if (!attached() || !owner_web_contents_
) {
482 // Some pages such as data URLs, javascript URLs, and about:blank
483 // do not load external resources and so they load prior to attachment.
484 // As a result, we must save all these IPCs until attachment and then
485 // forward them so that the embedder gets a chance to see and process
487 pending_messages_
.push_back(linked_ptr
<IPC::Message
>(msg
));
490 owner_web_contents_
->Send(msg
);
493 void BrowserPluginGuest::DragSourceEndedAt(int client_x
, int client_y
,
494 int screen_x
, int screen_y
, blink::WebDragOperation operation
) {
495 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x
, client_y
,
496 screen_x
, screen_y
, operation
);
497 seen_embedder_drag_source_ended_at_
= true;
498 EndSystemDragIfApplicable();
501 void BrowserPluginGuest::EndSystemDragIfApplicable() {
502 // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
503 // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
504 // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
505 // means we call it in all cases and also make sure we only call it once.
506 // This ensures that the input state of the guest stays correct, otherwise
507 // it will go stale and won't accept any further input events.
509 // The strategy used here to call DragSourceSystemDragEnded() on the RVH
510 // is when the following conditions are met:
511 // a. Embedder has seen SystemDragEnded()
512 // b. Embedder has seen DragSourceEndedAt()
513 // c. The guest has seen some drag status update other than
514 // WebDragStatusUnknown. Note that this step should ideally be done
515 // differently: The guest has seen at least one of
516 // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
517 // a source quickly outside of <webview> bounds, then the
518 // BrowserPluginGuest never sees any of these drag status updates,
519 // there we just check whether we've seen any drag status update or
521 if (last_drag_status_
!= blink::WebDragStatusOver
&&
522 seen_embedder_drag_source_ended_at_
&& seen_embedder_system_drag_ended_
) {
523 RenderViewHostImpl
* guest_rvh
= static_cast<RenderViewHostImpl
*>(
524 GetWebContents()->GetRenderViewHost());
525 guest_rvh
->DragSourceSystemDragEnded();
526 last_drag_status_
= blink::WebDragStatusUnknown
;
527 seen_embedder_system_drag_ended_
= false;
528 seen_embedder_drag_source_ended_at_
= false;
529 dragged_url_
= GURL();
533 void BrowserPluginGuest::EmbedderSystemDragEnded() {
534 seen_embedder_system_drag_ended_
= true;
535 EndSystemDragIfApplicable();
538 void BrowserPluginGuest::SendQueuedMessages() {
542 while (!pending_messages_
.empty()) {
543 linked_ptr
<IPC::Message
> message_ptr
= pending_messages_
.front();
544 pending_messages_
.pop_front();
545 SendMessageToEmbedder(message_ptr
.release());
549 void BrowserPluginGuest::SendTextInputTypeChangedToView(
550 RenderWidgetHostViewBase
* guest_rwhv
) {
554 if (!owner_web_contents_
) {
555 // If we were showing an interstitial, then we can end up here during
556 // embedder shutdown or when the embedder navigates to a different page.
557 // The call stack is roughly:
558 // BrowserPluginGuest::SetFocus()
559 // content::InterstitialPageImpl::Hide()
560 // content::InterstitialPageImpl::DontProceed().
562 // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed.
566 ViewHostMsg_TextInputState_Params params
;
567 params
.type
= last_text_input_type_
;
568 params
.mode
= last_input_mode_
;
569 params
.flags
= last_input_flags_
;
570 params
.can_compose_inline
= last_can_compose_inline_
;
571 guest_rwhv
->TextInputStateChanged(params
);
574 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
575 RenderFrameHost
* render_frame_host
,
577 ui::PageTransition transition_type
) {
578 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
581 void BrowserPluginGuest::RenderViewReady() {
582 RenderViewHost
* rvh
= GetWebContents()->GetRenderViewHost();
583 // TODO(fsamuel): Investigate whether it's possible to update state earlier
584 // here (see http://crbug.com/158151).
585 Send(new InputMsg_SetFocus(routing_id(), focused_
));
588 RenderWidgetHostImpl::From(rvh
)->set_hung_renderer_delay(
589 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs
));
592 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status
) {
593 SendMessageToEmbedder(
594 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
596 #if defined(OS_CHROMEOS)
597 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM
:
599 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED
:
600 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
602 case base::TERMINATION_STATUS_PROCESS_CRASHED
:
603 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
605 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION
:
607 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
615 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
616 const IPC::Message
& message
) {
617 return (message
.type() != BrowserPluginHostMsg_Attach::ID
) &&
618 (IPC_MESSAGE_CLASS(message
) == BrowserPluginMsgStart
);
621 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message
& message
) {
623 // In --site-per-process, we do not need most of BrowserPluginGuest to drive
624 // inner WebContents.
625 // Right now InputHostMsg_ImeCompositionRangeChanged hits NOTREACHED() in
626 // RWHVChildFrame, so we're disabling message handling entirely here.
627 // TODO(lazyboy): Fix this as part of http://crbug.com/330264. The required
628 // parts of code from this class should be extracted to a separate class for
629 // --site-per-process.
630 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
634 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest
, message
)
635 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition
,
636 OnImeCancelComposition
)
637 #if defined(OS_MACOSX) || defined(USE_AURA)
638 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged
,
639 OnImeCompositionRangeChanged
)
641 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers
,
642 OnHasTouchEventHandlers
)
643 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse
, OnLockMouse
)
644 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget
, OnShowWidget
)
645 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus
, OnTakeFocus
)
646 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged
,
647 OnTextInputStateChanged
)
648 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse
, OnUnlockMouse
)
649 IPC_MESSAGE_UNHANDLED(handled
= false)
650 IPC_END_MESSAGE_MAP()
654 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message
& message
,
655 RenderFrameHost
* render_frame_host
) {
656 // This will eventually be the home for more IPC handlers that depend on
657 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
658 // compile if there are no handlers for a platform. So we have both #if guards
659 // around the whole thing (unfortunate but temporary), and #if guards where
660 // they belong, only around the one IPC handler. TODO(avi): Move more of the
661 // frame-based handlers to this function and remove the outer #if layer.
662 #if defined(OS_MACOSX)
664 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest
, message
,
666 #if defined(OS_MACOSX)
667 // MacOS X creates and populates platform-specific select drop-down menus
668 // whereas other platforms merely create a popup window that the guest
669 // renderer process paints inside.
670 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup
, OnShowPopup
)
672 IPC_MESSAGE_UNHANDLED(handled
= false)
673 IPC_END_MESSAGE_MAP()
680 void BrowserPluginGuest::Attach(
681 int browser_plugin_instance_id
,
682 WebContentsImpl
* embedder_web_contents
,
683 const BrowserPluginHostMsg_Attach_Params
& params
) {
684 browser_plugin_instance_id_
= browser_plugin_instance_id
;
685 // If a guest is detaching from one container and attaching to another
686 // container, then late arriving ACKs may be lost if the mapping from
687 // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
688 // ensure that we always get new frames on attachment by ACKing the pending
689 // frame if it's still waiting on the ACK.
690 if (last_pending_frame_
) {
691 cc::CompositorFrameAck ack
;
692 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
693 last_pending_frame_
->producing_route_id
,
694 last_pending_frame_
->output_surface_id
,
695 last_pending_frame_
->producing_host_id
,
697 last_pending_frame_
.reset();
700 // The guest is owned by the embedder. Attach is queued up so we cannot
701 // change embedders before attach completes. If the embedder goes away,
702 // so does the guest and so we will never call WillAttachComplete because
703 // we have a weak ptr.
704 delegate_
->WillAttach(embedder_web_contents
, browser_plugin_instance_id
,
705 params
.is_full_page_plugin
,
706 base::Bind(&BrowserPluginGuest::OnWillAttachComplete
,
707 weak_ptr_factory_
.GetWeakPtr(),
708 embedder_web_contents
, params
));
711 void BrowserPluginGuest::OnWillAttachComplete(
712 WebContentsImpl
* embedder_web_contents
,
713 const BrowserPluginHostMsg_Attach_Params
& params
) {
714 bool use_cross_process_frames
=
715 BrowserPluginGuestMode::UseCrossProcessFramesForGuests();
716 // If a RenderView has already been created for this new window, then we need
717 // to initialize the browser-side state now so that the RenderFrameHostManager
718 // does not create a new RenderView on navigation.
719 if (!use_cross_process_frames
&& has_render_view_
) {
720 // This will trigger a callback to RenderViewReady after a round-trip IPC.
721 static_cast<RenderViewHostImpl
*>(
722 GetWebContents()->GetRenderViewHost())->Init();
723 WebContentsViewGuest
* web_contents_view
=
724 static_cast<WebContentsViewGuest
*>(GetWebContents()->GetView());
725 if (!web_contents()->GetRenderViewHost()->GetView()) {
726 web_contents_view
->CreateViewForWidget(
727 web_contents()->GetRenderViewHost(), true);
731 InitInternal(params
, embedder_web_contents
);
734 has_attached_since_surface_set_
= true;
735 SendQueuedMessages();
737 delegate_
->DidAttach(GetGuestProxyRoutingID());
739 if (!use_cross_process_frames
)
740 has_render_view_
= true;
742 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
745 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
746 int browser_plugin_instance_id
,
747 const FrameHostMsg_CompositorFrameSwappedACK_Params
& params
) {
748 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params
.producing_route_id
,
749 params
.output_surface_id
,
750 params
.producing_host_id
,
752 last_pending_frame_
.reset();
755 void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id
) {
759 // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
760 // it's attached again.
763 delegate_
->DidDetach();
766 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id
,
767 blink::WebDragStatus drag_status
,
768 const DropData
& drop_data
,
769 blink::WebDragOperationsMask mask
,
770 const gfx::Point
& location
) {
771 RenderViewHost
* host
= GetWebContents()->GetRenderViewHost();
772 auto embedder
= owner_web_contents_
->GetBrowserPluginEmbedder();
773 switch (drag_status
) {
774 case blink::WebDragStatusEnter
:
775 // Only track the URL being dragged over the guest if the link isn't
776 // coming from the guest.
777 if (!embedder
->DragEnteredGuest(this))
778 dragged_url_
= drop_data
.url
;
779 host
->DragTargetDragEnter(drop_data
, location
, location
, mask
, 0);
781 case blink::WebDragStatusOver
:
782 host
->DragTargetDragOver(location
, location
, mask
, 0);
784 case blink::WebDragStatusLeave
:
785 embedder
->DragLeftGuest(this);
786 host
->DragTargetDragLeave();
788 case blink::WebDragStatusDrop
:
789 host
->DragTargetDrop(location
, location
, 0);
790 if (dragged_url_
.is_valid()) {
791 delegate_
->DidDropLink(dragged_url_
);
792 dragged_url_
= GURL();
795 case blink::WebDragStatusUnknown
:
798 last_drag_status_
= drag_status
;
799 EndSystemDragIfApplicable();
802 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id
,
803 const std::string
& name
) {
804 RenderFrameHost
* focused_frame
= web_contents()->GetFocusedFrame();
808 focused_frame
->Send(new InputMsg_ExecuteNoValueEditCommand(
809 focused_frame
->GetRoutingID(), name
));
812 void BrowserPluginGuest::OnImeSetComposition(
813 int browser_plugin_instance_id
,
814 const std::string
& text
,
815 const std::vector
<blink::WebCompositionUnderline
>& underlines
,
818 Send(new InputMsg_ImeSetComposition(routing_id(),
819 base::UTF8ToUTF16(text
), underlines
,
820 selection_start
, selection_end
));
823 void BrowserPluginGuest::OnImeConfirmComposition(
824 int browser_plugin_instance_id
,
825 const std::string
& text
,
826 bool keep_selection
) {
827 Send(new InputMsg_ImeConfirmComposition(routing_id(),
828 base::UTF8ToUTF16(text
),
829 gfx::Range::InvalidRange(),
833 void BrowserPluginGuest::OnExtendSelectionAndDelete(
834 int browser_plugin_instance_id
,
837 RenderFrameHostImpl
* rfh
= static_cast<RenderFrameHostImpl
*>(
838 web_contents()->GetFocusedFrame());
840 rfh
->ExtendSelectionAndDelete(before
, after
);
843 void BrowserPluginGuest::OnReclaimCompositorResources(
844 int browser_plugin_instance_id
,
845 const FrameHostMsg_ReclaimCompositorResources_Params
& params
) {
846 RenderWidgetHostImpl::SendReclaimCompositorResources(params
.route_id
,
847 params
.output_surface_id
,
848 params
.renderer_host_id
,
852 void BrowserPluginGuest::OnLockMouse(bool user_gesture
,
853 bool last_unlocked_by_target
,
855 if (pending_lock_request_
) {
856 // Immediately reject the lock because only one pointerLock may be active
858 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
862 pending_lock_request_
= true;
864 delegate_
->RequestPointerLockPermission(
866 last_unlocked_by_target
,
867 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse
,
868 weak_ptr_factory_
.GetWeakPtr()));
871 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id
,
873 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded
));
874 pending_lock_request_
= false;
876 mouse_locked_
= true;
879 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id
,
881 blink::WebFocusType focus_type
) {
882 RenderWidgetHostView
* rwhv
= web_contents()->GetRenderWidgetHostView();
883 RenderWidgetHost
* rwh
= rwhv
? rwhv
->GetRenderWidgetHost() : nullptr;
884 SetFocus(rwh
, focused
, focus_type
);
887 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
888 int browser_plugin_instance_id
,
889 const std::vector
<EditCommand
>& edit_commands
) {
890 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
894 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id
,
896 guest_visible_
= visible
;
897 if (embedder_visible_
&& guest_visible_
)
898 GetWebContents()->WasShown();
900 GetWebContents()->WasHidden();
903 void BrowserPluginGuest::OnUnlockMouse() {
904 SendMessageToEmbedder(
905 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
908 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id
) {
909 // mouse_locked_ could be false here if the lock attempt was cancelled due
910 // to window focus, or for various other reasons before the guest was informed
911 // of the lock's success.
913 Send(new ViewMsg_MouseLockLost(routing_id()));
914 mouse_locked_
= false;
917 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id
,
918 const gfx::Rect
& view_rect
) {
919 // The plugin has moved within the embedder without resizing or the
920 // embedder/container's view rect changing.
921 guest_window_rect_
= view_rect
;
922 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
923 GetWebContents()->GetRenderViewHost());
925 rvh
->SendScreenRects();
928 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept
) {
929 SendMessageToEmbedder(
930 new BrowserPluginMsg_ShouldAcceptTouchEvents(
931 browser_plugin_instance_id(), accept
));
934 #if defined(OS_MACOSX)
935 void BrowserPluginGuest::OnShowPopup(
936 RenderFrameHost
* render_frame_host
,
937 const FrameHostMsg_ShowPopup_Params
& params
) {
938 gfx::Rect
translated_bounds(params
.bounds
);
939 translated_bounds
.Offset(guest_window_rect_
.OffsetFromOrigin());
940 BrowserPluginPopupMenuHelper
popup_menu_helper(
941 owner_web_contents_
->GetRenderViewHost(), render_frame_host
);
942 popup_menu_helper
.ShowPopupMenu(translated_bounds
,
944 params
.item_font_size
,
945 params
.selected_item
,
947 params
.right_aligned
,
948 params
.allow_multiple_selection
);
952 void BrowserPluginGuest::OnShowWidget(int route_id
,
953 const gfx::Rect
& initial_rect
) {
954 GetWebContents()->ShowCreatedWidget(route_id
, initial_rect
);
957 void BrowserPluginGuest::OnTakeFocus(bool reverse
) {
958 SendMessageToEmbedder(
959 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse
));
962 void BrowserPluginGuest::OnTextInputStateChanged(
963 const ViewHostMsg_TextInputState_Params
& params
) {
964 // Save the state of text input so we can restore it on focus.
965 last_text_input_type_
= params
.type
;
966 last_input_mode_
= params
.mode
;
967 last_input_flags_
= params
.flags
;
968 last_can_compose_inline_
= params
.can_compose_inline
;
970 SendTextInputTypeChangedToView(
971 static_cast<RenderWidgetHostViewBase
*>(
972 web_contents()->GetRenderWidgetHostView()));
975 void BrowserPluginGuest::OnImeCancelComposition() {
976 static_cast<RenderWidgetHostViewBase
*>(
977 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
980 #if defined(OS_MACOSX) || defined(USE_AURA)
981 void BrowserPluginGuest::OnImeCompositionRangeChanged(
982 const gfx::Range
& range
,
983 const std::vector
<gfx::Rect
>& character_bounds
) {
984 static_cast<RenderWidgetHostViewBase
*>(
985 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
986 range
, character_bounds
);
990 } // namespace content