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
44namespace content {
45
46class BrowserPluginGuest::EmbedderWebContentsObserver
47    : public WebContentsObserver {
48 public:
49  explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest)
50      : WebContentsObserver(guest->embedder_web_contents()),
51        browser_plugin_guest_(guest) {
52  }
53
54  virtual ~EmbedderWebContentsObserver() {
55  }
56
57  // WebContentsObserver implementation.
58  virtual void WasShown() OVERRIDE {
59    browser_plugin_guest_->EmbedderVisibilityChanged(true);
60  }
61
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
72BrowserPluginGuest::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
100void BrowserPluginGuest::WillDestroy() {
101  is_in_destruction_ = true;
102  embedder_web_contents_ = NULL;
103}
104
105base::WeakPtr<BrowserPluginGuest> BrowserPluginGuest::AsWeakPtr() {
106  return weak_ptr_factory_.GetWeakPtr();
107}
108
109void 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
127bool BrowserPluginGuest::LockMouse(bool allowed) {
128  if (!attached() || (mouse_locked_ == allowed))
129    return false;
130
131  return embedder_web_contents()->GotResponseToLockMouseRequest(allowed);
132}
133
134void BrowserPluginGuest::Destroy() {
135  delegate_->Destroy();
136}
137
138WebContentsImpl* 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
146bool 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
190void 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
254BrowserPluginGuest::~BrowserPluginGuest() {
255}
256
257// static
258BrowserPluginGuest* 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
266bool BrowserPluginGuest::IsGuest(WebContentsImpl* web_contents) {
267  return web_contents && web_contents->GetBrowserPluginGuest();
268}
269
270// static
271bool BrowserPluginGuest::IsGuest(RenderViewHostImpl* render_view_host) {
272  return render_view_host && IsGuest(
273      static_cast<WebContentsImpl*>(WebContents::FromRenderViewHost(
274          render_view_host)));
275}
276
277RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
278  if (!attached())
279    return NULL;
280  return embedder_web_contents_->GetRenderWidgetHostView();
281}
282
283void BrowserPluginGuest::UpdateVisibility() {
284  OnSetVisibility(browser_plugin_instance_id(), visible());
285}
286
287void 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
300BrowserPluginGuestManager*
301BrowserPluginGuest::GetBrowserPluginGuestManager() const {
302  return GetWebContents()->GetBrowserContext()->GetGuestManager();
303}
304
305void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
306  embedder_visible_ = visible;
307  UpdateVisibility();
308}
309
310void BrowserPluginGuest::PointerLockPermissionResponse(bool allow) {
311  SendMessageToEmbedder(
312      new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), allow));
313}
314
315void 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
342void BrowserPluginGuest::SetContentsOpaque(bool opaque) {
343  SendMessageToEmbedder(
344      new BrowserPluginMsg_SetContentsOpaque(
345          browser_plugin_instance_id(), opaque));
346}
347
348WebContentsImpl* BrowserPluginGuest::GetWebContents() const {
349  return static_cast<WebContentsImpl*>(web_contents());
350}
351
352gfx::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
367void 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
381void 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
387void BrowserPluginGuest::EndSystemDrag() {
388  RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
389      GetWebContents()->GetRenderViewHost());
390  guest_rvh->DragSourceSystemDragEnded();
391}
392
393void 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
404void 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
411void 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
422void 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
442bool 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
468bool 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
490bool 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
516void 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
551void 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
560void 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
588void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
589                                              const std::string& name) {
590  Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
591}
592
593void 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
604void 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
614void 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
624void 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
633void 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
652void 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
660void BrowserPluginGuest::OnPluginDestroyed(int browser_plugin_instance_id) {
661  Destroy();
662}
663
664void 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
690void 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
697void 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
704void 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
713void BrowserPluginGuest::OnUnlockMouse() {
714  SendMessageToEmbedder(
715      new BrowserPluginMsg_SetMouseLock(browser_plugin_instance_id(), false));
716}
717
718void 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
727void 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
739void 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
750void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
751  SendMessageToEmbedder(
752      new BrowserPluginMsg_ShouldAcceptTouchEvents(
753          browser_plugin_instance_id(), accept));
754}
755
756#if defined(OS_MACOSX)
757void 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
774void BrowserPluginGuest::OnShowWidget(int route_id,
775                                      const gfx::Rect& initial_pos) {
776  GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
777}
778
779void BrowserPluginGuest::OnTakeFocus(bool reverse) {
780  SendMessageToEmbedder(
781      new BrowserPluginMsg_AdvanceFocus(browser_plugin_instance_id(), reverse));
782}
783
784void 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
797void BrowserPluginGuest::OnImeCancelComposition() {
798  static_cast<RenderWidgetHostViewBase*>(
799      web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
800}
801
802#if defined(OS_MACOSX) || defined(USE_AURA)
803void 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