Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / browser_plugin / browser_plugin_guest.cc
blob54c3f5d6e53d8355fcd8f3afdbdd437bde96071d
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/command_line.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/pickle.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "cc/surfaces/surface.h"
14 #include "cc/surfaces/surface_manager.h"
15 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
16 #include "content/browser/browser_thread_impl.h"
17 #include "content/browser/child_process_security_policy_impl.h"
18 #include "content/browser/compositor/surface_utils.h"
19 #include "content/browser/frame_host/render_frame_host_impl.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/view_messages.h"
34 #include "content/public/browser/browser_context.h"
35 #include "content/public/browser/browser_plugin_guest_manager.h"
36 #include "content/public/browser/content_browser_client.h"
37 #include "content/public/browser/guest_host.h"
38 #include "content/public/browser/render_widget_host_view.h"
39 #include "content/public/browser/user_metrics.h"
40 #include "content/public/browser/web_contents_observer.h"
41 #include "content/public/common/content_switches.h"
42 #include "content/public/common/drop_data.h"
43 #include "ui/gfx/geometry/size_conversions.h"
45 #if defined(OS_MACOSX)
46 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
47 #include "content/common/frame_messages.h"
48 #endif
50 namespace content {
52 class BrowserPluginGuest::EmbedderVisibilityObserver
53 : public WebContentsObserver {
54 public:
55 explicit EmbedderVisibilityObserver(BrowserPluginGuest* guest)
56 : WebContentsObserver(guest->embedder_web_contents()),
57 browser_plugin_guest_(guest) {
60 ~EmbedderVisibilityObserver() override {}
62 // WebContentsObserver implementation.
63 void WasShown() override {
64 browser_plugin_guest_->EmbedderVisibilityChanged(true);
67 void WasHidden() override {
68 browser_plugin_guest_->EmbedderVisibilityChanged(false);
71 private:
72 BrowserPluginGuest* browser_plugin_guest_;
74 DISALLOW_COPY_AND_ASSIGN(EmbedderVisibilityObserver);
77 BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
78 WebContentsImpl* web_contents,
79 BrowserPluginGuestDelegate* delegate)
80 : WebContentsObserver(web_contents),
81 owner_web_contents_(nullptr),
82 attached_(false),
83 has_attached_since_surface_set_(false),
84 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
85 focused_(false),
86 mouse_locked_(false),
87 pending_lock_request_(false),
88 guest_visible_(false),
89 embedder_visible_(true),
90 is_full_page_plugin_(false),
91 has_render_view_(has_render_view),
92 is_in_destruction_(false),
93 initialized_(false),
94 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
95 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
96 last_input_flags_(0),
97 last_can_compose_inline_(true),
98 guest_proxy_routing_id_(MSG_ROUTING_NONE),
99 last_drag_status_(blink::WebDragStatusUnknown),
100 seen_embedder_system_drag_ended_(false),
101 seen_embedder_drag_source_ended_at_(false),
102 delegate_(delegate),
103 weak_ptr_factory_(this) {
104 DCHECK(web_contents);
105 DCHECK(delegate);
106 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
107 web_contents->SetBrowserPluginGuest(this);
108 delegate->SetGuestHost(this);
111 int BrowserPluginGuest::GetGuestProxyRoutingID() {
112 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
113 switches::kSitePerProcess)) {
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 guest_proxy_routing_id_ =
134 GetWebContents()->CreateSwappedOutRenderView(owner_site_instance);
136 return guest_proxy_routing_id_;
139 int BrowserPluginGuest::LoadURLWithParams(
140 const NavigationController::LoadURLParams& load_params) {
141 GetWebContents()->GetController().LoadURLWithParams(load_params);
142 return GetGuestProxyRoutingID();
145 void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) {
146 GetWebContents()->GetView()->SizeContents(new_size);
149 void BrowserPluginGuest::WillDestroy() {
150 is_in_destruction_ = true;
151 owner_web_contents_ = nullptr;
152 attached_ = false;
155 void BrowserPluginGuest::Init() {
156 if (initialized_)
157 return;
158 initialized_ = true;
160 // TODO(fsamuel): Initiailization prior to attachment should be behind a
161 // command line flag once we introduce experimental guest types that rely on
162 // this functionality.
163 if (!delegate_->CanRunInDetachedState())
164 return;
166 WebContentsImpl* owner_web_contents = static_cast<WebContentsImpl*>(
167 delegate_->GetOwnerWebContents());
168 owner_web_contents->CreateBrowserPluginEmbedderIfNecessary();
169 InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents);
172 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
173 return weak_ptr_factory_.GetWeakPtr();
176 void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh,
177 bool focused,
178 blink::WebFocusType focus_type) {
179 focused_ = focused;
180 if (!rwh)
181 return;
183 if ((focus_type == blink::WebFocusTypeForward) ||
184 (focus_type == blink::WebFocusTypeBackward)) {
185 static_cast<RenderViewHostImpl*>(RenderViewHost::From(rwh))->
186 SetInitialFocus(focus_type == blink::WebFocusTypeBackward);
188 rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
189 if (!focused && mouse_locked_)
190 OnUnlockMouse();
192 // Restore the last seen state of text input to the view.
193 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
194 rwh->GetView());
195 SendTextInputTypeChangedToView(rwhv);
198 void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
199 if (tooltip_text == current_tooltip_text_)
200 return;
201 current_tooltip_text_ = tooltip_text;
203 SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
204 browser_plugin_instance_id_, tooltip_text));
207 bool BrowserPluginGuest::LockMouse(bool allowed) {
208 if (!attached() || (mouse_locked_ == allowed))
209 return false;
211 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
214 WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow(
215 const WebContents::CreateParams& params) {
216 WebContentsImpl* new_contents =
217 static_cast<WebContentsImpl*>(delegate_->CreateNewGuestWindow(params));
218 DCHECK(new_contents);
219 return new_contents;
222 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
223 const IPC::Message& message) {
224 RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
225 web_contents()->GetRenderWidgetHostView());
226 // Until the guest is attached, it should not be handling input events.
227 if (attached() && rwhv && rwhv->OnMessageReceivedFromEmbedder(
228 message,
229 static_cast<RenderViewHostImpl*>(
230 embedder_web_contents()->GetRenderViewHost()))) {
231 return true;
234 bool handled = true;
235 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
236 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
237 OnCompositorFrameSwappedACK)
238 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach)
239 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
240 OnDragStatusUpdate)
241 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
242 OnExecuteEditCommand)
243 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
244 OnExtendSelectionAndDelete)
245 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
246 OnImeConfirmComposition)
247 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
248 OnImeSetComposition)
249 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
250 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
251 OnReclaimCompositorResources)
252 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
253 OnSetEditCommandsForNextKeyEvent)
254 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
255 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
256 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
257 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
258 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SatisfySequence, OnSatisfySequence)
259 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_RequireSequence, OnRequireSequence)
260 IPC_MESSAGE_UNHANDLED(handled = false)
261 IPC_END_MESSAGE_MAP()
262 return handled;
265 void BrowserPluginGuest::InitInternal(
266 const BrowserPluginHostMsg_Attach_Params& params,
267 WebContentsImpl* owner_web_contents) {
268 focused_ = params.focused;
269 OnSetFocus(browser_plugin::kInstanceIDNone,
270 focused_,
271 blink::WebFocusTypeNone);
273 guest_visible_ = params.visible;
274 UpdateVisibility();
276 is_full_page_plugin_ = params.is_full_page_plugin;
277 guest_window_rect_ = params.view_rect;
279 if (owner_web_contents_ != owner_web_contents) {
280 WebContentsViewGuest* new_view = nullptr;
281 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
282 switches::kSitePerProcess)) {
283 new_view =
284 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
287 if (owner_web_contents_ && new_view)
288 new_view->OnGuestDetached(owner_web_contents_->GetView());
290 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
291 // be attached.
292 owner_web_contents_ = owner_web_contents;
293 if (new_view)
294 new_view->OnGuestAttached(owner_web_contents_->GetView());
297 RendererPreferences* renderer_prefs =
298 GetWebContents()->GetMutableRendererPrefs();
299 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
300 // Copy renderer preferences (and nothing else) from the embedder's
301 // WebContents to the guest.
303 // For GTK and Aura this is necessary to get proper renderer configuration
304 // values for caret blinking interval, colors related to selection and
305 // focus.
306 *renderer_prefs = *owner_web_contents_->GetMutableRendererPrefs();
307 renderer_prefs->user_agent_override = guest_user_agent_override;
309 // We would like the guest to report changes to frame names so that we can
310 // update the BrowserPlugin's corresponding 'name' attribute.
311 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
312 renderer_prefs->report_frame_name_changes = true;
313 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
314 // navigations still continue to function inside the app.
315 renderer_prefs->browser_handles_all_top_level_requests = false;
316 // Disable "client blocked" error page for browser plugin.
317 renderer_prefs->disable_client_blocked_error_page = true;
319 embedder_visibility_observer_.reset(new EmbedderVisibilityObserver(this));
321 DCHECK(GetWebContents()->GetRenderViewHost());
323 // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
324 auto render_widget_host =
325 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
326 render_widget_host->NotifyScreenInfoChanged();
328 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
329 // be reset again the next time preferences are updated.
330 WebPreferences prefs =
331 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
332 prefs.navigate_on_drag_drop = false;
333 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
336 BrowserPluginGuest::~BrowserPluginGuest() {
339 // static
340 BrowserPluginGuest* BrowserPluginGuest::Create(
341 WebContentsImpl* web_contents,
342 BrowserPluginGuestDelegate* delegate) {
343 return new BrowserPluginGuest(
344 web_contents->HasOpener(), web_contents, delegate);
347 // static
348 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
349 return web_contents && web_contents->GetBrowserPluginGuest();
352 // static
353 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
354 return render_view_host && IsGuest(
355 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
356 render_view_host)));
359 RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
360 if (!owner_web_contents_)
361 return nullptr;
362 return owner_web_contents_->GetRenderWidgetHostView();
365 void BrowserPluginGuest::UpdateVisibility() {
366 OnSetVisibility(browser_plugin_instance_id(), visible());
369 BrowserPluginGuestManager*
370 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
371 return GetWebContents()->GetBrowserContext()->GetGuestManager();
374 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
375 embedder_visible_ = visible;
376 UpdateVisibility();
379 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
380 SendMessageToEmbedder(
381 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
384 void BrowserPluginGuest::UpdateGuestSizeIfNecessary(
385 const gfx::Size& frame_size, float scale_factor) {
386 gfx::Size view_size(
387 gfx::ToFlooredSize(gfx::ScaleSize(frame_size, 1.0f / scale_factor)));
389 if (last_seen_view_size_ != view_size) {
390 delegate_->GuestSizeChanged(view_size);
391 last_seen_view_size_ = view_size;
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 cc::RenderPass* root_pass =
403 frame->delegated_frame_data->render_pass_list.back();
404 UpdateGuestSizeIfNecessary(root_pass->output_rect.size(),
405 frame->metadata.device_scale_factor);
407 last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params());
408 frame->AssignTo(&last_pending_frame_->frame);
409 last_pending_frame_->output_surface_id = output_surface_id;
410 last_pending_frame_->producing_route_id = host_routing_id;
411 last_pending_frame_->producing_host_id = host_process_id;
413 SendMessageToEmbedder(
414 new BrowserPluginMsg_CompositorFrameSwapped(
415 browser_plugin_instance_id(), *last_pending_frame_));
418 void BrowserPluginGuest::SetChildFrameSurface(
419 const cc::SurfaceId& surface_id,
420 const gfx::Size& frame_size,
421 float scale_factor,
422 const cc::SurfaceSequence& sequence) {
423 has_attached_since_surface_set_ = false;
424 SendMessageToEmbedder(new BrowserPluginMsg_SetChildFrameSurface(
425 browser_plugin_instance_id(), surface_id, frame_size, scale_factor,
426 sequence));
429 void BrowserPluginGuest::OnSatisfySequence(
430 int instance_id,
431 const cc::SurfaceSequence& sequence) {
432 std::vector<uint32_t> sequences;
433 sequences.push_back(sequence.sequence);
434 cc::SurfaceManager* manager = GetSurfaceManager();
435 manager->DidSatisfySequences(sequence.id_namespace, &sequences);
438 void BrowserPluginGuest::OnRequireSequence(
439 int instance_id,
440 const cc::SurfaceId& id,
441 const cc::SurfaceSequence& sequence) {
442 cc::SurfaceManager* manager = GetSurfaceManager();
443 cc::Surface* surface = manager->GetSurfaceForId(id);
444 if (!surface) {
445 LOG(ERROR) << "Attempting to require callback on nonexistent surface";
446 return;
448 surface->AddDestructionDependency(sequence);
451 void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
452 SendMessageToEmbedder(
453 new BrowserPluginMsg_SetContentsOpaque(
454 browser_plugin_instance_id(), opaque));
457 bool BrowserPluginGuest::Find(int request_id,
458 const base::string16& search_text,
459 const blink::WebFindOptions& options) {
460 return delegate_->Find(request_id, search_text, options);
463 bool BrowserPluginGuest::StopFinding(StopFindAction action) {
464 return delegate_->StopFinding(action);
467 WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
468 return static_cast<WebContentsImpl*>(web_contents());
471 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
472 const gfx::Point& relative_position) const {
473 if (!attached())
474 return relative_position;
476 gfx::Point screen_pos(relative_position);
477 screen_pos += guest_window_rect_.OffsetFromOrigin();
478 return screen_pos;
481 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
482 // During tests, attache() may be true when there is no owner_web_contents_;
483 // in this case just queue any messages we receive.
484 if (!attached() || !owner_web_contents_) {
485 // Some pages such as data URLs, javascript URLs, and about:blank
486 // do not load external resources and so they load prior to attachment.
487 // As a result, we must save all these IPCs until attachment and then
488 // forward them so that the embedder gets a chance to see and process
489 // the load events.
490 pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
491 return;
493 owner_web_contents_->Send(msg);
496 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
497 int screen_x, int screen_y, blink::WebDragOperation operation) {
498 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
499 screen_x, screen_y, operation);
500 seen_embedder_drag_source_ended_at_ = true;
501 EndSystemDragIfApplicable();
504 void BrowserPluginGuest::EndSystemDragIfApplicable() {
505 // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
506 // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
507 // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
508 // means we call it in all cases and also make sure we only call it once.
509 // This ensures that the input state of the guest stays correct, otherwise
510 // it will go stale and won't accept any further input events.
512 // The strategy used here to call DragSourceSystemDragEnded() on the RVH
513 // is when the following conditions are met:
514 // a. Embedder has seen SystemDragEnded()
515 // b. Embedder has seen DragSourceEndedAt()
516 // c. The guest has seen some drag status update other than
517 // WebDragStatusUnknown. Note that this step should ideally be done
518 // differently: The guest has seen at least one of
519 // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
520 // a source quickly outside of <webview> bounds, then the
521 // BrowserPluginGuest never sees any of these drag status updates,
522 // there we just check whether we've seen any drag status update or
523 // not.
524 if (last_drag_status_ != blink::WebDragStatusOver &&
525 seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
526 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
527 GetWebContents()->GetRenderViewHost());
528 guest_rvh->DragSourceSystemDragEnded();
529 last_drag_status_ = blink::WebDragStatusUnknown;
530 seen_embedder_system_drag_ended_ = false;
531 seen_embedder_drag_source_ended_at_ = false;
532 dragged_url_ = GURL();
536 void BrowserPluginGuest::EmbedderSystemDragEnded() {
537 seen_embedder_system_drag_ended_ = true;
538 EndSystemDragIfApplicable();
541 void BrowserPluginGuest::SendQueuedMessages() {
542 if (!attached())
543 return;
545 while (!pending_messages_.empty()) {
546 linked_ptr<IPC::Message> message_ptr = pending_messages_.front();
547 pending_messages_.pop_front();
548 SendMessageToEmbedder(message_ptr.release());
552 void BrowserPluginGuest::SendTextInputTypeChangedToView(
553 RenderWidgetHostViewBase* guest_rwhv) {
554 if (!guest_rwhv)
555 return;
557 if (!owner_web_contents_) {
558 // If we were showing an interstitial, then we can end up here during
559 // embedder shutdown or when the embedder navigates to a different page.
560 // The call stack is roughly:
561 // BrowserPluginGuest::SetFocus()
562 // content::InterstitialPageImpl::Hide()
563 // content::InterstitialPageImpl::DontProceed().
565 // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed.
566 return;
569 guest_rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
570 last_can_compose_inline_, last_input_flags_);
573 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
574 RenderFrameHost* render_frame_host,
575 const GURL& url,
576 ui::PageTransition transition_type) {
577 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
580 void BrowserPluginGuest::RenderViewReady() {
581 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
582 // TODO(fsamuel): Investigate whether it's possible to update state earlier
583 // here (see http://crbug.com/158151).
584 Send(new InputMsg_SetFocus(routing_id(), focused_));
585 UpdateVisibility();
587 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay(
588 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
591 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
592 SendMessageToEmbedder(
593 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
594 switch (status) {
595 #if defined(OS_CHROMEOS)
596 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
597 #endif
598 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
599 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
600 break;
601 case base::TERMINATION_STATUS_PROCESS_CRASHED:
602 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
603 break;
604 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
605 RecordAction(
606 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
607 break;
608 default:
609 break;
613 // static
614 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
615 const IPC::Message& message) {
616 return (message.type() != BrowserPluginHostMsg_Attach::ID) &&
617 (IPC_MESSAGE_CLASS(message) == BrowserPluginMsgStart);
620 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
621 bool handled = true;
622 // In --site-per-process, we do not need most of BrowserPluginGuest to drive
623 // inner WebContents.
624 // Right now InputHostMsg_ImeCompositionRangeChanged hits NOTREACHED() in
625 // RWHVChildFrame, so we're disabling message handling entirely here.
626 // TODO(lazyboy): Fix this as part of http://crbug.com/330264. The required
627 // parts of code from this class should be extracted to a separate class for
628 // --site-per-process.
629 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
630 switches::kSitePerProcess)) {
631 return false;
634 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
635 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
636 OnImeCancelComposition)
637 #if defined(OS_MACOSX) || defined(USE_AURA)
638 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
639 OnImeCompositionRangeChanged)
640 #endif
641 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
642 OnHasTouchEventHandlers)
643 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
644 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
645 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
646 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
647 OnTextInputTypeChanged)
648 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
649 IPC_MESSAGE_UNHANDLED(handled = false)
650 IPC_END_MESSAGE_MAP()
651 return handled;
654 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message,
655 RenderFrameHost* render_frame_host) {
656 // This will eventually be the home for more IPC handlers that depend on
657 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
658 // compile if there are no handlers for a platform. So we have both #if guards
659 // around the whole thing (unfortunate but temporary), and #if guards where
660 // they belong, only around the one IPC handler. TODO(avi): Move more of the
661 // frame-based handlers to this function and remove the outer #if layer.
662 #if defined(OS_MACOSX)
663 bool handled = true;
664 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message,
665 render_frame_host)
666 #if defined(OS_MACOSX)
667 // MacOS X creates and populates platform-specific select drop-down menus
668 // whereas other platforms merely create a popup window that the guest
669 // renderer process paints inside.
670 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
671 #endif
672 IPC_MESSAGE_UNHANDLED(handled = false)
673 IPC_END_MESSAGE_MAP()
674 return handled;
675 #else
676 return false;
677 #endif
680 void BrowserPluginGuest::Attach(
681 int browser_plugin_instance_id,
682 WebContentsImpl* embedder_web_contents,
683 const BrowserPluginHostMsg_Attach_Params& params) {
684 browser_plugin_instance_id_ = browser_plugin_instance_id;
685 // If a guest is detaching from one container and attaching to another
686 // container, then late arriving ACKs may be lost if the mapping from
687 // |browser_plugin_instance_id| to |guest_instance_id| changes. Thus we
688 // ensure that we always get new frames on attachment by ACKing the pending
689 // frame if it's still waiting on the ACK.
690 if (last_pending_frame_) {
691 cc::CompositorFrameAck ack;
692 RenderWidgetHostImpl::SendSwapCompositorFrameAck(
693 last_pending_frame_->producing_route_id,
694 last_pending_frame_->output_surface_id,
695 last_pending_frame_->producing_host_id,
696 ack);
697 last_pending_frame_.reset();
700 // The guest is owned by the embedder. Attach is queued up so we cannot
701 // change embedders before attach completes. If the embedder goes away,
702 // so does the guest and so we will never call WillAttachComplete because
703 // we have a weak ptr.
704 delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id,
705 params.is_full_page_plugin,
706 base::Bind(&BrowserPluginGuest::OnWillAttachComplete,
707 weak_ptr_factory_.GetWeakPtr(),
708 embedder_web_contents, params));
711 void BrowserPluginGuest::OnWillAttachComplete(
712 WebContentsImpl* embedder_web_contents,
713 const BrowserPluginHostMsg_Attach_Params& params) {
714 bool use_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
715 switches::kSitePerProcess);
716 // If a RenderView has already been created for this new window, then we need
717 // to initialize the browser-side state now so that the RenderFrameHostManager
718 // does not create a new RenderView on navigation.
719 if (!use_site_per_process && has_render_view_) {
720 // This will trigger a callback to RenderViewReady after a round-trip IPC.
721 static_cast<RenderViewHostImpl*>(
722 GetWebContents()->GetRenderViewHost())->Init();
723 WebContentsViewGuest* web_contents_view =
724 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
725 if (!web_contents()->GetRenderViewHost()->GetView()) {
726 web_contents_view->CreateViewForWidget(
727 web_contents()->GetRenderViewHost(), true);
731 InitInternal(params, embedder_web_contents);
733 attached_ = true;
734 has_attached_since_surface_set_ = true;
735 SendQueuedMessages();
737 delegate_->DidAttach(GetGuestProxyRoutingID());
739 if (!use_site_per_process)
740 has_render_view_ = true;
742 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
745 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
746 int browser_plugin_instance_id,
747 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
748 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
749 params.output_surface_id,
750 params.producing_host_id,
751 params.ack);
752 last_pending_frame_.reset();
755 void BrowserPluginGuest::OnDetach(int browser_plugin_instance_id) {
756 if (!attached())
757 return;
759 // This tells BrowserPluginGuest to queue up all IPCs to BrowserPlugin until
760 // it's attached again.
761 attached_ = false;
763 delegate_->DidDetach();
766 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
767 blink::WebDragStatus drag_status,
768 const DropData& drop_data,
769 blink::WebDragOperationsMask mask,
770 const gfx::Point& location) {
771 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
772 auto embedder = owner_web_contents_->GetBrowserPluginEmbedder();
773 switch (drag_status) {
774 case blink::WebDragStatusEnter:
775 // Only track the URL being dragged over the guest if the link isn't
776 // coming from the guest.
777 if (!embedder->DragEnteredGuest(this))
778 dragged_url_ = drop_data.url;
779 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
780 break;
781 case blink::WebDragStatusOver:
782 host->DragTargetDragOver(location, location, mask, 0);
783 break;
784 case blink::WebDragStatusLeave:
785 embedder->DragLeftGuest(this);
786 host->DragTargetDragLeave();
787 break;
788 case blink::WebDragStatusDrop:
789 host->DragTargetDrop(location, location, 0);
790 if (dragged_url_.is_valid()) {
791 delegate_->DidDropLink(dragged_url_);
792 dragged_url_ = GURL();
794 break;
795 case blink::WebDragStatusUnknown:
796 NOTREACHED();
798 last_drag_status_ = drag_status;
799 EndSystemDragIfApplicable();
802 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
803 const std::string& name) {
804 RenderFrameHost* focused_frame = web_contents()->GetFocusedFrame();
805 if (!focused_frame)
806 return;
808 focused_frame->Send(new InputMsg_ExecuteNoValueEditCommand(
809 focused_frame->GetRoutingID(), name));
812 void BrowserPluginGuest::OnImeSetComposition(
813 int browser_plugin_instance_id,
814 const std::string& text,
815 const std::vector<blink::WebCompositionUnderline>& underlines,
816 int selection_start,
817 int selection_end) {
818 Send(new InputMsg_ImeSetComposition(routing_id(),
819 base::UTF8ToUTF16(text), underlines,
820 selection_start, selection_end));
823 void BrowserPluginGuest::OnImeConfirmComposition(
824 int browser_plugin_instance_id,
825 const std::string& text,
826 bool keep_selection) {
827 Send(new InputMsg_ImeConfirmComposition(routing_id(),
828 base::UTF8ToUTF16(text),
829 gfx::Range::InvalidRange(),
830 keep_selection));
833 void BrowserPluginGuest::OnExtendSelectionAndDelete(
834 int browser_plugin_instance_id,
835 int before,
836 int after) {
837 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
838 web_contents()->GetFocusedFrame());
839 if (rfh)
840 rfh->ExtendSelectionAndDelete(before, after);
843 void BrowserPluginGuest::OnReclaimCompositorResources(
844 int browser_plugin_instance_id,
845 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
846 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
847 params.output_surface_id,
848 params.renderer_host_id,
849 params.ack);
852 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
853 bool last_unlocked_by_target,
854 bool privileged) {
855 if (pending_lock_request_) {
856 // Immediately reject the lock because only one pointerLock may be active
857 // at a time.
858 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
859 return;
862 pending_lock_request_ = true;
864 delegate_->RequestPointerLockPermission(
865 user_gesture,
866 last_unlocked_by_target,
867 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
868 weak_ptr_factory_.GetWeakPtr()));
871 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
872 bool succeeded) {
873 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
874 pending_lock_request_ = false;
875 if (succeeded)
876 mouse_locked_ = true;
879 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id,
880 bool focused,
881 blink::WebFocusType focus_type) {
882 RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
883 RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : nullptr;
884 SetFocus(rwh, focused, focus_type);
887 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
888 int browser_plugin_instance_id,
889 const std::vector<EditCommand>& edit_commands) {
890 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
891 edit_commands));
894 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
895 bool visible) {
896 guest_visible_ = visible;
897 if (embedder_visible_ && guest_visible_)
898 GetWebContents()->WasShown();
899 else
900 GetWebContents()->WasHidden();
903 void BrowserPluginGuest::OnUnlockMouse() {
904 SendMessageToEmbedder(
905 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
908 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
909 // mouse_locked_ could be false here if the lock attempt was cancelled due
910 // to window focus, or for various other reasons before the guest was informed
911 // of the lock's success.
912 if (mouse_locked_)
913 Send(new ViewMsg_MouseLockLost(routing_id()));
914 mouse_locked_ = false;
917 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
918 const gfx::Rect& view_rect) {
919 // The plugin has moved within the embedder without resizing or the
920 // embedder/container's view rect changing.
921 guest_window_rect_ = view_rect;
922 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
923 GetWebContents()->GetRenderViewHost());
924 if (rvh)
925 rvh->SendScreenRects();
928 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
929 SendMessageToEmbedder(
930 new BrowserPluginMsg_ShouldAcceptTouchEvents(
931 browser_plugin_instance_id(), accept));
934 #if defined(OS_MACOSX)
935 void BrowserPluginGuest::OnShowPopup(
936 RenderFrameHost* render_frame_host,
937 const FrameHostMsg_ShowPopup_Params& params) {
938 gfx::Rect translated_bounds(params.bounds);
939 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
940 BrowserPluginPopupMenuHelper popup_menu_helper(
941 owner_web_contents_->GetRenderViewHost(), render_frame_host);
942 popup_menu_helper.ShowPopupMenu(translated_bounds,
943 params.item_height,
944 params.item_font_size,
945 params.selected_item,
946 params.popup_items,
947 params.right_aligned,
948 params.allow_multiple_selection);
950 #endif
952 void BrowserPluginGuest::OnShowWidget(int route_id,
953 const gfx::Rect& initial_rect) {
954 GetWebContents()->ShowCreatedWidget(route_id, initial_rect);
957 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
958 SendMessageToEmbedder(
959 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
962 void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
963 ui::TextInputMode input_mode,
964 bool can_compose_inline,
965 int flags) {
966 // Save the state of text input so we can restore it on focus.
967 last_text_input_type_ = type;
968 last_input_mode_ = input_mode;
969 last_input_flags_ = flags;
970 last_can_compose_inline_ = can_compose_inline;
972 SendTextInputTypeChangedToView(
973 static_cast<RenderWidgetHostViewBase*>(
974 web_contents()->GetRenderWidgetHostView()));
977 void BrowserPluginGuest::OnImeCancelComposition() {
978 static_cast<RenderWidgetHostViewBase*>(
979 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
982 #if defined(OS_MACOSX) || defined(USE_AURA)
983 void BrowserPluginGuest::OnImeCompositionRangeChanged(
984 const gfx::Range& range,
985 const std::vector<gfx::Rect>& character_bounds) {
986 static_cast<RenderWidgetHostViewBase*>(
987 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
988 range, character_bounds);
990 #endif
992 } // namespace content