Add remoting and PPAPI tests to GN build
[chromium-blink-merge.git] / content / browser / browser_plugin / browser_plugin_guest.cc
blob111e7a0812e659d525ecec153f0c4a7bc7889edd
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"
7 #include <algorithm>
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_sizer.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"
43 #endif
45 namespace content {
47 class BrowserPluginGuest::EmbedderVisibilityObserver
48 : public WebContentsObserver {
49 public:
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);
66 private:
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),
77 attached_(false),
78 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
79 focused_(false),
80 mouse_locked_(false),
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),
87 initialized_(false),
88 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
89 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
90 last_input_flags_(0),
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),
96 delegate_(delegate),
97 weak_ptr_factory_(this) {
98 DCHECK(web_contents);
99 DCHECK(delegate);
100 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
101 web_contents->SetBrowserPluginGuest(this);
102 delegate->RegisterDestructionCallback(
103 base::Bind(&BrowserPluginGuest::WillDestroy, AsWeakPtr()));
104 delegate->SetGuestSizer(this);
107 void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) {
108 GetWebContents()->GetView()->SizeContents(new_size);
111 void BrowserPluginGuest::Init() {
112 if (initialized_)
113 return;
114 initialized_ = true;
116 // TODO(fsamuel): Initiailization prior to attachment should be behind a
117 // command line flag once we introduce experimental guest types that rely on
118 // this functionality.
119 if (!delegate_->CanRunInDetachedState())
120 return;
122 WebContentsImpl* owner_web_contents = static_cast<WebContentsImpl*>(
123 delegate_->GetOwnerWebContents());
124 InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents);
127 void BrowserPluginGuest::WillDestroy() {
128 is_in_destruction_ = true;
129 owner_web_contents_ = nullptr;
130 attached_ = false;
133 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
134 return weak_ptr_factory_.GetWeakPtr();
137 void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh,
138 bool focused,
139 blink::WebFocusType focus_type) {
140 focused_ = focused;
141 if (!rwh)
142 return;
144 if ((focus_type == blink::WebFocusTypeForward) ||
145 (focus_type == blink::WebFocusTypeBackward)) {
146 static_cast<RenderViewHostImpl*>(RenderViewHost::From(rwh))->
147 SetInitialFocus(focus_type == blink::WebFocusTypeBackward);
149 rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
150 if (!focused && mouse_locked_)
151 OnUnlockMouse();
153 // Restore the last seen state of text input to the view.
154 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
155 rwh->GetView());
156 if (rwhv) {
157 rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
158 last_can_compose_inline_, last_input_flags_);
162 void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
163 if (tooltip_text == current_tooltip_text_)
164 return;
165 current_tooltip_text_ = tooltip_text;
167 SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
168 browser_plugin_instance_id_, tooltip_text));
171 bool BrowserPluginGuest::LockMouse(bool allowed) {
172 if (!attached() || (mouse_locked_ == allowed))
173 return false;
175 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
178 WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow(
179 const WebContents::CreateParams& params) {
180 WebContentsImpl* new_contents =
181 static_cast<WebContentsImpl*>(delegate_->CreateNewGuestWindow(params));
182 DCHECK(new_contents);
183 return new_contents;
186 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
187 const IPC::Message& message) {
188 RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
189 web_contents()->GetRenderWidgetHostView());
190 if (rwhv &&
191 rwhv->OnMessageReceivedFromEmbedder(
192 message,
193 static_cast<RenderViewHostImpl*>(
194 embedder_web_contents()->GetRenderViewHost()))) {
195 return true;
198 bool handled = true;
199 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
200 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
201 OnCompositorFrameSwappedACK)
202 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach)
203 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
204 OnDragStatusUpdate)
205 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
206 OnExecuteEditCommand)
207 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
208 OnExtendSelectionAndDelete)
209 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
210 OnImeConfirmComposition)
211 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
212 OnImeSetComposition)
213 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
214 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
215 OnReclaimCompositorResources)
216 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
217 OnSetEditCommandsForNextKeyEvent)
218 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
219 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
220 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
221 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
222 IPC_MESSAGE_UNHANDLED(handled = false)
223 IPC_END_MESSAGE_MAP()
224 return handled;
227 void BrowserPluginGuest::InitInternal(
228 const BrowserPluginHostMsg_Attach_Params& params,
229 WebContentsImpl* owner_web_contents) {
230 focused_ = params.focused;
231 OnSetFocus(browser_plugin::kInstanceIDNone,
232 focused_,
233 blink::WebFocusTypeNone);
235 guest_visible_ = params.visible;
236 UpdateVisibility();
238 is_full_page_plugin_ = params.is_full_page_plugin;
239 guest_window_rect_ = params.view_rect;
241 if (owner_web_contents_ != owner_web_contents) {
242 WebContentsViewGuest* new_view =
243 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
244 if (owner_web_contents_)
245 new_view->OnGuestDetached(owner_web_contents_->GetView());
247 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
248 // be attached.
249 owner_web_contents_ = owner_web_contents;
250 new_view->OnGuestAttached(owner_web_contents_->GetView());
253 RendererPreferences* renderer_prefs =
254 GetWebContents()->GetMutableRendererPrefs();
255 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
256 // Copy renderer preferences (and nothing else) from the embedder's
257 // WebContents to the guest.
259 // For GTK and Aura this is necessary to get proper renderer configuration
260 // values for caret blinking interval, colors related to selection and
261 // focus.
262 *renderer_prefs = *owner_web_contents_->GetMutableRendererPrefs();
263 renderer_prefs->user_agent_override = guest_user_agent_override;
265 // We would like the guest to report changes to frame names so that we can
266 // update the BrowserPlugin's corresponding 'name' attribute.
267 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
268 renderer_prefs->report_frame_name_changes = true;
269 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
270 // navigations still continue to function inside the app.
271 renderer_prefs->browser_handles_all_top_level_requests = false;
272 // Disable "client blocked" error page for browser plugin.
273 renderer_prefs->disable_client_blocked_error_page = true;
275 embedder_visibility_observer_.reset(new EmbedderVisibilityObserver(this));
277 DCHECK(GetWebContents()->GetRenderViewHost());
279 // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
280 auto render_widget_host =
281 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
282 render_widget_host->NotifyScreenInfoChanged();
284 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
285 // be reset again the next time preferences are updated.
286 WebPreferences prefs =
287 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
288 prefs.navigate_on_drag_drop = false;
289 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
292 BrowserPluginGuest::~BrowserPluginGuest() {
295 // static
296 BrowserPluginGuest* BrowserPluginGuest::Create(
297 WebContentsImpl* web_contents,
298 BrowserPluginGuestDelegate* delegate) {
299 return new BrowserPluginGuest(
300 web_contents->opener() != nullptr, web_contents, delegate);
303 // static
304 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
305 return web_contents && web_contents->GetBrowserPluginGuest();
308 // static
309 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
310 return render_view_host && IsGuest(
311 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
312 render_view_host)));
315 RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
316 if (!owner_web_contents_)
317 return nullptr;
318 return owner_web_contents_->GetRenderWidgetHostView();
321 void BrowserPluginGuest::UpdateVisibility() {
322 OnSetVisibility(browser_plugin_instance_id(), visible());
325 BrowserPluginGuestManager*
326 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
327 return GetWebContents()->GetBrowserContext()->GetGuestManager();
330 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
331 embedder_visible_ = visible;
332 UpdateVisibility();
335 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
336 SendMessageToEmbedder(
337 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
340 void BrowserPluginGuest::SwapCompositorFrame(
341 uint32 output_surface_id,
342 int host_process_id,
343 int host_routing_id,
344 scoped_ptr<cc::CompositorFrame> frame) {
345 cc::RenderPass* root_pass =
346 frame->delegated_frame_data->render_pass_list.back();
347 gfx::Size view_size(gfx::ToFlooredSize(gfx::ScaleSize(
348 root_pass->output_rect.size(),
349 1.0f / frame->metadata.device_scale_factor)));
351 if (last_seen_view_size_ != view_size) {
352 delegate_->GuestSizeChanged(view_size);
353 last_seen_view_size_ = view_size;
356 last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params());
357 frame->AssignTo(&last_pending_frame_->frame);
358 last_pending_frame_->output_surface_id = output_surface_id;
359 last_pending_frame_->producing_route_id = host_routing_id;
360 last_pending_frame_->producing_host_id = host_process_id;
362 SendMessageToEmbedder(
363 new BrowserPluginMsg_CompositorFrameSwapped(
364 browser_plugin_instance_id(), *last_pending_frame_));
367 void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
368 SendMessageToEmbedder(
369 new BrowserPluginMsg_SetContentsOpaque(
370 browser_plugin_instance_id(), opaque));
373 bool BrowserPluginGuest::Find(int request_id,
374 const base::string16& search_text,
375 const blink::WebFindOptions& options) {
376 return delegate_->Find(request_id, search_text, options);
379 bool BrowserPluginGuest::StopFinding(StopFindAction action) {
380 return delegate_->StopFinding(action);
383 WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
384 return static_cast<WebContentsImpl*>(web_contents());
387 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
388 const gfx::Point& relative_position) const {
389 if (!attached())
390 return relative_position;
392 gfx::Point screen_pos(relative_position);
393 screen_pos += guest_window_rect_.OffsetFromOrigin();
394 if (embedder_web_contents()->GetBrowserPluginGuest()) {
395 BrowserPluginGuest* embedder_guest =
396 embedder_web_contents()->GetBrowserPluginGuest();
397 screen_pos += embedder_guest->guest_window_rect_.OffsetFromOrigin();
399 return screen_pos;
402 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
403 if (!attached()) {
404 // Some pages such as data URLs, javascript URLs, and about:blank
405 // do not load external resources and so they load prior to attachment.
406 // As a result, we must save all these IPCs until attachment and then
407 // forward them so that the embedder gets a chance to see and process
408 // the load events.
409 pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
410 return;
412 owner_web_contents_->Send(msg);
415 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
416 int screen_x, int screen_y, blink::WebDragOperation operation) {
417 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
418 screen_x, screen_y, operation);
419 seen_embedder_drag_source_ended_at_ = true;
420 EndSystemDragIfApplicable();
423 void BrowserPluginGuest::EndSystemDragIfApplicable() {
424 // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
425 // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
426 // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
427 // means we call it in all cases and also make sure we only call it once.
428 // This ensures that the input state of the guest stays correct, otherwise
429 // it will go stale and won't accept any further input events.
431 // The strategy used here to call DragSourceSystemDragEnded() on the RVH
432 // is when the following conditions are met:
433 // a. Embedder has seen SystemDragEnded()
434 // b. Embedder has seen DragSourceEndedAt()
435 // c. The guest has seen some drag status update other than
436 // WebDragStatusUnknown. Note that this step should ideally be done
437 // differently: The guest has seen at least one of
438 // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
439 // a source quickly outside of <webview> bounds, then the
440 // BrowserPluginGuest never sees any of these drag status updates,
441 // there we just check whether we've seen any drag status update or
442 // not.
443 if (last_drag_status_ != blink::WebDragStatusOver &&
444 seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
445 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
446 GetWebContents()->GetRenderViewHost());
447 guest_rvh->DragSourceSystemDragEnded();
448 last_drag_status_ = blink::WebDragStatusUnknown;
449 seen_embedder_system_drag_ended_ = false;
450 seen_embedder_drag_source_ended_at_ = false;
451 dragged_url_ = GURL();
455 void BrowserPluginGuest::EmbedderSystemDragEnded() {
456 seen_embedder_system_drag_ended_ = true;
457 EndSystemDragIfApplicable();
460 void BrowserPluginGuest::SendQueuedMessages() {
461 if (!attached())
462 return;
464 while (!pending_messages_.empty()) {
465 linked_ptr<IPC::Message> message_ptr = pending_messages_.front();
466 pending_messages_.pop_front();
467 SendMessageToEmbedder(message_ptr.release());
471 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
472 RenderFrameHost* render_frame_host,
473 const GURL& url,
474 ui::PageTransition transition_type) {
475 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
478 void BrowserPluginGuest::RenderViewReady() {
479 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
480 // TODO(fsamuel): Investigate whether it's possible to update state earlier
481 // here (see http://crbug.com/158151).
482 Send(new InputMsg_SetFocus(routing_id(), focused_));
483 UpdateVisibility();
485 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay_ms(
486 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
489 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
490 SendMessageToEmbedder(
491 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
492 switch (status) {
493 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
494 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
495 break;
496 case base::TERMINATION_STATUS_PROCESS_CRASHED:
497 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
498 break;
499 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
500 RecordAction(
501 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
502 break;
503 default:
504 break;
508 // static
509 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
510 const IPC::Message& message) {
511 switch (message.type()) {
512 case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID:
513 case BrowserPluginHostMsg_Detach::ID:
514 case BrowserPluginHostMsg_DragStatusUpdate::ID:
515 case BrowserPluginHostMsg_ExecuteEditCommand::ID:
516 case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
517 case BrowserPluginHostMsg_HandleInputEvent::ID:
518 case BrowserPluginHostMsg_ImeConfirmComposition::ID:
519 case BrowserPluginHostMsg_ImeSetComposition::ID:
520 case BrowserPluginHostMsg_LockMouse_ACK::ID:
521 case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
522 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
523 case BrowserPluginHostMsg_SetFocus::ID:
524 case BrowserPluginHostMsg_SetVisibility::ID:
525 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
526 case BrowserPluginHostMsg_UpdateGeometry::ID:
527 return true;
528 default:
529 return false;
533 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
534 bool handled = true;
535 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
536 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
537 OnImeCancelComposition)
538 #if defined(OS_MACOSX) || defined(USE_AURA)
539 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
540 OnImeCompositionRangeChanged)
541 #endif
542 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
543 OnHasTouchEventHandlers)
544 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
545 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
546 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
547 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
548 OnTextInputTypeChanged)
549 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
550 IPC_MESSAGE_UNHANDLED(handled = false)
551 IPC_END_MESSAGE_MAP()
552 return handled;
555 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message,
556 RenderFrameHost* render_frame_host) {
557 // This will eventually be the home for more IPC handlers that depend on
558 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
559 // compile if there are no handlers for a platform. So we have both #if guards
560 // around the whole thing (unfortunate but temporary), and #if guards where
561 // they belong, only around the one IPC handler. TODO(avi): Move more of the
562 // frame-based handlers to this function and remove the outer #if layer.
563 #if defined(OS_MACOSX)
564 bool handled = true;
565 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message,
566 render_frame_host)
567 #if defined(OS_MACOSX)
568 // MacOS X creates and populates platform-specific select drop-down menus
569 // whereas other platforms merely create a popup window that the guest
570 // renderer process paints inside.
571 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
572 #endif
573 IPC_MESSAGE_UNHANDLED(handled = false)
574 IPC_END_MESSAGE_MAP()
575 return handled;
576 #else
577 return false;
578 #endif
581 void BrowserPluginGuest::Attach(
582 int browser_plugin_instance_id,
583 WebContentsImpl* embedder_web_contents,
584 const BrowserPluginHostMsg_Attach_Params& params) {
585 browser_plugin_instance_id_ = browser_plugin_instance_id;
586 // If a guest is detaching from one container and attaching to another
587 // container, then late arriving ACKs may be lost if the mapping from
588 // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
589 // ensure that we always get new frames on attachment by ACKing the pending
590 // frame if it's still waiting on the ACK.
591 if (last_pending_frame_) {
592 cc::CompositorFrameAck ack;
593 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
594 last_pending_frame_->producing_route_id,
595 last_pending_frame_->output_surface_id,
596 last_pending_frame_->producing_host_id,
597 ack);
598 last_pending_frame_.reset();
600 delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id,
601 params.is_full_page_plugin);
603 // If a RenderView has already been created for this new window, then we need
604 // to initialize the browser-side state now so that the RenderFrameHostManager
605 // does not create a new RenderView on navigation.
606 if (has_render_view_) {
607 // This will trigger a callback to RenderViewReady after a round-trip IPC.
608 static_cast<RenderViewHostImpl*>(
609 GetWebContents()->GetRenderViewHost())->Init();
610 WebContentsViewGuest* web_contents_view =
611 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
612 if (!web_contents()->GetRenderViewHost()->GetView()) {
613 web_contents_view->CreateViewForWidget(
614 web_contents()->GetRenderViewHost(), true);
618 InitInternal(params, embedder_web_contents);
620 attached_ = true;
621 SendQueuedMessages();
623 // Create a swapped out RenderView for the guest in the embedder render
624 // process, so that the embedder can access the guest's window object.
625 // On reattachment, we can reuse the same swapped out RenderView because
626 // the embedder process will always be the same even if the embedder
627 // WebContents changes.
628 if (guest_proxy_routing_id_ == MSG_ROUTING_NONE) {
629 guest_proxy_routing_id_ =
630 GetWebContents()->CreateSwappedOutRenderView(
631 owner_web_contents_->GetSiteInstance());
634 delegate_->DidAttach(guest_proxy_routing_id_);
636 has_render_view_ = true;
638 // Enable input method for guest if it's enabled for the embedder.
639 if (static_cast<RenderViewHostImpl*>(
640 owner_web_contents_->GetRenderViewHost())->input_method_active()) {
641 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
642 GetWebContents()->GetRenderViewHost());
643 guest_rvh->SetInputMethodActive(true);
646 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
649 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
650 int browser_plugin_instance_id,
651 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
652 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
653 params.output_surface_id,
654 params.producing_host_id,
655 params.ack);
656 last_pending_frame_.reset();
659 void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
660 if (!attached())
661 return;
663 // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
664 // it's attached again.
665 attached_ = false;
667 delegate_->DidDetach();
670 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
671 blink::WebDragStatus drag_status,
672 const DropData& drop_data,
673 blink::WebDragOperationsMask mask,
674 const gfx::Point& location) {
675 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
676 auto embedder = owner_web_contents_->GetBrowserPluginEmbedder();
677 switch (drag_status) {
678 case blink::WebDragStatusEnter:
679 // Only track the URL being dragged over the guest if the link isn't
680 // coming from the guest.
681 if (!embedder->DragEnteredGuest(this))
682 dragged_url_ = drop_data.url;
683 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
684 break;
685 case blink::WebDragStatusOver:
686 host->DragTargetDragOver(location, location, mask, 0);
687 break;
688 case blink::WebDragStatusLeave:
689 embedder->DragLeftGuest(this);
690 host->DragTargetDragLeave();
691 break;
692 case blink::WebDragStatusDrop:
693 host->DragTargetDrop(location, location, 0);
694 if (dragged_url_.is_valid()) {
695 delegate_->DidDropLink(dragged_url_);
696 dragged_url_ = GURL();
698 break;
699 case blink::WebDragStatusUnknown:
700 NOTREACHED();
702 last_drag_status_ = drag_status;
703 EndSystemDragIfApplicable();
706 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
707 const std::string& name) {
708 RenderFrameHost* focused_frame = web_contents()->GetFocusedFrame();
709 if (!focused_frame)
710 return;
712 focused_frame->Send(new InputMsg_ExecuteNoValueEditCommand(
713 focused_frame->GetRoutingID(), name));
716 void BrowserPluginGuest::OnImeSetComposition(
717 int browser_plugin_instance_id,
718 const std::string& text,
719 const std::vector<blink::WebCompositionUnderline>& underlines,
720 int selection_start,
721 int selection_end) {
722 Send(new InputMsg_ImeSetComposition(routing_id(),
723 base::UTF8ToUTF16(text), underlines,
724 selection_start, selection_end));
727 void BrowserPluginGuest::OnImeConfirmComposition(
728 int browser_plugin_instance_id,
729 const std::string& text,
730 bool keep_selection) {
731 Send(new InputMsg_ImeConfirmComposition(routing_id(),
732 base::UTF8ToUTF16(text),
733 gfx::Range::InvalidRange(),
734 keep_selection));
737 void BrowserPluginGuest::OnExtendSelectionAndDelete(
738 int browser_plugin_instance_id,
739 int before,
740 int after) {
741 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
742 web_contents()->GetFocusedFrame());
743 if (rfh)
744 rfh->ExtendSelectionAndDelete(before, after);
747 void BrowserPluginGuest::OnReclaimCompositorResources(
748 int browser_plugin_instance_id,
749 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
750 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
751 params.output_surface_id,
752 params.renderer_host_id,
753 params.ack);
756 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
757 bool last_unlocked_by_target,
758 bool privileged) {
759 if (pending_lock_request_) {
760 // Immediately reject the lock because only one pointerLock may be active
761 // at a time.
762 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
763 return;
766 pending_lock_request_ = true;
768 delegate_->RequestPointerLockPermission(
769 user_gesture,
770 last_unlocked_by_target,
771 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
772 weak_ptr_factory_.GetWeakPtr()));
775 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
776 bool succeeded) {
777 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
778 pending_lock_request_ = false;
779 if (succeeded)
780 mouse_locked_ = true;
783 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id,
784 bool focused,
785 blink::WebFocusType focus_type) {
786 RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
787 RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : nullptr;
788 SetFocus(rwh, focused, focus_type);
791 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
792 int browser_plugin_instance_id,
793 const std::vector<EditCommand>& edit_commands) {
794 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
795 edit_commands));
798 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
799 bool visible) {
800 guest_visible_ = visible;
801 if (embedder_visible_ && guest_visible_)
802 GetWebContents()->WasShown();
803 else
804 GetWebContents()->WasHidden();
807 void BrowserPluginGuest::OnUnlockMouse() {
808 SendMessageToEmbedder(
809 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
812 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
813 // mouse_locked_ could be false here if the lock attempt was cancelled due
814 // to window focus, or for various other reasons before the guest was informed
815 // of the lock's success.
816 if (mouse_locked_)
817 Send(new ViewMsg_MouseLockLost(routing_id()));
818 mouse_locked_ = false;
821 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
822 const gfx::Rect& view_rect) {
823 // The plugin has moved within the embedder without resizing or the
824 // embedder/container's view rect changing.
825 guest_window_rect_ = view_rect;
826 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
827 GetWebContents()->GetRenderViewHost());
828 if (rvh)
829 rvh->SendScreenRects();
832 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
833 SendMessageToEmbedder(
834 new BrowserPluginMsg_ShouldAcceptTouchEvents(
835 browser_plugin_instance_id(), accept));
838 #if defined(OS_MACOSX)
839 void BrowserPluginGuest::OnShowPopup(
840 RenderFrameHost* render_frame_host,
841 const FrameHostMsg_ShowPopup_Params& params) {
842 gfx::Rect translated_bounds(params.bounds);
843 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
844 BrowserPluginPopupMenuHelper popup_menu_helper(
845 owner_web_contents_->GetRenderViewHost(), render_frame_host);
846 popup_menu_helper.ShowPopupMenu(translated_bounds,
847 params.item_height,
848 params.item_font_size,
849 params.selected_item,
850 params.popup_items,
851 params.right_aligned,
852 params.allow_multiple_selection);
854 #endif
856 void BrowserPluginGuest::OnShowWidget(int route_id,
857 const gfx::Rect& initial_rect) {
858 GetWebContents()->ShowCreatedWidget(route_id, initial_rect);
861 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
862 SendMessageToEmbedder(
863 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
866 void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
867 ui::TextInputMode input_mode,
868 bool can_compose_inline,
869 int flags) {
870 // Save the state of text input so we can restore it on focus.
871 last_text_input_type_ = type;
872 last_input_mode_ = input_mode;
873 last_input_flags_ = flags;
874 last_can_compose_inline_ = can_compose_inline;
876 static_cast<RenderWidgetHostViewBase*>(
877 web_contents()->GetRenderWidgetHostView())->TextInputTypeChanged(
878 type, input_mode, can_compose_inline, flags);
881 void BrowserPluginGuest::OnImeCancelComposition() {
882 static_cast<RenderWidgetHostViewBase*>(
883 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
886 #if defined(OS_MACOSX) || defined(USE_AURA)
887 void BrowserPluginGuest::OnImeCompositionRangeChanged(
888 const gfx::Range& range,
889 const std::vector<gfx::Rect>& character_bounds) {
890 static_cast<RenderWidgetHostViewBase*>(
891 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
892 range, character_bounds);
894 #endif
896 } // namespace content