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