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