• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/extensions/extension_host.h"
6 
7 #include <list>
8 
9 #include "base/memory/singleton.h"
10 #include "base/message_loop.h"
11 #include "base/metrics/histogram.h"
12 #include "base/string_util.h"
13 #include "chrome/browser/browser_shutdown.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_tabs_module.h"
16 #include "chrome/browser/file_select_helper.h"
17 #include "chrome/browser/platform_util.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/renderer_preferences_util.h"
20 #include "chrome/browser/tab_contents/popup_menu_helper_mac.h"
21 #include "chrome/browser/ui/app_modal_dialogs/message_box_handler.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_list.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
26 #include "chrome/common/chrome_constants.h"
27 #include "chrome/common/extensions/extension.h"
28 #include "chrome/common/extensions/extension_constants.h"
29 #include "chrome/common/render_messages.h"
30 #include "chrome/common/url_constants.h"
31 #include "chrome/common/view_types.h"
32 #include "content/browser/browsing_instance.h"
33 #include "content/browser/renderer_host/browser_render_process_host.h"
34 #include "content/browser/renderer_host/render_process_host.h"
35 #include "content/browser/renderer_host/render_view_host.h"
36 #include "content/browser/renderer_host/render_widget_host.h"
37 #include "content/browser/renderer_host/render_widget_host_view.h"
38 #include "content/browser/site_instance.h"
39 #include "content/browser/tab_contents/tab_contents.h"
40 #include "content/browser/tab_contents/tab_contents_view.h"
41 #include "content/common/bindings_policy.h"
42 #include "content/common/native_web_keyboard_event.h"
43 #include "content/common/notification_service.h"
44 #include "content/common/view_messages.h"
45 #include "grit/browser_resources.h"
46 #include "grit/generated_resources.h"
47 #include "ui/base/keycodes/keyboard_codes.h"
48 #include "ui/base/l10n/l10n_util.h"
49 #include "ui/base/resource/resource_bundle.h"
50 #include "webkit/glue/context_menu.h"
51 
52 #if defined(TOOLKIT_VIEWS)
53 #include "views/widget/widget.h"
54 #endif
55 
56 using WebKit::WebDragOperation;
57 using WebKit::WebDragOperationsMask;
58 
59 // static
60 bool ExtensionHost::enable_dom_automation_ = false;
61 
62 // Helper class that rate-limits the creation of renderer processes for
63 // ExtensionHosts, to avoid blocking the UI.
64 class ExtensionHost::ProcessCreationQueue {
65  public:
GetInstance()66   static ProcessCreationQueue* GetInstance() {
67     return Singleton<ProcessCreationQueue>::get();
68   }
69 
70   // Add a host to the queue for RenderView creation.
CreateSoon(ExtensionHost * host)71   void CreateSoon(ExtensionHost* host) {
72     queue_.push_back(host);
73     PostTask();
74   }
75 
76   // Remove a host from the queue (in case it's being deleted).
Remove(ExtensionHost * host)77   void Remove(ExtensionHost* host) {
78     Queue::iterator it = std::find(queue_.begin(), queue_.end(), host);
79     if (it != queue_.end())
80       queue_.erase(it);
81   }
82 
83  private:
84   friend class Singleton<ProcessCreationQueue>;
85   friend struct DefaultSingletonTraits<ProcessCreationQueue>;
ProcessCreationQueue()86   ProcessCreationQueue()
87       : pending_create_(false),
88         ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { }
89 
90   // Queue up a delayed task to process the next ExtensionHost in the queue.
PostTask()91   void PostTask() {
92     if (!pending_create_) {
93       MessageLoop::current()->PostTask(FROM_HERE,
94           method_factory_.NewRunnableMethod(
95              &ProcessCreationQueue::ProcessOneHost));
96       pending_create_ = true;
97     }
98   }
99 
100   // Create the RenderView for the next host in the queue.
ProcessOneHost()101   void ProcessOneHost() {
102     pending_create_ = false;
103     if (queue_.empty())
104       return;  // can happen on shutdown
105 
106     queue_.front()->CreateRenderViewNow();
107     queue_.pop_front();
108 
109     if (!queue_.empty())
110       PostTask();
111   }
112 
113   typedef std::list<ExtensionHost*> Queue;
114   Queue queue_;
115   bool pending_create_;
116   ScopedRunnableMethodFactory<ProcessCreationQueue> method_factory_;
117 };
118 
119 ////////////////
120 // ExtensionHost
121 
ExtensionHost(const Extension * extension,SiteInstance * site_instance,const GURL & url,ViewType::Type host_type)122 ExtensionHost::ExtensionHost(const Extension* extension,
123                              SiteInstance* site_instance,
124                              const GURL& url,
125                              ViewType::Type host_type)
126     : extension_(extension),
127       extension_id_(extension->id()),
128       profile_(site_instance->browsing_instance()->profile()),
129       did_stop_loading_(false),
130       document_element_available_(false),
131       url_(url),
132       extension_host_type_(host_type),
133       associated_tab_contents_(NULL),
134       suppress_javascript_messages_(false) {
135   render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE,
136                                          NULL);
137   render_view_host_->set_is_extension_process(true);
138   if (extension->is_app()) {
139     BrowserRenderProcessHost* process = static_cast<BrowserRenderProcessHost*>(
140         render_view_host_->process());
141     process->set_installed_app(extension);
142   }
143   render_view_host_->AllowBindings(BindingsPolicy::EXTENSION);
144   if (enable_dom_automation_)
145     render_view_host_->AllowBindings(BindingsPolicy::DOM_AUTOMATION);
146 
147   // Listen for when the render process' handle is available so we can add it
148   // to the task manager then.
149   registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED,
150                  Source<RenderProcessHost>(render_process_host()));
151   // Listen for when an extension is unloaded from the same profile, as it may
152   // be the same extension that this points to.
153   registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
154                  Source<Profile>(profile_));
155 }
156 
~ExtensionHost()157 ExtensionHost::~ExtensionHost() {
158   NotificationService::current()->Notify(
159       NotificationType::EXTENSION_HOST_DESTROYED,
160       Source<Profile>(profile_),
161       Details<ExtensionHost>(this));
162   ProcessCreationQueue::GetInstance()->Remove(this);
163   render_view_host_->Shutdown();  // deletes render_view_host
164 }
165 
CreateView(Browser * browser)166 void ExtensionHost::CreateView(Browser* browser) {
167 #if defined(TOOLKIT_VIEWS)
168   view_.reset(new ExtensionView(this, browser));
169   // We own |view_|, so don't auto delete when it's removed from the view
170   // hierarchy.
171   view_->set_parent_owned(false);
172 #elif defined(OS_MACOSX)
173   view_.reset(new ExtensionViewMac(this, browser));
174   view_->Init();
175 #elif defined(TOOLKIT_USES_GTK)
176   view_.reset(new ExtensionViewGtk(this, browser));
177   view_->Init();
178 #else
179   // TODO(port)
180   NOTREACHED();
181 #endif
182 }
183 
associated_tab_contents() const184 TabContents* ExtensionHost::associated_tab_contents() const {
185   return associated_tab_contents_;
186 }
187 
render_process_host() const188 RenderProcessHost* ExtensionHost::render_process_host() const {
189   return render_view_host_->process();
190 }
191 
site_instance() const192 SiteInstance* ExtensionHost::site_instance() const {
193   return render_view_host_->site_instance();
194 }
195 
IsRenderViewLive() const196 bool ExtensionHost::IsRenderViewLive() const {
197   return render_view_host_->IsRenderViewLive();
198 }
199 
CreateRenderViewSoon(RenderWidgetHostView * host_view)200 void ExtensionHost::CreateRenderViewSoon(RenderWidgetHostView* host_view) {
201   render_view_host_->set_view(host_view);
202   if (render_view_host_->process()->HasConnection()) {
203     // If the process is already started, go ahead and initialize the RenderView
204     // synchronously. The process creation is the real meaty part that we want
205     // to defer.
206     CreateRenderViewNow();
207   } else {
208     ProcessCreationQueue::GetInstance()->CreateSoon(this);
209   }
210 }
211 
CreateRenderViewNow()212 void ExtensionHost::CreateRenderViewNow() {
213   render_view_host_->CreateRenderView(string16());
214   NavigateToURL(url_);
215   DCHECK(IsRenderViewLive());
216   if (is_background_page())
217     profile_->GetExtensionService()->DidCreateRenderViewForBackgroundPage(
218         this);
219 }
220 
GetBrowser() const221 const Browser* ExtensionHost::GetBrowser() const {
222   return view() ? view()->browser() : NULL;
223 }
224 
GetBrowser()225 Browser* ExtensionHost::GetBrowser() {
226   return view() ? view()->browser() : NULL;
227 }
228 
GetNativeViewOfHost()229 gfx::NativeView ExtensionHost::GetNativeViewOfHost() {
230   return view() ? view()->native_view() : NULL;
231 }
232 
NavigateToURL(const GURL & url)233 void ExtensionHost::NavigateToURL(const GURL& url) {
234   // Prevent explicit navigation to another extension id's pages.
235   // This method is only called by some APIs, so we still need to protect
236   // DidNavigate below (location = "").
237   if (url.SchemeIs(chrome::kExtensionScheme) && url.host() != extension_id()) {
238     // TODO(erikkay) communicate this back to the caller?
239     return;
240   }
241 
242   url_ = url;
243 
244   if (!is_background_page() &&
245       !profile_->GetExtensionService()->IsBackgroundPageReady(extension_)) {
246     // Make sure the background page loads before any others.
247     registrar_.Add(this, NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
248                    Source<Extension>(extension_));
249     return;
250   }
251 
252   render_view_host_->NavigateToURL(url_);
253 }
254 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)255 void ExtensionHost::Observe(NotificationType type,
256                             const NotificationSource& source,
257                             const NotificationDetails& details) {
258   switch (type.value) {
259     case NotificationType::EXTENSION_BACKGROUND_PAGE_READY:
260       DCHECK(profile_->GetExtensionService()->
261           IsBackgroundPageReady(extension_));
262       NavigateToURL(url_);
263       break;
264     case NotificationType::RENDERER_PROCESS_CREATED:
265       NotificationService::current()->Notify(
266           NotificationType::EXTENSION_PROCESS_CREATED,
267           Source<Profile>(profile_),
268           Details<ExtensionHost>(this));
269       break;
270     case NotificationType::EXTENSION_UNLOADED:
271       // The extension object will be deleted after this notification has been
272       // sent. NULL it out so that dirty pointer issues don't arise in cases
273       // when multiple ExtensionHost objects pointing to the same Extension are
274       // present.
275       if (extension_ == Details<UnloadedExtensionInfo>(details)->extension)
276         extension_ = NULL;
277       break;
278     default:
279       NOTREACHED() << "Unexpected notification sent.";
280       break;
281   }
282 }
283 
UpdatePreferredSize(const gfx::Size & new_size)284 void ExtensionHost::UpdatePreferredSize(const gfx::Size& new_size) {
285   if (view_.get())
286     view_->UpdatePreferredSize(new_size);
287 }
288 
UpdateInspectorSetting(const std::string & key,const std::string & value)289 void ExtensionHost::UpdateInspectorSetting(const std::string& key,
290                                          const std::string& value) {
291   RenderViewHostDelegateHelper::UpdateInspectorSetting(profile(), key, value);
292 }
293 
ClearInspectorSettings()294 void ExtensionHost::ClearInspectorSettings() {
295   RenderViewHostDelegateHelper::ClearInspectorSettings(profile());
296 }
297 
RenderViewGone(RenderViewHost * render_view_host,base::TerminationStatus status,int error_code)298 void ExtensionHost::RenderViewGone(RenderViewHost* render_view_host,
299                                    base::TerminationStatus status,
300                                    int error_code) {
301   // During browser shutdown, we may use sudden termination on an extension
302   // process, so it is expected to lose our connection to the render view.
303   // Do nothing.
304   if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
305     return;
306 
307   // In certain cases, multiple ExtensionHost objects may have pointed to
308   // the same Extension at some point (one with a background page and a
309   // popup, for example). When the first ExtensionHost goes away, the extension
310   // is unloaded, and any other host that pointed to that extension will have
311   // its pointer to it NULLed out so that any attempt to unload a dirty pointer
312   // will be averted.
313   if (!extension_)
314     return;
315 
316   DCHECK_EQ(render_view_host_, render_view_host);
317   NotificationService::current()->Notify(
318       NotificationType::EXTENSION_PROCESS_TERMINATED,
319       Source<Profile>(profile_),
320       Details<ExtensionHost>(this));
321 }
322 
DidNavigate(RenderViewHost * render_view_host,const ViewHostMsg_FrameNavigate_Params & params)323 void ExtensionHost::DidNavigate(RenderViewHost* render_view_host,
324     const ViewHostMsg_FrameNavigate_Params& params) {
325   // We only care when the outer frame changes.
326   if (!PageTransition::IsMainFrame(params.transition))
327     return;
328 
329   if (!params.url.SchemeIs(chrome::kExtensionScheme)) {
330     extension_function_dispatcher_.reset(NULL);
331     url_ = params.url;
332     return;
333   }
334 
335   // This catches two bogus use cases:
336   // (1) URLs that look like chrome-extension://somethingbogus or
337   //     chrome-extension://nosuchid/, in other words, no Extension would
338   //     be found.
339   // (2) URLs that refer to a different extension than this one.
340   // In both cases, we preserve the old URL and reset the EFD to NULL.  This
341   // will leave the host in kind of a bad state with poor UI and errors, but
342   // it's better than the alternative.
343   // TODO(erikkay) Perhaps we should display errors in developer mode.
344   if (params.url.host() != extension_id()) {
345     extension_function_dispatcher_.reset(NULL);
346     return;
347   }
348 
349   url_ = params.url;
350   extension_function_dispatcher_.reset(
351       ExtensionFunctionDispatcher::Create(render_view_host_, this, url_));
352 }
353 
InsertInfobarCSS()354 void ExtensionHost::InsertInfobarCSS() {
355   DCHECK(!is_background_page());
356 
357   static const base::StringPiece css(
358       ResourceBundle::GetSharedInstance().GetRawDataResource(
359       IDR_EXTENSIONS_INFOBAR_CSS));
360 
361   render_view_host()->InsertCSSInWebFrame(
362       L"", css.as_string(), "InfobarThemeCSS");
363 }
364 
DisableScrollbarsForSmallWindows(const gfx::Size & size_limit)365 void ExtensionHost::DisableScrollbarsForSmallWindows(
366     const gfx::Size& size_limit) {
367   render_view_host()->Send(new ViewMsg_DisableScrollbarsForSmallWindows(
368       render_view_host()->routing_id(), size_limit));
369 }
370 
DidStopLoading()371 void ExtensionHost::DidStopLoading() {
372   bool notify = !did_stop_loading_;
373   did_stop_loading_ = true;
374   if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
375       extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
376 #if defined(TOOLKIT_VIEWS)
377     if (view_.get())
378       view_->DidStopLoading();
379 #endif
380   }
381   if (notify) {
382     NotificationService::current()->Notify(
383         NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
384         Source<Profile>(profile_),
385         Details<ExtensionHost>(this));
386     if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) {
387       UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime",
388                           since_created_.Elapsed());
389     } else if (extension_host_type_ == ViewType::EXTENSION_POPUP) {
390       UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime",
391                           since_created_.Elapsed());
392     } else if (extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
393       UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime",
394         since_created_.Elapsed());
395     }
396   }
397 }
398 
DocumentAvailableInMainFrame(RenderViewHost * rvh)399 void ExtensionHost::DocumentAvailableInMainFrame(RenderViewHost* rvh) {
400   // If the document has already been marked as available for this host, then
401   // bail. No need for the redundant setup. http://crbug.com/31170
402   if (document_element_available_)
403     return;
404 
405   document_element_available_ = true;
406   if (is_background_page()) {
407     profile_->GetExtensionService()->SetBackgroundPageReady(extension_);
408   } else {
409     switch (extension_host_type_) {
410       case ViewType::EXTENSION_INFOBAR:
411         InsertInfobarCSS();
412         break;
413       default:
414         break;  // No style sheet for other types, at the moment.
415     }
416   }
417 }
418 
DocumentOnLoadCompletedInMainFrame(RenderViewHost * rvh,int32 page_id)419 void ExtensionHost::DocumentOnLoadCompletedInMainFrame(RenderViewHost* rvh,
420                                                        int32 page_id) {
421   if (ViewType::EXTENSION_POPUP == GetRenderViewType()) {
422     NotificationService::current()->Notify(
423         NotificationType::EXTENSION_POPUP_VIEW_READY,
424         Source<Profile>(profile_),
425         Details<ExtensionHost>(this));
426   }
427 }
428 
RunJavaScriptMessage(const std::wstring & message,const std::wstring & default_prompt,const GURL & frame_url,const int flags,IPC::Message * reply_msg,bool * did_suppress_message)429 void ExtensionHost::RunJavaScriptMessage(const std::wstring& message,
430                                          const std::wstring& default_prompt,
431                                          const GURL& frame_url,
432                                          const int flags,
433                                          IPC::Message* reply_msg,
434                                          bool* did_suppress_message) {
435   base::TimeDelta time_since_last_message(
436       base::TimeTicks::Now() - last_javascript_message_dismissal_);
437 
438   *did_suppress_message = suppress_javascript_messages_;
439   if (!suppress_javascript_messages_) {
440     bool show_suppress_checkbox = false;
441     // Show a checkbox offering to suppress further messages if this message is
442     // being displayed within kJavascriptMessageExpectedDelay of the last one.
443     if (time_since_last_message <
444         base::TimeDelta::FromMilliseconds(
445             chrome::kJavascriptMessageExpectedDelay))
446       show_suppress_checkbox = true;
447 
448     // Unlike for page alerts, navigations aren't a good signal for when to
449     // resume showing alerts, so we can't reasonably stop showing them even if
450     // the extension is spammy.
451     RunJavascriptMessageBox(profile_, this, frame_url, flags, message,
452                             default_prompt, show_suppress_checkbox, reply_msg);
453   } else {
454     // If we are suppressing messages, just reply as is if the user immediately
455     // pressed "Cancel".
456     OnMessageBoxClosed(reply_msg, false, std::wstring());
457   }
458 }
459 
GetMessageBoxRootWindow()460 gfx::NativeWindow ExtensionHost::GetMessageBoxRootWindow() {
461   // If we have a view, use that.
462   gfx::NativeView native_view = GetNativeViewOfHost();
463   if (native_view)
464     return platform_util::GetTopLevel(native_view);
465 
466   // Otherwise, try the active tab's view.
467   Browser* browser = extension_function_dispatcher_->GetCurrentBrowser(true);
468   if (browser) {
469     TabContents* active_tab = browser->GetSelectedTabContents();
470     if (active_tab)
471       return active_tab->view()->GetTopLevelNativeWindow();
472   }
473 
474   return NULL;
475 }
476 
AsTabContents()477 TabContents* ExtensionHost::AsTabContents() {
478   return NULL;
479 }
480 
AsExtensionHost()481 ExtensionHost* ExtensionHost::AsExtensionHost() {
482   return this;
483 }
484 
OnMessageBoxClosed(IPC::Message * reply_msg,bool success,const std::wstring & prompt)485 void ExtensionHost::OnMessageBoxClosed(IPC::Message* reply_msg,
486                                        bool success,
487                                        const std::wstring& prompt) {
488   last_javascript_message_dismissal_ = base::TimeTicks::Now();
489   render_view_host()->JavaScriptMessageBoxClosed(reply_msg, success, prompt);
490 }
491 
SetSuppressMessageBoxes(bool suppress_message_boxes)492 void ExtensionHost::SetSuppressMessageBoxes(bool suppress_message_boxes) {
493   suppress_javascript_messages_ = suppress_message_boxes;
494 }
495 
Close(RenderViewHost * render_view_host)496 void ExtensionHost::Close(RenderViewHost* render_view_host) {
497   if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
498       extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
499     NotificationService::current()->Notify(
500         NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
501         Source<Profile>(profile_),
502         Details<ExtensionHost>(this));
503   }
504 }
505 
GetRendererPrefs(Profile * profile) const506 RendererPreferences ExtensionHost::GetRendererPrefs(Profile* profile) const {
507   RendererPreferences preferences;
508 
509   TabContents* associated_contents = associated_tab_contents();
510   if (associated_contents)
511     preferences =
512         static_cast<RenderViewHostDelegate*>(associated_contents)->
513             GetRendererPrefs(profile);
514 
515   renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile);
516   return preferences;
517 }
518 
GetWebkitPrefs()519 WebPreferences ExtensionHost::GetWebkitPrefs() {
520   Profile* profile = render_view_host()->process()->profile();
521   WebPreferences webkit_prefs =
522       RenderViewHostDelegateHelper::GetWebkitPrefs(profile,
523                                                    false);  // is_web_ui
524   // Extensions are trusted so we override any user preferences for disabling
525   // javascript or images.
526   webkit_prefs.loads_images_automatically = true;
527   webkit_prefs.javascript_enabled = true;
528 
529   if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
530       extension_host_type_ == ViewType::EXTENSION_INFOBAR)
531     webkit_prefs.allow_scripts_to_close_windows = true;
532 
533   // Disable anything that requires the GPU process for background pages.
534   // See http://crbug.com/64512 and http://crbug.com/64841.
535   if (extension_host_type_ == ViewType::EXTENSION_BACKGROUND_PAGE) {
536     webkit_prefs.experimental_webgl_enabled = false;
537     webkit_prefs.accelerated_compositing_enabled = false;
538     webkit_prefs.accelerated_2d_canvas_enabled = false;
539   }
540 
541   // TODO(dcheng): incorporate this setting into kClipboardPermission check.
542   webkit_prefs.javascript_can_access_clipboard = true;
543 
544   // TODO(dcheng): check kClipboardPermission instead once it's implemented.
545   if (extension_->HasApiPermission(Extension::kExperimentalPermission))
546     webkit_prefs.dom_paste_enabled = true;
547   return webkit_prefs;
548 }
549 
ProcessWebUIMessage(const ExtensionHostMsg_DomMessage_Params & params)550 void ExtensionHost::ProcessWebUIMessage(
551     const ExtensionHostMsg_DomMessage_Params& params) {
552   if (extension_function_dispatcher_.get()) {
553     extension_function_dispatcher_->HandleRequest(params);
554   }
555 }
556 
GetViewDelegate()557 RenderViewHostDelegate::View* ExtensionHost::GetViewDelegate() {
558   return this;
559 }
560 
CreateNewWindow(int route_id,const ViewHostMsg_CreateWindow_Params & params)561 void ExtensionHost::CreateNewWindow(
562     int route_id,
563     const ViewHostMsg_CreateWindow_Params& params) {
564   // TODO(aa): Use the browser's profile if the extension is split mode
565   // incognito.
566   TabContents* new_contents = delegate_view_helper_.CreateNewWindow(
567       route_id,
568       render_view_host()->process()->profile(),
569       site_instance(),
570       ChromeWebUIFactory::GetInstance()->GetWebUIType(
571           render_view_host()->process()->profile(), url_),
572       this,
573       params.window_container_type,
574       params.frame_name);
575 
576   TabContents* associated_contents = associated_tab_contents();
577   if (associated_contents && associated_contents->delegate())
578     associated_contents->delegate()->TabContentsCreated(new_contents);
579 }
580 
CreateNewWidget(int route_id,WebKit::WebPopupType popup_type)581 void ExtensionHost::CreateNewWidget(int route_id,
582                                     WebKit::WebPopupType popup_type) {
583   CreateNewWidgetInternal(route_id, popup_type);
584 }
585 
CreateNewFullscreenWidget(int route_id)586 void ExtensionHost::CreateNewFullscreenWidget(int route_id) {
587   NOTREACHED()
588       << "ExtensionHost does not support showing full screen popups yet.";
589 }
590 
CreateNewWidgetInternal(int route_id,WebKit::WebPopupType popup_type)591 RenderWidgetHostView* ExtensionHost::CreateNewWidgetInternal(
592     int route_id, WebKit::WebPopupType popup_type) {
593   return delegate_view_helper_.CreateNewWidget(route_id, popup_type,
594                                                site_instance()->GetProcess());
595 }
596 
ShowCreatedWindow(int route_id,WindowOpenDisposition disposition,const gfx::Rect & initial_pos,bool user_gesture)597 void ExtensionHost::ShowCreatedWindow(int route_id,
598                                       WindowOpenDisposition disposition,
599                                       const gfx::Rect& initial_pos,
600                                       bool user_gesture) {
601   TabContents* contents = delegate_view_helper_.GetCreatedWindow(route_id);
602   if (!contents)
603     return;
604 
605   if (disposition == NEW_POPUP) {
606     // Create a new Browser window of type TYPE_APP_POPUP.
607     // (AddTabContents would otherwise create a window of type TYPE_POPUP).
608     Browser* browser = Browser::CreateForPopup(Browser::TYPE_APP_POPUP,
609                                                contents->profile(),
610                                                contents,
611                                                initial_pos);
612     if (user_gesture)
613       browser->window()->Show();
614     else
615       browser->window()->ShowInactive();
616     return;
617   }
618 
619   // If the tab contents isn't a popup, it's a normal tab. We need to find a
620   // home for it. This is typically a Browser, but it can also be some other
621   // TabContentsDelegate in the case of ChromeFrame.
622 
623   // First, if the creating extension view was associated with a tab contents,
624   // use that tab content's delegate. We must be careful here that the
625   // associated tab contents has the same profile as the new tab contents. In
626   // the case of extensions in 'spanning' incognito mode, they can mismatch.
627   // We don't want to end up putting a normal tab into an incognito window, or
628   // vice versa.
629   TabContents* associated_contents = associated_tab_contents();
630   if (associated_contents &&
631       associated_contents->profile() == contents->profile()) {
632     associated_contents->AddOrBlockNewContents(
633         contents, disposition, initial_pos, user_gesture);
634     return;
635   }
636 
637   // If there's no associated tab contents, or it doesn't have a matching
638   // profile, try finding an open window. Again, we must make sure to find a
639   // window with the correct profile.
640   Browser* browser = BrowserList::FindBrowserWithType(
641         contents->profile(),
642         Browser::TYPE_NORMAL,
643         false);  // Match incognito exactly.
644 
645   // If there's no Browser open with the right profile, create a new one.
646   if (!browser) {
647     browser = Browser::Create(contents->profile());
648     browser->window()->Show();
649   }
650   browser->AddTabContents(contents, disposition, initial_pos, user_gesture);
651 }
652 
ShowCreatedWidget(int route_id,const gfx::Rect & initial_pos)653 void ExtensionHost::ShowCreatedWidget(int route_id,
654                                       const gfx::Rect& initial_pos) {
655   ShowCreatedWidgetInternal(delegate_view_helper_.GetCreatedWidget(route_id),
656                             initial_pos);
657 }
658 
ShowCreatedFullscreenWidget(int route_id)659 void ExtensionHost::ShowCreatedFullscreenWidget(int route_id) {
660   NOTREACHED()
661       << "ExtensionHost does not support showing full screen popups yet.";
662 }
663 
ShowCreatedWidgetInternal(RenderWidgetHostView * widget_host_view,const gfx::Rect & initial_pos)664 void ExtensionHost::ShowCreatedWidgetInternal(
665     RenderWidgetHostView* widget_host_view,
666     const gfx::Rect& initial_pos) {
667   Browser *browser = GetBrowser();
668   DCHECK(browser);
669   if (!browser)
670     return;
671   browser->BrowserRenderWidgetShowing();
672   // TODO(erikkay): These two lines could be refactored with TabContentsView.
673   widget_host_view->InitAsPopup(render_view_host()->view(), initial_pos);
674   widget_host_view->GetRenderWidgetHost()->Init();
675 }
676 
ShowContextMenu(const ContextMenuParams & params)677 void ExtensionHost::ShowContextMenu(const ContextMenuParams& params) {
678   // TODO(erikkay) Show a default context menu.
679 }
680 
ShowPopupMenu(const gfx::Rect & bounds,int item_height,double item_font_size,int selected_item,const std::vector<WebMenuItem> & items,bool right_aligned)681 void ExtensionHost::ShowPopupMenu(const gfx::Rect& bounds,
682                                   int item_height,
683                                   double item_font_size,
684                                   int selected_item,
685                                   const std::vector<WebMenuItem>& items,
686                                   bool right_aligned) {
687 #if defined(OS_MACOSX)
688   PopupMenuHelper popup_menu_helper(render_view_host());
689   popup_menu_helper.ShowPopupMenu(bounds, item_height, item_font_size,
690                                   selected_item, items, right_aligned);
691 #else
692   // Only on Mac are select popup menus external.
693   NOTREACHED();
694 #endif
695 }
696 
StartDragging(const WebDropData & drop_data,WebDragOperationsMask operation_mask,const SkBitmap & image,const gfx::Point & image_offset)697 void ExtensionHost::StartDragging(const WebDropData& drop_data,
698     WebDragOperationsMask operation_mask,
699     const SkBitmap& image,
700     const gfx::Point& image_offset) {
701   // We're not going to do any drag & drop, but we have to tell the renderer the
702   // drag & drop ended, othewise the renderer thinks the drag operation is
703   // underway and mouse events won't work.  See bug 34061.
704   // TODO(twiz) Implement drag & drop support for ExtensionHost instances.
705   // See feature issue 36288.
706   render_view_host()->DragSourceSystemDragEnded();
707 }
708 
UpdateDragCursor(WebDragOperation operation)709 void ExtensionHost::UpdateDragCursor(WebDragOperation operation) {
710 }
711 
GotFocus()712 void ExtensionHost::GotFocus() {
713 #if defined(TOOLKIT_VIEWS) && !defined(TOUCH_UI)
714   // Request focus so that the FocusManager has a focused view and can perform
715   // normally its key event processing (so that it lets tab key events go to the
716   // renderer).
717   view()->RequestFocus();
718 #else
719   // TODO(port)
720 #endif
721 }
722 
TakeFocus(bool reverse)723 void ExtensionHost::TakeFocus(bool reverse) {
724 }
725 
LostCapture()726 void ExtensionHost::LostCapture() {
727 }
728 
Activate()729 void ExtensionHost::Activate() {
730 }
731 
Deactivate()732 void ExtensionHost::Deactivate() {
733 }
734 
PreHandleKeyboardEvent(const NativeWebKeyboardEvent & event,bool * is_keyboard_shortcut)735 bool ExtensionHost::PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
736                                            bool* is_keyboard_shortcut) {
737   if (extension_host_type_ == ViewType::EXTENSION_POPUP &&
738       event.type == NativeWebKeyboardEvent::RawKeyDown &&
739       event.windowsKeyCode == ui::VKEY_ESCAPE) {
740     DCHECK(is_keyboard_shortcut != NULL);
741     *is_keyboard_shortcut = true;
742   }
743   return false;
744 }
745 
HandleKeyboardEvent(const NativeWebKeyboardEvent & event)746 void ExtensionHost::HandleKeyboardEvent(const NativeWebKeyboardEvent& event) {
747   if (extension_host_type_ == ViewType::EXTENSION_POPUP) {
748     if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
749         event.windowsKeyCode == ui::VKEY_ESCAPE) {
750       NotificationService::current()->Notify(
751           NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
752           Source<Profile>(profile_),
753           Details<ExtensionHost>(this));
754       return;
755     }
756   }
757   UnhandledKeyboardEvent(event);
758 }
759 
HandleMouseMove()760 void ExtensionHost::HandleMouseMove() {
761 #if defined(OS_WIN)
762   if (view_.get())
763     view_->HandleMouseMove();
764 #endif
765 }
766 
HandleMouseDown()767 void ExtensionHost::HandleMouseDown() {
768 }
769 
HandleMouseLeave()770 void ExtensionHost::HandleMouseLeave() {
771 #if defined(OS_WIN)
772   if (view_.get())
773     view_->HandleMouseLeave();
774 #endif
775 }
776 
HandleMouseUp()777 void ExtensionHost::HandleMouseUp() {
778 }
779 
HandleMouseActivate()780 void ExtensionHost::HandleMouseActivate() {
781 }
782 
GetRenderViewType() const783 ViewType::Type ExtensionHost::GetRenderViewType() const {
784   return extension_host_type_;
785 }
786 
OnMessageReceived(const IPC::Message & message)787 bool ExtensionHost::OnMessageReceived(const IPC::Message& message) {
788   bool handled = true;
789   IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message)
790     IPC_MESSAGE_HANDLER(ViewHostMsg_RunFileChooser, OnRunFileChooser)
791     IPC_MESSAGE_UNHANDLED(handled = false)
792   IPC_END_MESSAGE_MAP()
793   return handled;
794 }
795 
GetURL() const796 const GURL& ExtensionHost::GetURL() const {
797   return url_;
798 }
799 
RenderViewCreated(RenderViewHost * render_view_host)800 void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) {
801   if (view_.get())
802     view_->RenderViewCreated();
803 
804   // TODO(mpcomplete): This is duplicated in DidNavigate, which means that
805   // we'll create 2 EFDs for the first navigation. We should try to find a
806   // better way to unify them.
807   // See http://code.google.com/p/chromium/issues/detail?id=18240
808   extension_function_dispatcher_.reset(
809       ExtensionFunctionDispatcher::Create(render_view_host, this, url_));
810 
811   if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
812       extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
813     render_view_host->EnablePreferredSizeChangedMode(
814         kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow);
815   }
816 }
817 
GetBrowserWindowID() const818 int ExtensionHost::GetBrowserWindowID() const {
819   // Hosts not attached to any browser window have an id of -1.  This includes
820   // those mentioned below, and background pages.
821   int window_id = extension_misc::kUnknownWindowId;
822   if (extension_host_type_ == ViewType::EXTENSION_POPUP ||
823       extension_host_type_ == ViewType::EXTENSION_INFOBAR) {
824     // If the host is bound to a browser, then extract its window id.
825     // Extensions hosted in ExternalTabContainer objects may not have
826     // an associated browser.
827     const Browser* browser = GetBrowser();
828     if (browser)
829       window_id = ExtensionTabUtil::GetWindowId(browser);
830   } else if (extension_host_type_ != ViewType::EXTENSION_BACKGROUND_PAGE) {
831     NOTREACHED();
832   }
833   return window_id;
834 }
835 
OnRunFileChooser(const ViewHostMsg_RunFileChooser_Params & params)836 void ExtensionHost::OnRunFileChooser(
837     const ViewHostMsg_RunFileChooser_Params& params) {
838   if (file_select_helper_.get() == NULL)
839     file_select_helper_.reset(new FileSelectHelper(profile()));
840   file_select_helper_->RunFileChooser(render_view_host_,
841                                       associated_tab_contents(), params);
842 }
843