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