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/browser_process.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/extension_view.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/autofill/chrome_autofill_client.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_dialogs.h"
17 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
18 #include "components/autofill/core/browser/autofill_manager.h"
19 #include "components/web_modal/web_contents_modal_dialog_manager.h"
20 #include "content/public/browser/notification_source.h"
21 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/web_contents.h"
23 #include "extensions/browser/extension_system.h"
24 #include "extensions/browser/runtime_data.h"
25 #include "grit/browser_resources.h"
26 #include "third_party/WebKit/public/web/WebInputEvent.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/events/keycodes/keyboard_codes.h"
30 using content::NativeWebKeyboardEvent
;
31 using content::OpenURLParams
;
32 using content::RenderViewHost
;
33 using content::WebContents
;
34 using content::WebContentsObserver
;
35 using web_modal::WebContentsModalDialogManager
;
37 namespace extensions
{
39 // Notifies an ExtensionViewHost when a WebContents is destroyed.
40 class ExtensionViewHost::AssociatedWebContentsObserver
41 : public WebContentsObserver
{
43 AssociatedWebContentsObserver(ExtensionViewHost
* host
,
44 WebContents
* web_contents
)
45 : WebContentsObserver(web_contents
), host_(host
) {}
46 ~AssociatedWebContentsObserver() override
{}
48 // content::WebContentsObserver:
49 void WebContentsDestroyed() override
{
50 // Deleting |this| from here is safe.
51 host_
->SetAssociatedWebContents(NULL
);
55 ExtensionViewHost
* host_
;
57 DISALLOW_COPY_AND_ASSIGN(AssociatedWebContentsObserver
);
60 ExtensionViewHost::ExtensionViewHost(
61 const Extension
* extension
,
62 content::SiteInstance
* site_instance
,
65 : ExtensionHost(extension
, site_instance
, url
, host_type
),
66 associated_web_contents_(NULL
) {
67 // Not used for panels, see PanelHost.
68 DCHECK(host_type
== VIEW_TYPE_EXTENSION_DIALOG
||
69 host_type
== VIEW_TYPE_EXTENSION_POPUP
);
71 // Attach WebContents helpers. Extension tabs automatically get them attached
72 // in TabHelpers::AttachTabHelpers, but popups don't.
73 // TODO(kalman): How much of TabHelpers::AttachTabHelpers should be here?
74 autofill::ChromeAutofillClient::CreateForWebContents(host_contents());
75 autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
77 autofill::ChromeAutofillClient::FromWebContents(host_contents()),
78 g_browser_process
->GetApplicationLocale(),
79 autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER
);
82 ExtensionViewHost::~ExtensionViewHost() {
83 // The hosting WebContents will be deleted in the base class, so unregister
84 // this object before it deletes the attached WebContentsModalDialogManager.
85 WebContentsModalDialogManager
* manager
=
86 WebContentsModalDialogManager::FromWebContents(host_contents());
88 manager
->SetDelegate(NULL
);
91 void ExtensionViewHost::CreateView(Browser
* browser
) {
92 view_
= CreateExtensionView(this, browser
);
95 void ExtensionViewHost::SetAssociatedWebContents(WebContents
* web_contents
) {
96 associated_web_contents_
= web_contents
;
97 if (associated_web_contents_
) {
98 // Observe the new WebContents for deletion.
99 associated_web_contents_observer_
.reset(
100 new AssociatedWebContentsObserver(this, associated_web_contents_
));
102 associated_web_contents_observer_
.reset();
106 void ExtensionViewHost::UnhandledKeyboardEvent(
108 const content::NativeWebKeyboardEvent
& event
) {
109 view_
->HandleKeyboardEvent(source
, event
);
112 // ExtensionHost overrides:
114 void ExtensionViewHost::OnDidStopFirstLoad() {
115 view_
->DidStopLoading();
118 void ExtensionViewHost::LoadInitialURL() {
119 if (!ExtensionSystem::Get(browser_context())->
120 runtime_data()->IsBackgroundPageReady(extension())) {
121 // Make sure the background page loads before any others.
123 extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY
,
124 content::Source
<Extension
>(extension()));
128 // Popups may spawn modal dialogs, which need positioning information.
129 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP
) {
130 WebContentsModalDialogManager::CreateForWebContents(host_contents());
131 WebContentsModalDialogManager::FromWebContents(
132 host_contents())->SetDelegate(this);
135 ExtensionHost::LoadInitialURL();
138 bool ExtensionViewHost::IsBackgroundPage() const {
143 // content::WebContentsDelegate overrides:
145 WebContents
* ExtensionViewHost::OpenURLFromTab(
147 const OpenURLParams
& params
) {
148 // Whitelist the dispositions we will allow to be opened.
149 switch (params
.disposition
) {
151 case NEW_FOREGROUND_TAB
:
152 case NEW_BACKGROUND_TAB
:
156 case OFF_THE_RECORD
: {
157 // Only allow these from hosts that are bound to a browser (e.g. popups).
158 // Otherwise they are not driven by a user gesture.
159 Browser
* browser
= view_
->GetBrowser();
160 return browser
? browser
->OpenURL(params
) : NULL
;
167 bool ExtensionViewHost::PreHandleKeyboardEvent(
169 const NativeWebKeyboardEvent
& event
,
170 bool* is_keyboard_shortcut
) {
171 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP
&&
172 event
.type
== NativeWebKeyboardEvent::RawKeyDown
&&
173 event
.windowsKeyCode
== ui::VKEY_ESCAPE
) {
174 DCHECK(is_keyboard_shortcut
!= NULL
);
175 *is_keyboard_shortcut
= true;
179 // Handle higher priority browser shortcuts such as Ctrl-w.
180 Browser
* browser
= view_
->GetBrowser();
182 return browser
->PreHandleKeyboardEvent(source
, event
, is_keyboard_shortcut
);
184 *is_keyboard_shortcut
= false;
188 void ExtensionViewHost::HandleKeyboardEvent(
190 const NativeWebKeyboardEvent
& event
) {
191 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP
) {
192 if (event
.type
== NativeWebKeyboardEvent::RawKeyDown
&&
193 event
.windowsKeyCode
== ui::VKEY_ESCAPE
) {
198 UnhandledKeyboardEvent(source
, event
);
201 bool ExtensionViewHost::PreHandleGestureEvent(
202 content::WebContents
* source
,
203 const blink::WebGestureEvent
& event
) {
204 // Disable pinch zooming.
205 return event
.type
== blink::WebGestureEvent::GesturePinchBegin
||
206 event
.type
== blink::WebGestureEvent::GesturePinchUpdate
||
207 event
.type
== blink::WebGestureEvent::GesturePinchEnd
;
210 content::ColorChooser
* ExtensionViewHost::OpenColorChooser(
211 WebContents
* web_contents
,
212 SkColor initial_color
,
213 const std::vector
<content::ColorSuggestion
>& suggestions
) {
214 // Similar to the file chooser below, opening a color chooser requires a
215 // visible <input> element to click on. Therefore this code only exists for
216 // extensions with a view.
217 return chrome::ShowColorChooser(web_contents
, initial_color
);
220 void ExtensionViewHost::RunFileChooser(
222 const content::FileChooserParams
& params
) {
223 // For security reasons opening a file picker requires a visible <input>
224 // element to click on, so this code only exists for extensions with a view.
225 FileSelectHelper::RunFileChooser(tab
, params
);
229 void ExtensionViewHost::ResizeDueToAutoResize(WebContents
* source
,
230 const gfx::Size
& new_size
) {
231 view_
->ResizeDueToAutoResize(source
, new_size
);
234 // content::WebContentsObserver overrides:
236 void ExtensionViewHost::RenderViewCreated(RenderViewHost
* render_view_host
) {
237 ExtensionHost::RenderViewCreated(render_view_host
);
238 view_
->RenderViewCreated(render_view_host
);
241 // web_modal::WebContentsModalDialogManagerDelegate overrides:
243 web_modal::WebContentsModalDialogHost
*
244 ExtensionViewHost::GetWebContentsModalDialogHost() {
248 bool ExtensionViewHost::IsWebContentsVisible(WebContents
* web_contents
) {
249 return platform_util::IsVisible(web_contents
->GetNativeView());
252 gfx::NativeView
ExtensionViewHost::GetHostView() const {
253 return view_
->GetNativeView();
256 gfx::Point
ExtensionViewHost::GetDialogPosition(const gfx::Size
& size
) {
257 if (!GetVisibleWebContents())
259 gfx::Rect bounds
= GetVisibleWebContents()->GetViewBounds();
261 std::max(0, (bounds
.width() - size
.width()) / 2),
262 std::max(0, (bounds
.height() - size
.height()) / 2));
265 gfx::Size
ExtensionViewHost::GetMaximumDialogSize() {
266 if (!GetVisibleWebContents())
268 return GetVisibleWebContents()->GetViewBounds().size();
271 void ExtensionViewHost::AddObserver(
272 web_modal::ModalDialogHostObserver
* observer
) {
275 void ExtensionViewHost::RemoveObserver(
276 web_modal::ModalDialogHostObserver
* observer
) {
279 WindowController
* ExtensionViewHost::GetExtensionWindowController() const {
280 Browser
* browser
= view_
->GetBrowser();
281 return browser
? browser
->extension_window_controller() : NULL
;
284 WebContents
* ExtensionViewHost::GetAssociatedWebContents() const {
285 return associated_web_contents_
;
288 WebContents
* ExtensionViewHost::GetVisibleWebContents() const {
289 if (associated_web_contents_
)
290 return associated_web_contents_
;
291 if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP
)
292 return host_contents();
296 void ExtensionViewHost::Observe(int type
,
297 const content::NotificationSource
& source
,
298 const content::NotificationDetails
& details
) {
299 DCHECK_EQ(type
, extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY
);
300 DCHECK(ExtensionSystem::Get(browser_context())
302 ->IsBackgroundPageReady(extension()));
306 } // namespace extensions