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/strings/string_util.h"
11#include "base/strings/utf_string_conversions.h"
12#include "content/browser/browser_plugin/browser_plugin_embedder.h"
13#include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
14#include "content/browser/browser_plugin/browser_plugin_host_factory.h"
15#include "content/browser/browser_thread_impl.h"
16#include "content/browser/child_process_security_policy_impl.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/web_contents/web_contents_impl.h"
21#include "content/browser/web_contents/web_contents_view_guest.h"
22#include "content/common/browser_plugin/browser_plugin_constants.h"
23#include "content/common/browser_plugin/browser_plugin_messages.h"
24#include "content/common/content_constants_internal.h"
25#include "content/common/drag_messages.h"
26#include "content/common/gpu/gpu_messages.h"
27#include "content/common/input_messages.h"
28#include "content/common/view_messages.h"
29#include "content/port/browser/render_view_host_delegate_view.h"
30#include "content/port/browser/render_widget_host_view_port.h"
31#include "content/public/browser/browser_context.h"
32#include "content/public/browser/content_browser_client.h"
33#include "content/public/browser/geolocation_permission_context.h"
34#include "content/public/browser/navigation_controller.h"
35#include "content/public/browser/render_process_host.h"
36#include "content/public/browser/render_widget_host_view.h"
37#include "content/public/browser/resource_request_details.h"
38#include "content/public/browser/user_metrics.h"
39#include "content/public/browser/web_contents_observer.h"
40#include "content/public/browser/web_contents_view.h"
41#include "content/public/common/drop_data.h"
42#include "content/public/common/media_stream_request.h"
43#include "content/public/common/result_codes.h"
44#include "content/public/common/url_constants.h"
45#include "content/public/common/url_utils.h"
46#include "net/url_request/url_request.h"
47#include "third_party/WebKit/public/platform/WebCursorInfo.h"
48#include "ui/events/keycodes/keyboard_codes.h"
49#include "ui/surface/transport_dib.h"
50#include "webkit/common/resource_type.h"
51
52#if defined(OS_MACOSX)
53#include "content/browser/browser_plugin/browser_plugin_popup_menu_helper_mac.h"
54#endif
55
56namespace content {
57
58// static
59BrowserPluginHostFactory* BrowserPluginGuest::factory_ = NULL;
60
61// Parent class for the various types of permission requests, each of which
62// should be able to handle the response to their permission request.
63class BrowserPluginGuest::PermissionRequest :
64    public base::RefCounted<BrowserPluginGuest::PermissionRequest> {
65 public:
66  virtual void Respond(bool should_allow, const std::string& user_input) = 0;
67  virtual bool AllowedByDefault() const {
68    return false;
69  }
70 protected:
71  PermissionRequest() {
72    RecordAction(UserMetricsAction("BrowserPlugin.Guest.PermissionRequest"));
73  }
74  virtual ~PermissionRequest() {}
75  // Friend RefCounted so that the dtor can be non-public.
76  friend class base::RefCounted<BrowserPluginGuest::PermissionRequest>;
77};
78
79class BrowserPluginGuest::DownloadRequest : public PermissionRequest {
80 public:
81  explicit DownloadRequest(base::Callback<void(bool)> callback)
82      : callback_(callback) {
83    RecordAction(
84        UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Download"));
85  }
86  virtual void Respond(bool should_allow,
87                       const std::string& user_input) OVERRIDE {
88    callback_.Run(should_allow);
89  }
90
91 private:
92  virtual ~DownloadRequest() {}
93  base::Callback<void(bool)> callback_;
94};
95
96class BrowserPluginGuest::GeolocationRequest : public PermissionRequest {
97 public:
98  GeolocationRequest(GeolocationCallback callback,
99                     int bridge_id,
100                     base::WeakPtrFactory<BrowserPluginGuest>* weak_ptr_factory)
101                     : callback_(callback),
102                       bridge_id_(bridge_id),
103                       weak_ptr_factory_(weak_ptr_factory) {
104    RecordAction(
105        UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Geolocation"));
106  }
107
108  virtual void Respond(bool should_allow,
109                       const std::string& user_input) OVERRIDE {
110    base::WeakPtr<BrowserPluginGuest> guest(weak_ptr_factory_->GetWeakPtr());
111
112    WebContents* web_contents = guest->embedder_web_contents();
113    if (should_allow && web_contents) {
114      // If renderer side embedder decides to allow gelocation, we need to check
115      // if the app/embedder itself has geolocation access.
116      BrowserContext* browser_context = web_contents->GetBrowserContext();
117      if (browser_context) {
118        GeolocationPermissionContext* geolocation_context =
119            browser_context->GetGeolocationPermissionContext();
120        if (geolocation_context) {
121          base::Callback<void(bool)> geolocation_callback = base::Bind(
122              &BrowserPluginGuest::SetGeolocationPermission,
123              guest,
124              callback_,
125              bridge_id_);
126          geolocation_context->RequestGeolocationPermission(
127              web_contents->GetRenderProcessHost()->GetID(),
128              web_contents->GetRoutingID(),
129              // The geolocation permission request here is not initiated
130              // through WebGeolocationPermissionRequest. We are only interested
131              // in the fact whether the embedder/app has geolocation
132              // permission. Therefore we use an invalid |bridge_id|.
133              -1 /* bridge_id */,
134              web_contents->GetLastCommittedURL(),
135              geolocation_callback);
136          return;
137        }
138      }
139    }
140    guest->SetGeolocationPermission(callback_, bridge_id_, false);
141  }
142
143 private:
144  virtual ~GeolocationRequest() {}
145  base::Callback<void(bool)> callback_;
146  int bridge_id_;
147  base::WeakPtrFactory<BrowserPluginGuest>* weak_ptr_factory_;
148};
149
150class BrowserPluginGuest::MediaRequest : public PermissionRequest {
151 public:
152  MediaRequest(const MediaStreamRequest& request,
153               const MediaResponseCallback& callback,
154               BrowserPluginGuest* guest)
155               : request_(request),
156                 callback_(callback),
157                 guest_(guest) {
158    RecordAction(
159        UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.Media"));
160  }
161
162  virtual void Respond(bool should_allow,
163                       const std::string& user_input) OVERRIDE {
164    WebContentsImpl* web_contents = guest_->embedder_web_contents();
165    if (should_allow && web_contents) {
166      // Re-route the request to the embedder's WebContents; the guest gets the
167      // permission this way.
168      web_contents->RequestMediaAccessPermission(request_, callback_);
169    } else {
170      // Deny the request.
171      callback_.Run(MediaStreamDevices(), scoped_ptr<MediaStreamUI>());
172    }
173  }
174
175 private:
176  virtual ~MediaRequest() {}
177  MediaStreamRequest request_;
178  MediaResponseCallback callback_;
179  BrowserPluginGuest* guest_;
180};
181
182class BrowserPluginGuest::NewWindowRequest : public PermissionRequest {
183 public:
184  NewWindowRequest(int instance_id, BrowserPluginGuest* guest)
185      : instance_id_(instance_id),
186        guest_(guest) {
187    RecordAction(
188        UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.NewWindow"));
189  }
190
191  virtual void Respond(bool should_allow,
192                       const std::string& user_input) OVERRIDE {
193    int embedder_render_process_id =
194        guest_->embedder_web_contents()->GetRenderProcessHost()->GetID();
195    BrowserPluginGuest* guest =
196        guest_->GetWebContents()->GetBrowserPluginGuestManager()->
197            GetGuestByInstanceID(instance_id_, embedder_render_process_id);
198    if (!guest) {
199      VLOG(0) << "Guest not found. Instance ID: " << instance_id_;
200      return;
201    }
202
203    // If we do not destroy the guest then we allow the new window.
204    if (!should_allow)
205      guest->Destroy();
206  }
207
208 private:
209  virtual ~NewWindowRequest() {}
210  int instance_id_;
211  BrowserPluginGuest* guest_;
212};
213
214class BrowserPluginGuest::JavaScriptDialogRequest : public PermissionRequest {
215 public:
216  JavaScriptDialogRequest(const DialogClosedCallback& callback)
217      : callback_(callback) {
218    RecordAction(
219        UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.JSDialog"));
220  }
221
222  virtual void Respond(bool should_allow,
223                       const std::string& user_input) OVERRIDE {
224    callback_.Run(should_allow, UTF8ToUTF16(user_input));
225  }
226
227 private:
228  virtual ~JavaScriptDialogRequest() {}
229  DialogClosedCallback callback_;
230};
231
232class BrowserPluginGuest::PointerLockRequest : public PermissionRequest {
233 public:
234  PointerLockRequest(BrowserPluginGuest* guest)
235      : guest_(guest) {
236    RecordAction(
237        UserMetricsAction("BrowserPlugin.Guest.PermissionRequest.PointerLock"));
238  }
239
240  virtual void Respond(bool should_allow,
241                       const std::string& user_input) OVERRIDE {
242    guest_->SendMessageToEmbedder(
243        new BrowserPluginMsg_SetMouseLock(guest_->instance_id(), should_allow));
244  }
245
246 private:
247  virtual ~PointerLockRequest() {}
248  BrowserPluginGuest* guest_;
249};
250
251namespace {
252std::string WindowOpenDispositionToString(
253  WindowOpenDisposition window_open_disposition) {
254  switch (window_open_disposition) {
255    case IGNORE_ACTION:
256      return "ignore";
257    case SAVE_TO_DISK:
258      return "save_to_disk";
259    case CURRENT_TAB:
260      return "current_tab";
261    case NEW_BACKGROUND_TAB:
262      return "new_background_tab";
263    case NEW_FOREGROUND_TAB:
264      return "new_foreground_tab";
265    case NEW_WINDOW:
266      return "new_window";
267    case NEW_POPUP:
268      return "new_popup";
269    default:
270      NOTREACHED() << "Unknown Window Open Disposition";
271      return "ignore";
272  }
273}
274
275std::string JavaScriptMessageTypeToString(JavaScriptMessageType message_type) {
276  switch (message_type) {
277    case JAVASCRIPT_MESSAGE_TYPE_ALERT:
278      return "alert";
279    case JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
280      return "confirm";
281    case JAVASCRIPT_MESSAGE_TYPE_PROMPT:
282      return "prompt";
283    default:
284      NOTREACHED() << "Unknown JavaScript Message Type.";
285      return "unknown";
286  }
287}
288
289// Called on IO thread.
290static std::string RetrieveDownloadURLFromRequestId(
291    RenderViewHost* render_view_host,
292    int url_request_id) {
293  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
294
295  int render_process_id = render_view_host->GetProcess()->GetID();
296  GlobalRequestID global_id(render_process_id, url_request_id);
297  net::URLRequest* url_request =
298      ResourceDispatcherHostImpl::Get()->GetURLRequest(global_id);
299  if (url_request)
300    return url_request->url().possibly_invalid_spec();
301  return "";
302}
303
304}  // namespace
305
306class BrowserPluginGuest::EmbedderWebContentsObserver
307    : public WebContentsObserver {
308 public:
309  explicit EmbedderWebContentsObserver(BrowserPluginGuest* guest)
310      : WebContentsObserver(guest->embedder_web_contents()),
311        browser_plugin_guest_(guest) {
312  }
313
314  virtual ~EmbedderWebContentsObserver() {
315  }
316
317  // WebContentsObserver:
318  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
319    browser_plugin_guest_->EmbedderDestroyed();
320  }
321
322  virtual void WasShown() OVERRIDE {
323    browser_plugin_guest_->EmbedderVisibilityChanged(true);
324  }
325
326  virtual void WasHidden() OVERRIDE {
327    browser_plugin_guest_->EmbedderVisibilityChanged(false);
328  }
329
330 private:
331  BrowserPluginGuest* browser_plugin_guest_;
332
333  DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
334};
335
336BrowserPluginGuest::BrowserPluginGuest(
337    int instance_id,
338    bool has_render_view,
339    WebContentsImpl* web_contents,
340    BrowserPluginGuest* opener)
341    : WebContentsObserver(web_contents),
342      weak_ptr_factory_(this),
343      embedder_web_contents_(NULL),
344      instance_id_(instance_id),
345      damage_buffer_sequence_id_(0),
346      damage_buffer_size_(0),
347      damage_buffer_scale_factor_(1.0f),
348      guest_device_scale_factor_(1.0f),
349      guest_hang_timeout_(
350          base::TimeDelta::FromMilliseconds(kHungRendererDelayMs)),
351      focused_(false),
352      mouse_locked_(false),
353      pending_lock_request_(false),
354      embedder_visible_(true),
355      copy_request_id_(0),
356      next_permission_request_id_(browser_plugin::kInvalidPermissionRequestID),
357      has_render_view_(has_render_view),
358      last_seen_auto_size_enabled_(false),
359      is_in_destruction_(false) {
360  DCHECK(web_contents);
361  web_contents->SetDelegate(this);
362  if (opener)
363    opener_ = opener->AsWeakPtr();
364  GetWebContents()->GetBrowserPluginGuestManager()->AddGuest(instance_id_,
365                                                             GetWebContents());
366}
367
368bool BrowserPluginGuest::AddMessageToConsole(WebContents* source,
369                                             int32 level,
370                                             const base::string16& message,
371                                             int32 line_no,
372                                             const base::string16& source_id) {
373  if (!delegate_)
374    return false;
375
376  delegate_->AddMessageToConsole(level, message, line_no, source_id);
377  return true;
378}
379
380void BrowserPluginGuest::DestroyUnattachedWindows() {
381  // Destroy() reaches in and removes the BrowserPluginGuest from its opener's
382  // pending_new_windows_ set. To avoid mutating the set while iterating, we
383  // create a copy of the pending new windows set and iterate over the copy.
384  PendingWindowMap pending_new_windows(pending_new_windows_);
385  // Clean up unattached new windows opened by this guest.
386  for (PendingWindowMap::const_iterator it = pending_new_windows.begin();
387       it != pending_new_windows.end(); ++it) {
388    it->first->Destroy();
389  }
390  // All pending windows should be removed from the set after Destroy() is
391  // called on all of them.
392  DCHECK(pending_new_windows_.empty());
393}
394
395void BrowserPluginGuest::LoadURLWithParams(const GURL& url,
396                                           const Referrer& referrer,
397                                           PageTransition transition_type,
398                                           WebContents* web_contents) {
399  NavigationController::LoadURLParams load_url_params(url);
400  load_url_params.referrer = referrer;
401  load_url_params.transition_type = transition_type;
402  load_url_params.extra_headers = std::string();
403  if (delegate_ && delegate_->IsOverridingUserAgent()) {
404    load_url_params.override_user_agent =
405        NavigationController::UA_OVERRIDE_TRUE;
406  }
407  web_contents->GetController().LoadURLWithParams(load_url_params);
408}
409
410void BrowserPluginGuest::RespondToPermissionRequest(
411    int request_id,
412    bool should_allow,
413    const std::string& user_input) {
414  RequestMap::iterator request_itr = permission_request_map_.find(request_id);
415  if (request_itr == permission_request_map_.end()) {
416    VLOG(0) << "Not a valid request ID.";
417    return;
418  }
419  request_itr->second->Respond(should_allow, user_input);
420  permission_request_map_.erase(request_itr);
421}
422
423int BrowserPluginGuest::RequestPermission(
424    BrowserPluginPermissionType permission_type,
425    scoped_refptr<BrowserPluginGuest::PermissionRequest> request,
426    const base::DictionaryValue& request_info) {
427  if (!delegate_) {
428    request->Respond(false, "");
429    return browser_plugin::kInvalidPermissionRequestID;
430  }
431
432  int request_id = ++next_permission_request_id_;
433  permission_request_map_[request_id] = request;
434
435  BrowserPluginGuestDelegate::PermissionResponseCallback callback =
436      base::Bind(&BrowserPluginGuest::RespondToPermissionRequest,
437                  AsWeakPtr(),
438                  request_id);
439  // If BrowserPluginGuestDelegate hasn't handled the permission then we simply
440  // perform the default action (which is one of allow or reject) immediately.
441  if (!delegate_->RequestPermission(
442      permission_type, request_info, callback, request->AllowedByDefault())) {
443    callback.Run(request->AllowedByDefault(), "");
444    return browser_plugin::kInvalidPermissionRequestID;
445  }
446
447  return request_id;
448}
449
450BrowserPluginGuest* BrowserPluginGuest::CreateNewGuestWindow(
451    const OpenURLParams& params) {
452  BrowserPluginGuestManager* guest_manager =
453      GetWebContents()->GetBrowserPluginGuestManager();
454
455  // Allocate a new instance ID for the new guest.
456  int instance_id = guest_manager->get_next_instance_id();
457
458  // Set the attach params to use the same partition as the opener.
459  // We pull the partition information from the site's URL, which is of the form
460  // guest://site/{persist}?{partition_name}.
461  const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
462  BrowserPluginHostMsg_Attach_Params attach_params;
463  attach_params.storage_partition_id = site_url.query();
464  attach_params.persist_storage =
465      site_url.path().find("persist") != std::string::npos;
466
467  // The new guest gets a copy of this guest's extra params so that the content
468  // embedder exposes the same API for this guest as its opener.
469  scoped_ptr<base::DictionaryValue> extra_params(
470      extra_attach_params_->DeepCopy());
471  BrowserPluginGuest* new_guest =
472      GetWebContents()->GetBrowserPluginGuestManager()->CreateGuest(
473          GetWebContents()->GetSiteInstance(), instance_id,
474          attach_params, extra_params.Pass());
475  new_guest->opener_ = AsWeakPtr();
476
477  // Take ownership of |new_guest|.
478  pending_new_windows_.insert(
479      std::make_pair(new_guest, NewWindowInfo(params.url, std::string())));
480
481  // Request permission to show the new window.
482  RequestNewWindowPermission(params.disposition, gfx::Rect(),
483                             params.user_gesture, new_guest->GetWebContents());
484
485  return new_guest;
486}
487
488void BrowserPluginGuest::EmbedderDestroyed() {
489  embedder_web_contents_ = NULL;
490  if (delegate_)
491    delegate_->EmbedderDestroyed();
492  Destroy();
493}
494
495void BrowserPluginGuest::Destroy() {
496  is_in_destruction_ = true;
497  if (!attached() && opener())
498    opener()->pending_new_windows_.erase(this);
499  DestroyUnattachedWindows();
500  GetWebContents()->GetBrowserPluginGuestManager()->RemoveGuest(instance_id_);
501  delete GetWebContents();
502}
503
504bool BrowserPluginGuest::OnMessageReceivedFromEmbedder(
505    const IPC::Message& message) {
506  bool handled = true;
507  IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
508    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_BuffersSwappedACK,
509                        OnSwapBuffersACK)
510    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CompositorFrameACK,
511                        OnCompositorFrameACK)
512    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_CopyFromCompositingSurfaceAck,
513                        OnCopyFromCompositingSurfaceAck)
514    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_DragStatusUpdate,
515                        OnDragStatusUpdate)
516    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExecuteEditCommand,
517                        OnExecuteEditCommand)
518    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ExtendSelectionAndDelete,
519                        OnExtendSelectionAndDelete)
520    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
521                        OnHandleInputEvent)
522    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeConfirmComposition,
523                        OnImeConfirmComposition)
524    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ImeSetComposition,
525                        OnImeSetComposition)
526    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_LockMouse_ACK, OnLockMouseAck)
527    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_NavigateGuest, OnNavigateGuest)
528    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_PluginDestroyed, OnPluginDestroyed)
529    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ReclaimCompositorResources,
530                        OnReclaimCompositorResources)
531    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_ResizeGuest, OnResizeGuest)
532    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetAutoSize, OnSetSize)
533    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent,
534                        OnSetEditCommandsForNextKeyEvent)
535    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetFocus, OnSetFocus)
536    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetName, OnSetName)
537    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetContentsOpaque,
538                        OnSetContentsOpaque)
539    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_SetVisibility, OnSetVisibility)
540    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UnlockMouse_ACK, OnUnlockMouseAck)
541    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateGeometry, OnUpdateGeometry)
542    IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_UpdateRect_ACK, OnUpdateRectACK)
543    IPC_MESSAGE_UNHANDLED(handled = false)
544  IPC_END_MESSAGE_MAP()
545  return handled;
546}
547
548void BrowserPluginGuest::Initialize(
549    const BrowserPluginHostMsg_Attach_Params& params,
550    WebContentsImpl* embedder_web_contents) {
551  focused_ = params.focused;
552  guest_visible_ = params.visible;
553  guest_opaque_ = params.opaque;
554  guest_window_rect_ = params.resize_guest_params.view_rect;
555
556  if (!params.name.empty())
557    name_ = params.name;
558  auto_size_enabled_ = params.auto_size_params.enable;
559  max_auto_size_ = params.auto_size_params.max_size;
560  min_auto_size_ = params.auto_size_params.min_size;
561
562  // Once a BrowserPluginGuest has an embedder WebContents, it's considered to
563  // be attached.
564  embedder_web_contents_ = embedder_web_contents;
565
566  WebContentsViewGuest* new_view =
567      static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
568  new_view->OnGuestInitialized(embedder_web_contents->GetView());
569
570  RendererPreferences* renderer_prefs =
571      GetWebContents()->GetMutableRendererPrefs();
572  std::string guest_user_agent_override = renderer_prefs->user_agent_override;
573  // Copy renderer preferences (and nothing else) from the embedder's
574  // WebContents to the guest.
575  //
576  // For GTK and Aura this is necessary to get proper renderer configuration
577  // values for caret blinking interval, colors related to selection and
578  // focus.
579  *renderer_prefs = *embedder_web_contents_->GetMutableRendererPrefs();
580  renderer_prefs->user_agent_override = guest_user_agent_override;
581
582  // We would like the guest to report changes to frame names so that we can
583  // update the BrowserPlugin's corresponding 'name' attribute.
584  // TODO(fsamuel): Remove this once http://crbug.com/169110 is addressed.
585  renderer_prefs->report_frame_name_changes = true;
586  // Navigation is disabled in Chrome Apps. We want to make sure guest-initiated
587  // navigations still continue to function inside the app.
588  renderer_prefs->browser_handles_all_top_level_requests = false;
589  // Disable "client blocked" error page for browser plugin.
590  renderer_prefs->disable_client_blocked_error_page = true;
591
592  embedder_web_contents_observer_.reset(new EmbedderWebContentsObserver(this));
593
594  OnSetSize(instance_id_, params.auto_size_params, params.resize_guest_params);
595
596  // Create a swapped out RenderView for the guest in the embedder render
597  // process, so that the embedder can access the guest's window object.
598  int guest_routing_id =
599      GetWebContents()->CreateSwappedOutRenderView(
600          embedder_web_contents_->GetSiteInstance());
601  SendMessageToEmbedder(
602      new BrowserPluginMsg_GuestContentWindowReady(instance_id_,
603                                                   guest_routing_id));
604
605  if (!params.src.empty()) {
606    // params.src will be validated in BrowserPluginGuest::OnNavigateGuest.
607    OnNavigateGuest(instance_id_, params.src);
608  }
609
610  has_render_view_ = true;
611
612  if (!embedder_web_contents_->
613          GetWebkitPrefs().accelerated_compositing_enabled) {
614    WebPreferences prefs = GetWebContents()->GetWebkitPrefs();
615    prefs.accelerated_compositing_enabled = false;
616    GetWebContents()->GetRenderViewHost()->UpdateWebkitPreferences(prefs);
617  }
618
619  // Enable input method for guest if it's enabled for the embedder.
620  if (static_cast<RenderViewHostImpl*>(
621      embedder_web_contents_->GetRenderViewHost())->input_method_active()) {
622    RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
623        GetWebContents()->GetRenderViewHost());
624    guest_rvh->SetInputMethodActive(true);
625  }
626
627  // Inform the embedder of the guest's information.
628  // We pull the partition information from the site's URL, which is of the form
629  // guest://site/{persist}?{partition_name}.
630  const GURL& site_url = GetWebContents()->GetSiteInstance()->GetSiteURL();
631  BrowserPluginMsg_Attach_ACK_Params ack_params;
632  ack_params.storage_partition_id = site_url.query();
633  ack_params.persist_storage =
634      site_url.path().find("persist") != std::string::npos;
635  ack_params.name = name_;
636  SendMessageToEmbedder(
637      new BrowserPluginMsg_Attach_ACK(instance_id_, ack_params));
638
639  if (delegate_)
640    delegate_->DidAttach();
641}
642
643BrowserPluginGuest::~BrowserPluginGuest() {
644  while (!pending_messages_.empty()) {
645    delete pending_messages_.front();
646    pending_messages_.pop();
647  }
648}
649
650// static
651BrowserPluginGuest* BrowserPluginGuest::Create(
652    int instance_id,
653    SiteInstance* guest_site_instance,
654    WebContentsImpl* web_contents,
655    scoped_ptr<base::DictionaryValue> extra_params) {
656  RecordAction(UserMetricsAction("BrowserPlugin.Guest.Create"));
657  BrowserPluginGuest* guest = NULL;
658  if (factory_) {
659    guest = factory_->CreateBrowserPluginGuest(instance_id, web_contents);
660  } else {
661    guest = new BrowserPluginGuest(instance_id, false, web_contents, NULL);
662  }
663  guest->extra_attach_params_.reset(extra_params->DeepCopy());
664  web_contents->SetBrowserPluginGuest(guest);
665  BrowserPluginGuestDelegate* delegate = NULL;
666  GetContentClient()->browser()->GuestWebContentsCreated(
667      guest_site_instance, web_contents, NULL, &delegate, extra_params.Pass());
668  guest->SetDelegate(delegate);
669  return guest;
670}
671
672// static
673BrowserPluginGuest* BrowserPluginGuest::CreateWithOpener(
674    int instance_id,
675    bool has_render_view,
676    WebContentsImpl* web_contents,
677    BrowserPluginGuest* opener) {
678  BrowserPluginGuest* guest =
679      new BrowserPluginGuest(
680          instance_id, has_render_view, web_contents, opener);
681  web_contents->SetBrowserPluginGuest(guest);
682  BrowserPluginGuestDelegate* delegate = NULL;
683  GetContentClient()->browser()->GuestWebContentsCreated(
684      opener->GetWebContents()->GetSiteInstance(),
685      web_contents, opener->GetWebContents(), &delegate,
686      scoped_ptr<base::DictionaryValue>());
687  guest->SetDelegate(delegate);
688  return guest;
689}
690
691RenderWidgetHostView* BrowserPluginGuest::GetEmbedderRenderWidgetHostView() {
692  return embedder_web_contents_->GetRenderWidgetHostView();
693}
694
695void BrowserPluginGuest::UpdateVisibility() {
696  OnSetVisibility(instance_id_, visible());
697}
698
699void BrowserPluginGuest::CopyFromCompositingSurface(
700      gfx::Rect src_subrect,
701      gfx::Size dst_size,
702      const base::Callback<void(bool, const SkBitmap&)>& callback) {
703  copy_request_callbacks_.insert(std::make_pair(++copy_request_id_, callback));
704  SendMessageToEmbedder(
705      new BrowserPluginMsg_CopyFromCompositingSurface(instance_id(),
706          copy_request_id_, src_subrect, dst_size));
707}
708
709// screen.
710gfx::Rect BrowserPluginGuest::ToGuestRect(const gfx::Rect& bounds) {
711  gfx::Rect guest_rect(bounds);
712  guest_rect.Offset(guest_window_rect_.OffsetFromOrigin());
713  return guest_rect;
714}
715
716void BrowserPluginGuest::EmbedderVisibilityChanged(bool visible) {
717  embedder_visible_ = visible;
718  UpdateVisibility();
719}
720
721void BrowserPluginGuest::AddNewContents(WebContents* source,
722                                        WebContents* new_contents,
723                                        WindowOpenDisposition disposition,
724                                        const gfx::Rect& initial_pos,
725                                        bool user_gesture,
726                                        bool* was_blocked) {
727  if (was_blocked)
728    *was_blocked = false;
729  RequestNewWindowPermission(disposition, initial_pos, user_gesture,
730                             static_cast<WebContentsImpl*>(new_contents));
731}
732
733void BrowserPluginGuest::CanDownload(
734    RenderViewHost* render_view_host,
735    int request_id,
736    const std::string& request_method,
737    const base::Callback<void(bool)>& callback) {
738  BrowserThread::PostTaskAndReplyWithResult(
739      BrowserThread::IO, FROM_HERE,
740      base::Bind(&RetrieveDownloadURLFromRequestId,
741                 render_view_host, request_id),
742      base::Bind(&BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId,
743                 weak_ptr_factory_.GetWeakPtr(),
744                 request_method,
745                 callback));
746}
747
748void BrowserPluginGuest::LoadProgressChanged(WebContents* contents,
749                                             double progress) {
750  if (delegate_)
751    delegate_->LoadProgressed(progress);
752}
753
754void BrowserPluginGuest::CloseContents(WebContents* source) {
755  if (!delegate_)
756    return;
757
758  delegate_->Close();
759}
760
761JavaScriptDialogManager* BrowserPluginGuest::GetJavaScriptDialogManager() {
762  return this;
763}
764
765bool BrowserPluginGuest::HandleContextMenu(const ContextMenuParams& params) {
766  // TODO(fsamuel): We show the regular page context menu handler for now until
767  // we implement the Apps Context Menu API for Browser Plugin (see
768  // http://crbug.com/140315).
769  return false;  // Will be handled by WebContentsViewGuest.
770}
771
772void BrowserPluginGuest::HandleKeyboardEvent(
773    WebContents* source,
774    const NativeWebKeyboardEvent& event) {
775  if (!attached())
776    return;
777
778  if (UnlockMouseIfNecessary(event))
779    return;
780
781  if (delegate_ && delegate_->HandleKeyboardEvent(event))
782    return;
783
784  if (!embedder_web_contents_->GetDelegate())
785    return;
786
787  // Send the unhandled keyboard events back to the embedder to reprocess them.
788  // TODO(fsamuel): This introduces the possibility of out-of-order keyboard
789  // events because the guest may be arbitrarily delayed when responding to
790  // keyboard events. In that time, the embedder may have received and processed
791  // additional key events. This needs to be fixed as soon as possible.
792  // See http://crbug.com/229882.
793  embedder_web_contents_->GetDelegate()->HandleKeyboardEvent(
794      web_contents(), event);
795}
796
797WebContents* BrowserPluginGuest::OpenURLFromTab(WebContents* source,
798                                                const OpenURLParams& params) {
799  // If the guest wishes to navigate away prior to attachment then we save the
800  // navigation to perform upon attachment. Navigation initializes a lot of
801  // state that assumes an embedder exists, such as RenderWidgetHostViewGuest.
802  // Navigation also resumes resource loading which we don't want to allow
803  // until attachment.
804  if (!attached()) {
805    PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
806    if (it == opener()->pending_new_windows_.end())
807      return NULL;
808    const NewWindowInfo& old_target_url = it->second;
809    NewWindowInfo new_window_info(params.url, old_target_url.name);
810    new_window_info.changed = new_window_info.url != old_target_url.url;
811    it->second = new_window_info;
812    return NULL;
813  }
814  if (params.disposition == CURRENT_TAB) {
815    // This can happen for cross-site redirects.
816    LoadURLWithParams(params.url, params.referrer, params.transition, source);
817    return source;
818  }
819
820  return CreateNewGuestWindow(params)->GetWebContents();
821}
822
823void BrowserPluginGuest::WebContentsCreated(WebContents* source_contents,
824                                            int64 source_frame_id,
825                                            const base::string16& frame_name,
826                                            const GURL& target_url,
827                                            WebContents* new_contents) {
828  WebContentsImpl* new_contents_impl =
829      static_cast<WebContentsImpl*>(new_contents);
830  BrowserPluginGuest* guest = new_contents_impl->GetBrowserPluginGuest();
831  guest->opener_ = AsWeakPtr();
832  std::string guest_name = UTF16ToUTF8(frame_name);
833  guest->name_ = guest_name;
834  // Take ownership of the new guest until it is attached to the embedder's DOM
835  // tree to avoid leaking a guest if this guest is destroyed before attaching
836  // the new guest.
837  pending_new_windows_.insert(
838      std::make_pair(guest, NewWindowInfo(target_url, guest_name)));
839}
840
841void BrowserPluginGuest::RendererUnresponsive(WebContents* source) {
842  RecordAction(UserMetricsAction("BrowserPlugin.Guest.Hung"));
843  if (!delegate_)
844    return;
845  delegate_->RendererUnresponsive();
846}
847
848void BrowserPluginGuest::RendererResponsive(WebContents* source) {
849  RecordAction(UserMetricsAction("BrowserPlugin.Guest.Responsive"));
850  if (!delegate_)
851    return;
852  delegate_->RendererResponsive();
853}
854
855void BrowserPluginGuest::RunFileChooser(WebContents* web_contents,
856                                        const FileChooserParams& params) {
857  if (!attached())
858    return;
859
860  if (!embedder_web_contents_->GetDelegate())
861    return;
862
863  embedder_web_contents_->GetDelegate()->RunFileChooser(web_contents, params);
864}
865
866bool BrowserPluginGuest::ShouldFocusPageAfterCrash() {
867  // Rather than managing focus in WebContentsImpl::RenderViewReady, we will
868  // manage the focus ourselves.
869  return false;
870}
871
872WebContentsImpl* BrowserPluginGuest::GetWebContents() {
873  return static_cast<WebContentsImpl*>(web_contents());
874}
875
876base::SharedMemory* BrowserPluginGuest::GetDamageBufferFromEmbedder(
877    const BrowserPluginHostMsg_ResizeGuest_Params& params) {
878  if (!attached()) {
879    LOG(WARNING) << "Attempting to map a damage buffer prior to attachment.";
880    return NULL;
881  }
882#if defined(OS_WIN)
883  base::ProcessHandle handle =
884      embedder_web_contents_->GetRenderProcessHost()->GetHandle();
885  scoped_ptr<base::SharedMemory> shared_buf(
886      new base::SharedMemory(params.damage_buffer_handle, false, handle));
887#elif defined(OS_POSIX)
888  scoped_ptr<base::SharedMemory> shared_buf(
889      new base::SharedMemory(params.damage_buffer_handle, false));
890#endif
891  if (!shared_buf->Map(params.damage_buffer_size)) {
892    LOG(WARNING) << "Unable to map the embedder's damage buffer.";
893    return NULL;
894  }
895  return shared_buf.release();
896}
897
898void BrowserPluginGuest::SetDamageBuffer(
899    const BrowserPluginHostMsg_ResizeGuest_Params& params) {
900  damage_buffer_.reset(GetDamageBufferFromEmbedder(params));
901  // Sanity check: Verify that we've correctly shared the damage buffer memory
902  // between the embedder and browser processes.
903  DCHECK(!damage_buffer_ ||
904      *static_cast<unsigned int*>(damage_buffer_->memory()) == 0xdeadbeef);
905  damage_buffer_sequence_id_ = params.damage_buffer_sequence_id;
906  damage_buffer_size_ = params.damage_buffer_size;
907  damage_view_size_ = params.view_rect.size();
908  damage_buffer_scale_factor_ = params.scale_factor;
909}
910
911gfx::Point BrowserPluginGuest::GetScreenCoordinates(
912    const gfx::Point& relative_position) const {
913  gfx::Point screen_pos(relative_position);
914  screen_pos += guest_window_rect_.OffsetFromOrigin();
915  return screen_pos;
916}
917
918bool BrowserPluginGuest::InAutoSizeBounds(const gfx::Size& size) const {
919  return size.width() <= max_auto_size_.width() &&
920      size.height() <= max_auto_size_.height();
921}
922
923void BrowserPluginGuest::RequestNewWindowPermission(
924    WindowOpenDisposition disposition,
925    const gfx::Rect& initial_bounds,
926    bool user_gesture,
927    WebContentsImpl* new_contents) {
928  BrowserPluginGuest* guest = new_contents->GetBrowserPluginGuest();
929  PendingWindowMap::iterator it = pending_new_windows_.find(guest);
930  if (it == pending_new_windows_.end())
931    return;
932  const NewWindowInfo& new_window_info = it->second;
933
934  base::DictionaryValue request_info;
935  request_info.Set(browser_plugin::kInitialHeight,
936                   base::Value::CreateIntegerValue(initial_bounds.height()));
937  request_info.Set(browser_plugin::kInitialWidth,
938                   base::Value::CreateIntegerValue(initial_bounds.width()));
939  request_info.Set(browser_plugin::kTargetURL,
940                   base::Value::CreateStringValue(new_window_info.url.spec()));
941  request_info.Set(browser_plugin::kName,
942                   base::Value::CreateStringValue(new_window_info.name));
943  request_info.Set(browser_plugin::kWindowID,
944                   base::Value::CreateIntegerValue(guest->instance_id()));
945  request_info.Set(browser_plugin::kWindowOpenDisposition,
946                   base::Value::CreateStringValue(
947                       WindowOpenDispositionToString(disposition)));
948
949  RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_NEW_WINDOW,
950                    new NewWindowRequest(guest->instance_id(), this),
951                    request_info);
952}
953
954bool BrowserPluginGuest::UnlockMouseIfNecessary(
955    const NativeWebKeyboardEvent& event) {
956  if (!mouse_locked_)
957    return false;
958
959  embedder_web_contents()->GotResponseToLockMouseRequest(false);
960  return true;
961}
962
963void BrowserPluginGuest::SendMessageToEmbedder(IPC::Message* msg) {
964  if (!attached()) {
965    // Some pages such as data URLs, javascript URLs, and about:blank
966    // do not load external resources and so they load prior to attachment.
967    // As a result, we must save all these IPCs until attachment and then
968    // forward them so that the embedder gets a chance to see and process
969    // the load events.
970    pending_messages_.push(msg);
971    return;
972  }
973  msg->set_routing_id(embedder_web_contents_->GetRoutingID());
974  embedder_web_contents_->Send(msg);
975}
976
977void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
978    int screen_x, int screen_y, blink::WebDragOperation operation) {
979  web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
980      screen_x, screen_y, operation);
981}
982
983void BrowserPluginGuest::DragSourceMovedTo(int client_x, int client_y,
984                                           int screen_x, int screen_y) {
985  web_contents()->GetRenderViewHost()->DragSourceMovedTo(client_x, client_y,
986                                                         screen_x, screen_y);
987}
988
989void BrowserPluginGuest::EndSystemDrag() {
990  RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
991      GetWebContents()->GetRenderViewHost());
992  guest_rvh->DragSourceSystemDragEnded();
993  // Issue a MouseUp event to get out of a selection state.
994  blink::WebMouseEvent mouse_event;
995  mouse_event.type = blink::WebInputEvent::MouseUp;
996  mouse_event.button = blink::WebMouseEvent::ButtonLeft;
997  guest_rvh->ForwardMouseEvent(mouse_event);
998}
999
1000void BrowserPluginGuest::SetDelegate(BrowserPluginGuestDelegate* delegate) {
1001  DCHECK(!delegate_);
1002  delegate_.reset(delegate);
1003}
1004
1005void BrowserPluginGuest::AskEmbedderForGeolocationPermission(
1006    int bridge_id,
1007    const GURL& requesting_frame,
1008    const GeolocationCallback& callback) {
1009  base::DictionaryValue request_info;
1010  request_info.Set(browser_plugin::kURL,
1011                   base::Value::CreateStringValue(requesting_frame.spec()));
1012
1013  int request_id =
1014      RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_GEOLOCATION,
1015                        new GeolocationRequest(
1016                            callback, bridge_id, &weak_ptr_factory_),
1017                        request_info);
1018
1019  DCHECK(bridge_id_to_request_id_map_.find(bridge_id) ==
1020         bridge_id_to_request_id_map_.end());
1021  bridge_id_to_request_id_map_[bridge_id] = request_id;
1022}
1023
1024int BrowserPluginGuest::RemoveBridgeID(int bridge_id) {
1025  std::map<int, int>::iterator bridge_itr =
1026      bridge_id_to_request_id_map_.find(bridge_id);
1027  if (bridge_itr == bridge_id_to_request_id_map_.end())
1028    return browser_plugin::kInvalidPermissionRequestID;
1029
1030  int request_id = bridge_itr->second;
1031  bridge_id_to_request_id_map_.erase(bridge_itr);
1032  return request_id;
1033}
1034
1035void BrowserPluginGuest::CancelGeolocationRequest(int bridge_id) {
1036  int request_id = RemoveBridgeID(bridge_id);
1037  RequestMap::iterator request_itr = permission_request_map_.find(request_id);
1038  if (request_itr == permission_request_map_.end())
1039    return;
1040  permission_request_map_.erase(request_itr);
1041}
1042
1043void BrowserPluginGuest::SetGeolocationPermission(GeolocationCallback callback,
1044                                                  int bridge_id,
1045                                                  bool allowed) {
1046  callback.Run(allowed);
1047  RemoveBridgeID(bridge_id);
1048}
1049
1050void BrowserPluginGuest::SendQueuedMessages() {
1051  if (!attached())
1052    return;
1053
1054  while (!pending_messages_.empty()) {
1055    IPC::Message* message = pending_messages_.front();
1056    pending_messages_.pop();
1057    SendMessageToEmbedder(message);
1058  }
1059}
1060
1061void BrowserPluginGuest::DidCommitProvisionalLoadForFrame(
1062    int64 frame_id,
1063    const base::string16& frame_unique_name,
1064    bool is_main_frame,
1065    const GURL& url,
1066    PageTransition transition_type,
1067    RenderViewHost* render_view_host) {
1068  RecordAction(UserMetricsAction("BrowserPlugin.Guest.DidNavigate"));
1069}
1070
1071void BrowserPluginGuest::DidStopLoading(RenderViewHost* render_view_host) {
1072  bool enable_dragdrop = delegate_ && delegate_->IsDragAndDropEnabled();
1073  if (!enable_dragdrop) {
1074    // Initiating a drag from inside a guest is currently not supported without
1075    // the kEnableBrowserPluginDragDrop flag on a linux platform. So inject some
1076    // JS to disable it. http://crbug.com/161112
1077    const char script[] = "window.addEventListener('dragstart', function() { "
1078                          "  window.event.preventDefault(); "
1079                          "});";
1080    render_view_host->ExecuteJavascriptInWebFrame(base::string16(),
1081                                                  ASCIIToUTF16(script));
1082  }
1083}
1084
1085void BrowserPluginGuest::RenderViewReady() {
1086  RenderViewHost* rvh = GetWebContents()->GetRenderViewHost();
1087  // The guest RenderView should always live in a guest process.
1088  CHECK(rvh->GetProcess()->IsGuest());
1089  // TODO(fsamuel): Investigate whether it's possible to update state earlier
1090  // here (see http://crbug.com/158151).
1091  Send(new InputMsg_SetFocus(routing_id(), focused_));
1092  UpdateVisibility();
1093  if (auto_size_enabled_)
1094    rvh->EnableAutoResize(min_auto_size_, max_auto_size_);
1095  else
1096    rvh->DisableAutoResize(damage_view_size_);
1097
1098  Send(new ViewMsg_SetName(routing_id(), name_));
1099  OnSetContentsOpaque(instance_id_, guest_opaque_);
1100
1101  RenderWidgetHostImpl::From(rvh)->
1102      set_hung_renderer_delay_ms(guest_hang_timeout_);
1103}
1104
1105void BrowserPluginGuest::RenderProcessGone(base::TerminationStatus status) {
1106  SendMessageToEmbedder(new BrowserPluginMsg_GuestGone(instance_id()));
1107  switch (status) {
1108    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
1109      RecordAction(UserMetricsAction("BrowserPlugin.Guest.Killed"));
1110      break;
1111    case base::TERMINATION_STATUS_PROCESS_CRASHED:
1112      RecordAction(UserMetricsAction("BrowserPlugin.Guest.Crashed"));
1113      break;
1114    case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
1115      RecordAction(UserMetricsAction("BrowserPlugin.Guest.AbnormalDeath"));
1116      break;
1117    default:
1118      break;
1119  }
1120  // TODO(fsamuel): Consider whether we should be clearing
1121  // |permission_request_map_| here.
1122  if (delegate_)
1123    delegate_->GuestProcessGone(status);
1124}
1125
1126// static
1127void BrowserPluginGuest::AcknowledgeBufferPresent(
1128    int route_id,
1129    int gpu_host_id,
1130    const std::string& mailbox_name,
1131    uint32 sync_point) {
1132  AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
1133  ack_params.mailbox_name = mailbox_name;
1134  ack_params.sync_point = sync_point;
1135  RenderWidgetHostImpl::AcknowledgeBufferPresent(route_id,
1136                                                 gpu_host_id,
1137                                                 ack_params);
1138}
1139
1140// static
1141bool BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(
1142    const IPC::Message& message) {
1143  switch (message.type()) {
1144    case BrowserPluginHostMsg_BuffersSwappedACK::ID:
1145    case BrowserPluginHostMsg_CompositorFrameACK::ID:
1146    case BrowserPluginHostMsg_CopyFromCompositingSurfaceAck::ID:
1147    case BrowserPluginHostMsg_DragStatusUpdate::ID:
1148    case BrowserPluginHostMsg_ExecuteEditCommand::ID:
1149    case BrowserPluginHostMsg_ExtendSelectionAndDelete::ID:
1150    case BrowserPluginHostMsg_HandleInputEvent::ID:
1151    case BrowserPluginHostMsg_ImeConfirmComposition::ID:
1152    case BrowserPluginHostMsg_ImeSetComposition::ID:
1153    case BrowserPluginHostMsg_LockMouse_ACK::ID:
1154    case BrowserPluginHostMsg_NavigateGuest::ID:
1155    case BrowserPluginHostMsg_PluginDestroyed::ID:
1156    case BrowserPluginHostMsg_ReclaimCompositorResources::ID:
1157    case BrowserPluginHostMsg_ResizeGuest::ID:
1158    case BrowserPluginHostMsg_SetAutoSize::ID:
1159    case BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent::ID:
1160    case BrowserPluginHostMsg_SetFocus::ID:
1161    case BrowserPluginHostMsg_SetName::ID:
1162    case BrowserPluginHostMsg_SetContentsOpaque::ID:
1163    case BrowserPluginHostMsg_SetVisibility::ID:
1164    case BrowserPluginHostMsg_UnlockMouse_ACK::ID:
1165    case BrowserPluginHostMsg_UpdateGeometry::ID:
1166    case BrowserPluginHostMsg_UpdateRect_ACK::ID:
1167      return true;
1168    default:
1169      return false;
1170  }
1171}
1172
1173bool BrowserPluginGuest::OnMessageReceived(const IPC::Message& message) {
1174  bool handled = true;
1175  IPC_BEGIN_MESSAGE_MAP(BrowserPluginGuest, message)
1176    IPC_MESSAGE_HANDLER(ViewHostMsg_HasTouchEventHandlers,
1177                        OnHasTouchEventHandlers)
1178    IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnLockMouse)
1179    IPC_MESSAGE_HANDLER(ViewHostMsg_SetCursor, OnSetCursor)
1180 #if defined(OS_MACOSX)
1181    // MacOSX creates and populates platform-specific select drop-down menus
1182    // whereas other platforms merely create a popup window that the guest
1183    // renderer process paints inside.
1184    IPC_MESSAGE_HANDLER(ViewHostMsg_ShowPopup, OnShowPopup)
1185 #endif
1186    IPC_MESSAGE_HANDLER(ViewHostMsg_ShowWidget, OnShowWidget)
1187    IPC_MESSAGE_HANDLER(ViewHostMsg_TakeFocus, OnTakeFocus)
1188    IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputTypeChanged,
1189                        OnTextInputTypeChanged)
1190    IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCancelComposition,
1191                        OnImeCancelComposition)
1192#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
1193    IPC_MESSAGE_HANDLER(ViewHostMsg_ImeCompositionRangeChanged,
1194                        OnImeCompositionRangeChanged)
1195#endif
1196    IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnUnlockMouse)
1197    IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFrameName, OnUpdateFrameName)
1198    IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnUpdateRect)
1199    IPC_MESSAGE_UNHANDLED(handled = false)
1200  IPC_END_MESSAGE_MAP()
1201  return handled;
1202}
1203
1204void BrowserPluginGuest::Attach(
1205    WebContentsImpl* embedder_web_contents,
1206    BrowserPluginHostMsg_Attach_Params params,
1207    const base::DictionaryValue& extra_params) {
1208  if (attached())
1209    return;
1210
1211  extra_attach_params_.reset(extra_params.DeepCopy());
1212
1213  // Clear parameters that get inherited from the opener.
1214  params.storage_partition_id.clear();
1215  params.persist_storage = false;
1216  params.src.clear();
1217
1218  // If a RenderView has already been created for this new window, then we need
1219  // to initialize the browser-side state now so that the RenderFrameHostManager
1220  // does not create a new RenderView on navigation.
1221  if (has_render_view_) {
1222    static_cast<RenderViewHostImpl*>(
1223        GetWebContents()->GetRenderViewHost())->Init();
1224    WebContentsViewGuest* new_view =
1225        static_cast<WebContentsViewGuest*>(GetWebContents()->GetView());
1226    new_view->CreateViewForWidget(web_contents()->GetRenderViewHost());
1227  }
1228
1229  // We need to do a navigation here if the target URL has changed between
1230  // the time the WebContents was created and the time it was attached.
1231  // We also need to do an initial navigation if a RenderView was never
1232  // created for the new window in cases where there is no referrer.
1233  PendingWindowMap::iterator it = opener()->pending_new_windows_.find(this);
1234  if (it != opener()->pending_new_windows_.end()) {
1235    const NewWindowInfo& new_window_info = it->second;
1236    if (new_window_info.changed || !has_render_view_)
1237      params.src = it->second.url.spec();
1238  } else {
1239    NOTREACHED();
1240  }
1241
1242  // Once a new guest is attached to the DOM of the embedder page, then the
1243  // lifetime of the new guest is no longer managed by the opener guest.
1244  opener()->pending_new_windows_.erase(this);
1245
1246  // The guest's frame name takes precedence over the BrowserPlugin's name.
1247  // The guest's frame name is assigned in
1248  // BrowserPluginGuest::WebContentsCreated.
1249  if (!name_.empty())
1250    params.name.clear();
1251
1252  Initialize(params, embedder_web_contents);
1253
1254  SendQueuedMessages();
1255
1256  RecordAction(UserMetricsAction("BrowserPlugin.Guest.Attached"));
1257}
1258
1259void BrowserPluginGuest::OnCompositorFrameACK(
1260    int instance_id,
1261    int route_id,
1262    uint32 output_surface_id,
1263    int renderer_host_id,
1264    const cc::CompositorFrameAck& ack) {
1265  RenderWidgetHostImpl::SendSwapCompositorFrameAck(route_id,
1266                                                   output_surface_id,
1267                                                   renderer_host_id,
1268                                                   ack);
1269}
1270
1271void BrowserPluginGuest::OnDragStatusUpdate(int instance_id,
1272                                            blink::WebDragStatus drag_status,
1273                                            const DropData& drop_data,
1274                                            blink::WebDragOperationsMask mask,
1275                                            const gfx::Point& location) {
1276  RenderViewHost* host = GetWebContents()->GetRenderViewHost();
1277  switch (drag_status) {
1278    case blink::WebDragStatusEnter:
1279      embedder_web_contents_->GetBrowserPluginEmbedder()->DragEnteredGuest(
1280          this);
1281      host->DragTargetDragEnter(drop_data, location, location, mask, 0);
1282      break;
1283    case blink::WebDragStatusOver:
1284      host->DragTargetDragOver(location, location, mask, 0);
1285      break;
1286    case blink::WebDragStatusLeave:
1287      embedder_web_contents_->GetBrowserPluginEmbedder()->DragLeftGuest(this);
1288      host->DragTargetDragLeave();
1289      break;
1290    case blink::WebDragStatusDrop:
1291      host->DragTargetDrop(location, location, 0);
1292      EndSystemDrag();
1293      break;
1294    case blink::WebDragStatusUnknown:
1295      NOTREACHED();
1296  }
1297}
1298
1299void BrowserPluginGuest::OnExecuteEditCommand(int instance_id,
1300                                              const std::string& name) {
1301  Send(new InputMsg_ExecuteEditCommand(routing_id(), name, std::string()));
1302}
1303
1304void BrowserPluginGuest::OnImeSetComposition(
1305    int instance_id,
1306    const std::string& text,
1307    const std::vector<blink::WebCompositionUnderline>& underlines,
1308    int selection_start,
1309    int selection_end) {
1310  Send(new ViewMsg_ImeSetComposition(routing_id(),
1311                                     UTF8ToUTF16(text), underlines,
1312                                     selection_start, selection_end));
1313}
1314
1315void BrowserPluginGuest::OnImeConfirmComposition(
1316    int instance_id,
1317    const std::string& text,
1318    bool keep_selection) {
1319  Send(new ViewMsg_ImeConfirmComposition(routing_id(),
1320                                         UTF8ToUTF16(text),
1321                                         gfx::Range::InvalidRange(),
1322                                         keep_selection));
1323}
1324
1325void BrowserPluginGuest::OnExtendSelectionAndDelete(
1326    int instance_id,
1327    int before,
1328    int after) {
1329  Send(new ViewMsg_ExtendSelectionAndDelete(routing_id(), before, after));
1330}
1331
1332void BrowserPluginGuest::OnReclaimCompositorResources(
1333    int instance_id,
1334    int route_id,
1335    uint32 output_surface_id,
1336    int renderer_host_id,
1337    const cc::CompositorFrameAck& ack) {
1338  RenderWidgetHostImpl::SendReclaimCompositorResources(route_id,
1339                                                       output_surface_id,
1340                                                       renderer_host_id,
1341                                                       ack);
1342}
1343
1344void BrowserPluginGuest::OnHandleInputEvent(
1345    int instance_id,
1346    const gfx::Rect& guest_window_rect,
1347    const blink::WebInputEvent* event) {
1348  guest_window_rect_ = guest_window_rect;
1349  // If the embedder's RWHV is destroyed then that means that the embedder's
1350  // window has been closed but the embedder's WebContents has not yet been
1351  // destroyed. Computing screen coordinates of a BrowserPlugin only makes sense
1352  // if there is a visible embedder.
1353  if (embedder_web_contents_->GetRenderWidgetHostView()) {
1354    guest_screen_rect_ = guest_window_rect;
1355    guest_screen_rect_.Offset(
1356        embedder_web_contents_->GetRenderWidgetHostView()->
1357            GetViewBounds().OffsetFromOrigin());
1358  }
1359  RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
1360      GetWebContents()->GetRenderViewHost());
1361
1362  if (blink::WebInputEvent::isMouseEventType(event->type)) {
1363    guest_rvh->ForwardMouseEvent(
1364        *static_cast<const blink::WebMouseEvent*>(event));
1365    return;
1366  }
1367
1368  if (event->type == blink::WebInputEvent::MouseWheel) {
1369    guest_rvh->ForwardWheelEvent(
1370        *static_cast<const blink::WebMouseWheelEvent*>(event));
1371    return;
1372  }
1373
1374  if (blink::WebInputEvent::isKeyboardEventType(event->type)) {
1375    RenderViewHostImpl* embedder_rvh = static_cast<RenderViewHostImpl*>(
1376        embedder_web_contents_->GetRenderViewHost());
1377    if (!embedder_rvh->GetLastKeyboardEvent())
1378      return;
1379    NativeWebKeyboardEvent keyboard_event(
1380        *embedder_rvh->GetLastKeyboardEvent());
1381    guest_rvh->ForwardKeyboardEvent(keyboard_event);
1382    return;
1383  }
1384
1385  if (blink::WebInputEvent::isTouchEventType(event->type)) {
1386    guest_rvh->ForwardTouchEventWithLatencyInfo(
1387        *static_cast<const blink::WebTouchEvent*>(event),
1388        ui::LatencyInfo());
1389    return;
1390  }
1391
1392  if (blink::WebInputEvent::isGestureEventType(event->type)) {
1393    guest_rvh->ForwardGestureEvent(
1394        *static_cast<const blink::WebGestureEvent*>(event));
1395    return;
1396  }
1397}
1398
1399void BrowserPluginGuest::OnLockMouse(bool user_gesture,
1400                                     bool last_unlocked_by_target,
1401                                     bool privileged) {
1402  if (pending_lock_request_) {
1403    // Immediately reject the lock because only one pointerLock may be active
1404    // at a time.
1405    Send(new ViewMsg_LockMouse_ACK(routing_id(), false));
1406    return;
1407  }
1408  pending_lock_request_ = true;
1409  base::DictionaryValue request_info;
1410  request_info.Set(browser_plugin::kUserGesture,
1411                   base::Value::CreateBooleanValue(user_gesture));
1412  request_info.Set(browser_plugin::kLastUnlockedBySelf,
1413                   base::Value::CreateBooleanValue(last_unlocked_by_target));
1414  request_info.Set(browser_plugin::kURL,
1415                   base::Value::CreateStringValue(
1416                       web_contents()->GetLastCommittedURL().spec()));
1417
1418  RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_POINTER_LOCK,
1419                    new PointerLockRequest(this),
1420                    request_info);
1421}
1422
1423void BrowserPluginGuest::OnLockMouseAck(int instance_id, bool succeeded) {
1424  Send(new ViewMsg_LockMouse_ACK(routing_id(), succeeded));
1425  pending_lock_request_ = false;
1426  if (succeeded)
1427    mouse_locked_ = true;
1428}
1429
1430void BrowserPluginGuest::OnNavigateGuest(
1431    int instance_id,
1432    const std::string& src) {
1433  GURL url = delegate_ ? delegate_->ResolveURL(src) : GURL(src);
1434  // We do not load empty urls in web_contents.
1435  // If a guest sets empty src attribute after it has navigated to some
1436  // non-empty page, the action is considered no-op. This empty src navigation
1437  // should never be sent to BrowserPluginGuest (browser process).
1438  DCHECK(!src.empty());
1439  if (src.empty())
1440    return;
1441
1442  // Do not allow navigating a guest to schemes other than known safe schemes.
1443  // This will block the embedder trying to load unwanted schemes, e.g.
1444  // chrome://settings.
1445  bool scheme_is_blocked =
1446      (!ChildProcessSecurityPolicyImpl::GetInstance()->IsWebSafeScheme(
1447          url.scheme()) &&
1448      !ChildProcessSecurityPolicyImpl::GetInstance()->IsPseudoScheme(
1449          url.scheme())) ||
1450      url.SchemeIs(kJavaScriptScheme);
1451  if (scheme_is_blocked || !url.is_valid()) {
1452    if (delegate_) {
1453      std::string error_type;
1454      base::RemoveChars(net::ErrorToString(net::ERR_ABORTED), "net::",
1455                        &error_type);
1456      delegate_->LoadAbort(true /* is_top_level */, url, error_type);
1457    }
1458    return;
1459  }
1460
1461  GURL validated_url(url);
1462  RenderViewHost::FilterURL(
1463      GetWebContents()->GetRenderProcessHost(),
1464      false,
1465      &validated_url);
1466  // As guests do not swap processes on navigation, only navigations to
1467  // normal web URLs are supported.  No protocol handlers are installed for
1468  // other schemes (e.g., WebUI or extensions), and no permissions or bindings
1469  // can be granted to the guest process.
1470  LoadURLWithParams(validated_url, Referrer(), PAGE_TRANSITION_AUTO_TOPLEVEL,
1471                    GetWebContents());
1472}
1473
1474void BrowserPluginGuest::OnPluginDestroyed(int instance_id) {
1475  Destroy();
1476}
1477
1478void BrowserPluginGuest::OnResizeGuest(
1479    int instance_id,
1480    const BrowserPluginHostMsg_ResizeGuest_Params& params) {
1481  if (!params.size_changed)
1482    return;
1483  // BrowserPlugin manages resize flow control itself and does not depend
1484  // on RenderWidgetHost's mechanisms for flow control, so we reset those flags
1485  // here. If we are setting the size for the first time before navigating then
1486  // BrowserPluginGuest does not yet have a RenderViewHost.
1487  if (GetWebContents()->GetRenderViewHost()) {
1488    RenderWidgetHostImpl* render_widget_host =
1489        RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
1490    render_widget_host->ResetSizeAndRepaintPendingFlags();
1491
1492    if (guest_device_scale_factor_ != params.scale_factor) {
1493      guest_device_scale_factor_ = params.scale_factor;
1494      render_widget_host->NotifyScreenInfoChanged();
1495    }
1496  }
1497  // When autosize is turned off and as a result there is a layout change, we
1498  // send a sizechanged event.
1499  if (!auto_size_enabled_ && last_seen_auto_size_enabled_ &&
1500      !params.view_rect.size().IsEmpty() && delegate_) {
1501    delegate_->SizeChanged(last_seen_view_size_, params.view_rect.size());
1502    last_seen_auto_size_enabled_ = false;
1503  }
1504  // Invalid damage buffer means we are in HW compositing mode,
1505  // so just resize the WebContents and repaint if needed.
1506  if (base::SharedMemory::IsHandleValid(params.damage_buffer_handle))
1507    SetDamageBuffer(params);
1508  if (!params.view_rect.size().IsEmpty())
1509    GetWebContents()->GetView()->SizeContents(params.view_rect.size());
1510  if (params.repaint)
1511    Send(new ViewMsg_Repaint(routing_id(), params.view_rect.size()));
1512}
1513
1514void BrowserPluginGuest::OnSetFocus(int instance_id, bool focused) {
1515  if (focused_ == focused)
1516      return;
1517  focused_ = focused;
1518  Send(new InputMsg_SetFocus(routing_id(), focused));
1519  if (!focused && mouse_locked_)
1520    OnUnlockMouse();
1521}
1522
1523void BrowserPluginGuest::OnSetName(int instance_id, const std::string& name) {
1524  if (name == name_)
1525    return;
1526  name_ = name;
1527  Send(new ViewMsg_SetName(routing_id(), name));
1528}
1529
1530void BrowserPluginGuest::OnSetSize(
1531    int instance_id,
1532    const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1533    const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1534  bool old_auto_size_enabled = auto_size_enabled_;
1535  gfx::Size old_max_size = max_auto_size_;
1536  gfx::Size old_min_size = min_auto_size_;
1537  auto_size_enabled_ = auto_size_params.enable;
1538  max_auto_size_ = auto_size_params.max_size;
1539  min_auto_size_ = auto_size_params.min_size;
1540  if (auto_size_enabled_ && (!old_auto_size_enabled ||
1541                             (old_max_size != max_auto_size_) ||
1542                             (old_min_size != min_auto_size_))) {
1543    RecordAction(UserMetricsAction("BrowserPlugin.Guest.EnableAutoResize"));
1544    GetWebContents()->GetRenderViewHost()->EnableAutoResize(
1545        min_auto_size_, max_auto_size_);
1546    // TODO(fsamuel): If we're changing autosize parameters, then we force
1547    // the guest to completely repaint itself, because BrowserPlugin has
1548    // allocated a new damage buffer and expects a full frame of pixels.
1549    // Ideally, we shouldn't need to do this because we shouldn't need to
1550    // allocate a new damage buffer unless |max_auto_size_| has changed.
1551    // However, even in that case, layout may not change and so we may
1552    // not get a full frame worth of pixels.
1553    Send(new ViewMsg_Repaint(routing_id(), max_auto_size_));
1554  } else if (!auto_size_enabled_ && old_auto_size_enabled) {
1555    GetWebContents()->GetRenderViewHost()->DisableAutoResize(
1556        resize_guest_params.view_rect.size());
1557  }
1558  OnResizeGuest(instance_id_, resize_guest_params);
1559}
1560
1561void BrowserPluginGuest::OnSetEditCommandsForNextKeyEvent(
1562    int instance_id,
1563    const std::vector<EditCommand>& edit_commands) {
1564  Send(new InputMsg_SetEditCommandsForNextKeyEvent(routing_id(),
1565                                                   edit_commands));
1566}
1567
1568void BrowserPluginGuest::OnSetContentsOpaque(int instance_id, bool opaque) {
1569  guest_opaque_ = opaque;
1570
1571  SkBitmap background;
1572  if (!guest_opaque_) {
1573    background.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
1574    unsigned int color = 0;
1575    background.setPixels(&color);
1576  }
1577  Send(new ViewMsg_SetBackground(routing_id(), background));
1578}
1579
1580void BrowserPluginGuest::OnSetVisibility(int instance_id, bool visible) {
1581  guest_visible_ = visible;
1582  if (embedder_visible_ && guest_visible_)
1583    GetWebContents()->WasShown();
1584  else
1585    GetWebContents()->WasHidden();
1586}
1587
1588void BrowserPluginGuest::OnSwapBuffersACK(int instance_id,
1589                                          int route_id,
1590                                          int gpu_host_id,
1591                                          const std::string& mailbox_name,
1592                                          uint32 sync_point) {
1593  AcknowledgeBufferPresent(route_id, gpu_host_id, mailbox_name, sync_point);
1594
1595// This is only relevant on MACOSX and WIN when threaded compositing
1596// is not enabled. In threaded mode, above ACK is sufficient.
1597#if defined(OS_MACOSX) || defined(OS_WIN)
1598  RenderWidgetHostImpl* render_widget_host =
1599        RenderWidgetHostImpl::From(GetWebContents()->GetRenderViewHost());
1600  render_widget_host->AcknowledgeSwapBuffersToRenderer();
1601#endif  // defined(OS_MACOSX) || defined(OS_WIN)
1602}
1603
1604void BrowserPluginGuest::OnUnlockMouse() {
1605  SendMessageToEmbedder(
1606      new BrowserPluginMsg_SetMouseLock(instance_id(), false));
1607}
1608
1609void BrowserPluginGuest::OnUnlockMouseAck(int instance_id) {
1610  // mouse_locked_ could be false here if the lock attempt was cancelled due
1611  // to window focus, or for various other reasons before the guest was informed
1612  // of the lock's success.
1613  if (mouse_locked_)
1614    Send(new ViewMsg_MouseLockLost(routing_id()));
1615  mouse_locked_ = false;
1616}
1617
1618void BrowserPluginGuest::OnUpdateRectACK(
1619    int instance_id,
1620    bool needs_ack,
1621    const BrowserPluginHostMsg_AutoSize_Params& auto_size_params,
1622    const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params) {
1623  // Only the software path expects an ACK.
1624  if (needs_ack)
1625    Send(new ViewMsg_UpdateRect_ACK(routing_id()));
1626  OnSetSize(instance_id_, auto_size_params, resize_guest_params);
1627}
1628
1629void BrowserPluginGuest::OnCopyFromCompositingSurfaceAck(
1630    int instance_id,
1631    int request_id,
1632    const SkBitmap& bitmap) {
1633  CHECK(copy_request_callbacks_.count(request_id));
1634  if (!copy_request_callbacks_.count(request_id))
1635    return;
1636  const CopyRequestCallback& callback = copy_request_callbacks_[request_id];
1637  callback.Run(!bitmap.empty() && !bitmap.isNull(), bitmap);
1638  copy_request_callbacks_.erase(request_id);
1639}
1640
1641void BrowserPluginGuest::OnUpdateGeometry(int instance_id,
1642                                          const gfx::Rect& view_rect) {
1643  // The plugin has moved within the embedder without resizing or the
1644  // embedder/container's view rect changing.
1645  guest_window_rect_ = view_rect;
1646  RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1647      GetWebContents()->GetRenderViewHost());
1648  if (rvh)
1649    rvh->SendScreenRects();
1650}
1651
1652void BrowserPluginGuest::OnHasTouchEventHandlers(bool accept) {
1653  SendMessageToEmbedder(
1654      new BrowserPluginMsg_ShouldAcceptTouchEvents(instance_id(), accept));
1655}
1656
1657void BrowserPluginGuest::OnSetCursor(const WebCursor& cursor) {
1658  SendMessageToEmbedder(new BrowserPluginMsg_SetCursor(instance_id(), cursor));
1659}
1660
1661#if defined(OS_MACOSX)
1662void BrowserPluginGuest::OnShowPopup(
1663    const ViewHostMsg_ShowPopup_Params& params) {
1664  gfx::Rect translated_bounds(params.bounds);
1665  translated_bounds.Offset(guest_window_rect_.OffsetFromOrigin());
1666  BrowserPluginPopupMenuHelper popup_menu_helper(
1667      embedder_web_contents_->GetRenderViewHost(),
1668      GetWebContents()->GetRenderViewHost());
1669  popup_menu_helper.ShowPopupMenu(translated_bounds,
1670                                  params.item_height,
1671                                  params.item_font_size,
1672                                  params.selected_item,
1673                                  params.popup_items,
1674                                  params.right_aligned,
1675                                  params.allow_multiple_selection);
1676}
1677#endif
1678
1679void BrowserPluginGuest::OnShowWidget(int route_id,
1680                                      const gfx::Rect& initial_pos) {
1681  GetWebContents()->ShowCreatedWidget(route_id, initial_pos);
1682}
1683
1684void BrowserPluginGuest::OnTakeFocus(bool reverse) {
1685  SendMessageToEmbedder(
1686      new BrowserPluginMsg_AdvanceFocus(instance_id(), reverse));
1687}
1688
1689void BrowserPluginGuest::OnUpdateFrameName(int frame_id,
1690                                           bool is_top_level,
1691                                           const std::string& name) {
1692  if (!is_top_level)
1693    return;
1694
1695  name_ = name;
1696  SendMessageToEmbedder(new BrowserPluginMsg_UpdatedName(instance_id_, name));
1697}
1698
1699void BrowserPluginGuest::RequestMediaAccessPermission(
1700    WebContents* web_contents,
1701    const MediaStreamRequest& request,
1702    const MediaResponseCallback& callback) {
1703  base::DictionaryValue request_info;
1704  request_info.Set(
1705      browser_plugin::kURL,
1706      base::Value::CreateStringValue(request.security_origin.spec()));
1707
1708  RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_MEDIA,
1709                    new MediaRequest(request, callback, this),
1710                    request_info);
1711}
1712
1713void BrowserPluginGuest::RunJavaScriptDialog(
1714    WebContents* web_contents,
1715    const GURL& origin_url,
1716    const std::string& accept_lang,
1717    JavaScriptMessageType javascript_message_type,
1718    const base::string16& message_text,
1719    const base::string16& default_prompt_text,
1720    const DialogClosedCallback& callback,
1721    bool* did_suppress_message) {
1722  base::DictionaryValue request_info;
1723  request_info.Set(
1724      browser_plugin::kDefaultPromptText,
1725      base::Value::CreateStringValue(UTF16ToUTF8(default_prompt_text)));
1726  request_info.Set(
1727      browser_plugin::kMessageText,
1728      base::Value::CreateStringValue(UTF16ToUTF8(message_text)));
1729  request_info.Set(
1730      browser_plugin::kMessageType,
1731      base::Value::CreateStringValue(
1732          JavaScriptMessageTypeToString(javascript_message_type)));
1733  request_info.Set(
1734      browser_plugin::kURL,
1735      base::Value::CreateStringValue(origin_url.spec()));
1736
1737  RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_JAVASCRIPT_DIALOG,
1738                    new JavaScriptDialogRequest(callback),
1739                    request_info);
1740}
1741
1742void BrowserPluginGuest::RunBeforeUnloadDialog(
1743    WebContents* web_contents,
1744    const base::string16& message_text,
1745    bool is_reload,
1746    const DialogClosedCallback& callback) {
1747  // This is called if the guest has a beforeunload event handler.
1748  // This callback allows navigation to proceed.
1749  callback.Run(true, base::string16());
1750}
1751
1752bool BrowserPluginGuest::HandleJavaScriptDialog(
1753    WebContents* web_contents,
1754    bool accept,
1755    const base::string16* prompt_override) {
1756  return false;
1757}
1758
1759void BrowserPluginGuest::CancelActiveAndPendingDialogs(
1760    WebContents* web_contents) {
1761}
1762
1763void BrowserPluginGuest::WebContentsDestroyed(WebContents* web_contents) {
1764}
1765
1766void BrowserPluginGuest::OnUpdateRect(
1767    const ViewHostMsg_UpdateRect_Params& params) {
1768  BrowserPluginMsg_UpdateRect_Params relay_params;
1769  relay_params.view_size = params.view_size;
1770  relay_params.scale_factor = params.scale_factor;
1771  relay_params.is_resize_ack = ViewHostMsg_UpdateRect_Flags::is_resize_ack(
1772      params.flags);
1773  relay_params.needs_ack = params.needs_ack;
1774
1775  bool size_changed = last_seen_view_size_ != params.view_size;
1776  gfx::Size old_size = last_seen_view_size_;
1777  last_seen_view_size_ = params.view_size;
1778
1779  if ((auto_size_enabled_ || last_seen_auto_size_enabled_) &&
1780      size_changed && delegate_) {
1781    delegate_->SizeChanged(old_size, last_seen_view_size_);
1782  }
1783  last_seen_auto_size_enabled_ = auto_size_enabled_;
1784
1785  // HW accelerated case, acknowledge resize only
1786  if (!params.needs_ack || !damage_buffer_) {
1787    relay_params.damage_buffer_sequence_id = 0;
1788    SendMessageToEmbedder(
1789        new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1790    return;
1791  }
1792
1793  // Only copy damage if the guest is in autosize mode and the guest's view size
1794  // is less than the maximum size or the guest's view size is equal to the
1795  // damage buffer's size and the guest's scale factor is equal to the damage
1796  // buffer's scale factor.
1797  // The scaling change can happen due to asynchronous updates of the DPI on a
1798  // resolution change.
1799  if (((auto_size_enabled_ && InAutoSizeBounds(params.view_size)) ||
1800      (params.view_size == damage_view_size())) &&
1801       params.scale_factor == damage_buffer_scale_factor()) {
1802    TransportDIB* dib = GetWebContents()->GetRenderProcessHost()->
1803        GetTransportDIB(params.bitmap);
1804    if (dib) {
1805      size_t guest_damage_buffer_size =
1806#if defined(OS_WIN)
1807          params.bitmap_rect.width() *
1808          params.bitmap_rect.height() * 4;
1809#else
1810          dib->size();
1811#endif
1812      size_t embedder_damage_buffer_size = damage_buffer_size_;
1813      void* guest_memory = dib->memory();
1814      void* embedder_memory = damage_buffer_->memory();
1815      size_t size = std::min(guest_damage_buffer_size,
1816                             embedder_damage_buffer_size);
1817      memcpy(embedder_memory, guest_memory, size);
1818    }
1819  }
1820  relay_params.damage_buffer_sequence_id = damage_buffer_sequence_id_;
1821  relay_params.bitmap_rect = params.bitmap_rect;
1822  relay_params.scroll_delta = params.scroll_delta;
1823  relay_params.scroll_rect = params.scroll_rect;
1824  relay_params.copy_rects = params.copy_rects;
1825
1826  SendMessageToEmbedder(
1827      new BrowserPluginMsg_UpdateRect(instance_id(), relay_params));
1828}
1829
1830void BrowserPluginGuest::OnTextInputTypeChanged(ui::TextInputType type,
1831                                                ui::TextInputMode input_mode,
1832                                                bool can_compose_inline) {
1833  RenderWidgetHostViewPort::FromRWHV(
1834      web_contents()->GetRenderWidgetHostView())->TextInputTypeChanged(
1835          type, input_mode, can_compose_inline);
1836}
1837
1838void BrowserPluginGuest::OnImeCancelComposition() {
1839  RenderWidgetHostViewPort::FromRWHV(
1840      web_contents()->GetRenderWidgetHostView())->ImeCancelComposition();
1841}
1842
1843#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA)
1844void BrowserPluginGuest::OnImeCompositionRangeChanged(
1845      const gfx::Range& range,
1846      const std::vector<gfx::Rect>& character_bounds) {
1847  RenderWidgetHostViewPort::FromRWHV(
1848      web_contents()->GetRenderWidgetHostView())->ImeCompositionRangeChanged(
1849          range, character_bounds);
1850}
1851#endif
1852
1853void BrowserPluginGuest::DidRetrieveDownloadURLFromRequestId(
1854    const std::string& request_method,
1855    const base::Callback<void(bool)>& callback,
1856    const std::string& url) {
1857  if (url.empty()) {
1858    callback.Run(false);
1859    return;
1860  }
1861
1862  base::DictionaryValue request_info;
1863  request_info.Set(browser_plugin::kRequestMethod,
1864                   base::Value::CreateStringValue(request_method));
1865  request_info.Set(browser_plugin::kURL, base::Value::CreateStringValue(url));
1866
1867  RequestPermission(BROWSER_PLUGIN_PERMISSION_TYPE_DOWNLOAD,
1868                    new DownloadRequest(callback),
1869                    request_info);
1870}
1871
1872}  // namespace content
1873