Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_view_host.cc
blobc60c467a56c4a2cc3099363f971faf070ede7074
1 // Copyright 2013 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.
5 #include "chrome/browser/extensions/extension_view_host.h"
7 #include "base/strings/string_piece.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_system.h"
11 #include "chrome/browser/extensions/window_controller.h"
12 #include "chrome/browser/file_select_helper.h"
13 #include "chrome/browser/platform_util.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_dialogs.h"
16 #include "chrome/common/extensions/extension_messages.h"
17 #include "components/web_modal/web_contents_modal_dialog_manager.h"
18 #include "content/public/browser/notification_source.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/browser/web_contents_view.h"
22 #include "grit/browser_resources.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/events/keycodes/keyboard_codes.h"
26 using content::NativeWebKeyboardEvent;
27 using content::OpenURLParams;
28 using content::RenderViewHost;
29 using content::WebContents;
30 using content::WebContentsObserver;
31 using web_modal::WebContentsModalDialogManager;
33 namespace extensions {
35 // Notifies an ExtensionViewHost when a WebContents is destroyed.
36 class ExtensionViewHost::AssociatedWebContentsObserver
37 : public WebContentsObserver {
38 public:
39 AssociatedWebContentsObserver(ExtensionViewHost* host,
40 WebContents* web_contents)
41 : WebContentsObserver(web_contents), host_(host) {}
42 virtual ~AssociatedWebContentsObserver() {}
44 // content::WebContentsObserver:
45 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
46 // Deleting |this| from here is safe.
47 host_->SetAssociatedWebContents(NULL);
50 private:
51 ExtensionViewHost* host_;
53 DISALLOW_COPY_AND_ASSIGN(AssociatedWebContentsObserver);
56 ExtensionViewHost::ExtensionViewHost(
57 const Extension* extension,
58 content::SiteInstance* site_instance,
59 const GURL& url,
60 ViewType host_type)
61 : ExtensionHost(extension, site_instance, url, host_type),
62 associated_web_contents_(NULL) {
63 // Not used for panels, see PanelHost.
64 DCHECK(host_type == VIEW_TYPE_EXTENSION_DIALOG ||
65 host_type == VIEW_TYPE_EXTENSION_INFOBAR ||
66 host_type == VIEW_TYPE_EXTENSION_POPUP);
69 ExtensionViewHost::~ExtensionViewHost() {
70 // The hosting WebContents will be deleted in the base class, so unregister
71 // this object before it deletes the attached WebContentsModalDialogManager.
72 WebContentsModalDialogManager* manager =
73 WebContentsModalDialogManager::FromWebContents(host_contents());
74 if (manager)
75 manager->SetDelegate(NULL);
78 void ExtensionViewHost::CreateView(Browser* browser) {
79 #if defined(TOOLKIT_VIEWS)
80 view_.reset(new ExtensionViewViews(this, browser));
81 // We own |view_|, so don't auto delete when it's removed from the view
82 // hierarchy.
83 view_->set_owned_by_client();
84 #elif defined(OS_MACOSX)
85 view_.reset(new ExtensionViewMac(this, browser));
86 view_->Init();
87 #elif defined(TOOLKIT_GTK)
88 view_.reset(new ExtensionViewGtk(this, browser));
89 view_->Init();
90 #else
91 // TODO(port)
92 NOTREACHED();
93 #endif
96 void ExtensionViewHost::SetAssociatedWebContents(WebContents* web_contents) {
97 associated_web_contents_ = web_contents;
98 if (associated_web_contents_) {
99 // Observe the new WebContents for deletion.
100 associated_web_contents_observer_.reset(
101 new AssociatedWebContentsObserver(this, associated_web_contents_));
102 } else {
103 associated_web_contents_observer_.reset();
107 void ExtensionViewHost::UnhandledKeyboardEvent(
108 WebContents* source,
109 const content::NativeWebKeyboardEvent& event) {
110 Browser* browser = view_->browser();
111 if (browser) {
112 // Handle lower priority browser shortcuts such as Ctrl-f.
113 return browser->HandleKeyboardEvent(source, event);
114 } else {
115 #if defined(TOOLKIT_VIEWS)
116 // In case there's no Browser (e.g. for dialogs), pass it to
117 // ExtensionViewViews to handle accelerators. The view's FocusManager does
118 // not know anything about Browser accelerators, but might know others such
119 // as Ash's.
120 view_->HandleKeyboardEvent(event);
121 #endif
125 // ExtensionHost overrides:
127 void ExtensionViewHost::OnDidStopLoading() {
128 DCHECK(did_stop_loading());
129 #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
130 view_->DidStopLoading();
131 #endif
134 void ExtensionViewHost::OnDocumentAvailable() {
135 if (extension_host_type() == VIEW_TYPE_EXTENSION_INFOBAR) {
136 // No style sheet for other types, at the moment.
137 InsertInfobarCSS();
141 void ExtensionViewHost::LoadInitialURL() {
142 if (!ExtensionSystem::GetForBrowserContext(browser_context())->
143 extension_service()->IsBackgroundPageReady(extension())) {
144 // Make sure the background page loads before any others.
145 registrar()->Add(this,
146 chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
147 content::Source<Extension>(extension()));
148 return;
151 // Popups may spawn modal dialogs, which need positioning information.
152 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP) {
153 WebContentsModalDialogManager::CreateForWebContents(host_contents());
154 WebContentsModalDialogManager::FromWebContents(
155 host_contents())->SetDelegate(this);
158 ExtensionHost::LoadInitialURL();
161 bool ExtensionViewHost::IsBackgroundPage() const {
162 DCHECK(view_);
163 return false;
166 // content::WebContentsDelegate overrides:
168 WebContents* ExtensionViewHost::OpenURLFromTab(
169 WebContents* source,
170 const OpenURLParams& params) {
171 // Whitelist the dispositions we will allow to be opened.
172 switch (params.disposition) {
173 case SINGLETON_TAB:
174 case NEW_FOREGROUND_TAB:
175 case NEW_BACKGROUND_TAB:
176 case NEW_POPUP:
177 case NEW_WINDOW:
178 case SAVE_TO_DISK:
179 case OFF_THE_RECORD: {
180 // Only allow these from hosts that are bound to a browser (e.g. popups).
181 // Otherwise they are not driven by a user gesture.
182 Browser* browser = view_->browser();
183 return browser ? browser->OpenURL(params) : NULL;
185 default:
186 return NULL;
190 bool ExtensionViewHost::PreHandleKeyboardEvent(
191 WebContents* source,
192 const NativeWebKeyboardEvent& event,
193 bool* is_keyboard_shortcut) {
194 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP &&
195 event.type == NativeWebKeyboardEvent::RawKeyDown &&
196 event.windowsKeyCode == ui::VKEY_ESCAPE) {
197 DCHECK(is_keyboard_shortcut != NULL);
198 *is_keyboard_shortcut = true;
199 return false;
202 // Handle higher priority browser shortcuts such as Ctrl-w.
203 Browser* browser = view_->browser();
204 if (browser)
205 return browser->PreHandleKeyboardEvent(source, event, is_keyboard_shortcut);
207 *is_keyboard_shortcut = false;
208 return false;
211 void ExtensionViewHost::HandleKeyboardEvent(
212 WebContents* source,
213 const NativeWebKeyboardEvent& event) {
214 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP) {
215 if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
216 event.windowsKeyCode == ui::VKEY_ESCAPE) {
217 Close();
218 return;
221 UnhandledKeyboardEvent(source, event);
224 content::ColorChooser* ExtensionViewHost::OpenColorChooser(
225 WebContents* web_contents,
226 SkColor initial_color,
227 const std::vector<content::ColorSuggestion>& suggestions) {
228 // Similar to the file chooser below, opening a color chooser requires a
229 // visible <input> element to click on. Therefore this code only exists for
230 // extensions with a view.
231 return chrome::ShowColorChooser(web_contents, initial_color);
234 void ExtensionViewHost::RunFileChooser(
235 WebContents* tab,
236 const content::FileChooserParams& params) {
237 // For security reasons opening a file picker requires a visible <input>
238 // element to click on, so this code only exists for extensions with a view.
239 FileSelectHelper::RunFileChooser(tab, params);
243 void ExtensionViewHost::ResizeDueToAutoResize(WebContents* source,
244 const gfx::Size& new_size) {
245 view_->ResizeDueToAutoResize(new_size);
248 // content::WebContentsObserver overrides:
250 void ExtensionViewHost::RenderViewCreated(RenderViewHost* render_view_host) {
251 ExtensionHost::RenderViewCreated(render_view_host);
253 view_->RenderViewCreated();
255 // If the host is bound to a window, then extract its id. Extensions hosted
256 // in ExternalTabContainer objects may not have an associated window.
257 WindowController* window = GetExtensionWindowController();
258 if (window) {
259 render_view_host->Send(new ExtensionMsg_UpdateBrowserWindowId(
260 render_view_host->GetRoutingID(), window->GetWindowId()));
264 // web_modal::WebContentsModalDialogManagerDelegate overrides:
266 web_modal::WebContentsModalDialogHost*
267 ExtensionViewHost::GetWebContentsModalDialogHost() {
268 return this;
271 bool ExtensionViewHost::IsWebContentsVisible(WebContents* web_contents) {
272 return platform_util::IsVisible(web_contents->GetView()->GetNativeView());
275 gfx::NativeView ExtensionViewHost::GetHostView() const {
276 return view_->native_view();
279 gfx::Point ExtensionViewHost::GetDialogPosition(const gfx::Size& size) {
280 if (!GetVisibleWebContents())
281 return gfx::Point();
282 gfx::Rect bounds = GetVisibleWebContents()->GetView()->GetViewBounds();
283 return gfx::Point(
284 std::max(0, (bounds.width() - size.width()) / 2),
285 std::max(0, (bounds.height() - size.height()) / 2));
288 gfx::Size ExtensionViewHost::GetMaximumDialogSize() {
289 if (!GetVisibleWebContents())
290 return gfx::Size();
291 return GetVisibleWebContents()->GetView()->GetViewBounds().size();
294 void ExtensionViewHost::AddObserver(
295 web_modal::ModalDialogHostObserver* observer) {
298 void ExtensionViewHost::RemoveObserver(
299 web_modal::ModalDialogHostObserver* observer) {
302 WindowController* ExtensionViewHost::GetExtensionWindowController() const {
303 return view_->browser() ? view_->browser()->extension_window_controller()
304 : NULL;
307 WebContents* ExtensionViewHost::GetAssociatedWebContents() const {
308 return associated_web_contents_;
311 WebContents* ExtensionViewHost::GetVisibleWebContents() const {
312 if (associated_web_contents_)
313 return associated_web_contents_;
314 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP)
315 return host_contents();
316 return NULL;
319 void ExtensionViewHost::Observe(int type,
320 const content::NotificationSource& source,
321 const content::NotificationDetails& details) {
322 if (type == chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY) {
323 DCHECK(ExtensionSystem::GetForBrowserContext(browser_context())->
324 extension_service()->IsBackgroundPageReady(extension()));
325 LoadInitialURL();
326 return;
328 ExtensionHost::Observe(type, source, details);
331 void ExtensionViewHost::InsertInfobarCSS() {
332 static const base::StringPiece css(
333 ResourceBundle::GetSharedInstance().GetRawDataResource(
334 IDR_EXTENSIONS_INFOBAR_CSS));
336 render_view_host()->InsertCSS(base::string16(), css.as_string());
339 } // namespace extensions