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.
4
5 #include "content/browser/browser_plugin/browser_plugin_guest.h"
6
7 #include <algorithm>
8
9 #include "base/message_loop/message_loop.h"
10 #include "base/pickle.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "content/browser/browser_plugin/browser_plugin_embedder.h"
13 #include "content/browser/browser_thread_impl.h"
14 #include "content/browser/child_process_security_policy_impl.h"
15 #include "content/browser/frame_host/render_frame_host_impl.h"
16 #include "content/browser/frame_host/render_widget_host_view_guest.h"
17 #include "content/browser/loader/resource_dispatcher_host_impl.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/renderer_host/render_widget_host_impl.h"
20 #include "content/browser/renderer_host/render_widget_host_view_base.h"
21 #include "content/browser/web_contents/web_contents_impl.h"
22 #include "content/browser/web_contents/web_contents_view_guest.h"
23 #include "content/common/browser_plugin/browser_plugin_constants.h"
24 #include "content/common/browser_plugin/browser_plugin_messages.h"
25 #include "content/common/content_constants_internal.h"
26 #include "content/common/drag_messages.h"
27 #include "content/common/frame_messages.h"
28 #include "content/common/host_shared_bitmap_manager.h"
29 #include "content/common/input_messages.h"
30 #include "content/common/view_messages.h"
31 #include "content/public/browser/browser_context.h"
32 #include "content/public/browser/browser_plugin_guest_manager.h"
33 #include "content/public/browser/content_browser_client.h"
34 #include "content/public/browser/render_widget_host_view.h"
35 #include "content/public/browser/user_metrics.h"
36 #include "content/public/browser/web_contents_observer.h"
37 #include "content/public/common/drop_data.h"
38 #include "ui/gfx/geometry/size_conversions.h"
39
40 #if defined(OS_MACOSX)
41 #include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
42 #endif
43
44 namespace content {
45
46 class BrowserPluginGuest::EmbedderWebContentsObserver
47 : public WebContentsObserver {
48 public:
EmbedderWebContentsObserver(BrowserPluginGuest * guest)49 explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest)
50 : WebContentsObserver(guest->embedder_web_contents()),
51 browser_plugin_guest_(guest) {
52 }
53
~EmbedderWebContentsObserver()54 virtual ~EmbedderWebContentsObserver() {
55 }
56
57 // WebContentsObserver implementation.
WasShown()58 virtual void WasShown() OVERRIDE {
59 browser_plugin_guest_->EmbedderVisibilityChanged(true);
60 }
61
WasHidden()62 virtual void WasHidden() OVERRIDE {
63 browser_plugin_guest_->EmbedderVisibilityChanged(false);
64 }
65
66 private:
67 BrowserPluginGuest* browser_plugin_guest_;
68
69 DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
70 };
71
BrowserPluginGuest(bool has_render_view,WebContentsImpl * web_contents,BrowserPluginGuestDelegate * delegate)72 BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
73 WebContentsImpl* web_contents,
74 BrowserPluginGuestDelegate* delegate)
75 : WebContentsObserver(web_contents),
76 embedder_web_contents_(NULL),
77 browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
78 guest_device_scale_factor_(1.0f),
79 focused_(false),
80 mouse_locked_(false),
81 pending_lock_request_(false),
82 guest_visible_(false),
83 embedder_visible_(true),
84 copy_request_id_(0),
85 has_render_view_(has_render_view),
86 is_in_destruction_(false),
87 last_text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
88 last_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
89 last_can_compose_inline_(true),
90 delegate_(delegate),
91 weak_ptr_factory_(this) {
92 DCHECK(web_contents);
93 DCHECK(delegate);
94 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Create"));
95 web_contents->SetBrowserPluginGuest(this);
96 delegate->RegisterDestructionCallback(
97 base::Bind(&BrowserPluginGuest::WillDestroy, AsWeakPtr()));
98 }
99
WillDestroy()100 void BrowserPluginGuest::WillDestroy() {
101 is_in_destruction_ = true;
102 embedder_web_contents_ = NULL;
103 }
104
AsWeakPtr()105 base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
106 return weak_ptr_factory_.GetWeakPtr();
107 }
108
SetFocus(RenderWidgetHost * rwh,bool focused)109 void BrowserPluginGuest::SetFocus(RenderWidgetHost* rwh, bool focused) {
110 focused_ = focused;
111 if (!rwh)
112 return;
113
114 rwh->Send(new InputMsg_SetFocus(rwh->GetRoutingID(), focused));
115 if (!focused && mouse_locked_)
116 OnUnlockMouse();
117
118 // Restore the last seen state of text input to the view.
119 RenderWidgetHostViewBase* rwhv = static_cast<RenderWidgetHostViewBase*>(
120 rwh->GetView());
121 if (rwhv) {
122 rwhv->TextInputTypeChanged(last_text_input_type_, last_input_mode_,
123 last_can_compose_inline_);
124 }
125 }
126
LockMouse(bool allowed)127 bool BrowserPluginGuest::LockMouse(bool allowed) {
128 if (!attached() || (mouse_locked_ == allowed))
129 return false;
130
131 return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
132 }
133
Destroy()134 void BrowserPluginGuest::Destroy() {
135 delegate_->Destroy();
136 }
137
CreateNewGuestWindow(const WebContents::CreateParams & params)138 WebContentsImpl* BrowserPluginGuest::CreateNewGuestWindow(
139 const WebContents::CreateParams& params) {
140 WebContentsImpl* new_contents =
141 static_cast<WebContentsImpl*>(delegate_->CreateNewGuestWindow(params));
142 DCHECK(new_contents);
143 return new_contents;
144 }
145
OnMessageReceivedFromEmbedder(const IPC::Message & message)146 bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
147 const IPC::Message& message) {
148 RenderWidgetHostViewGuest* rwhv = static_cast<RenderWidgetHostViewGuest*>(
149 web_contents()->GetRenderWidgetHostView());
150 if (rwhv &&
151 rwhv->OnMessageReceivedFromEmbedder(
152 message,
153 static_cast<RenderViewHostImpl*>(
154 embedder_web_contents()->GetRenderViewHost()))) {
155 return true;
156 }
157
158 bool handled = true;
159 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
160 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameSwappedACK,
161 OnCompositorFrameSwappedACK)
162 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck,
163 OnCopyFromCompositingSurfaceAck)
164 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
165 OnDragStatusUpdate)
166 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
167 OnExecuteEditCommand)
168 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
169 OnExtendSelectionAndDelete)
170 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
171 OnImeConfirmComposition)
172 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
173 OnImeSetComposition)
174 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
175 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
176 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
177 OnReclaimCompositorResources)
178 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
179 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
180 OnSetEditCommandsForNextKeyEvent)
181 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
182 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
183 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
184 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
185 IPC_MESSAGE_UNHANDLED(handled = false)
186 IPC_END_MESSAGE_MAP()
187 return handled;
188 }
189
Initialize(int browser_plugin_instance_id,const BrowserPluginHostMsg_Attach_Params & params,WebContentsImpl * embedder_web_contents)190 void BrowserPluginGuest::Initialize(
191 int browser_plugin_instance_id,
192 const BrowserPluginHostMsg_Attach_Params& params,
193 WebContentsImpl* embedder_web_contents) {
194 browser_plugin_instance_id_ = browser_plugin_instance_id;
195 focused_ = params.focused;
196 guest_visible_ = params.visible;
197 guest_window_rect_ = gfx::Rect(params.origin,
198 params.resize_guest_params.view_size);
199
200 // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
201 // be attached.
202 embedder_web_contents_ = embedder_web_contents;
203
204 WebContentsViewGuest* new_view =
205 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
206 new_view->OnGuestInitialized(embedder_web_contents->GetView());
207
208 RendererPreferences* renderer_prefs =
209 GetWebContents()->GetMutableRendererPrefs();
210 std::string guest_user_agent_override = renderer_prefs->user_agent_override;
211 // Copy renderer preferences (and nothing else) from the embedder's
212 // WebContents to the guest.
213 //
214 // For GTK and Aura this is necessary to get proper renderer configuration
215 // values for caret blinking interval, colors related to selection and
216 // focus.
217 *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs();
218 renderer_prefs->user_agent_override = guest_user_agent_override;
219
220 // We would like the guest to report changes to frame names so that we can
221 // update the BrowserPlugin's corresponding 'name' attribute.
222 // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
223 renderer_prefs->report_frame_name_changes = true;
224 // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
225 // navigations still continue to function inside the app.
226 renderer_prefs->browser_handles_all_top_level_requests = false;
227 // Disable "client blocked" error page for browser plugin.
228 renderer_prefs->disable_client_blocked_error_page = true;
229
230 embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this));
231
232 OnResizeGuest(browser_plugin_instance_id_, params.resize_guest_params);
233
234 // TODO(chrishtr): this code is wrong. The navigate_on_drag_drop field will
235 // be reset again the next time preferences are updated.
236 WebPreferences prefs =
237 GetWebContents()->GetRenderViewHost()->GetWebkitPreferences();
238 prefs.navigate_on_drag_drop = false;
239 GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
240
241 // Enable input method for guest if it's enabled for the embedder.
242 if (static_cast<RenderViewHostImpl*>(
243 embedder_web_contents_->GetRenderViewHost())->input_method_active()) {
244 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
245 GetWebContents()->GetRenderViewHost());
246 guest_rvh->SetInputMethodActive(true);
247 }
248
249 // Inform the embedder of the guest's attachment.
250 SendMessageToEmbedder(
251 new BrowserPluginMsg_Attach_ACK(browser_plugin_instance_id_));
252 }
253
~BrowserPluginGuest()254 BrowserPluginGuest::~BrowserPluginGuest() {
255 }
256
257 // static
Create(WebContentsImpl * web_contents,BrowserPluginGuestDelegate * delegate)258 BrowserPluginGuest* BrowserPluginGuest::Create(
259 WebContentsImpl* web_contents,
260 BrowserPluginGuestDelegate* delegate) {
261 return new BrowserPluginGuest(
262 web_contents->opener() != NULL, web_contents, delegate);
263 }
264
265 // static
IsGuest(WebContentsImpl * web_contents)266 bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
267 return web_contents && web_contents->GetBrowserPluginGuest();
268 }
269
270 // static
IsGuest(RenderViewHostImpl * render_view_host)271 bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
272 return render_view_host && IsGuest(
273 static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
274 render_view_host)));
275 }
276
GetEmbedderRenderWidgetHostView()277 RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
278 if (!attached())
279 return NULL;
280 return embedder_web_contents_->GetRenderWidgetHostView();
281 }
282
UpdateVisibility()283 void BrowserPluginGuest::UpdateVisibility() {
284 OnSetVisibility(browser_plugin_instance_id(), visible());
285 }
286
CopyFromCompositingSurface(gfx::Rect src_subrect,gfx::Size dst_size,const base::Callback<void (bool,const SkBitmap &)> & callback)287 void BrowserPluginGuest::CopyFromCompositingSurface(
288 gfx::Rect src_subrect,
289 gfx::Size dst_size,
290 const base::Callback<void(bool, const SkBitmap&)>& callback) {
291 copy_request_callbacks_.insert(std::make_pair(++copy_request_id_, callback));
292 SendMessageToEmbedder(
293 new BrowserPluginMsg_CopyFromCompositingSurface(
294 browser_plugin_instance_id(),
295 copy_request_id_,
296 src_subrect,
297 dst_size));
298 }
299
300 BrowserPluginGuestManager*
GetBrowserPluginGuestManager() const301 BrowserPluginGuest::GetBrowserPluginGuestManager() const {
302 return GetWebContents()->GetBrowserContext()->GetGuestManager();
303 }
304
EmbedderVisibilityChanged(bool visible)305 void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
306 embedder_visible_ = visible;
307 UpdateVisibility();
308 }
309
PointerLockPermissionResponse(bool allow)310 void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
311 SendMessageToEmbedder(
312 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
313 }
314
SwapCompositorFrame(uint32 output_surface_id,int host_process_id,int host_routing_id,scoped_ptr<cc::CompositorFrame> frame)315 void BrowserPluginGuest::SwapCompositorFrame(
316 uint32 output_surface_id,
317 int host_process_id,
318 int host_routing_id,
319 scoped_ptr<cc::CompositorFrame> frame) {
320 cc::RenderPass* root_pass =
321 frame->delegated_frame_data->render_pass_list.back();
322 gfx::Size view_size(gfx::ToFlooredSize(gfx::ScaleSize(
323 root_pass->output_rect.size(),
324 1.0f / frame->metadata.device_scale_factor)));
325
326 if (last_seen_view_size_ != view_size) {
327 delegate_->GuestSizeChanged(last_seen_view_size_, view_size);
328 last_seen_view_size_ = view_size;
329 }
330
331 FrameMsg_CompositorFrameSwapped_Params guest_params;
332 frame->AssignTo(&guest_params.frame);
333 guest_params.output_surface_id = output_surface_id;
334 guest_params.producing_route_id = host_routing_id;
335 guest_params.producing_host_id = host_process_id;
336
337 SendMessageToEmbedder(
338 new BrowserPluginMsg_CompositorFrameSwapped(
339 browser_plugin_instance_id(), guest_params));
340 }
341
SetContentsOpaque(bool opaque)342 void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
343 SendMessageToEmbedder(
344 new BrowserPluginMsg_SetContentsOpaque(
345 browser_plugin_instance_id(), opaque));
346 }
347
GetWebContents() const348 WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
349 return static_cast<WebContentsImpl*>(web_contents());
350 }
351
GetScreenCoordinates(const gfx::Point & relative_position) const352 gfx::Point BrowserPluginGuest::GetScreenCoordinates(
353 const gfx::Point& relative_position) const {
354 if (!attached())
355 return relative_position;
356
357 gfx::Point screen_pos(relative_position);
358 screen_pos += guest_window_rect_.OffsetFromOrigin();
359 if (embedder_web_contents()->GetBrowserPluginGuest()) {
360 BrowserPluginGuest* embedder_guest =
361 embedder_web_contents()->GetBrowserPluginGuest();
362 screen_pos += embedder_guest->guest_window_rect_.OffsetFromOrigin();
363 }
364 return screen_pos;
365 }
366
SendMessageToEmbedder(IPC::Message * msg)367 void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
368 if (!attached()) {
369 // Some pages such as data URLs, javascript URLs, and about:blank
370 // do not load external resources and so they load prior to attachment.
371 // As a result, we must save all these IPCs until attachment and then
372 // forward them so that the embedder gets a chance to see and process
373 // the load events.
374 pending_messages_.push_back(linked_ptr<IPC::Message>(msg));
375 return;
376 }
377 msg->set_routing_id(embedder_web_contents_->GetRoutingID());
378 embedder_web_contents_->Send(msg);
379 }
380
DragSourceEndedAt(int client_x,int client_y,int screen_x,int screen_y,blink::WebDragOperation operation)381 void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
382 int screen_x, int screen_y, blink::WebDragOperation operation) {
383 web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
384 screen_x, screen_y, operation);
385 }
386
EndSystemDrag()387 void BrowserPluginGuest::EndSystemDrag() {
388 RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
389 GetWebContents()->GetRenderViewHost());
390 guest_rvh->DragSourceSystemDragEnded();
391 }
392
SendQueuedMessages()393 void BrowserPluginGuest::SendQueuedMessages() {
394 if (!attached())
395 return;
396
397 while (!pending_messages_.empty()) {
398 linked_ptr<IPC::Message> message_ptr = pending_messages_.front();
399 pending_messages_.pop_front();
400 SendMessageToEmbedder(message_ptr.release());
401 }
402 }
403
DidCommitProvisionalLoadForFrame(RenderFrameHost * render_frame_host,const GURL & url,ui::PageTransition transition_type)404 void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
405 RenderFrameHost* render_frame_host,
406 const GURL& url,
407 ui::PageTransition transition_type) {
408 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
409 }
410
RenderViewReady()411 void BrowserPluginGuest::RenderViewReady() {
412 RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
413 // TODO(fsamuel): Investigate whether it's possible to update state earlier
414 // here (see http://crbug.com/158151).
415 Send(new InputMsg_SetFocus(routing_id(), focused_));
416 UpdateVisibility();
417
418 RenderWidgetHostImpl::From(rvh)->set_hung_renderer_delay_ms(
419 base::TimeDelta::FromMilliseconds(kHungRendererDelayMs));
420 }
421
RenderProcessGone(base::TerminationStatus status)422 void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
423 SendMessageToEmbedder(
424 new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
425 switch (status) {
426 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
427 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
428 break;
429 case base::TERMINATION_STATUS_PROCESS_CRASHED:
430 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Crashed"));
431 break;
432 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
433 RecordAction(
434 base::UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
435 break;
436 default:
437 break;
438 }
439 }
440
441 // static
ShouldForwardToBrowserPluginGuest(const IPC::Message & message)442 bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
443 const IPC::Message& message) {
444 switch (message.type()) {
445 case BrowserPluginHostMsg_CompositorFrameSwappedACK::ID:
446 case BrowserPluginHostMsg_CopyFromCompositingSurfaceAck::ID:
447 case BrowserPluginHostMsg_DragStatusUpdate::ID:
448 case BrowserPluginHostMsg_ExecuteEditCommand::ID:
449 case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
450 case BrowserPluginHostMsg_HandleInputEvent::ID:
451 case BrowserPluginHostMsg_ImeConfirmComposition::ID:
452 case BrowserPluginHostMsg_ImeSetComposition::ID:
453 case BrowserPluginHostMsg_LockMouse_ACK::ID:
454 case BrowserPluginHostMsg_PluginDestroyed::ID:
455 case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
456 case BrowserPluginHostMsg_ResizeGuest::ID:
457 case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
458 case BrowserPluginHostMsg_SetFocus::ID:
459 case BrowserPluginHostMsg_SetVisibility::ID:
460 case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
461 case BrowserPluginHostMsg_UpdateGeometry::ID:
462 return true;
463 default:
464 return false;
465 }
466 }
467
OnMessageReceived(const IPC::Message & message)468 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
469 bool handled = true;
470 IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
471 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCancelComposition,
472 OnImeCancelComposition)
473 #if defined(OS_MACOSX) || defined(USE_AURA)
474 IPC_MESSAGE_HANDLER(InputHostMsg_ImeCompositionRangeChanged,
475 OnImeCompositionRangeChanged)
476 #endif
477 IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
478 OnHasTouchEventHandlers)
479 IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
480 IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
481 IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
482 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
483 OnTextInputTypeChanged)
484 IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
485 IPC_MESSAGE_UNHANDLED(handled = false)
486 IPC_END_MESSAGE_MAP()
487 return handled;
488 }
489
OnMessageReceived(const IPC::Message & message,RenderFrameHost * render_frame_host)490 bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message,
491 RenderFrameHost* render_frame_host) {
492 // This will eventually be the home for more IPC handlers that depend on
493 // RenderFrameHost. Until more are moved here, though, the IPC_* macros won't
494 // compile if there are no handlers for a platform. So we have both #if guards
495 // around the whole thing (unfortunate but temporary), and #if guards where
496 // they belong, only around the one IPC handler. TODO(avi): Move more of the
497 // frame-based handlers to this function and remove the outer #if layer.
498 #if defined(OS_MACOSX)
499 bool handled = true;
500 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserPluginGuest, message,
501 render_frame_host)
502 #if defined(OS_MACOSX)
503 // MacOS X creates and populates platform-specific select drop-down menus
504 // whereas other platforms merely create a popup window that the guest
505 // renderer process paints inside.
506 IPC_MESSAGE_HANDLER(FrameHostMsg_ShowPopup, OnShowPopup)
507 #endif
508 IPC_MESSAGE_UNHANDLED(handled = false)
509 IPC_END_MESSAGE_MAP()
510 return handled;
511 #else
512 return false;
513 #endif
514 }
515
Attach(int browser_plugin_instance_id,WebContentsImpl * embedder_web_contents,const BrowserPluginHostMsg_Attach_Params & params)516 void BrowserPluginGuest::Attach(
517 int browser_plugin_instance_id,
518 WebContentsImpl* embedder_web_contents,
519 const BrowserPluginHostMsg_Attach_Params& params) {
520 if (attached())
521 return;
522
523 delegate_->WillAttach(embedder_web_contents, browser_plugin_instance_id);
524
525 // If a RenderView has already been created for this new window, then we need
526 // to initialize the browser-side state now so that the RenderFrameHostManager
527 // does not create a new RenderView on navigation.
528 if (has_render_view_) {
529 static_cast<RenderViewHostImpl*>(
530 GetWebContents()->GetRenderViewHost())->Init();
531 WebContentsViewGuest* new_view =
532 static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
533 new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
534 }
535
536 Initialize(browser_plugin_instance_id, params, embedder_web_contents);
537
538 SendQueuedMessages();
539
540 // Create a swapped out RenderView for the guest in the embedder render
541 // process, so that the embedder can access the guest's window object.
542 int guest_routing_id =
543 GetWebContents()->CreateSwappedOutRenderView(
544 embedder_web_contents_->GetSiteInstance());
545
546 delegate_->DidAttach(guest_routing_id);
547
548 RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Attached"));
549 }
550
OnCompositorFrameSwappedACK(int browser_plugin_instance_id,const FrameHostMsg_CompositorFrameSwappedACK_Params & params)551 void BrowserPluginGuest::OnCompositorFrameSwappedACK(
552 int browser_plugin_instance_id,
553 const FrameHostMsg_CompositorFrameSwappedACK_Params& params) {
554 RenderWidgetHostImpl::SendSwapCompositorFrameAck(params.producing_route_id,
555 params.output_surface_id,
556 params.producing_host_id,
557 params.ack);
558 }
559
OnDragStatusUpdate(int browser_plugin_instance_id,blink::WebDragStatus drag_status,const DropData & drop_data,blink::WebDragOperationsMask mask,const gfx::Point & location)560 void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
561 blink::WebDragStatus drag_status,
562 const DropData& drop_data,
563 blink::WebDragOperationsMask mask,
564 const gfx::Point& location) {
565 RenderViewHost* host = GetWebContents()->GetRenderViewHost();
566 switch (drag_status) {
567 case blink::WebDragStatusEnter:
568 embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest(
569 this);
570 host->DragTargetDragEnter(drop_data, location, location, mask, 0);
571 break;
572 case blink::WebDragStatusOver:
573 host->DragTargetDragOver(location, location, mask, 0);
574 break;
575 case blink::WebDragStatusLeave:
576 embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this);
577 host->DragTargetDragLeave();
578 break;
579 case blink::WebDragStatusDrop:
580 host->DragTargetDrop(location, location, 0);
581 EndSystemDrag();
582 break;
583 case blink::WebDragStatusUnknown:
584 NOTREACHED();
585 }
586 }
587
OnExecuteEditCommand(int browser_plugin_instance_id,const std::string & name)588 void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
589 const std::string& name) {
590 Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
591 }
592
OnImeSetComposition(int browser_plugin_instance_id,const std::string & text,const std::vector<blink::WebCompositionUnderline> & underlines,int selection_start,int selection_end)593 void BrowserPluginGuest::OnImeSetComposition(
594 int browser_plugin_instance_id,
595 const std::string& text,
596 const std::vector<blink::WebCompositionUnderline>& underlines,
597 int selection_start,
598 int selection_end) {
599 Send(new InputMsg_ImeSetComposition(routing_id(),
600 base::UTF8ToUTF16(text), underlines,
601 selection_start, selection_end));
602 }
603
OnImeConfirmComposition(int browser_plugin_instance_id,const std::string & text,bool keep_selection)604 void BrowserPluginGuest::OnImeConfirmComposition(
605 int browser_plugin_instance_id,
606 const std::string& text,
607 bool keep_selection) {
608 Send(new InputMsg_ImeConfirmComposition(routing_id(),
609 base::UTF8ToUTF16(text),
610 gfx::Range::InvalidRange(),
611 keep_selection));
612 }
613
OnExtendSelectionAndDelete(int browser_plugin_instance_id,int before,int after)614 void BrowserPluginGuest::OnExtendSelectionAndDelete(
615 int browser_plugin_instance_id,
616 int before,
617 int after) {
618 RenderFrameHostImpl* rfh = static_cast<RenderFrameHostImpl*>(
619 web_contents()->GetFocusedFrame());
620 if (rfh)
621 rfh->ExtendSelectionAndDelete(before, after);
622 }
623
OnReclaimCompositorResources(int browser_plugin_instance_id,const FrameHostMsg_ReclaimCompositorResources_Params & params)624 void BrowserPluginGuest::OnReclaimCompositorResources(
625 int browser_plugin_instance_id,
626 const FrameHostMsg_ReclaimCompositorResources_Params& params) {
627 RenderWidgetHostImpl::SendReclaimCompositorResources(params.route_id,
628 params.output_surface_id,
629 params.renderer_host_id,
630 params.ack);
631 }
632
OnLockMouse(bool user_gesture,bool last_unlocked_by_target,bool privileged)633 void BrowserPluginGuest::OnLockMouse(bool user_gesture,
634 bool last_unlocked_by_target,
635 bool privileged) {
636 if (pending_lock_request_) {
637 // Immediately reject the lock because only one pointerLock may be active
638 // at a time.
639 Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
640 return;
641 }
642
643 pending_lock_request_ = true;
644
645 delegate_->RequestPointerLockPermission(
646 user_gesture,
647 last_unlocked_by_target,
648 base::Bind(&BrowserPluginGuest::PointerLockPermissionResponse,
649 weak_ptr_factory_.GetWeakPtr()));
650 }
651
OnLockMouseAck(int browser_plugin_instance_id,bool succeeded)652 void BrowserPluginGuest::OnLockMouseAck(int browser_plugin_instance_id,
653 bool succeeded) {
654 Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
655 pending_lock_request_ = false;
656 if (succeeded)
657 mouse_locked_ = true;
658 }
659
OnPluginDestroyed(int browser_plugin_instance_id)660 void BrowserPluginGuest::OnPluginDestroyed(int browser_plugin_instance_id) {
661 Destroy();
662 }
663
OnResizeGuest(int browser_plugin_instance_id,const BrowserPluginHostMsg_ResizeGuest_Params & params)664 void BrowserPluginGuest::OnResizeGuest(
665 int browser_plugin_instance_id,
666 const BrowserPluginHostMsg_ResizeGuest_Params& params) {
667 // If we are setting the size for the first time before navigating then
668 // BrowserPluginGuest does not yet have a RenderViewHost.
669 if (guest_device_scale_factor_ != params.scale_factor &&
670 GetWebContents()->GetRenderViewHost()) {
671 RenderWidgetHostImpl* render_widget_host =
672 RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
673 guest_device_scale_factor_ = params.scale_factor;
674 render_widget_host->NotifyScreenInfoChanged();
675 }
676
677 if (last_seen_browser_plugin_size_ != params.view_size) {
678 delegate_->ElementSizeChanged(last_seen_browser_plugin_size_,
679 params.view_size);
680 last_seen_browser_plugin_size_ = params.view_size;
681 }
682
683 // Just resize the WebContents and repaint if needed.
684 if (!params.view_size.IsEmpty())
685 GetWebContents()->GetView()->SizeContents(params.view_size);
686 if (params.repaint)
687 Send(new ViewMsg_Repaint(routing_id(), params.view_size));
688 }
689
OnSetFocus(int browser_plugin_instance_id,bool focused)690 void BrowserPluginGuest::OnSetFocus(int browser_plugin_instance_id,
691 bool focused) {
692 RenderWidgetHostView* rwhv = web_contents()->GetRenderWidgetHostView();
693 RenderWidgetHost* rwh = rwhv ? rwhv->GetRenderWidgetHost() : NULL;
694 SetFocus(rwh, focused);
695 }
696
OnSetEditCommandsForNextKeyEvent(int browser_plugin_instance_id,const std::vector<EditCommand> & edit_commands)697 void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
698 int browser_plugin_instance_id,
699 const std::vector<EditCommand>& edit_commands) {
700 Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
701 edit_commands));
702 }
703
OnSetVisibility(int browser_plugin_instance_id,bool visible)704 void BrowserPluginGuest::OnSetVisibility(int browser_plugin_instance_id,
705 bool visible) {
706 guest_visible_ = visible;
707 if (embedder_visible_ && guest_visible_)
708 GetWebContents()->WasShown();
709 else
710 GetWebContents()->WasHidden();
711 }
712
OnUnlockMouse()713 void BrowserPluginGuest::OnUnlockMouse() {
714 SendMessageToEmbedder(
715 new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
716 }
717
OnUnlockMouseAck(int browser_plugin_instance_id)718 void BrowserPluginGuest::OnUnlockMouseAck(int browser_plugin_instance_id) {
719 // mouse_locked_ could be false here if the lock attempt was cancelled due
720 // to window focus, or for various other reasons before the guest was informed
721 // of the lock's success.
722 if (mouse_locked_)
723 Send(new ViewMsg_MouseLockLost(routing_id()));
724 mouse_locked_ = false;
725 }
726
OnCopyFromCompositingSurfaceAck(int browser_plugin_instance_id,int request_id,const SkBitmap & bitmap)727 void BrowserPluginGuest::OnCopyFromCompositingSurfaceAck(
728 int browser_plugin_instance_id,
729 int request_id,
730 const SkBitmap& bitmap) {
731 CHECK(copy_request_callbacks_.count(request_id));
732 if (!copy_request_callbacks_.count(request_id))
733 return;
734 const CopyRequestCallback& callback = copy_request_callbacks_[request_id];
735 callback.Run(!bitmap.empty() && !bitmap.isNull(), bitmap);
736 copy_request_callbacks_.erase(request_id);
737 }
738
OnUpdateGeometry(int browser_plugin_instance_id,const gfx::Rect & view_rect)739 void BrowserPluginGuest::OnUpdateGeometry(int browser_plugin_instance_id,
740 const gfx::Rect& view_rect) {
741 // The plugin has moved within the embedder without resizing or the
742 // embedder/container's view rect changing.
743 guest_window_rect_ = view_rect;
744 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
745 GetWebContents()->GetRenderViewHost());
746 if (rvh)
747 rvh->SendScreenRects();
748 }
749
OnHasTouchEventHandlers(bool accept)750 void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
751 SendMessageToEmbedder(
752 new BrowserPluginMsg_ShouldAcceptTouchEvents(
753 browser_plugin_instance_id(), accept));
754 }
755
756 #if defined(OS_MACOSX)
OnShowPopup(RenderFrameHost * render_frame_host,const FrameHostMsg_ShowPopup_Params & params)757 void BrowserPluginGuest::OnShowPopup(
758 RenderFrameHost* render_frame_host,
759 const FrameHostMsg_ShowPopup_Params& params) {
760 gfx::Rect translated_bounds(params.bounds);
761 translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
762 BrowserPluginPopupMenuHelper popup_menu_helper(
763 embedder_web_contents_->GetRenderViewHost(), render_frame_host);
764 popup_menu_helper.ShowPopupMenu(translated_bounds,
765 params.item_height,
766 params.item_font_size,
767 params.selected_item,
768 params.popup_items,
769 params.right_aligned,
770 params.allow_multiple_selection);
771 }
772 #endif
773
OnShowWidget(int route_id,const gfx::Rect & initial_pos)774 void BrowserPluginGuest::OnShowWidget(int route_id,
775 const gfx::Rect& initial_pos) {
776 GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
777 }
778
OnTakeFocus(bool reverse)779 void BrowserPluginGuest::OnTakeFocus(bool reverse) {
780 SendMessageToEmbedder(
781 new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
782 }
783
OnTextInputTypeChanged(ui::TextInputType type,ui::TextInputMode input_mode,bool can_compose_inline)784 void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
785 ui::TextInputMode input_mode,
786 bool can_compose_inline) {
787 // Save the state of text input so we can restore it on focus.
788 last_text_input_type_ = type;
789 last_input_mode_ = input_mode;
790 last_can_compose_inline_ = can_compose_inline;
791
792 static_cast<RenderWidgetHostViewBase*>(
793 web_contents()->GetRenderWidgetHostView())->TextInputTypeChanged(
794 type, input_mode, can_compose_inline);
795 }
796
OnImeCancelComposition()797 void BrowserPluginGuest::OnImeCancelComposition() {
798 static_cast<RenderWidgetHostViewBase*>(
799 web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
800 }
801
802 #if defined(OS_MACOSX) || defined(USE_AURA)
OnImeCompositionRangeChanged(const gfx::Range & range,const std::vector<gfx::Rect> & character_bounds)803 void BrowserPluginGuest::OnImeCompositionRangeChanged(
804 const gfx::Range& range,
805 const std::vector<gfx::Rect>& character_bounds) {
806 static_cast<RenderWidgetHostViewBase*>(
807 web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
808 range, character_bounds);
809 }
810 #endif
811
812 } // namespace content
813