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