- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_host.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 "chrome/browser/extensions/extension_host.h"
6
7 #include <list>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/singleton.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/metrics/histogram.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/browser_shutdown.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/extensions/error_console/error_console.h"
20 #include "chrome/browser/extensions/event_router.h"
21 #include "chrome/browser/extensions/extension_process_manager.h"
22 #include "chrome/browser/extensions/extension_service.h"
23 #include "chrome/browser/extensions/extension_system.h"
24 #include "chrome/browser/extensions/extension_tab_util.h"
25 #include "chrome/browser/extensions/extension_web_contents_observer.h"
26 #include "chrome/browser/extensions/window_controller.h"
27 #include "chrome/browser/file_select_helper.h"
28 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
31 #include "chrome/browser/ui/browser.h"
32 #include "chrome/browser/ui/browser_dialogs.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/browser_list.h"
35 #include "chrome/browser/ui/browser_window.h"
36 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
37 #include "chrome/common/chrome_constants.h"
38 #include "chrome/common/extensions/background_info.h"
39 #include "chrome/common/extensions/extension.h"
40 #include "chrome/common/extensions/extension_constants.h"
41 #include "chrome/common/extensions/extension_messages.h"
42 #include "chrome/common/extensions/feature_switch.h"
43 #include "chrome/common/render_messages.h"
44 #include "chrome/common/url_constants.h"
45 #include "content/public/browser/content_browser_client.h"
46 #include "content/public/browser/native_web_keyboard_event.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/render_process_host.h"
49 #include "content/public/browser/render_view_host.h"
50 #include "content/public/browser/render_widget_host_view.h"
51 #include "content/public/browser/site_instance.h"
52 #include "content/public/browser/web_contents.h"
53 #include "content/public/browser/web_contents_view.h"
54 #include "extensions/browser/extension_error.h"
55 #include "extensions/browser/view_type_utils.h"
56 #include "extensions/common/extension_urls.h"
57 #include "grit/browser_resources.h"
58 #include "grit/chromium_strings.h"
59 #include "grit/generated_resources.h"
60 #include "ui/base/l10n/l10n_util.h"
61 #include "ui/base/resource/resource_bundle.h"
62 #include "ui/events/keycodes/keyboard_codes.h"
63
64 #if !defined(OS_ANDROID)
65 #include "components/web_modal/web_contents_modal_dialog_manager.h"
66 #endif
67
68 using WebKit::WebDragOperation;
69 using WebKit::WebDragOperationsMask;
70 using content::NativeWebKeyboardEvent;
71 using content::OpenURLParams;
72 using content::RenderViewHost;
73 using content::SiteInstance;
74 using content::WebContents;
75
76 namespace extensions {
77
78 // Helper class that rate-limits the creation of renderer processes for
79 // ExtensionHosts, to avoid blocking the UI.
80 class ExtensionHost::ProcessCreationQueue {
81  public:
82   static ProcessCreationQueue* GetInstance() {
83     return Singleton<ProcessCreationQueue>::get();
84   }
85
86   // Add a host to the queue for RenderView creation.
87   void CreateSoon(ExtensionHost* host) {
88     queue_.push_back(host);
89     PostTask();
90   }
91
92   // Remove a host from the queue (in case it's being deleted).
93   void Remove(ExtensionHost* host) {
94     Queue::iterator it = std::find(queue_.begin(), queue_.end(), host);
95     if (it != queue_.end())
96       queue_.erase(it);
97   }
98
99  private:
100   friend class Singleton<ProcessCreationQueue>;
101   friend struct DefaultSingletonTraits<ProcessCreationQueue>;
102   ProcessCreationQueue()
103       : pending_create_(false),
104         ptr_factory_(this) {}
105
106   // Queue up a delayed task to process the next ExtensionHost in the queue.
107   void PostTask() {
108     if (!pending_create_) {
109       base::MessageLoop::current()->PostTask(FROM_HERE,
110           base::Bind(&ProcessCreationQueue::ProcessOneHost,
111                      ptr_factory_.GetWeakPtr()));
112       pending_create_ = true;
113     }
114   }
115
116   // Create the RenderView for the next host in the queue.
117   void ProcessOneHost() {
118     pending_create_ = false;
119     if (queue_.empty())
120       return;  // can happen on shutdown
121
122     queue_.front()->CreateRenderViewNow();
123     queue_.pop_front();
124
125     if (!queue_.empty())
126       PostTask();
127   }
128
129   typedef std::list<ExtensionHost*> Queue;
130   Queue queue_;
131   bool pending_create_;
132   base::WeakPtrFactory<ProcessCreationQueue> ptr_factory_;
133 };
134
135 ////////////////
136 // ExtensionHost
137
138 ExtensionHost::ExtensionHost(const Extension* extension,
139                              SiteInstance* site_instance,
140                              const GURL& url,
141                              ViewType host_type)
142     : extension_(extension),
143       extension_id_(extension->id()),
144       profile_(Profile::FromBrowserContext(
145           site_instance->GetBrowserContext())),
146       render_view_host_(NULL),
147       did_stop_loading_(false),
148       document_element_available_(false),
149       initial_url_(url),
150       extension_function_dispatcher_(profile_, this),
151       extension_host_type_(host_type),
152       associated_web_contents_(NULL) {
153   host_contents_.reset(WebContents::Create(
154       WebContents::CreateParams(profile_, site_instance))),
155   content::WebContentsObserver::Observe(host_contents_.get());
156   host_contents_->SetDelegate(this);
157   SetViewType(host_contents_.get(), host_type);
158
159   ExtensionWebContentsObserver::CreateForWebContents(host_contents());
160   PrefsTabHelper::CreateForWebContents(host_contents());
161
162   render_view_host_ = host_contents_->GetRenderViewHost();
163
164   // Listen for when an extension is unloaded from the same profile, as it may
165   // be the same extension that this points to.
166   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
167                  content::Source<Profile>(profile_));
168 }
169
170 ExtensionHost::~ExtensionHost() {
171   if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE &&
172       extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_)) {
173     UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageActiveTime",
174                              since_created_.Elapsed());
175   }
176   content::NotificationService::current()->Notify(
177       chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
178       content::Source<Profile>(profile_),
179       content::Details<ExtensionHost>(this));
180   ProcessCreationQueue::GetInstance()->Remove(this);
181 }
182
183 void ExtensionHost::CreateView(Browser* browser) {
184 #if defined(TOOLKIT_VIEWS)
185   view_.reset(new ExtensionViewViews(this, browser));
186   // We own |view_|, so don't auto delete when it's removed from the view
187   // hierarchy.
188   view_->set_owned_by_client();
189 #elif defined(OS_MACOSX)
190   view_.reset(new ExtensionViewMac(this, browser));
191   view_->Init();
192 #elif defined(TOOLKIT_GTK)
193   view_.reset(new ExtensionViewGtk(this, browser));
194   view_->Init();
195 #else
196   // TODO(port)
197   NOTREACHED();
198 #endif
199 }
200
201 WebContents* ExtensionHost::GetAssociatedWebContents() const {
202   return associated_web_contents_;
203 }
204
205 WebContents* ExtensionHost::GetVisibleWebContents() const {
206   if (associated_web_contents_)
207     return associated_web_contents_;
208   if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) ||
209       (extension_host_type_ == VIEW_TYPE_PANEL))
210     return host_contents_.get();
211   return NULL;
212 }
213
214 void ExtensionHost::SetAssociatedWebContents(
215     content::WebContents* web_contents) {
216   associated_web_contents_ = web_contents;
217   if (web_contents) {
218     registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
219                    content::Source<WebContents>(associated_web_contents_));
220   }
221 }
222
223 content::RenderProcessHost* ExtensionHost::render_process_host() const {
224   return render_view_host()->GetProcess();
225 }
226
227 RenderViewHost* ExtensionHost::render_view_host() const {
228   // TODO(mpcomplete): This can be NULL. How do we handle that?
229   return render_view_host_;
230 }
231
232 bool ExtensionHost::IsRenderViewLive() const {
233   return render_view_host()->IsRenderViewLive();
234 }
235
236 void ExtensionHost::CreateRenderViewSoon() {
237   if ((render_process_host() && render_process_host()->HasConnection())) {
238     // If the process is already started, go ahead and initialize the RenderView
239     // synchronously. The process creation is the real meaty part that we want
240     // to defer.
241     CreateRenderViewNow();
242   } else {
243     ProcessCreationQueue::GetInstance()->CreateSoon(this);
244   }
245 }
246
247 void ExtensionHost::CreateRenderViewNow() {
248   LoadInitialURL();
249   if (is_background_page()) {
250     DCHECK(IsRenderViewLive());
251     ExtensionSystem::Get(profile_)->extension_service()->
252         DidCreateRenderViewForBackgroundPage(this);
253   }
254 }
255
256 WindowController* ExtensionHost::GetExtensionWindowController() const {
257   return view() && view()->browser() ?
258       view()->browser()->extension_window_controller() : NULL;
259 }
260
261 content::BrowserContext* ExtensionHost::browser_context() {
262   return profile_;
263 }
264
265 const GURL& ExtensionHost::GetURL() const {
266   return host_contents()->GetURL();
267 }
268
269 void ExtensionHost::LoadInitialURL() {
270   if (!is_background_page() &&
271       !ExtensionSystem::Get(profile_)->extension_service()->
272           IsBackgroundPageReady(extension_)) {
273     // Make sure the background page loads before any others.
274     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
275                    content::Source<Extension>(extension_));
276     return;
277   }
278
279 #if !defined(OS_ANDROID)
280   if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) ||
281       (extension_host_type_ == VIEW_TYPE_PANEL)) {
282     web_modal::WebContentsModalDialogManager::CreateForWebContents(
283         host_contents_.get());
284     web_modal::WebContentsModalDialogManager::FromWebContents(
285         host_contents_.get())->SetDelegate(this);
286   }
287 #endif
288
289   host_contents_->GetController().LoadURL(
290       initial_url_, content::Referrer(), content::PAGE_TRANSITION_LINK,
291       std::string());
292 }
293
294 void ExtensionHost::Close() {
295   content::NotificationService::current()->Notify(
296       chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
297       content::Source<Profile>(profile_),
298       content::Details<ExtensionHost>(this));
299 }
300
301 #if !defined(OS_ANDROID)
302 web_modal::WebContentsModalDialogHost*
303 ExtensionHost::GetWebContentsModalDialogHost() {
304   return this;
305 }
306
307 gfx::NativeView ExtensionHost::GetHostView() const {
308   return view_ ? view_->native_view() : NULL;
309 }
310
311 gfx::Point ExtensionHost::GetDialogPosition(const gfx::Size& size) {
312   if (!GetVisibleWebContents())
313     return gfx::Point();
314   gfx::Rect bounds = GetVisibleWebContents()->GetView()->GetViewBounds();
315   return gfx::Point(
316       std::max(0, (bounds.width() - size.width()) / 2),
317       std::max(0, (bounds.height() - size.height()) / 2));
318 }
319
320 gfx::Size ExtensionHost::GetMaximumDialogSize() {
321   if (!GetVisibleWebContents())
322     return gfx::Size();
323   return GetVisibleWebContents()->GetView()->GetViewBounds().size();
324 }
325
326 void ExtensionHost::AddObserver(
327     web_modal::ModalDialogHostObserver* observer) {
328 }
329
330 void ExtensionHost::RemoveObserver(
331     web_modal::ModalDialogHostObserver* observer) {
332 }
333 #endif
334
335 void ExtensionHost::Observe(int type,
336                             const content::NotificationSource& source,
337                             const content::NotificationDetails& details) {
338   switch (type) {
339     case chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY:
340       DCHECK(ExtensionSystem::Get(profile_)->extension_service()->
341           IsBackgroundPageReady(extension_));
342       LoadInitialURL();
343       break;
344     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
345       // The extension object will be deleted after this notification has been
346       // sent. NULL it out so that dirty pointer issues don't arise in cases
347       // when multiple ExtensionHost objects pointing to the same Extension are
348       // present.
349       if (extension_ == content::Details<UnloadedExtensionInfo>(details)->
350           extension) {
351         extension_ = NULL;
352       }
353       break;
354     case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
355       if (content::Source<WebContents>(source).ptr() ==
356           associated_web_contents_) {
357         associated_web_contents_ = NULL;
358       }
359       break;
360     default:
361       NOTREACHED() << "Unexpected notification sent.";
362       break;
363   }
364 }
365
366 void ExtensionHost::ResizeDueToAutoResize(WebContents* source,
367                                           const gfx::Size& new_size) {
368   if (view())
369     view()->ResizeDueToAutoResize(new_size);
370 }
371
372 void ExtensionHost::RenderProcessGone(base::TerminationStatus status) {
373   // During browser shutdown, we may use sudden termination on an extension
374   // process, so it is expected to lose our connection to the render view.
375   // Do nothing.
376   if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
377     return;
378
379   // In certain cases, multiple ExtensionHost objects may have pointed to
380   // the same Extension at some point (one with a background page and a
381   // popup, for example). When the first ExtensionHost goes away, the extension
382   // is unloaded, and any other host that pointed to that extension will have
383   // its pointer to it NULLed out so that any attempt to unload a dirty pointer
384   // will be averted.
385   if (!extension_)
386     return;
387
388   // TODO(aa): This is suspicious. There can be multiple views in an extension,
389   // and they aren't all going to use ExtensionHost. This should be in someplace
390   // more central, like EPM maybe.
391   content::NotificationService::current()->Notify(
392       chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
393       content::Source<Profile>(profile_),
394       content::Details<ExtensionHost>(this));
395 }
396
397 void ExtensionHost::InsertInfobarCSS() {
398   DCHECK(!is_background_page());
399
400   static const base::StringPiece css(
401       ResourceBundle::GetSharedInstance().GetRawDataResource(
402       IDR_EXTENSIONS_INFOBAR_CSS));
403
404   render_view_host()->InsertCSS(string16(), css.as_string());
405 }
406
407 void ExtensionHost::DidStopLoading(content::RenderViewHost* render_view_host) {
408   bool notify = !did_stop_loading_;
409   did_stop_loading_ = true;
410   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP ||
411       extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG ||
412       extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR ||
413       extension_host_type_ == VIEW_TYPE_PANEL) {
414 #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
415     if (view())
416       view()->DidStopLoading();
417 #endif
418   }
419   if (notify) {
420     if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
421       if (extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_)) {
422         UMA_HISTOGRAM_TIMES("Extensions.EventPageLoadTime",
423                             since_created_.Elapsed());
424       } else {
425         UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime",
426                             since_created_.Elapsed());
427       }
428     } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG) {
429       UMA_HISTOGRAM_TIMES("Extensions.DialogLoadTime",
430                           since_created_.Elapsed());
431     } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) {
432       UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime",
433                           since_created_.Elapsed());
434     } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR) {
435       UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime",
436         since_created_.Elapsed());
437     } else if (extension_host_type_ == VIEW_TYPE_PANEL) {
438       UMA_HISTOGRAM_TIMES("Extensions.PanelLoadTime", since_created_.Elapsed());
439     }
440
441     // Send the notification last, because it might result in this being
442     // deleted.
443     content::NotificationService::current()->Notify(
444         chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
445         content::Source<Profile>(profile_),
446         content::Details<ExtensionHost>(this));
447   }
448 }
449
450 void ExtensionHost::DocumentAvailableInMainFrame() {
451   // If the document has already been marked as available for this host, then
452   // bail. No need for the redundant setup. http://crbug.com/31170
453   if (document_element_available_)
454     return;
455
456   document_element_available_ = true;
457   if (is_background_page()) {
458     ExtensionSystem::Get(profile_)->extension_service()->
459         SetBackgroundPageReady(extension_);
460   } else {
461     switch (extension_host_type_) {
462       case VIEW_TYPE_EXTENSION_INFOBAR:
463         InsertInfobarCSS();
464         break;
465       default:
466         break;  // No style sheet for other types, at the moment.
467     }
468   }
469 }
470
471 void ExtensionHost::CloseContents(WebContents* contents) {
472   // TODO(mpcomplete): is this check really necessary?
473   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP ||
474       extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG ||
475       extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
476       extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR ||
477       extension_host_type_ == VIEW_TYPE_PANEL) {
478     Close();
479   }
480 }
481
482 void ExtensionHost::WillRunJavaScriptDialog() {
483   ExtensionProcessManager* pm =
484       ExtensionSystem::Get(profile_)->process_manager();
485   if (pm)
486     pm->IncrementLazyKeepaliveCount(extension());
487 }
488
489 void ExtensionHost::DidCloseJavaScriptDialog() {
490   ExtensionProcessManager* pm =
491       ExtensionSystem::Get(profile_)->process_manager();
492   if (pm)
493     pm->DecrementLazyKeepaliveCount(extension());
494 }
495
496 WebContents* ExtensionHost::OpenURLFromTab(WebContents* source,
497                                            const OpenURLParams& params) {
498   // Whitelist the dispositions we will allow to be opened.
499   switch (params.disposition) {
500     case SINGLETON_TAB:
501     case NEW_FOREGROUND_TAB:
502     case NEW_BACKGROUND_TAB:
503     case NEW_POPUP:
504     case NEW_WINDOW:
505     case SAVE_TO_DISK:
506     case OFF_THE_RECORD: {
507       // Only allow these from hosts that are bound to a browser (e.g. popups).
508       // Otherwise they are not driven by a user gesture.
509       Browser* browser = view() ? view()->browser() : NULL;
510       return browser ? browser->OpenURL(params) : NULL;
511     }
512     default:
513       return NULL;
514   }
515 }
516
517 bool ExtensionHost::PreHandleKeyboardEvent(WebContents* source,
518                                            const NativeWebKeyboardEvent& event,
519                                            bool* is_keyboard_shortcut) {
520   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP &&
521       event.type == NativeWebKeyboardEvent::RawKeyDown &&
522       event.windowsKeyCode == ui::VKEY_ESCAPE) {
523     DCHECK(is_keyboard_shortcut != NULL);
524     *is_keyboard_shortcut = true;
525     return false;
526   }
527
528   // Handle higher priority browser shortcuts such as Ctrl-w.
529   Browser* browser = view() ? view()->browser() : NULL;
530   if (browser)
531     return browser->PreHandleKeyboardEvent(source, event, is_keyboard_shortcut);
532
533   *is_keyboard_shortcut = false;
534   return false;
535 }
536
537 void ExtensionHost::HandleKeyboardEvent(WebContents* source,
538                                         const NativeWebKeyboardEvent& event) {
539   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) {
540     if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
541         event.windowsKeyCode == ui::VKEY_ESCAPE) {
542       Close();
543       return;
544     }
545   }
546   UnhandledKeyboardEvent(source, event);
547 }
548
549 bool ExtensionHost::OnMessageReceived(const IPC::Message& message) {
550   bool handled = true;
551   IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message)
552     IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
553     IPC_MESSAGE_HANDLER(ExtensionHostMsg_EventAck, OnEventAck)
554     IPC_MESSAGE_HANDLER(ExtensionHostMsg_IncrementLazyKeepaliveCount,
555                         OnIncrementLazyKeepaliveCount)
556     IPC_MESSAGE_HANDLER(ExtensionHostMsg_DecrementLazyKeepaliveCount,
557                         OnDecrementLazyKeepaliveCount)
558     IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DetailedConsoleMessageAdded,
559                         OnDetailedConsoleMessageAdded)
560     IPC_MESSAGE_UNHANDLED(handled = false)
561   IPC_END_MESSAGE_MAP()
562   return handled;
563 }
564
565 void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
566   extension_function_dispatcher_.Dispatch(params, render_view_host());
567 }
568
569 void ExtensionHost::OnEventAck() {
570   EventRouter* router = ExtensionSystem::Get(profile_)->event_router();
571   if (router)
572     router->OnEventAck(profile_, extension_id());
573 }
574
575 void ExtensionHost::OnIncrementLazyKeepaliveCount() {
576   ExtensionProcessManager* pm =
577       ExtensionSystem::Get(profile_)->process_manager();
578   if (pm)
579     pm->IncrementLazyKeepaliveCount(extension());
580 }
581
582 void ExtensionHost::OnDecrementLazyKeepaliveCount() {
583   ExtensionProcessManager* pm =
584       ExtensionSystem::Get(profile_)->process_manager();
585   if (pm)
586     pm->DecrementLazyKeepaliveCount(extension());
587 }
588
589 void ExtensionHost::OnDetailedConsoleMessageAdded(
590     const base::string16& message,
591     const base::string16& source,
592     const StackTrace& stack_trace,
593     int32 severity_level) {
594   if (IsSourceFromAnExtension(source)) {
595     GURL context_url;
596     if (associated_web_contents_)
597       context_url = associated_web_contents_->GetLastCommittedURL();
598     else if (host_contents_.get())
599       context_url = host_contents_->GetLastCommittedURL();
600
601     ErrorConsole::Get(profile_)->ReportError(
602         scoped_ptr<ExtensionError>(new RuntimeError(
603             extension_id_,
604             profile_->IsOffTheRecord(),
605             source,
606             message,
607             stack_trace,
608             context_url,
609             static_cast<logging::LogSeverity>(severity_level),
610             render_view_host_->GetRoutingID(),
611             render_view_host_->GetProcess()->GetID())));
612   }
613 }
614
615 void ExtensionHost::UnhandledKeyboardEvent(
616     WebContents* source,
617     const content::NativeWebKeyboardEvent& event) {
618   Browser* browser = view() ? view()->browser() : NULL;
619   if (browser) {
620     // Handle lower priority browser shortcuts such as Ctrl-f.
621     return browser->HandleKeyboardEvent(source, event);
622   } else {
623 #if defined(TOOLKIT_VIEWS)
624     // In case there's no Browser (e.g. for dialogs), pass it to
625     // ExtensionViewViews to handle acceleratos. The view's FocusManager does
626     // not know anything about Browser accelerators, but might know others such
627     // as Ash's.
628     if (view())
629       view()->HandleKeyboardEvent(event);
630 #endif
631   }
632 }
633
634 void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) {
635   render_view_host_ = render_view_host;
636
637   if (view())
638     view()->RenderViewCreated();
639
640   // If the host is bound to a window, then extract its id. Extensions hosted
641   // in ExternalTabContainer objects may not have an associated window.
642   WindowController* window = GetExtensionWindowController();
643   if (window) {
644     render_view_host->Send(new ExtensionMsg_UpdateBrowserWindowId(
645         render_view_host->GetRoutingID(), window->GetWindowId()));
646   }
647 }
648
649 void ExtensionHost::RenderViewDeleted(RenderViewHost* render_view_host) {
650   // If our RenderViewHost is deleted, fall back to the host_contents' current
651   // RVH. There is sometimes a small gap between the pending RVH being deleted
652   // and RenderViewCreated being called, so we update it here.
653   if (render_view_host == render_view_host_)
654     render_view_host_ = host_contents_->GetRenderViewHost();
655 }
656
657 content::JavaScriptDialogManager* ExtensionHost::GetJavaScriptDialogManager() {
658   if (!dialog_manager_) {
659     dialog_manager_.reset(CreateJavaScriptDialogManagerInstance(this));
660   }
661   return dialog_manager_.get();
662 }
663
664 content::ColorChooser* ExtensionHost::OpenColorChooser(
665     WebContents* web_contents, SkColor initial_color) {
666   return chrome::ShowColorChooser(web_contents, initial_color);
667 }
668
669 void ExtensionHost::RunFileChooser(WebContents* tab,
670                                    const content::FileChooserParams& params) {
671   FileSelectHelper::RunFileChooser(tab, params);
672 }
673
674 void ExtensionHost::AddNewContents(WebContents* source,
675                                    WebContents* new_contents,
676                                    WindowOpenDisposition disposition,
677                                    const gfx::Rect& initial_pos,
678                                    bool user_gesture,
679                                    bool* was_blocked) {
680   // First, if the creating extension view was associated with a tab contents,
681   // use that tab content's delegate. We must be careful here that the
682   // associated tab contents has the same profile as the new tab contents. In
683   // the case of extensions in 'spanning' incognito mode, they can mismatch.
684   // We don't want to end up putting a normal tab into an incognito window, or
685   // vice versa.
686   // Note that we don't do this for popup windows, because we need to associate
687   // those with their extension_app_id.
688   if (disposition != NEW_POPUP) {
689     WebContents* associated_contents = GetAssociatedWebContents();
690     if (associated_contents &&
691         associated_contents->GetBrowserContext() ==
692             new_contents->GetBrowserContext()) {
693       WebContentsDelegate* delegate = associated_contents->GetDelegate();
694       if (delegate) {
695         delegate->AddNewContents(
696             associated_contents, new_contents, disposition, initial_pos,
697             user_gesture, was_blocked);
698         return;
699       }
700     }
701   }
702
703   ExtensionTabUtil::CreateTab(new_contents, extension_id_, disposition,
704                               initial_pos, user_gesture);
705 }
706
707 void ExtensionHost::RenderViewReady() {
708   content::NotificationService::current()->Notify(
709       chrome::NOTIFICATION_EXTENSION_HOST_CREATED,
710       content::Source<Profile>(profile_),
711       content::Details<ExtensionHost>(this));
712 }
713
714 void ExtensionHost::RequestMediaAccessPermission(
715     content::WebContents* web_contents,
716     const content::MediaStreamRequest& request,
717     const content::MediaResponseCallback& callback) {
718   MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
719       web_contents, request, callback, extension());
720 }
721
722 }  // namespace extensions