Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / browser_plugin / browser_plugin_guest.cc
blob3f3d7cad9134af58a64b6fa8127542e92ed0f21c
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_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"
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->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
118 // to enable this.
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;
139 attached_ = false;
142 void BrowserPluginGuest::Init() {
143 if (initialized_)
144 return;
145 initialized_ = true;
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())
151 return;
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,
164 bool focused,
165 blink::WebFocusType focus_type) {
166 focused_ = focused;
167 if (!rwh)
168 return;
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_)
177 OnUnlockMouse();
179 // Restore the last seen state of text input to the view.
180 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
181 rwh->GetView());
182 SendTextInputTypeChangedToView(rwhv);
185 void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
186 if (tooltip_text == current_tooltip_text_)
187 return;
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))
196 return false;
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);
206 return new_contents;
209 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
210 const IPC::Message& message) {
211 RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
212 web_contents()->GetRenderWidgetHostView());
213 if (rwhv &&
214 rwhv->OnMessageReceivedFromEmbedder(
215 message,
216 static_cast<RenderViewHostImpl*>(
217 embedder_web_contents()->GetRenderViewHost()))) {
218 return true;
221 bool handled = true;
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,
227 OnDragStatusUpdate)
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,
235 OnImeSetComposition)
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()
247 return handled;
250 void BrowserPluginGuest::InitInternal(
251 const BrowserPluginHostMsg_Attach_Params& params,
252 WebContentsImpl* owner_web_contents) {
253 focused_ = params.focused;
254 OnSetFocus(browser_plugin::kInstanceIDNone,
255 focused_,
256 blink::WebFocusTypeNone);
258 guest_visible_ = params.visible;
259 UpdateVisibility();
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
271 // be attached.
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
284 // focus.
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() {
318 // static
319 BrowserPluginGuest* BrowserPluginGuest::Create(
320 WebContentsImpl* web_contents,
321 BrowserPluginGuestDelegate* delegate) {
322 return new BrowserPluginGuest(
323 web_contents->opener() != nullptr, web_contents, delegate);
326 // static
327 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
328 return web_contents && web_contents->GetBrowserPluginGuest();
331 // static
332 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
333 return render_view_host && IsGuest(
334 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
335 render_view_host)));
338 RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
339 if (!owner_web_contents_)
340 return nullptr;
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;
355 UpdateVisibility();
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,
365 int host_process_id,
366 int host_routing_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 {
412 if (!attached())
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();
422 return screen_pos;
425 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
426 if (!attached()) {
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
431 // the load events.
432 pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
433 return;
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
465 // not.
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() {
484 if (!attached())
485 return;
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) {
496 if (!guest_rwhv)
497 return;
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.
508 return;
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()) {
516 return;
518 RenderViewHostImpl* guest_rvh =
519 static_cast<RenderViewHostImpl*>(GetWebContents()->GetRenderViewHost());
520 guest_rvh->SetInputMethodActive(true);
523 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
524 RenderFrameHost* render_frame_host,
525 const GURL& url,
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_));
535 UpdateVisibility();
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()));
544 switch (status) {
545 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
546 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
547 break;
548 case base::TERMINATION_STATUS_PROCESS_CRASHED:
549 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
550 break;
551 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
552 RecordAction(
553 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
554 break;
555 default:
556 break;
560 // static
561 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
562 const IPC::Message& message) {
563 switch (message.type()) {
564 case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID:
565 case BrowserPluginHostMsg_Detach::ID:
566 case BrowserPluginHostMsg_DragStatusUpdate::ID:
567 case BrowserPluginHostMsg_ExecuteEditCommand::ID:
568 case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
569 case BrowserPluginHostMsg_HandleInputEvent::ID:
570 case BrowserPluginHostMsg_ImeConfirmComposition::ID:
571 case BrowserPluginHostMsg_ImeSetComposition::ID:
572 case BrowserPluginHostMsg_LockMouse_ACK::ID:
573 case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
574 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
575 case BrowserPluginHostMsg_SetFocus::ID:
576 case BrowserPluginHostMsg_SetVisibility::ID:
577 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
578 case BrowserPluginHostMsg_UpdateGeometry::ID:
579 return true;
580 default:
581 return false;
585 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
586 bool handled = true;
587 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
588 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
589 OnImeCancelComposition)
590 #if defined(OS_MACOSX) || defined(USE_AURA)
591 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
592 OnImeCompositionRangeChanged)
593 #endif
594 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
595 OnHasTouchEventHandlers)
596 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
597 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
598 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
599 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
600 OnTextInputTypeChanged)
601 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
602 IPC_MESSAGE_UNHANDLED(handled = false)
603 IPC_END_MESSAGE_MAP()
604 return handled;
607 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message,
608 RenderFrameHost* render_frame_host) {
609 // This will eventually be the home for more IPC handlers that depend on
610 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
611 // compile if there are no handlers for a platform. So we have both #if guards
612 // around the whole thing (unfortunate but temporary), and #if guards where
613 // they belong, only around the one IPC handler. TODO(avi): Move more of the
614 // frame-based handlers to this function and remove the outer #if layer.
615 #if defined(OS_MACOSX)
616 bool handled = true;
617 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message,
618 render_frame_host)
619 #if defined(OS_MACOSX)
620 // MacOS X creates and populates platform-specific select drop-down menus
621 // whereas other platforms merely create a popup window that the guest
622 // renderer process paints inside.
623 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
624 #endif
625 IPC_MESSAGE_UNHANDLED(handled = false)
626 IPC_END_MESSAGE_MAP()
627 return handled;
628 #else
629 return false;
630 #endif
633 void BrowserPluginGuest::Attach(
634 int browser_plugin_instance_id,
635 WebContentsImpl* embedder_web_contents,
636 const BrowserPluginHostMsg_Attach_Params& params) {
637 browser_plugin_instance_id_ = browser_plugin_instance_id;
638 // If a guest is detaching from one container and attaching to another
639 // container, then late arriving ACKs may be lost if the mapping from
640 // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
641 // ensure that we always get new frames on attachment by ACKing the pending
642 // frame if it's still waiting on the ACK.
643 if (last_pending_frame_) {
644 cc::CompositorFrameAck ack;
645 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
646 last_pending_frame_->producing_route_id,
647 last_pending_frame_->output_surface_id,
648 last_pending_frame_->producing_host_id,
649 ack);
650 last_pending_frame_.reset();
652 delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id,
653 params.is_full_page_plugin);
655 // If a RenderView has already been created for this new window, then we need
656 // to initialize the browser-side state now so that the RenderFrameHostManager
657 // does not create a new RenderView on navigation.
658 if (has_render_view_) {
659 // This will trigger a callback to RenderViewReady after a round-trip IPC.
660 static_cast<RenderViewHostImpl*>(
661 GetWebContents()->GetRenderViewHost())->Init();
662 WebContentsViewGuest* web_contents_view =
663 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
664 if (!web_contents()->GetRenderViewHost()->GetView()) {
665 web_contents_view->CreateViewForWidget(
666 web_contents()->GetRenderViewHost(), true);
670 InitInternal(params, embedder_web_contents);
672 attached_ = true;
673 SendQueuedMessages();
675 delegate_->DidAttach(GetGuestProxyRoutingID());
677 has_render_view_ = true;
679 // Enable input method for guest if it's enabled for the embedder.
680 if (static_cast<RenderViewHostImpl*>(
681 owner_web_contents_->GetRenderViewHost())->input_method_active()) {
682 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
683 GetWebContents()->GetRenderViewHost());
684 guest_rvh->SetInputMethodActive(true);
687 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
690 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
691 int browser_plugin_instance_id,
692 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
693 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
694 params.output_surface_id,
695 params.producing_host_id,
696 params.ack);
697 last_pending_frame_.reset();
700 void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
701 if (!attached())
702 return;
704 // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
705 // it's attached again.
706 attached_ = false;
708 delegate_->DidDetach();
711 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
712 blink::WebDragStatus drag_status,
713 const DropData& drop_data,
714 blink::WebDragOperationsMask mask,
715 const gfx::Point& location) {
716 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
717 auto embedder = owner_web_contents_->GetBrowserPluginEmbedder();
718 switch (drag_status) {
719 case blink::WebDragStatusEnter:
720 // Only track the URL being dragged over the guest if the link isn't
721 // coming from the guest.
722 if (!embedder->DragEnteredGuest(this))
723 dragged_url_ = drop_data.url;
724 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
725 break;
726 case blink::WebDragStatusOver:
727 host->DragTargetDragOver(location, location, mask, 0);
728 break;
729 case blink::WebDragStatusLeave:
730 embedder->DragLeftGuest(this);
731 host->DragTargetDragLeave();
732 break;
733 case blink::WebDragStatusDrop:
734 host->DragTargetDrop(location, location, 0);
735 if (dragged_url_.is_valid()) {
736 delegate_->DidDropLink(dragged_url_);
737 dragged_url_ = GURL();
739 break;
740 case blink::WebDragStatusUnknown:
741 NOTREACHED();
743 last_drag_status_ = drag_status;
744 EndSystemDragIfApplicable();
747 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
748 const std::string& name) {
749 RenderFrameHost* focused_frame = web_contents()->GetFocusedFrame();
750 if (!focused_frame)
751 return;
753 focused_frame->Send(new InputMsg_ExecuteNoValueEditCommand(
754 focused_frame->GetRoutingID(), name));
757 void BrowserPluginGuest::OnImeSetComposition(
758 int browser_plugin_instance_id,
759 const std::string& text,
760 const std::vector<blink::WebCompositionUnderline>& underlines,
761 int selection_start,
762 int selection_end) {
763 Send(new InputMsg_ImeSetComposition(routing_id(),
764 base::UTF8ToUTF16(text), underlines,
765 selection_start, selection_end));
768 void BrowserPluginGuest::OnImeConfirmComposition(
769 int browser_plugin_instance_id,
770 const std::string& text,
771 bool keep_selection) {
772 Send(new InputMsg_ImeConfirmComposition(routing_id(),
773 base::UTF8ToUTF16(text),
774 gfx::Range::InvalidRange(),
775 keep_selection));
778 void BrowserPluginGuest::OnExtendSelectionAndDelete(
779 int browser_plugin_instance_id,
780 int before,
781 int after) {
782 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
783 web_contents()->GetFocusedFrame());
784 if (rfh)
785 rfh->ExtendSelectionAndDelete(before, after);
788 void BrowserPluginGuest::OnReclaimCompositorResources(
789 int browser_plugin_instance_id,
790 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
791 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
792 params.output_surface_id,
793 params.renderer_host_id,
794 params.ack);
797 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
798 bool last_unlocked_by_target,
799 bool privileged) {
800 if (pending_lock_request_) {
801 // Immediately reject the lock because only one pointerLock may be active
802 // at a time.
803 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
804 return;
807 pending_lock_request_ = true;
809 delegate_->RequestPointerLockPermission(
810 user_gesture,
811 last_unlocked_by_target,
812 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
813 weak_ptr_factory_.GetWeakPtr()));
816 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
817 bool succeeded) {
818 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
819 pending_lock_request_ = false;
820 if (succeeded)
821 mouse_locked_ = true;
824 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id,
825 bool focused,
826 blink::WebFocusType focus_type) {
827 RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
828 RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : nullptr;
829 SetFocus(rwh, focused, focus_type);
832 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
833 int browser_plugin_instance_id,
834 const std::vector<EditCommand>& edit_commands) {
835 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
836 edit_commands));
839 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
840 bool visible) {
841 guest_visible_ = visible;
842 if (embedder_visible_ && guest_visible_)
843 GetWebContents()->WasShown();
844 else
845 GetWebContents()->WasHidden();
848 void BrowserPluginGuest::OnUnlockMouse() {
849 SendMessageToEmbedder(
850 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
853 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
854 // mouse_locked_ could be false here if the lock attempt was cancelled due
855 // to window focus, or for various other reasons before the guest was informed
856 // of the lock's success.
857 if (mouse_locked_)
858 Send(new ViewMsg_MouseLockLost(routing_id()));
859 mouse_locked_ = false;
862 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
863 const gfx::Rect& view_rect) {
864 // The plugin has moved within the embedder without resizing or the
865 // embedder/container's view rect changing.
866 guest_window_rect_ = view_rect;
867 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
868 GetWebContents()->GetRenderViewHost());
869 if (rvh)
870 rvh->SendScreenRects();
873 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
874 SendMessageToEmbedder(
875 new BrowserPluginMsg_ShouldAcceptTouchEvents(
876 browser_plugin_instance_id(), accept));
879 #if defined(OS_MACOSX)
880 void BrowserPluginGuest::OnShowPopup(
881 RenderFrameHost* render_frame_host,
882 const FrameHostMsg_ShowPopup_Params& params) {
883 gfx::Rect translated_bounds(params.bounds);
884 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
885 BrowserPluginPopupMenuHelper popup_menu_helper(
886 owner_web_contents_->GetRenderViewHost(), render_frame_host);
887 popup_menu_helper.ShowPopupMenu(translated_bounds,
888 params.item_height,
889 params.item_font_size,
890 params.selected_item,
891 params.popup_items,
892 params.right_aligned,
893 params.allow_multiple_selection);
895 #endif
897 void BrowserPluginGuest::OnShowWidget(int route_id,
898 const gfx::Rect& initial_rect) {
899 GetWebContents()->ShowCreatedWidget(route_id, initial_rect);
902 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
903 SendMessageToEmbedder(
904 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
907 void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
908 ui::TextInputMode input_mode,
909 bool can_compose_inline,
910 int flags) {
911 // Save the state of text input so we can restore it on focus.
912 last_text_input_type_ = type;
913 last_input_mode_ = input_mode;
914 last_input_flags_ = flags;
915 last_can_compose_inline_ = can_compose_inline;
917 SendTextInputTypeChangedToView(
918 static_cast<RenderWidgetHostViewBase*>(
919 web_contents()->GetRenderWidgetHostView()));
922 void BrowserPluginGuest::OnImeCancelComposition() {
923 static_cast<RenderWidgetHostViewBase*>(
924 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
927 #if defined(OS_MACOSX) || defined(USE_AURA)
928 void BrowserPluginGuest::OnImeCompositionRangeChanged(
929 const gfx::Range& range,
930 const std::vector<gfx::Rect>& character_bounds) {
931 static_cast<RenderWidgetHostViewBase*>(
932 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
933 range, character_bounds);
935 #endif
937 } // namespace content