[MacViews] Show comboboxes with a native NSMenu
[chromium-blink-merge.git] / content / browser / browser_plugin / browser_plugin_guest.cc
blob7942c4f1199725217a91e63a4171126c6572c23c
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 "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_frame_proxy_host.h"
20 #include "content/browser/frame_host/render_widget_host_view_guest.h"
21 #include "content/browser/loader/resource_dispatcher_host_impl.h"
22 #include "content/browser/renderer_host/render_view_host_impl.h"
23 #include "content/browser/renderer_host/render_widget_host_impl.h"
24 #include "content/browser/renderer_host/render_widget_host_view_base.h"
25 #include "content/browser/web_contents/web_contents_impl.h"
26 #include "content/browser/web_contents/web_contents_view_guest.h"
27 #include "content/common/browser_plugin/browser_plugin_constants.h"
28 #include "content/common/browser_plugin/browser_plugin_messages.h"
29 #include "content/common/content_constants_internal.h"
30 #include "content/common/drag_messages.h"
31 #include "content/common/host_shared_bitmap_manager.h"
32 #include "content/common/input_messages.h"
33 #include "content/common/site_isolation_policy.h"
34 #include "content/common/view_messages.h"
35 #include "content/public/browser/browser_context.h"
36 #include "content/public/browser/browser_plugin_guest_manager.h"
37 #include "content/public/browser/content_browser_client.h"
38 #include "content/public/browser/guest_host.h"
39 #include "content/public/browser/render_widget_host_view.h"
40 #include "content/public/browser/user_metrics.h"
41 #include "content/public/browser/web_contents_observer.h"
42 #include "content/public/common/browser_plugin_guest_mode.h"
43 #include "content/public/common/drop_data.h"
44 #include "ui/gfx/geometry/size_conversions.h"
46 #if defined(OS_MACOSX)
47 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
48 #include "content/common/frame_messages.h"
49 #endif
51 namespace content {
53 class BrowserPluginGuest::EmbedderVisibilityObserver
54 : public WebContentsObserver {
55 public:
56 explicit EmbedderVisibilityObserver(BrowserPluginGuest* guest)
57 : WebContentsObserver(guest->embedder_web_contents()),
58 browser_plugin_guest_(guest) {
61 ~EmbedderVisibilityObserver() override {}
63 // WebContentsObserver implementation.
64 void WasShown() override {
65 browser_plugin_guest_->EmbedderVisibilityChanged(true);
68 void WasHidden() override {
69 browser_plugin_guest_->EmbedderVisibilityChanged(false);
72 private:
73 BrowserPluginGuest* browser_plugin_guest_;
75 DISALLOW_COPY_AND_ASSIGN(EmbedderVisibilityObserver);
78 BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
79 WebContentsImpl* web_contents,
80 BrowserPluginGuestDelegate* delegate)
81 : WebContentsObserver(web_contents),
82 owner_web_contents_(nullptr),
83 attached_(false),
84 has_attached_since_surface_set_(false),
85 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
86 focused_(false),
87 mouse_locked_(false),
88 pending_lock_request_(false),
89 guest_visible_(false),
90 embedder_visible_(true),
91 is_full_page_plugin_(false),
92 has_render_view_(has_render_view),
93 is_in_destruction_(false),
94 initialized_(false),
95 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
96 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
97 last_input_flags_(0),
98 last_can_compose_inline_(true),
99 guest_proxy_routing_id_(MSG_ROUTING_NONE),
100 last_drag_status_(blink::WebDragStatusUnknown),
101 seen_embedder_system_drag_ended_(false),
102 seen_embedder_drag_source_ended_at_(false),
103 delegate_(delegate),
104 weak_ptr_factory_(this) {
105 DCHECK(web_contents);
106 DCHECK(delegate);
107 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
108 web_contents->SetBrowserPluginGuest(this);
109 delegate->SetGuestHost(this);
112 int BrowserPluginGuest::GetGuestProxyRoutingID() {
113 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
114 // We don't use the proxy to send postMessage in --site-per-process, since
115 // we use the contentWindow directly from the frame element instead.
116 return MSG_ROUTING_NONE;
119 if (guest_proxy_routing_id_ != MSG_ROUTING_NONE)
120 return guest_proxy_routing_id_;
122 // Create a swapped out RenderView for the guest in the embedder renderer
123 // process, so that the embedder can access the guest's window object.
124 // On reattachment, we can reuse the same swapped out RenderView because
125 // the embedder process will always be the same even if the embedder
126 // WebContents changes.
128 // TODO(fsamuel): Make sure this works for transferring guests across
129 // owners in different processes. We probably need to clear the
130 // |guest_proxy_routing_id_| and perform any necessary cleanup on Detach
131 // to enable this.
132 SiteInstance* owner_site_instance = owner_web_contents_->GetSiteInstance();
133 if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
134 int proxy_routing_id =
135 GetWebContents()->GetFrameTree()->root()->render_manager()->
136 CreateRenderFrameProxy(owner_site_instance);
137 guest_proxy_routing_id_ = RenderFrameProxyHost::FromID(
138 owner_site_instance->GetProcess()->GetID(), proxy_routing_id)
139 ->GetRenderViewHost()->GetRoutingID();
140 } else {
141 guest_proxy_routing_id_ =
142 GetWebContents()->CreateSwappedOutRenderView(owner_site_instance);
145 return guest_proxy_routing_id_;
148 int BrowserPluginGuest::LoadURLWithParams(
149 const NavigationController::LoadURLParams& load_params) {
150 GetWebContents()->GetController().LoadURLWithParams(load_params);
151 return GetGuestProxyRoutingID();
154 void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) {
155 GetWebContents()->GetView()->SizeContents(new_size);
158 void BrowserPluginGuest::WillDestroy() {
159 is_in_destruction_ = true;
160 owner_web_contents_ = nullptr;
161 attached_ = false;
164 void BrowserPluginGuest::Init() {
165 if (initialized_)
166 return;
167 initialized_ = true;
169 // TODO(fsamuel): Initiailization prior to attachment should be behind a
170 // command line flag once we introduce experimental guest types that rely on
171 // this functionality.
172 if (!delegate_->CanRunInDetachedState())
173 return;
175 WebContentsImpl* owner_web_contents = static_cast<WebContentsImpl*>(
176 delegate_->GetOwnerWebContents());
177 owner_web_contents->CreateBrowserPluginEmbedderIfNecessary();
178 InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents);
181 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
182 return weak_ptr_factory_.GetWeakPtr();
185 void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh,
186 bool focused,
187 blink::WebFocusType focus_type) {
188 focused_ = focused;
189 if (!rwh)
190 return;
192 if ((focus_type == blink::WebFocusTypeForward) ||
193 (focus_type == blink::WebFocusTypeBackward)) {
194 static_cast<RenderViewHostImpl*>(RenderViewHost::From(rwh))->
195 SetInitialFocus(focus_type == blink::WebFocusTypeBackward);
197 rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
198 if (!focused && mouse_locked_)
199 OnUnlockMouse();
201 // Restore the last seen state of text input to the view.
202 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
203 rwh->GetView());
204 SendTextInputTypeChangedToView(rwhv);
207 void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
208 if (tooltip_text == current_tooltip_text_)
209 return;
210 current_tooltip_text_ = tooltip_text;
212 SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
213 browser_plugin_instance_id_, tooltip_text));
216 bool BrowserPluginGuest::LockMouse(bool allowed) {
217 if (!attached() || (mouse_locked_ == allowed))
218 return false;
220 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
223 WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow(
224 const WebContents::CreateParams& params) {
225 WebContentsImpl* new_contents =
226 static_cast<WebContentsImpl*>(delegate_->CreateNewGuestWindow(params));
227 DCHECK(new_contents);
228 return new_contents;
231 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
232 const IPC::Message& message) {
233 RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
234 web_contents()->GetRenderWidgetHostView());
235 // Until the guest is attached, it should not be handling input events.
236 if (attached() && rwhv && rwhv->OnMessageReceivedFromEmbedder(
237 message,
238 static_cast<RenderViewHostImpl*>(
239 embedder_web_contents()->GetRenderViewHost()))) {
240 return true;
243 bool handled = true;
244 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
245 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
246 OnCompositorFrameSwappedACK)
247 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach)
248 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
249 OnDragStatusUpdate)
250 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
251 OnExecuteEditCommand)
252 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
253 OnExtendSelectionAndDelete)
254 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
255 OnImeConfirmComposition)
256 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
257 OnImeSetComposition)
258 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
259 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
260 OnReclaimCompositorResources)
261 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
262 OnSetEditCommandsForNextKeyEvent)
263 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
264 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
265 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
266 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
267 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SatisfySequence, OnSatisfySequence)
268 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_RequireSequence, OnRequireSequence)
269 IPC_MESSAGE_UNHANDLED(handled = false)
270 IPC_END_MESSAGE_MAP()
271 return handled;
274 void BrowserPluginGuest::InitInternal(
275 const BrowserPluginHostMsg_Attach_Params& params,
276 WebContentsImpl* owner_web_contents) {
277 focused_ = params.focused;
278 OnSetFocus(browser_plugin::kInstanceIDNone,
279 focused_,
280 blink::WebFocusTypeNone);
282 guest_visible_ = params.visible;
283 UpdateVisibility();
285 is_full_page_plugin_ = params.is_full_page_plugin;
286 guest_window_rect_ = params.view_rect;
288 if (owner_web_contents_ != owner_web_contents) {
289 WebContentsViewGuest* new_view = nullptr;
290 if (!BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
291 new_view =
292 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
295 if (owner_web_contents_ && new_view)
296 new_view->OnGuestDetached(owner_web_contents_->GetView());
298 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
299 // be attached.
300 owner_web_contents_ = owner_web_contents;
301 if (new_view)
302 new_view->OnGuestAttached(owner_web_contents_->GetView());
305 RendererPreferences* renderer_prefs =
306 GetWebContents()->GetMutableRendererPrefs();
307 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
308 // Copy renderer preferences (and nothing else) from the embedder's
309 // WebContents to the guest.
311 // For GTK and Aura this is necessary to get proper renderer configuration
312 // values for caret blinking interval, colors related to selection and
313 // focus.
314 *renderer_prefs = *owner_web_contents_->GetMutableRendererPrefs();
315 renderer_prefs->user_agent_override = guest_user_agent_override;
317 // We would like the guest to report changes to frame names so that we can
318 // update the BrowserPlugin's corresponding 'name' attribute.
319 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
320 renderer_prefs->report_frame_name_changes = true;
321 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
322 // navigations still continue to function inside the app.
323 renderer_prefs->browser_handles_all_top_level_requests = false;
324 // Disable "client blocked" error page for browser plugin.
325 renderer_prefs->disable_client_blocked_error_page = true;
327 embedder_visibility_observer_.reset(new EmbedderVisibilityObserver(this));
329 DCHECK(GetWebContents()->GetRenderViewHost());
331 // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
332 auto render_widget_host =
333 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
334 render_widget_host->NotifyScreenInfoChanged();
336 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
337 // be reset again the next time preferences are updated.
338 WebPreferences prefs =
339 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
340 prefs.navigate_on_drag_drop = false;
341 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
344 BrowserPluginGuest::~BrowserPluginGuest() {
347 // static
348 BrowserPluginGuest* BrowserPluginGuest::Create(
349 WebContentsImpl* web_contents,
350 BrowserPluginGuestDelegate* delegate) {
351 return new BrowserPluginGuest(
352 web_contents->HasOpener(), web_contents, delegate);
355 // static
356 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
357 return web_contents && web_contents->GetBrowserPluginGuest();
360 // static
361 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
362 return render_view_host && IsGuest(
363 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
364 render_view_host)));
367 RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
368 if (!owner_web_contents_)
369 return nullptr;
370 return owner_web_contents_->GetRenderWidgetHostView();
373 void BrowserPluginGuest::UpdateVisibility() {
374 OnSetVisibility(browser_plugin_instance_id(), visible());
377 BrowserPluginGuestManager*
378 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
379 return GetWebContents()->GetBrowserContext()->GetGuestManager();
382 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
383 embedder_visible_ = visible;
384 UpdateVisibility();
387 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
388 SendMessageToEmbedder(
389 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
392 void BrowserPluginGuest::UpdateGuestSizeIfNecessary(
393 const gfx::Size& frame_size, float scale_factor) {
394 gfx::Size view_size(
395 gfx::ToFlooredSize(gfx::ScaleSize(frame_size, 1.0f / scale_factor)));
397 if (last_seen_view_size_ != view_size) {
398 delegate_->GuestSizeChanged(view_size);
399 last_seen_view_size_ = view_size;
403 // TODO(wjmaclean): Remove this once any remaining users of this pathway
404 // are gone.
405 void BrowserPluginGuest::SwapCompositorFrame(
406 uint32 output_surface_id,
407 int host_process_id,
408 int host_routing_id,
409 scoped_ptr<cc::CompositorFrame> frame) {
410 cc::RenderPass* root_pass =
411 frame->delegated_frame_data->render_pass_list.back();
412 UpdateGuestSizeIfNecessary(root_pass->output_rect.size(),
413 frame->metadata.device_scale_factor);
415 last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params());
416 frame->AssignTo(&last_pending_frame_->frame);
417 last_pending_frame_->output_surface_id = output_surface_id;
418 last_pending_frame_->producing_route_id = host_routing_id;
419 last_pending_frame_->producing_host_id = host_process_id;
421 SendMessageToEmbedder(
422 new BrowserPluginMsg_CompositorFrameSwapped(
423 browser_plugin_instance_id(), *last_pending_frame_));
426 void BrowserPluginGuest::SetChildFrameSurface(
427 const cc::SurfaceId& surface_id,
428 const gfx::Size& frame_size,
429 float scale_factor,
430 const cc::SurfaceSequence& sequence) {
431 has_attached_since_surface_set_ = false;
432 SendMessageToEmbedder(new BrowserPluginMsg_SetChildFrameSurface(
433 browser_plugin_instance_id(), surface_id, frame_size, scale_factor,
434 sequence));
437 void BrowserPluginGuest::OnSatisfySequence(
438 int instance_id,
439 const cc::SurfaceSequence& sequence) {
440 std::vector<uint32_t> sequences;
441 sequences.push_back(sequence.sequence);
442 cc::SurfaceManager* manager = GetSurfaceManager();
443 manager->DidSatisfySequences(sequence.id_namespace, &sequences);
446 void BrowserPluginGuest::OnRequireSequence(
447 int instance_id,
448 const cc::SurfaceId& id,
449 const cc::SurfaceSequence& sequence) {
450 cc::SurfaceManager* manager = GetSurfaceManager();
451 cc::Surface* surface = manager->GetSurfaceForId(id);
452 if (!surface) {
453 LOG(ERROR) << "Attempting to require callback on nonexistent surface";
454 return;
456 surface->AddDestructionDependency(sequence);
459 void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
460 SendMessageToEmbedder(
461 new BrowserPluginMsg_SetContentsOpaque(
462 browser_plugin_instance_id(), opaque));
465 bool BrowserPluginGuest::Find(int request_id,
466 const base::string16& search_text,
467 const blink::WebFindOptions& options) {
468 return delegate_->Find(request_id, search_text, options);
471 bool BrowserPluginGuest::StopFinding(StopFindAction action) {
472 return delegate_->StopFinding(action);
475 WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
476 return static_cast<WebContentsImpl*>(web_contents());
479 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
480 const gfx::Point& relative_position) const {
481 if (!attached())
482 return relative_position;
484 gfx::Point screen_pos(relative_position);
485 screen_pos += guest_window_rect_.OffsetFromOrigin();
486 return screen_pos;
489 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
490 // During tests, attache() may be true when there is no owner_web_contents_;
491 // in this case just queue any messages we receive.
492 if (!attached() || !owner_web_contents_) {
493 // Some pages such as data URLs, javascript URLs, and about:blank
494 // do not load external resources and so they load prior to attachment.
495 // As a result, we must save all these IPCs until attachment and then
496 // forward them so that the embedder gets a chance to see and process
497 // the load events.
498 pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
499 return;
501 owner_web_contents_->Send(msg);
504 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
505 int screen_x, int screen_y, blink::WebDragOperation operation) {
506 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
507 screen_x, screen_y, operation);
508 seen_embedder_drag_source_ended_at_ = true;
509 EndSystemDragIfApplicable();
512 void BrowserPluginGuest::EndSystemDragIfApplicable() {
513 // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
514 // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
515 // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
516 // means we call it in all cases and also make sure we only call it once.
517 // This ensures that the input state of the guest stays correct, otherwise
518 // it will go stale and won't accept any further input events.
520 // The strategy used here to call DragSourceSystemDragEnded() on the RVH
521 // is when the following conditions are met:
522 // a. Embedder has seen SystemDragEnded()
523 // b. Embedder has seen DragSourceEndedAt()
524 // c. The guest has seen some drag status update other than
525 // WebDragStatusUnknown. Note that this step should ideally be done
526 // differently: The guest has seen at least one of
527 // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
528 // a source quickly outside of <webview> bounds, then the
529 // BrowserPluginGuest never sees any of these drag status updates,
530 // there we just check whether we've seen any drag status update or
531 // not.
532 if (last_drag_status_ != blink::WebDragStatusOver &&
533 seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
534 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
535 GetWebContents()->GetRenderViewHost());
536 guest_rvh->DragSourceSystemDragEnded();
537 last_drag_status_ = blink::WebDragStatusUnknown;
538 seen_embedder_system_drag_ended_ = false;
539 seen_embedder_drag_source_ended_at_ = false;
540 dragged_url_ = GURL();
544 void BrowserPluginGuest::EmbedderSystemDragEnded() {
545 seen_embedder_system_drag_ended_ = true;
546 EndSystemDragIfApplicable();
549 void BrowserPluginGuest::SendQueuedMessages() {
550 if (!attached())
551 return;
553 while (!pending_messages_.empty()) {
554 linked_ptr<IPC::Message> message_ptr = pending_messages_.front();
555 pending_messages_.pop_front();
556 SendMessageToEmbedder(message_ptr.release());
560 void BrowserPluginGuest::SendTextInputTypeChangedToView(
561 RenderWidgetHostViewBase* guest_rwhv) {
562 if (!guest_rwhv)
563 return;
565 if (!owner_web_contents_) {
566 // If we were showing an interstitial, then we can end up here during
567 // embedder shutdown or when the embedder navigates to a different page.
568 // The call stack is roughly:
569 // BrowserPluginGuest::SetFocus()
570 // content::InterstitialPageImpl::Hide()
571 // content::InterstitialPageImpl::DontProceed().
573 // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed.
574 return;
577 ViewHostMsg_TextInputState_Params params;
578 params.type = last_text_input_type_;
579 params.mode = last_input_mode_;
580 params.flags = last_input_flags_;
581 params.can_compose_inline = last_can_compose_inline_;
582 guest_rwhv->TextInputStateChanged(params);
585 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
586 RenderFrameHost* render_frame_host,
587 const GURL& url,
588 ui::PageTransition transition_type) {
589 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
592 void BrowserPluginGuest::RenderViewReady() {
593 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
594 // TODO(fsamuel): Investigate whether it's possible to update state earlier
595 // here (see http://crbug.com/158151).
596 Send(new InputMsg_SetFocus(routing_id(), focused_));
597 UpdateVisibility();
599 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay(
600 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
603 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
604 SendMessageToEmbedder(
605 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
606 switch (status) {
607 #if defined(OS_CHROMEOS)
608 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
609 #endif
610 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
611 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
612 break;
613 case base::TERMINATION_STATUS_PROCESS_CRASHED:
614 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
615 break;
616 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
617 RecordAction(
618 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
619 break;
620 case base::TERMINATION_STATUS_LAUNCH_FAILED:
621 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.LaunchFailed"));
622 break;
623 default:
624 break;
628 // static
629 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
630 const IPC::Message& message) {
631 return (message.type() != BrowserPluginHostMsg_Attach::ID) &&
632 (IPC_MESSAGE_CLASS(message) == BrowserPluginMsgStart);
635 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
636 bool handled = true;
637 // In --site-per-process, we do not need most of BrowserPluginGuest to drive
638 // inner WebContents.
639 // Right now InputHostMsg_ImeCompositionRangeChanged hits NOTREACHED() in
640 // RWHVChildFrame, so we're disabling message handling entirely here.
641 // TODO(lazyboy): Fix this as part of http://crbug.com/330264. The required
642 // parts of code from this class should be extracted to a separate class for
643 // --site-per-process.
644 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
645 return false;
648 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
649 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
650 OnImeCancelComposition)
651 #if defined(OS_MACOSX) || defined(USE_AURA)
652 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
653 OnImeCompositionRangeChanged)
654 #endif
655 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
656 OnHasTouchEventHandlers)
657 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
658 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
659 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
660 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
661 OnTextInputStateChanged)
662 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
663 IPC_MESSAGE_UNHANDLED(handled = false)
664 IPC_END_MESSAGE_MAP()
665 return handled;
668 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message,
669 RenderFrameHost* render_frame_host) {
670 // This will eventually be the home for more IPC handlers that depend on
671 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
672 // compile if there are no handlers for a platform. So we have both #if guards
673 // around the whole thing (unfortunate but temporary), and #if guards where
674 // they belong, only around the one IPC handler. TODO(avi): Move more of the
675 // frame-based handlers to this function and remove the outer #if layer.
676 #if defined(OS_MACOSX)
677 bool handled = true;
678 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message,
679 render_frame_host)
680 #if defined(OS_MACOSX)
681 // MacOS X creates and populates platform-specific select drop-down menus
682 // whereas other platforms merely create a popup window that the guest
683 // renderer process paints inside.
684 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
685 #endif
686 IPC_MESSAGE_UNHANDLED(handled = false)
687 IPC_END_MESSAGE_MAP()
688 return handled;
689 #else
690 return false;
691 #endif
694 void BrowserPluginGuest::Attach(
695 int browser_plugin_instance_id,
696 WebContentsImpl* embedder_web_contents,
697 const BrowserPluginHostMsg_Attach_Params& params) {
698 browser_plugin_instance_id_ = browser_plugin_instance_id;
699 // If a guest is detaching from one container and attaching to another
700 // container, then late arriving ACKs may be lost if the mapping from
701 // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
702 // ensure that we always get new frames on attachment by ACKing the pending
703 // frame if it's still waiting on the ACK.
704 if (last_pending_frame_) {
705 cc::CompositorFrameAck ack;
706 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
707 last_pending_frame_->producing_route_id,
708 last_pending_frame_->output_surface_id,
709 last_pending_frame_->producing_host_id,
710 ack);
711 last_pending_frame_.reset();
714 // The guest is owned by the embedder. Attach is queued up so we cannot
715 // change embedders before attach completes. If the embedder goes away,
716 // so does the guest and so we will never call WillAttachComplete because
717 // we have a weak ptr.
718 delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id,
719 params.is_full_page_plugin,
720 base::Bind(&BrowserPluginGuest::OnWillAttachComplete,
721 weak_ptr_factory_.GetWeakPtr(),
722 embedder_web_contents, params));
725 void BrowserPluginGuest::OnWillAttachComplete(
726 WebContentsImpl* embedder_web_contents,
727 const BrowserPluginHostMsg_Attach_Params& params) {
728 bool use_cross_process_frames =
729 BrowserPluginGuestMode::UseCrossProcessFramesForGuests();
730 // If a RenderView has already been created for this new window, then we need
731 // to initialize the browser-side state now so that the RenderFrameHostManager
732 // does not create a new RenderView on navigation.
733 if (!use_cross_process_frames && has_render_view_) {
734 // This will trigger a callback to RenderViewReady after a round-trip IPC.
735 static_cast<RenderViewHostImpl*>(
736 GetWebContents()->GetRenderViewHost())->Init();
737 WebContentsViewGuest* web_contents_view =
738 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
739 if (!web_contents()->GetRenderViewHost()->GetView()) {
740 web_contents_view->CreateViewForWidget(
741 web_contents()->GetRenderViewHost(), true);
745 InitInternal(params, embedder_web_contents);
747 attached_ = true;
748 has_attached_since_surface_set_ = true;
749 SendQueuedMessages();
751 delegate_->DidAttach(GetGuestProxyRoutingID());
753 if (!use_cross_process_frames)
754 has_render_view_ = true;
756 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
759 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
760 int browser_plugin_instance_id,
761 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
762 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
763 params.output_surface_id,
764 params.producing_host_id,
765 params.ack);
766 last_pending_frame_.reset();
769 void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
770 if (!attached())
771 return;
773 // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
774 // it's attached again.
775 attached_ = false;
777 delegate_->DidDetach();
780 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
781 blink::WebDragStatus drag_status,
782 const DropData& drop_data,
783 blink::WebDragOperationsMask mask,
784 const gfx::Point& location) {
785 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
786 auto embedder = owner_web_contents_->GetBrowserPluginEmbedder();
787 switch (drag_status) {
788 case blink::WebDragStatusEnter:
789 // Only track the URL being dragged over the guest if the link isn't
790 // coming from the guest.
791 if (!embedder->DragEnteredGuest(this))
792 dragged_url_ = drop_data.url;
793 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
794 break;
795 case blink::WebDragStatusOver:
796 host->DragTargetDragOver(location, location, mask, 0);
797 break;
798 case blink::WebDragStatusLeave:
799 embedder->DragLeftGuest(this);
800 host->DragTargetDragLeave();
801 break;
802 case blink::WebDragStatusDrop:
803 host->DragTargetDrop(location, location, 0);
804 if (dragged_url_.is_valid()) {
805 delegate_->DidDropLink(dragged_url_);
806 dragged_url_ = GURL();
808 break;
809 case blink::WebDragStatusUnknown:
810 NOTREACHED();
812 last_drag_status_ = drag_status;
813 EndSystemDragIfApplicable();
816 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
817 const std::string& name) {
818 RenderFrameHost* focused_frame = web_contents()->GetFocusedFrame();
819 if (!focused_frame)
820 return;
822 focused_frame->Send(new InputMsg_ExecuteNoValueEditCommand(
823 focused_frame->GetRoutingID(), name));
826 void BrowserPluginGuest::OnImeSetComposition(
827 int browser_plugin_instance_id,
828 const std::string& text,
829 const std::vector<blink::WebCompositionUnderline>& underlines,
830 int selection_start,
831 int selection_end) {
832 Send(new InputMsg_ImeSetComposition(routing_id(),
833 base::UTF8ToUTF16(text), underlines,
834 selection_start, selection_end));
837 void BrowserPluginGuest::OnImeConfirmComposition(
838 int browser_plugin_instance_id,
839 const std::string& text,
840 bool keep_selection) {
841 Send(new InputMsg_ImeConfirmComposition(routing_id(),
842 base::UTF8ToUTF16(text),
843 gfx::Range::InvalidRange(),
844 keep_selection));
847 void BrowserPluginGuest::OnExtendSelectionAndDelete(
848 int browser_plugin_instance_id,
849 int before,
850 int after) {
851 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
852 web_contents()->GetFocusedFrame());
853 if (rfh)
854 rfh->ExtendSelectionAndDelete(before, after);
857 void BrowserPluginGuest::OnReclaimCompositorResources(
858 int browser_plugin_instance_id,
859 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
860 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
861 params.output_surface_id,
862 params.renderer_host_id,
863 params.ack);
866 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
867 bool last_unlocked_by_target,
868 bool privileged) {
869 if (pending_lock_request_) {
870 // Immediately reject the lock because only one pointerLock may be active
871 // at a time.
872 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
873 return;
876 pending_lock_request_ = true;
878 delegate_->RequestPointerLockPermission(
879 user_gesture,
880 last_unlocked_by_target,
881 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
882 weak_ptr_factory_.GetWeakPtr()));
885 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
886 bool succeeded) {
887 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
888 pending_lock_request_ = false;
889 if (succeeded)
890 mouse_locked_ = true;
893 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id,
894 bool focused,
895 blink::WebFocusType focus_type) {
896 RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
897 RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : nullptr;
898 SetFocus(rwh, focused, focus_type);
901 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
902 int browser_plugin_instance_id,
903 const std::vector<EditCommand>& edit_commands) {
904 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
905 edit_commands));
908 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
909 bool visible) {
910 guest_visible_ = visible;
911 if (embedder_visible_ && guest_visible_)
912 GetWebContents()->WasShown();
913 else
914 GetWebContents()->WasHidden();
917 void BrowserPluginGuest::OnUnlockMouse() {
918 SendMessageToEmbedder(
919 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
922 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
923 // mouse_locked_ could be false here if the lock attempt was cancelled due
924 // to window focus, or for various other reasons before the guest was informed
925 // of the lock's success.
926 if (mouse_locked_)
927 Send(new ViewMsg_MouseLockLost(routing_id()));
928 mouse_locked_ = false;
931 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
932 const gfx::Rect& view_rect) {
933 // The plugin has moved within the embedder without resizing or the
934 // embedder/container's view rect changing.
935 guest_window_rect_ = view_rect;
936 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
937 GetWebContents()->GetRenderViewHost());
938 if (rvh)
939 rvh->SendScreenRects();
942 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
943 SendMessageToEmbedder(
944 new BrowserPluginMsg_ShouldAcceptTouchEvents(
945 browser_plugin_instance_id(), accept));
948 #if defined(OS_MACOSX)
949 void BrowserPluginGuest::OnShowPopup(
950 RenderFrameHost* render_frame_host,
951 const FrameHostMsg_ShowPopup_Params& params) {
952 gfx::Rect translated_bounds(params.bounds);
953 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
954 BrowserPluginPopupMenuHelper popup_menu_helper(
955 owner_web_contents_->GetRenderViewHost(), render_frame_host);
956 popup_menu_helper.ShowPopupMenu(translated_bounds,
957 params.item_height,
958 params.item_font_size,
959 params.selected_item,
960 params.popup_items,
961 params.right_aligned,
962 params.allow_multiple_selection);
964 #endif
966 void BrowserPluginGuest::OnShowWidget(int route_id,
967 const gfx::Rect& initial_rect) {
968 GetWebContents()->ShowCreatedWidget(route_id, initial_rect);
971 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
972 SendMessageToEmbedder(
973 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
976 void BrowserPluginGuest::OnTextInputStateChanged(
977 const ViewHostMsg_TextInputState_Params& params) {
978 // Save the state of text input so we can restore it on focus.
979 last_text_input_type_ = params.type;
980 last_input_mode_ = params.mode;
981 last_input_flags_ = params.flags;
982 last_can_compose_inline_ = params.can_compose_inline;
984 SendTextInputTypeChangedToView(
985 static_cast<RenderWidgetHostViewBase*>(
986 web_contents()->GetRenderWidgetHostView()));
989 void BrowserPluginGuest::OnImeCancelComposition() {
990 static_cast<RenderWidgetHostViewBase*>(
991 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
994 #if defined(OS_MACOSX) || defined(USE_AURA)
995 void BrowserPluginGuest::OnImeCompositionRangeChanged(
996 const gfx::Range& range,
997 const std::vector<gfx::Rect>& character_bounds) {
998 static_cast<RenderWidgetHostViewBase*>(
999 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
1000 range, character_bounds);
1002 #endif
1004 void BrowserPluginGuest::SetContextMenuPosition(const gfx::Point& position) {
1005 if (delegate_)
1006 delegate_->SetContextMenuPosition(position);
1009 } // namespace content