Add ICU message format support
[chromium-blink-merge.git] / content / browser / browser_plugin / browser_plugin_guest.cc
blob6991a29f73f1a75947aa2c84d543412f422823cc
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_widget_host_view_guest.h"
20 #include "content/browser/loader/resource_dispatcher_host_impl.h"
21 #include "content/browser/renderer_host/render_view_host_impl.h"
22 #include "content/browser/renderer_host/render_widget_host_impl.h"
23 #include "content/browser/renderer_host/render_widget_host_view_base.h"
24 #include "content/browser/web_contents/web_contents_impl.h"
25 #include "content/browser/web_contents/web_contents_view_guest.h"
26 #include "content/common/browser_plugin/browser_plugin_constants.h"
27 #include "content/common/browser_plugin/browser_plugin_messages.h"
28 #include "content/common/content_constants_internal.h"
29 #include "content/common/drag_messages.h"
30 #include "content/common/host_shared_bitmap_manager.h"
31 #include "content/common/input_messages.h"
32 #include "content/common/view_messages.h"
33 #include "content/public/browser/browser_context.h"
34 #include "content/public/browser/browser_plugin_guest_manager.h"
35 #include "content/public/browser/content_browser_client.h"
36 #include "content/public/browser/guest_host.h"
37 #include "content/public/browser/render_widget_host_view.h"
38 #include "content/public/browser/user_metrics.h"
39 #include "content/public/browser/web_contents_observer.h"
40 #include "content/public/common/browser_plugin_guest_mode.h"
41 #include "content/public/common/drop_data.h"
42 #include "ui/gfx/geometry/size_conversions.h"
44 #if defined(OS_MACOSX)
45 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
46 #include "content/common/frame_messages.h"
47 #endif
49 namespace content {
51 class BrowserPluginGuest::EmbedderVisibilityObserver
52 : public WebContentsObserver {
53 public:
54 explicit EmbedderVisibilityObserver(BrowserPluginGuest* guest)
55 : WebContentsObserver(guest->embedder_web_contents()),
56 browser_plugin_guest_(guest) {
59 ~EmbedderVisibilityObserver() override {}
61 // WebContentsObserver implementation.
62 void WasShown() override {
63 browser_plugin_guest_->EmbedderVisibilityChanged(true);
66 void WasHidden() override {
67 browser_plugin_guest_->EmbedderVisibilityChanged(false);
70 private:
71 BrowserPluginGuest* browser_plugin_guest_;
73 DISALLOW_COPY_AND_ASSIGN(EmbedderVisibilityObserver);
76 BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
77 WebContentsImpl* web_contents,
78 BrowserPluginGuestDelegate* delegate)
79 : WebContentsObserver(web_contents),
80 owner_web_contents_(nullptr),
81 attached_(false),
82 has_attached_since_surface_set_(false),
83 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
84 focused_(false),
85 mouse_locked_(false),
86 pending_lock_request_(false),
87 guest_visible_(false),
88 embedder_visible_(true),
89 is_full_page_plugin_(false),
90 has_render_view_(has_render_view),
91 is_in_destruction_(false),
92 initialized_(false),
93 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
94 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
95 last_input_flags_(0),
96 last_can_compose_inline_(true),
97 guest_proxy_routing_id_(MSG_ROUTING_NONE),
98 last_drag_status_(blink::WebDragStatusUnknown),
99 seen_embedder_system_drag_ended_(false),
100 seen_embedder_drag_source_ended_at_(false),
101 delegate_(delegate),
102 weak_ptr_factory_(this) {
103 DCHECK(web_contents);
104 DCHECK(delegate);
105 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
106 web_contents->SetBrowserPluginGuest(this);
107 delegate->SetGuestHost(this);
110 int BrowserPluginGuest::GetGuestProxyRoutingID() {
111 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
112 // We don't use the proxy to send postMessage in --site-per-process, since
113 // we use the contentWindow directly from the frame element instead.
114 return MSG_ROUTING_NONE;
117 if (guest_proxy_routing_id_ != MSG_ROUTING_NONE)
118 return guest_proxy_routing_id_;
120 // Create a swapped out RenderView for the guest in the embedder renderer
121 // process, so that the embedder can access the guest's window object.
122 // On reattachment, we can reuse the same swapped out RenderView because
123 // the embedder process will always be the same even if the embedder
124 // WebContents changes.
126 // TODO(fsamuel): Make sure this works for transferring guests across
127 // owners in different processes. We probably need to clear the
128 // |guest_proxy_routing_id_| and perform any necessary cleanup on Detach
129 // to enable this.
130 SiteInstance* owner_site_instance = owner_web_contents_->GetSiteInstance();
131 guest_proxy_routing_id_ =
132 GetWebContents()->CreateSwappedOutRenderView(owner_site_instance);
134 return guest_proxy_routing_id_;
137 int BrowserPluginGuest::LoadURLWithParams(
138 const NavigationController::LoadURLParams& load_params) {
139 GetWebContents()->GetController().LoadURLWithParams(load_params);
140 return GetGuestProxyRoutingID();
143 void BrowserPluginGuest::SizeContents(const gfx::Size& new_size) {
144 GetWebContents()->GetView()->SizeContents(new_size);
147 void BrowserPluginGuest::WillDestroy() {
148 is_in_destruction_ = true;
149 owner_web_contents_ = nullptr;
150 attached_ = false;
153 void BrowserPluginGuest::Init() {
154 if (initialized_)
155 return;
156 initialized_ = true;
158 // TODO(fsamuel): Initiailization prior to attachment should be behind a
159 // command line flag once we introduce experimental guest types that rely on
160 // this functionality.
161 if (!delegate_->CanRunInDetachedState())
162 return;
164 WebContentsImpl* owner_web_contents = static_cast<WebContentsImpl*>(
165 delegate_->GetOwnerWebContents());
166 owner_web_contents->CreateBrowserPluginEmbedderIfNecessary();
167 InitInternal(BrowserPluginHostMsg_Attach_Params(), owner_web_contents);
170 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
171 return weak_ptr_factory_.GetWeakPtr();
174 void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh,
175 bool focused,
176 blink::WebFocusType focus_type) {
177 focused_ = focused;
178 if (!rwh)
179 return;
181 if ((focus_type == blink::WebFocusTypeForward) ||
182 (focus_type == blink::WebFocusTypeBackward)) {
183 static_cast<RenderViewHostImpl*>(RenderViewHost::From(rwh))->
184 SetInitialFocus(focus_type == blink::WebFocusTypeBackward);
186 rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
187 if (!focused && mouse_locked_)
188 OnUnlockMouse();
190 // Restore the last seen state of text input to the view.
191 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
192 rwh->GetView());
193 SendTextInputTypeChangedToView(rwhv);
196 void BrowserPluginGuest::SetTooltipText(const base::string16& tooltip_text) {
197 if (tooltip_text == current_tooltip_text_)
198 return;
199 current_tooltip_text_ = tooltip_text;
201 SendMessageToEmbedder(new BrowserPluginMsg_SetTooltipText(
202 browser_plugin_instance_id_, tooltip_text));
205 bool BrowserPluginGuest::LockMouse(bool allowed) {
206 if (!attached() || (mouse_locked_ == allowed))
207 return false;
209 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
212 WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow(
213 const WebContents::CreateParams& params) {
214 WebContentsImpl* new_contents =
215 static_cast<WebContentsImpl*>(delegate_->CreateNewGuestWindow(params));
216 DCHECK(new_contents);
217 return new_contents;
220 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
221 const IPC::Message& message) {
222 RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
223 web_contents()->GetRenderWidgetHostView());
224 // Until the guest is attached, it should not be handling input events.
225 if (attached() && rwhv && rwhv->OnMessageReceivedFromEmbedder(
226 message,
227 static_cast<RenderViewHostImpl*>(
228 embedder_web_contents()->GetRenderViewHost()))) {
229 return true;
232 bool handled = true;
233 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
234 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
235 OnCompositorFrameSwappedACK)
236 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_Detach, OnDetach)
237 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
238 OnDragStatusUpdate)
239 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
240 OnExecuteEditCommand)
241 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
242 OnExtendSelectionAndDelete)
243 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
244 OnImeConfirmComposition)
245 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
246 OnImeSetComposition)
247 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
248 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
249 OnReclaimCompositorResources)
250 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
251 OnSetEditCommandsForNextKeyEvent)
252 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
253 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
254 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
255 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
256 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SatisfySequence, OnSatisfySequence)
257 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_RequireSequence, OnRequireSequence)
258 IPC_MESSAGE_UNHANDLED(handled = false)
259 IPC_END_MESSAGE_MAP()
260 return handled;
263 void BrowserPluginGuest::InitInternal(
264 const BrowserPluginHostMsg_Attach_Params& params,
265 WebContentsImpl* owner_web_contents) {
266 focused_ = params.focused;
267 OnSetFocus(browser_plugin::kInstanceIDNone,
268 focused_,
269 blink::WebFocusTypeNone);
271 guest_visible_ = params.visible;
272 UpdateVisibility();
274 is_full_page_plugin_ = params.is_full_page_plugin;
275 guest_window_rect_ = params.view_rect;
277 if (owner_web_contents_ != owner_web_contents) {
278 WebContentsViewGuest* new_view = nullptr;
279 if (!BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
280 new_view =
281 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
284 if (owner_web_contents_ && new_view)
285 new_view->OnGuestDetached(owner_web_contents_->GetView());
287 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
288 // be attached.
289 owner_web_contents_ = owner_web_contents;
290 if (new_view)
291 new_view->OnGuestAttached(owner_web_contents_->GetView());
294 RendererPreferences* renderer_prefs =
295 GetWebContents()->GetMutableRendererPrefs();
296 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
297 // Copy renderer preferences (and nothing else) from the embedder's
298 // WebContents to the guest.
300 // For GTK and Aura this is necessary to get proper renderer configuration
301 // values for caret blinking interval, colors related to selection and
302 // focus.
303 *renderer_prefs = *owner_web_contents_->GetMutableRendererPrefs();
304 renderer_prefs->user_agent_override = guest_user_agent_override;
306 // We would like the guest to report changes to frame names so that we can
307 // update the BrowserPlugin's corresponding 'name' attribute.
308 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
309 renderer_prefs->report_frame_name_changes = true;
310 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
311 // navigations still continue to function inside the app.
312 renderer_prefs->browser_handles_all_top_level_requests = false;
313 // Disable "client blocked" error page for browser plugin.
314 renderer_prefs->disable_client_blocked_error_page = true;
316 embedder_visibility_observer_.reset(new EmbedderVisibilityObserver(this));
318 DCHECK(GetWebContents()->GetRenderViewHost());
320 // Initialize the device scale factor by calling |NotifyScreenInfoChanged|.
321 auto render_widget_host =
322 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
323 render_widget_host->NotifyScreenInfoChanged();
325 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
326 // be reset again the next time preferences are updated.
327 WebPreferences prefs =
328 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
329 prefs.navigate_on_drag_drop = false;
330 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
333 BrowserPluginGuest::~BrowserPluginGuest() {
336 // static
337 BrowserPluginGuest* BrowserPluginGuest::Create(
338 WebContentsImpl* web_contents,
339 BrowserPluginGuestDelegate* delegate) {
340 return new BrowserPluginGuest(
341 web_contents->HasOpener(), web_contents, delegate);
344 // static
345 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
346 return web_contents && web_contents->GetBrowserPluginGuest();
349 // static
350 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
351 return render_view_host && IsGuest(
352 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
353 render_view_host)));
356 RenderWidgetHostView* BrowserPluginGuest::GetOwnerRenderWidgetHostView() {
357 if (!owner_web_contents_)
358 return nullptr;
359 return owner_web_contents_->GetRenderWidgetHostView();
362 void BrowserPluginGuest::UpdateVisibility() {
363 OnSetVisibility(browser_plugin_instance_id(), visible());
366 BrowserPluginGuestManager*
367 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
368 return GetWebContents()->GetBrowserContext()->GetGuestManager();
371 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
372 embedder_visible_ = visible;
373 UpdateVisibility();
376 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
377 SendMessageToEmbedder(
378 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
381 void BrowserPluginGuest::UpdateGuestSizeIfNecessary(
382 const gfx::Size& frame_size, float scale_factor) {
383 gfx::Size view_size(
384 gfx::ToFlooredSize(gfx::ScaleSize(frame_size, 1.0f / scale_factor)));
386 if (last_seen_view_size_ != view_size) {
387 delegate_->GuestSizeChanged(view_size);
388 last_seen_view_size_ = view_size;
392 // TODO(wjmaclean): Remove this once any remaining users of this pathway
393 // are gone.
394 void BrowserPluginGuest::SwapCompositorFrame(
395 uint32 output_surface_id,
396 int host_process_id,
397 int host_routing_id,
398 scoped_ptr<cc::CompositorFrame> frame) {
399 cc::RenderPass* root_pass =
400 frame->delegated_frame_data->render_pass_list.back();
401 UpdateGuestSizeIfNecessary(root_pass->output_rect.size(),
402 frame->metadata.device_scale_factor);
404 last_pending_frame_.reset(new FrameMsg_CompositorFrameSwapped_Params());
405 frame->AssignTo(&last_pending_frame_->frame);
406 last_pending_frame_->output_surface_id = output_surface_id;
407 last_pending_frame_->producing_route_id = host_routing_id;
408 last_pending_frame_->producing_host_id = host_process_id;
410 SendMessageToEmbedder(
411 new BrowserPluginMsg_CompositorFrameSwapped(
412 browser_plugin_instance_id(), *last_pending_frame_));
415 void BrowserPluginGuest::SetChildFrameSurface(
416 const cc::SurfaceId& surface_id,
417 const gfx::Size& frame_size,
418 float scale_factor,
419 const cc::SurfaceSequence& sequence) {
420 has_attached_since_surface_set_ = false;
421 SendMessageToEmbedder(new BrowserPluginMsg_SetChildFrameSurface(
422 browser_plugin_instance_id(), surface_id, frame_size, scale_factor,
423 sequence));
426 void BrowserPluginGuest::OnSatisfySequence(
427 int instance_id,
428 const cc::SurfaceSequence& sequence) {
429 std::vector<uint32_t> sequences;
430 sequences.push_back(sequence.sequence);
431 cc::SurfaceManager* manager = GetSurfaceManager();
432 manager->DidSatisfySequences(sequence.id_namespace, &sequences);
435 void BrowserPluginGuest::OnRequireSequence(
436 int instance_id,
437 const cc::SurfaceId& id,
438 const cc::SurfaceSequence& sequence) {
439 cc::SurfaceManager* manager = GetSurfaceManager();
440 cc::Surface* surface = manager->GetSurfaceForId(id);
441 if (!surface) {
442 LOG(ERROR) << "Attempting to require callback on nonexistent surface";
443 return;
445 surface->AddDestructionDependency(sequence);
448 void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
449 SendMessageToEmbedder(
450 new BrowserPluginMsg_SetContentsOpaque(
451 browser_plugin_instance_id(), opaque));
454 bool BrowserPluginGuest::Find(int request_id,
455 const base::string16& search_text,
456 const blink::WebFindOptions& options) {
457 return delegate_->Find(request_id, search_text, options);
460 bool BrowserPluginGuest::StopFinding(StopFindAction action) {
461 return delegate_->StopFinding(action);
464 WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
465 return static_cast<WebContentsImpl*>(web_contents());
468 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
469 const gfx::Point& relative_position) const {
470 if (!attached())
471 return relative_position;
473 gfx::Point screen_pos(relative_position);
474 screen_pos += guest_window_rect_.OffsetFromOrigin();
475 return screen_pos;
478 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
479 // During tests, attache() may be true when there is no owner_web_contents_;
480 // in this case just queue any messages we receive.
481 if (!attached() || !owner_web_contents_) {
482 // Some pages such as data URLs, javascript URLs, and about:blank
483 // do not load external resources and so they load prior to attachment.
484 // As a result, we must save all these IPCs until attachment and then
485 // forward them so that the embedder gets a chance to see and process
486 // the load events.
487 pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
488 return;
490 owner_web_contents_->Send(msg);
493 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
494 int screen_x, int screen_y, blink::WebDragOperation operation) {
495 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
496 screen_x, screen_y, operation);
497 seen_embedder_drag_source_ended_at_ = true;
498 EndSystemDragIfApplicable();
501 void BrowserPluginGuest::EndSystemDragIfApplicable() {
502 // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
503 // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
504 // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
505 // means we call it in all cases and also make sure we only call it once.
506 // This ensures that the input state of the guest stays correct, otherwise
507 // it will go stale and won't accept any further input events.
509 // The strategy used here to call DragSourceSystemDragEnded() on the RVH
510 // is when the following conditions are met:
511 // a. Embedder has seen SystemDragEnded()
512 // b. Embedder has seen DragSourceEndedAt()
513 // c. The guest has seen some drag status update other than
514 // WebDragStatusUnknown. Note that this step should ideally be done
515 // differently: The guest has seen at least one of
516 // {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
517 // a source quickly outside of <webview> bounds, then the
518 // BrowserPluginGuest never sees any of these drag status updates,
519 // there we just check whether we've seen any drag status update or
520 // not.
521 if (last_drag_status_ != blink::WebDragStatusOver &&
522 seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
523 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
524 GetWebContents()->GetRenderViewHost());
525 guest_rvh->DragSourceSystemDragEnded();
526 last_drag_status_ = blink::WebDragStatusUnknown;
527 seen_embedder_system_drag_ended_ = false;
528 seen_embedder_drag_source_ended_at_ = false;
529 dragged_url_ = GURL();
533 void BrowserPluginGuest::EmbedderSystemDragEnded() {
534 seen_embedder_system_drag_ended_ = true;
535 EndSystemDragIfApplicable();
538 void BrowserPluginGuest::SendQueuedMessages() {
539 if (!attached())
540 return;
542 while (!pending_messages_.empty()) {
543 linked_ptr<IPC::Message> message_ptr = pending_messages_.front();
544 pending_messages_.pop_front();
545 SendMessageToEmbedder(message_ptr.release());
549 void BrowserPluginGuest::SendTextInputTypeChangedToView(
550 RenderWidgetHostViewBase* guest_rwhv) {
551 if (!guest_rwhv)
552 return;
554 if (!owner_web_contents_) {
555 // If we were showing an interstitial, then we can end up here during
556 // embedder shutdown or when the embedder navigates to a different page.
557 // The call stack is roughly:
558 // BrowserPluginGuest::SetFocus()
559 // content::InterstitialPageImpl::Hide()
560 // content::InterstitialPageImpl::DontProceed().
562 // TODO(lazyboy): Write a WebUI test once http://crbug.com/463674 is fixed.
563 return;
566 ViewHostMsg_TextInputState_Params params;
567 params.type = last_text_input_type_;
568 params.mode = last_input_mode_;
569 params.flags = last_input_flags_;
570 params.can_compose_inline = last_can_compose_inline_;
571 guest_rwhv->TextInputStateChanged(params);
574 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
575 RenderFrameHost* render_frame_host,
576 const GURL& url,
577 ui::PageTransition transition_type) {
578 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
581 void BrowserPluginGuest::RenderViewReady() {
582 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
583 // TODO(fsamuel): Investigate whether it's possible to update state earlier
584 // here (see http://crbug.com/158151).
585 Send(new InputMsg_SetFocus(routing_id(), focused_));
586 UpdateVisibility();
588 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay(
589 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
592 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
593 SendMessageToEmbedder(
594 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
595 switch (status) {
596 #if defined(OS_CHROMEOS)
597 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
598 #endif
599 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
600 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
601 break;
602 case base::TERMINATION_STATUS_PROCESS_CRASHED:
603 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
604 break;
605 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
606 RecordAction(
607 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
608 break;
609 default:
610 break;
614 // static
615 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
616 const IPC::Message& message) {
617 return (message.type() != BrowserPluginHostMsg_Attach::ID) &&
618 (IPC_MESSAGE_CLASS(message) == BrowserPluginMsgStart);
621 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
622 bool handled = true;
623 // In --site-per-process, we do not need most of BrowserPluginGuest to drive
624 // inner WebContents.
625 // Right now InputHostMsg_ImeCompositionRangeChanged hits NOTREACHED() in
626 // RWHVChildFrame, so we're disabling message handling entirely here.
627 // TODO(lazyboy): Fix this as part of http://crbug.com/330264. The required
628 // parts of code from this class should be extracted to a separate class for
629 // --site-per-process.
630 if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests()) {
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_TextInputStateChanged,
647 OnTextInputStateChanged)
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_cross_process_frames =
715 BrowserPluginGuestMode::UseCrossProcessFramesForGuests();
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_cross_process_frames && 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_cross_process_frames)
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::OnTextInputStateChanged(
963 const ViewHostMsg_TextInputState_Params& params) {
964 // Save the state of text input so we can restore it on focus.
965 last_text_input_type_ = params.type;
966 last_input_mode_ = params.mode;
967 last_input_flags_ = params.flags;
968 last_can_compose_inline_ = params.can_compose_inline;
970 SendTextInputTypeChangedToView(
971 static_cast<RenderWidgetHostViewBase*>(
972 web_contents()->GetRenderWidgetHostView()));
975 void BrowserPluginGuest::OnImeCancelComposition() {
976 static_cast<RenderWidgetHostViewBase*>(
977 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
980 #if defined(OS_MACOSX) || defined(USE_AURA)
981 void BrowserPluginGuest::OnImeCompositionRangeChanged(
982 const gfx::Range& range,
983 const std::vector<gfx::Rect>& character_bounds) {
984 static_cast<RenderWidgetHostViewBase*>(
985 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
986 range, character_bounds);
988 #endif
990 } // namespace content