Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_view_host.cc
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.
4
5 #include "chrome/browser/extensions/extension_view_host.h"
6
7 #include "base/strings/string_piece.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/extensions/extension_view.h"
10 #include "chrome/browser/extensions/window_controller.h"
11 #include "chrome/browser/file_select_helper.h"
12 #include "chrome/browser/platform_util.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_dialogs.h"
15 #include "components/web_modal/web_contents_modal_dialog_manager.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/runtime_data.h"
21 #include "extensions/common/extension_messages.h"
22 #include "grit/browser_resources.h"
23 #include "third_party/WebKit/public/web/WebInputEvent.h"
24 #include "ui/base/resource/resource_bundle.h"
25 #include "ui/events/keycodes/keyboard_codes.h"
26
27 using content::NativeWebKeyboardEvent;
28 using content::OpenURLParams;
29 using content::RenderViewHost;
30 using content::WebContents;
31 using content::WebContentsObserver;
32 using web_modal::WebContentsModalDialogManager;
33
34 namespace extensions {
35
36 // Notifies an ExtensionViewHost when a WebContents is destroyed.
37 class ExtensionViewHost::AssociatedWebContentsObserver
38     : public WebContentsObserver {
39  public:
40   AssociatedWebContentsObserver(ExtensionViewHost* host,
41                                 WebContents* web_contents)
42       : WebContentsObserver(web_contents), host_(host) {}
43   virtual ~AssociatedWebContentsObserver() {}
44
45   // content::WebContentsObserver:
46   virtual void WebContentsDestroyed() OVERRIDE {
47     // Deleting |this| from here is safe.
48     host_->SetAssociatedWebContents(NULL);
49   }
50
51  private:
52   ExtensionViewHost* host_;
53
54   DISALLOW_COPY_AND_ASSIGN(AssociatedWebContentsObserver);
55 };
56
57 ExtensionViewHost::ExtensionViewHost(
58     const Extension* extension,
59     content::SiteInstance* site_instance,
60     const GURL& url,
61     ViewType host_type)
62     : ExtensionHost(extension, site_instance, url, host_type),
63       associated_web_contents_(NULL) {
64   // Not used for panels, see PanelHost.
65   DCHECK(host_type == VIEW_TYPE_EXTENSION_DIALOG ||
66          host_type == VIEW_TYPE_EXTENSION_INFOBAR ||
67          host_type == VIEW_TYPE_EXTENSION_POPUP);
68 }
69
70 ExtensionViewHost::~ExtensionViewHost() {
71   // The hosting WebContents will be deleted in the base class, so unregister
72   // this object before it deletes the attached WebContentsModalDialogManager.
73   WebContentsModalDialogManager* manager =
74       WebContentsModalDialogManager::FromWebContents(host_contents());
75   if (manager)
76     manager->SetDelegate(NULL);
77 }
78
79 void ExtensionViewHost::CreateView(Browser* browser) {
80   view_ = CreateExtensionView(this, browser);
81   view_->Init();
82 }
83
84 void ExtensionViewHost::SetAssociatedWebContents(WebContents* web_contents) {
85   associated_web_contents_ = web_contents;
86   if (associated_web_contents_) {
87     // Observe the new WebContents for deletion.
88     associated_web_contents_observer_.reset(
89         new AssociatedWebContentsObserver(this, associated_web_contents_));
90   } else {
91     associated_web_contents_observer_.reset();
92   }
93 }
94
95 void ExtensionViewHost::UnhandledKeyboardEvent(
96     WebContents* source,
97     const content::NativeWebKeyboardEvent& event) {
98   view_->HandleKeyboardEvent(source, event);
99 }
100
101 // ExtensionHost overrides:
102
103 void ExtensionViewHost::OnDidStopLoading() {
104   DCHECK(did_stop_loading());
105   view_->DidStopLoading();
106 }
107
108 void ExtensionViewHost::OnDocumentAvailable() {
109   if (extension_host_type() == VIEW_TYPE_EXTENSION_INFOBAR) {
110     // No style sheet for other types, at the moment.
111     InsertInfobarCSS();
112   }
113 }
114
115 void ExtensionViewHost::LoadInitialURL() {
116   if (!ExtensionSystem::Get(browser_context())->
117           runtime_data()->IsBackgroundPageReady(extension())) {
118     // Make sure the background page loads before any others.
119     registrar()->Add(this,
120                      extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
121                      content::Source<Extension>(extension()));
122     return;
123   }
124
125   // Popups may spawn modal dialogs, which need positioning information.
126   if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP) {
127     WebContentsModalDialogManager::CreateForWebContents(host_contents());
128     WebContentsModalDialogManager::FromWebContents(
129         host_contents())->SetDelegate(this);
130   }
131
132   ExtensionHost::LoadInitialURL();
133 }
134
135 bool ExtensionViewHost::IsBackgroundPage() const {
136   DCHECK(view_);
137   return false;
138 }
139
140 // content::WebContentsDelegate overrides:
141
142 WebContents* ExtensionViewHost::OpenURLFromTab(
143     WebContents* source,
144     const OpenURLParams& params) {
145   // Whitelist the dispositions we will allow to be opened.
146   switch (params.disposition) {
147     case SINGLETON_TAB:
148     case NEW_FOREGROUND_TAB:
149     case NEW_BACKGROUND_TAB:
150     case NEW_POPUP:
151     case NEW_WINDOW:
152     case SAVE_TO_DISK:
153     case OFF_THE_RECORD: {
154       // Only allow these from hosts that are bound to a browser (e.g. popups).
155       // Otherwise they are not driven by a user gesture.
156       Browser* browser = view_->GetBrowser();
157       return browser ? browser->OpenURL(params) : NULL;
158     }
159     default:
160       return NULL;
161   }
162 }
163
164 bool ExtensionViewHost::PreHandleKeyboardEvent(
165     WebContents* source,
166     const NativeWebKeyboardEvent& event,
167     bool* is_keyboard_shortcut) {
168   if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP &&
169       event.type == NativeWebKeyboardEvent::RawKeyDown &&
170       event.windowsKeyCode == ui::VKEY_ESCAPE) {
171     DCHECK(is_keyboard_shortcut != NULL);
172     *is_keyboard_shortcut = true;
173     return false;
174   }
175
176   // Handle higher priority browser shortcuts such as Ctrl-w.
177   Browser* browser = view_->GetBrowser();
178   if (browser)
179     return browser->PreHandleKeyboardEvent(source, event, is_keyboard_shortcut);
180
181   *is_keyboard_shortcut = false;
182   return false;
183 }
184
185 void ExtensionViewHost::HandleKeyboardEvent(
186     WebContents* source,
187     const NativeWebKeyboardEvent& event) {
188   if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP) {
189     if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
190         event.windowsKeyCode == ui::VKEY_ESCAPE) {
191       Close();
192       return;
193     }
194   }
195   UnhandledKeyboardEvent(source, event);
196 }
197
198 bool ExtensionViewHost::PreHandleGestureEvent(
199     content::WebContents* source,
200     const blink::WebGestureEvent& event) {
201   // Disable pinch zooming.
202   return event.type == blink::WebGestureEvent::GesturePinchBegin ||
203       event.type == blink::WebGestureEvent::GesturePinchUpdate ||
204       event.type == blink::WebGestureEvent::GesturePinchEnd;
205 }
206
207 content::ColorChooser* ExtensionViewHost::OpenColorChooser(
208     WebContents* web_contents,
209     SkColor initial_color,
210     const std::vector<content::ColorSuggestion>& suggestions) {
211   // Similar to the file chooser below, opening a color chooser requires a
212   // visible <input> element to click on. Therefore this code only exists for
213   // extensions with a view.
214   return chrome::ShowColorChooser(web_contents, initial_color);
215 }
216
217 void ExtensionViewHost::RunFileChooser(
218     WebContents* tab,
219     const content::FileChooserParams& params) {
220   // For security reasons opening a file picker requires a visible <input>
221   // element to click on, so this code only exists for extensions with a view.
222   FileSelectHelper::RunFileChooser(tab, params);
223 }
224
225
226 void ExtensionViewHost::ResizeDueToAutoResize(WebContents* source,
227                                           const gfx::Size& new_size) {
228   view_->ResizeDueToAutoResize(new_size);
229 }
230
231 // content::WebContentsObserver overrides:
232
233 void ExtensionViewHost::RenderViewCreated(RenderViewHost* render_view_host) {
234   ExtensionHost::RenderViewCreated(render_view_host);
235
236   view_->RenderViewCreated();
237
238   // If the host is bound to a window, then extract its id. Extensions hosted
239   // in ExternalTabContainer objects may not have an associated window.
240   WindowController* window = GetExtensionWindowController();
241   if (window) {
242     render_view_host->Send(new ExtensionMsg_UpdateBrowserWindowId(
243         render_view_host->GetRoutingID(), window->GetWindowId()));
244   }
245 }
246
247 // web_modal::WebContentsModalDialogManagerDelegate overrides:
248
249 web_modal::WebContentsModalDialogHost*
250 ExtensionViewHost::GetWebContentsModalDialogHost() {
251   return this;
252 }
253
254 bool ExtensionViewHost::IsWebContentsVisible(WebContents* web_contents) {
255   return platform_util::IsVisible(web_contents->GetNativeView());
256 }
257
258 gfx::NativeView ExtensionViewHost::GetHostView() const {
259   return view_->GetNativeView();
260 }
261
262 gfx::Point ExtensionViewHost::GetDialogPosition(const gfx::Size& size) {
263   if (!GetVisibleWebContents())
264     return gfx::Point();
265   gfx::Rect bounds = GetVisibleWebContents()->GetViewBounds();
266   return gfx::Point(
267       std::max(0, (bounds.width() - size.width()) / 2),
268       std::max(0, (bounds.height() - size.height()) / 2));
269 }
270
271 gfx::Size ExtensionViewHost::GetMaximumDialogSize() {
272   if (!GetVisibleWebContents())
273     return gfx::Size();
274   return GetVisibleWebContents()->GetViewBounds().size();
275 }
276
277 void ExtensionViewHost::AddObserver(
278     web_modal::ModalDialogHostObserver* observer) {
279 }
280
281 void ExtensionViewHost::RemoveObserver(
282     web_modal::ModalDialogHostObserver* observer) {
283 }
284
285 WindowController* ExtensionViewHost::GetExtensionWindowController() const {
286   Browser* browser = view_->GetBrowser();
287   return browser ? browser->extension_window_controller() : NULL;
288 }
289
290 WebContents* ExtensionViewHost::GetAssociatedWebContents() const {
291   return associated_web_contents_;
292 }
293
294 WebContents* ExtensionViewHost::GetVisibleWebContents() const {
295   if (associated_web_contents_)
296     return associated_web_contents_;
297   if (extension_host_type() == VIEW_TYPE_EXTENSION_POPUP)
298     return host_contents();
299   return NULL;
300 }
301
302 void ExtensionViewHost::Observe(int type,
303                                 const content::NotificationSource& source,
304                                 const content::NotificationDetails& details) {
305   if (type == extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY) {
306     DCHECK(ExtensionSystem::Get(browser_context())->
307                runtime_data()->IsBackgroundPageReady(extension()));
308     LoadInitialURL();
309     return;
310   }
311   ExtensionHost::Observe(type, source, details);
312 }
313
314 void ExtensionViewHost::InsertInfobarCSS() {
315   static const base::StringPiece css(
316       ResourceBundle::GetSharedInstance().GetRawDataResource(
317       IDR_EXTENSIONS_INFOBAR_CSS));
318
319   host_contents()->InsertCSS(css.as_string());
320 }
321
322 }  // namespace extensions