Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / browser_plugin / browser_plugin_guest.cc
blobbb41b7e34347d8c758b9070b78dae2314bf9bcc9
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 guest_proxy_routing_id_(MSG_ROUTING_NONE),
96 last_drag_status_(blink::WebDragStatusUnknown),
97 seen_embedder_system_drag_ended_(false),
98 seen_embedder_drag_source_ended_at_(false),
99 delegate_(delegate),
100 weak_ptr_factory_(this) {
101 DCHECK(web_contents);
102 DCHECK(delegate);
103 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
104 web_contents->SetBrowserPluginGuest(this);
105 delegate->SetGuestHost(this);
108 int BrowserPluginGuest::GetGuestProxyRoutingID() {
109 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
110 // We don't use the proxy to send postMessage in --site-per-process, since
111 // we use the contentWindow directly from the frame element instead.
112 return MSG_ROUTING_NONE;
115 if (guest_proxy_routing_id_ != MSG_ROUTING_NONE)
116 return guest_proxy_routing_id_;
118 // Create a swapped out RenderView for the guest in the embedder renderer
119 // process, so that the embedder can access the guest's window object.
120 // On reattachment, we can reuse the same swapped out RenderView because
121 // the embedder process will always be the same even if the embedder
122 // WebContents changes.
124 // TODO(fsamuel): Make sure this works for transferring guests across
125 // owners in different processes. We probably need to clear the
126 // |guest_proxy_routing_id_| and perform any necessary cleanup on Detach
127 // to enable this.
128 SiteInstance* owner_site_instance = owner_web_contents_->GetSiteInstance();
129 if (SiteIsolationPolicy::IsSwappedOutStateForbidden()) {
130 int proxy_routing_id =
131 GetWebContents()->GetFrameTree()->root()->render_manager()->
132 CreateRenderFrameProxy(owner_site_instance);
133 guest_proxy_routing_id_ = RenderFrameProxyHost::FromID(
134 owner_site_instance->GetProcess()->GetID(), proxy_routing_id)
135 ->GetRenderViewHost()->GetRoutingID();
136 } else {
137 guest_proxy_routing_id_ =
138 GetWebContents()->CreateSwappedOutRenderView(owner_site_instance);
141 return guest_proxy_routing_id_;
144 int BrowserPluginGuest::LoadURLWithParams(
145 const NavigationController::LoadURLParams& load_params) {
146 GetWebContents()->GetController().LoadURLWithParams(load_params);
147 return GetGuestProxyRoutingID();
150 void BrowserPluginGuest::GuestResizeDueToAutoResize(const gfx::Size& new_size) {
151 if (last_seen_view_size_ != new_size) {
152 delegate_->GuestSizeChanged(new_size);
153 last_seen_view_size_ = new_size;
157 void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) {
158 GetWebContents()->GetView()->SizeContents(new_size);
161 void BrowserPluginGuest::WillDestroy() {
162 is_in_destruction_ = true;
163 owner_web_contents_ = nullptr;
164 attached_ = false;
167 void BrowserPluginGuest::Init() {
168 if (initialized_)
169 return;
170 initialized_ = true;
172 // TODO(fsamuel): Initiailization prior to attachment should be behind a
173 // command line flag once we introduce experimental guest types that rely on
174 // this functionality.
175 if (!delegate_->CanRunInDetachedState())
176 return;
178 WebContentsImpl* owner_web_contents = static_cast<WebContentsImpl*>(
179 delegate_->GetOwnerWebContents());
180 owner_web_contents->CreateBrowserPluginEmbedderIfNecessary();
181 InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents);
184 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
185 return weak_ptr_factory_.GetWeakPtr();
188 void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh,
189 bool focused,
190 blink::WebFocusType focus_type) {
191 focused_ = focused;
192 if (!rwh)
193 return;
195 if ((focus_type == blink::WebFocusTypeForward) ||
196 (focus_type == blink::WebFocusTypeBackward)) {
197 static_cast<RenderViewHostImpl*>(RenderViewHost::From(rwh))->
198 SetInitialFocus(focus_type == blink::WebFocusTypeBackward);
200 rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
201 if (!focused && mouse_locked_)
202 OnUnlockMouse();
204 // Restore the last seen state of text input to the view.
205 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
206 rwh->GetView());
207 SendTextInputTypeChangedToView(rwhv);
210 void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
211 if (tooltip_text == current_tooltip_text_)
212 return;
213 current_tooltip_text_ = tooltip_text;
215 SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
216 browser_plugin_instance_id_, tooltip_text));
219 bool BrowserPluginGuest::LockMouse(bool allowed) {
220 if (!attached() || (mouse_locked_ == allowed))
221 return false;
223 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
226 WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow(
227 const WebContents::CreateParams& params) {
228 WebContentsImpl* new_contents =
229 static_cast<WebContentsImpl*>(delegate_->CreateNewGuestWindow(params));
230 DCHECK(new_contents);
231 return new_contents;
234 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
235 const IPC::Message& message) {
236 RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
237 web_contents()->GetRenderWidgetHostView());
238 // Until the guest is attached, it should not be handling input events.
239 if (attached() && rwhv && rwhv->OnMessageReceivedFromEmbedder(
240 message,
241 static_cast<RenderViewHostImpl*>(
242 embedder_web_contents()->GetRenderViewHost()))) {
243 return true;
246 bool handled = true;
247 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
248 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
249 OnCompositorFrameSwappedACK)
250 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach)
251 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
252 OnDragStatusUpdate)
253 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
254 OnExecuteEditCommand)
255 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
256 OnExtendSelectionAndDelete)
257 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
258 OnImeConfirmComposition)
259 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
260 OnImeSetComposition)
261 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
262 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
263 OnReclaimCompositorResources)
264 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
265 OnSetEditCommandsForNextKeyEvent)
266 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
267 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
268 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
269 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
270 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SatisfySequence, OnSatisfySequence)
271 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_RequireSequence, OnRequireSequence)
272 IPC_MESSAGE_UNHANDLED(handled = false)
273 IPC_END_MESSAGE_MAP()
274 return handled;
277 void BrowserPluginGuest::InitInternal(
278 const BrowserPluginHostMsg_Attach_Params& params,
279 WebContentsImpl* owner_web_contents) {
280 focused_ = params.focused;
281 OnSetFocus(browser_plugin::kInstanceIDNone,
282 focused_,
283 blink::WebFocusTypeNone);
285 guest_visible_ = params.visible;
286 UpdateVisibility();
288 is_full_page_plugin_ = params.is_full_page_plugin;
289 guest_window_rect_ = params.view_rect;
291 if (owner_web_contents_ != owner_web_contents) {
292 WebContentsViewGuest* new_view = nullptr;
293 if (!BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
294 new_view =
295 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
298 if (owner_web_contents_ && new_view)
299 new_view->OnGuestDetached(owner_web_contents_->GetView());
301 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
302 // be attached.
303 owner_web_contents_ = owner_web_contents;
304 if (new_view)
305 new_view->OnGuestAttached(owner_web_contents_->GetView());
308 RendererPreferences* renderer_prefs =
309 GetWebContents()->GetMutableRendererPrefs();
310 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
311 // Copy renderer preferences (and nothing else) from the embedder's
312 // WebContents to the guest.
314 // For GTK and Aura this is necessary to get proper renderer configuration
315 // values for caret blinking interval, colors related to selection and
316 // focus.
317 *renderer_prefs = *owner_web_contents_->GetMutableRendererPrefs();
318 renderer_prefs->user_agent_override = guest_user_agent_override;
320 // We would like the guest to report changes to frame names so that we can
321 // update the BrowserPlugin's corresponding 'name' attribute.
322 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
323 renderer_prefs->report_frame_name_changes = true;
324 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
325 // navigations still continue to function inside the app.
326 renderer_prefs->browser_handles_all_top_level_requests = false;
327 // Disable "client blocked" error page for browser plugin.
328 renderer_prefs->disable_client_blocked_error_page = true;
330 embedder_visibility_observer_.reset(new EmbedderVisibilityObserver(this));
332 DCHECK(GetWebContents()->GetRenderViewHost());
334 // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
335 auto render_widget_host =
336 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
337 render_widget_host->NotifyScreenInfoChanged();
339 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
340 // be reset again the next time preferences are updated.
341 WebPreferences prefs =
342 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
343 prefs.navigate_on_drag_drop = false;
344 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
347 BrowserPluginGuest::~BrowserPluginGuest() {
350 // static
351 BrowserPluginGuest* BrowserPluginGuest::Create(
352 WebContentsImpl* web_contents,
353 BrowserPluginGuestDelegate* delegate) {
354 return new BrowserPluginGuest(
355 web_contents->HasOpener(), web_contents, delegate);
358 // static
359 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
360 return web_contents && web_contents->GetBrowserPluginGuest();
363 // static
364 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
365 return render_view_host && IsGuest(
366 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
367 render_view_host)));
370 RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
371 if (!owner_web_contents_)
372 return nullptr;
373 return owner_web_contents_->GetRenderWidgetHostView();
376 void BrowserPluginGuest::UpdateVisibility() {
377 OnSetVisibility(browser_plugin_instance_id(), visible());
380 BrowserPluginGuestManager*
381 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
382 return GetWebContents()->GetBrowserContext()->GetGuestManager();
385 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
386 embedder_visible_ = visible;
387 UpdateVisibility();
390 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
391 SendMessageToEmbedder(
392 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
395 // TODO(wjmaclean): Remove this once any remaining users of this pathway
396 // are gone.
397 void BrowserPluginGuest::SwapCompositorFrame(
398 uint32 output_surface_id,
399 int host_process_id,
400 int host_routing_id,
401 scoped_ptr<cc::CompositorFrame> frame) {
402 last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params());
403 frame->AssignTo(&last_pending_frame_->frame);
404 last_pending_frame_->output_surface_id = output_surface_id;
405 last_pending_frame_->producing_route_id = host_routing_id;
406 last_pending_frame_->producing_host_id = host_process_id;
408 SendMessageToEmbedder(
409 new BrowserPluginMsg_CompositorFrameSwapped(
410 browser_plugin_instance_id(), *last_pending_frame_));
413 void BrowserPluginGuest::SetChildFrameSurface(
414 const cc::SurfaceId& surface_id,
415 const gfx::Size& frame_size,
416 float scale_factor,
417 const cc::SurfaceSequence& sequence) {
418 has_attached_since_surface_set_ = false;
419 SendMessageToEmbedder(new BrowserPluginMsg_SetChildFrameSurface(
420 browser_plugin_instance_id(), surface_id, frame_size, scale_factor,
421 sequence));
424 void BrowserPluginGuest::OnSatisfySequence(
425 int instance_id,
426 const cc::SurfaceSequence& sequence) {
427 std::vector<uint32_t> sequences;
428 sequences.push_back(sequence.sequence);
429 cc::SurfaceManager* manager = GetSurfaceManager();
430 manager->DidSatisfySequences(sequence.id_namespace, &sequences);
433 void BrowserPluginGuest::OnRequireSequence(
434 int instance_id,
435 const cc::SurfaceId& id,
436 const cc::SurfaceSequence& sequence) {
437 cc::SurfaceManager* manager = GetSurfaceManager();
438 cc::Surface* surface = manager->GetSurfaceForId(id);
439 if (!surface) {
440 LOG(ERROR) << "Attempting to require callback on nonexistent surface";
441 return;
443 surface->AddDestructionDependency(sequence);
446 void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
447 SendMessageToEmbedder(
448 new BrowserPluginMsg_SetContentsOpaque(
449 browser_plugin_instance_id(), opaque));
452 bool BrowserPluginGuest::Find(int request_id,
453 const base::string16& search_text,
454 const blink::WebFindOptions& options) {
455 return delegate_->Find(request_id, search_text, options);
458 bool BrowserPluginGuest::StopFinding(StopFindAction action) {
459 return delegate_->StopFinding(action);
462 WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
463 return static_cast<WebContentsImpl*>(web_contents());
466 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
467 const gfx::Point& relative_position) const {
468 if (!attached())
469 return relative_position;
471 gfx::Point screen_pos(relative_position);
472 screen_pos += guest_window_rect_.OffsetFromOrigin();
473 return screen_pos;
476 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
477 // During tests, attache() may be true when there is no owner_web_contents_;
478 // in this case just queue any messages we receive.
479 if (!attached() || !owner_web_contents_) {
480 // Some pages such as data URLs, javascript URLs, and about:blank
481 // do not load external resources and so they load prior to attachment.
482 // As a result, we must save all these IPCs until attachment and then
483 // forward them so that the embedder gets a chance to see and process
484 // the load events.
485 pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
486 return;
488 owner_web_contents_->Send(msg);
491 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
492 int screen_x, int screen_y, blink::WebDragOperation operation) {
493 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
494 screen_x, screen_y, operation);
495 seen_embedder_drag_source_ended_at_ = true;
496 EndSystemDragIfApplicable();
499 void BrowserPluginGuest::EndSystemDragIfApplicable() {
500 // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
501 // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
502 // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
503 // means we call it in all cases and also make sure we only call it once.
504 // This ensures that the input state of the guest stays correct, otherwise
505 // it will go stale and won't accept any further input events.
507 // The strategy used here to call DragSourceSystemDragEnded() on the RVH
508 // is when the following conditions are met:
509 // a. Embedder has seen SystemDragEnded()
510 // b. Embedder has seen DragSourceEndedAt()
511 // c. The guest has seen some drag status update other than
512 // WebDragStatusUnknown. Note that this step should ideally be done
513 // differently: The guest has seen at least one of
514 // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
515 // a source quickly outside of <webview> bounds, then the
516 // BrowserPluginGuest never sees any of these drag status updates,
517 // there we just check whether we've seen any drag status update or
518 // not.
519 if (last_drag_status_ != blink::WebDragStatusOver &&
520 seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
521 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
522 GetWebContents()->GetRenderViewHost());
523 guest_rvh->DragSourceSystemDragEnded();
524 last_drag_status_ = blink::WebDragStatusUnknown;
525 seen_embedder_system_drag_ended_ = false;
526 seen_embedder_drag_source_ended_at_ = false;
527 dragged_url_ = GURL();
531 void BrowserPluginGuest::EmbedderSystemDragEnded() {
532 seen_embedder_system_drag_ended_ = true;
533 EndSystemDragIfApplicable();
536 void BrowserPluginGuest::SendQueuedMessages() {
537 if (!attached())
538 return;
540 while (!pending_messages_.empty()) {
541 linked_ptr<IPC::Message> message_ptr = pending_messages_.front();
542 pending_messages_.pop_front();
543 SendMessageToEmbedder(message_ptr.release());
547 void BrowserPluginGuest::SendTextInputTypeChangedToView(
548 RenderWidgetHostViewBase* guest_rwhv) {
549 if (!guest_rwhv)
550 return;
552 if (!owner_web_contents_) {
553 // If we were showing an interstitial, then we can end up here during
554 // embedder shutdown or when the embedder navigates to a different page.
555 // The call stack is roughly:
556 // BrowserPluginGuest::SetFocus()
557 // content::InterstitialPageImpl::Hide()
558 // content::InterstitialPageImpl::DontProceed().
560 // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed.
561 return;
564 if (last_text_input_state_.get())
565 guest_rwhv->TextInputStateChanged(*last_text_input_state_);
568 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
569 RenderFrameHost* render_frame_host,
570 const GURL& url,
571 ui::PageTransition transition_type) {
572 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
575 void BrowserPluginGuest::RenderViewReady() {
576 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
577 // TODO(fsamuel): Investigate whether it's possible to update state earlier
578 // here (see http://crbug.com/158151).
579 Send(new InputMsg_SetFocus(routing_id(), focused_));
580 UpdateVisibility();
582 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay(
583 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
586 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
587 SendMessageToEmbedder(
588 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
589 switch (status) {
590 #if defined(OS_CHROMEOS)
591 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
592 #endif
593 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
594 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
595 break;
596 case base::TERMINATION_STATUS_PROCESS_CRASHED:
597 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
598 break;
599 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
600 RecordAction(
601 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
602 break;
603 case base::TERMINATION_STATUS_LAUNCH_FAILED:
604 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.LaunchFailed"));
605 break;
606 default:
607 break;
611 // static
612 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
613 const IPC::Message& message) {
614 return (message.type() != BrowserPluginHostMsg_Attach::ID) &&
615 (IPC_MESSAGE_CLASS(message) == BrowserPluginMsgStart);
618 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
619 bool handled = true;
620 // In --site-per-process, we do not need most of BrowserPluginGuest to drive
621 // inner WebContents.
622 // Right now InputHostMsg_ImeCompositionRangeChanged hits NOTREACHED() in
623 // RWHVChildFrame, so we're disabling message handling entirely here.
624 // TODO(lazyboy): Fix this as part of http://crbug.com/330264. The required
625 // parts of code from this class should be extracted to a separate class for
626 // --site-per-process.
627 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
628 return false;
631 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
632 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
633 OnImeCancelComposition)
634 #if defined(OS_MACOSX) || defined(USE_AURA)
635 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
636 OnImeCompositionRangeChanged)
637 #endif
638 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
639 OnHasTouchEventHandlers)
640 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
641 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
642 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
643 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged,
644 OnTextInputStateChanged)
645 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
646 IPC_MESSAGE_UNHANDLED(handled = false)
647 IPC_END_MESSAGE_MAP()
648 return handled;
651 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message,
652 RenderFrameHost* render_frame_host) {
653 // This will eventually be the home for more IPC handlers that depend on
654 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
655 // compile if there are no handlers for a platform. So we have both #if guards
656 // around the whole thing (unfortunate but temporary), and #if guards where
657 // they belong, only around the one IPC handler. TODO(avi): Move more of the
658 // frame-based handlers to this function and remove the outer #if layer.
659 #if defined(OS_MACOSX)
660 bool handled = true;
661 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message,
662 render_frame_host)
663 #if defined(OS_MACOSX)
664 // MacOS X creates and populates platform-specific select drop-down menus
665 // whereas other platforms merely create a popup window that the guest
666 // renderer process paints inside.
667 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
668 #endif
669 IPC_MESSAGE_UNHANDLED(handled = false)
670 IPC_END_MESSAGE_MAP()
671 return handled;
672 #else
673 return false;
674 #endif
677 void BrowserPluginGuest::Attach(
678 int browser_plugin_instance_id,
679 WebContentsImpl* embedder_web_contents,
680 const BrowserPluginHostMsg_Attach_Params& params) {
681 browser_plugin_instance_id_ = browser_plugin_instance_id;
682 // If a guest is detaching from one container and attaching to another
683 // container, then late arriving ACKs may be lost if the mapping from
684 // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
685 // ensure that we always get new frames on attachment by ACKing the pending
686 // frame if it's still waiting on the ACK.
687 if (last_pending_frame_) {
688 cc::CompositorFrameAck ack;
689 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
690 last_pending_frame_->producing_route_id,
691 last_pending_frame_->output_surface_id,
692 last_pending_frame_->producing_host_id,
693 ack);
694 last_pending_frame_.reset();
697 // The guest is owned by the embedder. Attach is queued up so we cannot
698 // change embedders before attach completes. If the embedder goes away,
699 // so does the guest and so we will never call WillAttachComplete because
700 // we have a weak ptr.
701 delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id,
702 params.is_full_page_plugin,
703 base::Bind(&BrowserPluginGuest::OnWillAttachComplete,
704 weak_ptr_factory_.GetWeakPtr(),
705 embedder_web_contents, params));
708 void BrowserPluginGuest::OnWillAttachComplete(
709 WebContentsImpl* embedder_web_contents,
710 const BrowserPluginHostMsg_Attach_Params& params) {
711 bool use_cross_process_frames =
712 BrowserPluginGuestMode::UseCrossProcessFramesForGuests();
713 // If a RenderView has already been created for this new window, then we need
714 // to initialize the browser-side state now so that the RenderFrameHostManager
715 // does not create a new RenderView on navigation.
716 if (!use_cross_process_frames && has_render_view_) {
717 // This will trigger a callback to RenderViewReady after a round-trip IPC.
718 static_cast<RenderViewHostImpl*>(
719 GetWebContents()->GetRenderViewHost())->Init();
720 WebContentsViewGuest* web_contents_view =
721 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
722 if (!web_contents()->GetRenderViewHost()->GetView()) {
723 web_contents_view->CreateViewForWidget(
724 web_contents()->GetRenderViewHost(), true);
728 InitInternal(params, embedder_web_contents);
730 attached_ = true;
731 has_attached_since_surface_set_ = true;
732 SendQueuedMessages();
734 delegate_->DidAttach(GetGuestProxyRoutingID());
736 if (!use_cross_process_frames)
737 has_render_view_ = true;
739 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
742 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
743 int browser_plugin_instance_id,
744 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
745 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
746 params.output_surface_id,
747 params.producing_host_id,
748 params.ack);
749 last_pending_frame_.reset();
752 void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
753 if (!attached())
754 return;
756 // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
757 // it's attached again.
758 attached_ = false;
760 delegate_->DidDetach();
763 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
764 blink::WebDragStatus drag_status,
765 const DropData& drop_data,
766 blink::WebDragOperationsMask mask,
767 const gfx::Point& location) {
768 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
769 auto embedder = owner_web_contents_->GetBrowserPluginEmbedder();
770 switch (drag_status) {
771 case blink::WebDragStatusEnter:
772 // Only track the URL being dragged over the guest if the link isn't
773 // coming from the guest.
774 if (!embedder->DragEnteredGuest(this))
775 dragged_url_ = drop_data.url;
776 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
777 break;
778 case blink::WebDragStatusOver:
779 host->DragTargetDragOver(location, location, mask, 0);
780 break;
781 case blink::WebDragStatusLeave:
782 embedder->DragLeftGuest(this);
783 host->DragTargetDragLeave();
784 break;
785 case blink::WebDragStatusDrop:
786 host->DragTargetDrop(location, location, 0);
787 if (dragged_url_.is_valid()) {
788 delegate_->DidDropLink(dragged_url_);
789 dragged_url_ = GURL();
791 break;
792 case blink::WebDragStatusUnknown:
793 NOTREACHED();
795 last_drag_status_ = drag_status;
796 EndSystemDragIfApplicable();
799 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
800 const std::string& name) {
801 RenderFrameHost* focused_frame = web_contents()->GetFocusedFrame();
802 if (!focused_frame)
803 return;
805 focused_frame->Send(new InputMsg_ExecuteNoValueEditCommand(
806 focused_frame->GetRoutingID(), name));
809 void BrowserPluginGuest::OnImeSetComposition(
810 int browser_plugin_instance_id,
811 const std::string& text,
812 const std::vector<blink::WebCompositionUnderline>& underlines,
813 int selection_start,
814 int selection_end) {
815 Send(new InputMsg_ImeSetComposition(routing_id(),
816 base::UTF8ToUTF16(text), underlines,
817 selection_start, selection_end));
820 void BrowserPluginGuest::OnImeConfirmComposition(
821 int browser_plugin_instance_id,
822 const std::string& text,
823 bool keep_selection) {
824 Send(new InputMsg_ImeConfirmComposition(routing_id(),
825 base::UTF8ToUTF16(text),
826 gfx::Range::InvalidRange(),
827 keep_selection));
830 void BrowserPluginGuest::OnExtendSelectionAndDelete(
831 int browser_plugin_instance_id,
832 int before,
833 int after) {
834 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
835 web_contents()->GetFocusedFrame());
836 if (rfh)
837 rfh->ExtendSelectionAndDelete(before, after);
840 void BrowserPluginGuest::OnReclaimCompositorResources(
841 int browser_plugin_instance_id,
842 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
843 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
844 params.output_surface_id,
845 params.renderer_host_id,
846 params.ack);
849 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
850 bool last_unlocked_by_target,
851 bool privileged) {
852 if (pending_lock_request_) {
853 // Immediately reject the lock because only one pointerLock may be active
854 // at a time.
855 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
856 return;
859 pending_lock_request_ = true;
861 delegate_->RequestPointerLockPermission(
862 user_gesture,
863 last_unlocked_by_target,
864 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
865 weak_ptr_factory_.GetWeakPtr()));
868 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
869 bool succeeded) {
870 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
871 pending_lock_request_ = false;
872 if (succeeded)
873 mouse_locked_ = true;
876 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id,
877 bool focused,
878 blink::WebFocusType focus_type) {
879 RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
880 RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : nullptr;
881 SetFocus(rwh, focused, focus_type);
884 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
885 int browser_plugin_instance_id,
886 const std::vector<EditCommand>& edit_commands) {
887 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
888 edit_commands));
891 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
892 bool visible) {
893 guest_visible_ = visible;
894 if (embedder_visible_ && guest_visible_)
895 GetWebContents()->WasShown();
896 else
897 GetWebContents()->WasHidden();
900 void BrowserPluginGuest::OnUnlockMouse() {
901 SendMessageToEmbedder(
902 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
905 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
906 // mouse_locked_ could be false here if the lock attempt was cancelled due
907 // to window focus, or for various other reasons before the guest was informed
908 // of the lock's success.
909 if (mouse_locked_)
910 Send(new ViewMsg_MouseLockLost(routing_id()));
911 mouse_locked_ = false;
914 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
915 const gfx::Rect& view_rect) {
916 // The plugin has moved within the embedder without resizing or the
917 // embedder/container's view rect changing.
918 guest_window_rect_ = view_rect;
919 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
920 GetWebContents()->GetRenderViewHost());
921 if (rvh)
922 rvh->SendScreenRects();
925 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
926 SendMessageToEmbedder(
927 new BrowserPluginMsg_ShouldAcceptTouchEvents(
928 browser_plugin_instance_id(), accept));
931 #if defined(OS_MACOSX)
932 void BrowserPluginGuest::OnShowPopup(
933 RenderFrameHost* render_frame_host,
934 const FrameHostMsg_ShowPopup_Params& params) {
935 gfx::Rect translated_bounds(params.bounds);
936 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
937 BrowserPluginPopupMenuHelper popup_menu_helper(
938 owner_web_contents_->GetRenderViewHost(), render_frame_host);
939 popup_menu_helper.ShowPopupMenu(translated_bounds,
940 params.item_height,
941 params.item_font_size,
942 params.selected_item,
943 params.popup_items,
944 params.right_aligned,
945 params.allow_multiple_selection);
947 #endif
949 void BrowserPluginGuest::OnShowWidget(int route_id,
950 const gfx::Rect& initial_rect) {
951 GetWebContents()->ShowCreatedWidget(route_id, initial_rect);
954 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
955 SendMessageToEmbedder(
956 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
959 void BrowserPluginGuest::OnTextInputStateChanged(
960 const ViewHostMsg_TextInputState_Params& params) {
961 // Save the state of text input so we can restore it on focus.
962 last_text_input_state_.reset(new ViewHostMsg_TextInputState_Params(params));
964 SendTextInputTypeChangedToView(
965 static_cast<RenderWidgetHostViewBase*>(
966 web_contents()->GetRenderWidgetHostView()));
969 void BrowserPluginGuest::OnImeCancelComposition() {
970 static_cast<RenderWidgetHostViewBase*>(
971 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
974 #if defined(OS_MACOSX) || defined(USE_AURA)
975 void BrowserPluginGuest::OnImeCompositionRangeChanged(
976 const gfx::Range& range,
977 const std::vector<gfx::Rect>& character_bounds) {
978 static_cast<RenderWidgetHostViewBase*>(
979 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
980 range, character_bounds);
982 #endif
984 void BrowserPluginGuest::SetContextMenuPosition(const gfx::Point& position) {
985 if (delegate_)
986 delegate_->SetContextMenuPosition(position);
989 } // namespace content