- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_tab_util.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_tab_util.h"
6
7 #include "apps/shell_window.h"
8 #include "apps/shell_window_registry.h"
9 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
10 #include "chrome/browser/extensions/tab_helper.h"
11 #include "chrome/browser/extensions/window_controller.h"
12 #include "chrome/browser/extensions/window_controller_list.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/sessions/session_id.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/browser_finder.h"
17 #include "chrome/browser/ui/browser_iterator.h"
18 #include "chrome/browser/ui/browser_window.h"
19 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
20 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/extensions/extension.h"
23 #include "chrome/common/extensions/manifest_url_handler.h"
24 #include "chrome/common/extensions/permissions/permissions_data.h"
25 #include "chrome/common/net/url_fixer_upper.h"
26 #include "chrome/common/url_constants.h"
27 #include "content/public/browser/favicon_status.h"
28 #include "content/public/browser/navigation_entry.h"
29 #include "content/public/browser/web_contents.h"
30 #include "content/public/browser/web_contents_view.h"
31 #include "extensions/common/manifest_constants.h"
32 #include "extensions/common/permissions/api_permission.h"
33 #include "url/gurl.h"
34
35 namespace keys = extensions::tabs_constants;
36 namespace tabs = extensions::api::tabs;
37
38 using apps::ShellWindow;
39 using content::NavigationEntry;
40 using content::WebContents;
41 using extensions::APIPermission;
42 using extensions::Extension;
43
44 namespace {
45
46 extensions::WindowController* GetShellWindowController(
47     const WebContents* contents) {
48   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
49   apps::ShellWindowRegistry* registry =
50       apps::ShellWindowRegistry::Get(profile);
51   if (!registry)
52     return NULL;
53   ShellWindow* shell_window =
54       registry->GetShellWindowForRenderViewHost(contents->GetRenderViewHost());
55   if (!shell_window)
56     return NULL;
57   return extensions::WindowControllerList::GetInstance()->
58       FindWindowById(shell_window->session_id().id());
59 }
60
61 }  // namespace
62
63 int ExtensionTabUtil::GetWindowId(const Browser* browser) {
64   return browser->session_id().id();
65 }
66
67 int ExtensionTabUtil::GetWindowIdOfTabStripModel(
68     const TabStripModel* tab_strip_model) {
69   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
70     if (it->tab_strip_model() == tab_strip_model)
71       return GetWindowId(*it);
72   }
73   return -1;
74 }
75
76 int ExtensionTabUtil::GetTabId(const WebContents* web_contents) {
77   return SessionID::IdForTab(web_contents);
78 }
79
80 std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) {
81   return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete;
82 }
83
84 int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) {
85   return SessionID::IdForWindowContainingTab(web_contents);
86 }
87
88 DictionaryValue* ExtensionTabUtil::CreateTabValue(
89     const WebContents* contents,
90     TabStripModel* tab_strip,
91     int tab_index,
92     const Extension* extension) {
93   // If we have a matching ShellWindow with a controller, get the tab value
94   // from its controller instead.
95   extensions::WindowController* controller = GetShellWindowController(contents);
96   if (controller &&
97       (!extension || controller->IsVisibleToExtension(extension))) {
98     return controller->CreateTabValue(extension, tab_index);
99   }
100   DictionaryValue *result = CreateTabValue(contents, tab_strip, tab_index);
101   ScrubTabValueForExtension(contents, extension, result);
102   return result;
103 }
104
105 base::ListValue* ExtensionTabUtil::CreateTabList(
106     const Browser* browser,
107     const Extension* extension) {
108   base::ListValue* tab_list = new base::ListValue();
109   TabStripModel* tab_strip = browser->tab_strip_model();
110   for (int i = 0; i < tab_strip->count(); ++i) {
111     tab_list->Append(CreateTabValue(tab_strip->GetWebContentsAt(i),
112                                     tab_strip,
113                                     i,
114                                     extension));
115   }
116
117   return tab_list;
118 }
119
120 DictionaryValue* ExtensionTabUtil::CreateTabValue(
121     const WebContents* contents,
122     TabStripModel* tab_strip,
123     int tab_index) {
124   // If we have a matching ShellWindow with a controller, get the tab value
125   // from its controller instead.
126   extensions::WindowController* controller = GetShellWindowController(contents);
127   if (controller)
128     return controller->CreateTabValue(NULL, tab_index);
129
130   if (!tab_strip)
131     ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index);
132
133   DictionaryValue* result = new DictionaryValue();
134   bool is_loading = contents->IsLoading();
135   result->SetInteger(keys::kIdKey, GetTabId(contents));
136   result->SetInteger(keys::kIndexKey, tab_index);
137   result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents));
138   result->SetString(keys::kStatusKey, GetTabStatusText(is_loading));
139   result->SetBoolean(keys::kActiveKey,
140                      tab_strip && tab_index == tab_strip->active_index());
141   result->SetBoolean(keys::kSelectedKey,
142                      tab_strip && tab_index == tab_strip->active_index());
143   result->SetBoolean(keys::kHighlightedKey,
144                    tab_strip && tab_strip->IsTabSelected(tab_index));
145   result->SetBoolean(keys::kPinnedKey,
146                      tab_strip && tab_strip->IsTabPinned(tab_index));
147   result->SetBoolean(keys::kIncognitoKey,
148                      contents->GetBrowserContext()->IsOffTheRecord());
149   result->SetInteger(keys::kWidthKey,
150                      contents->GetView()->GetContainerSize().width());
151   result->SetInteger(keys::kHeightKey,
152                      contents->GetView()->GetContainerSize().height());
153
154   // Privacy-sensitive fields: these should be stripped off by
155   // ScrubTabValueForExtension if the extension should not see them.
156   result->SetString(keys::kUrlKey, contents->GetURL().spec());
157   result->SetString(keys::kTitleKey, contents->GetTitle());
158   if (!is_loading) {
159     NavigationEntry* entry = contents->GetController().GetVisibleEntry();
160     if (entry && entry->GetFavicon().valid)
161       result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec());
162   }
163
164   if (tab_strip) {
165     WebContents* opener = tab_strip->GetOpenerOfWebContentsAt(tab_index);
166     if (opener)
167       result->SetInteger(keys::kOpenerTabIdKey, GetTabId(opener));
168   }
169
170   return result;
171 }
172
173 void ExtensionTabUtil::ScrubTabValueForExtension(const WebContents* contents,
174                                                  const Extension* extension,
175                                                  DictionaryValue* tab_info) {
176   bool has_permission =
177       extension &&
178       extensions::PermissionsData::HasAPIPermissionForTab(
179           extension, GetTabId(contents), APIPermission::kTab);
180
181   if (!has_permission) {
182     tab_info->Remove(keys::kUrlKey, NULL);
183     tab_info->Remove(keys::kTitleKey, NULL);
184     tab_info->Remove(keys::kFaviconUrlKey, NULL);
185   }
186 }
187
188 void ExtensionTabUtil::ScrubTabForExtension(const Extension* extension,
189                                             tabs::Tab* tab) {
190   bool has_permission = extension && extension->HasAPIPermission(
191       APIPermission::kTab);
192
193   if (!has_permission) {
194     tab->url.reset();
195     tab->title.reset();
196     tab->fav_icon_url.reset();
197   }
198 }
199
200 bool ExtensionTabUtil::GetTabStripModel(const WebContents* web_contents,
201                                         TabStripModel** tab_strip_model,
202                                         int* tab_index) {
203   DCHECK(web_contents);
204   DCHECK(tab_strip_model);
205   DCHECK(tab_index);
206
207   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
208     TabStripModel* tab_strip = it->tab_strip_model();
209     int index = tab_strip->GetIndexOfWebContents(web_contents);
210     if (index != -1) {
211       *tab_strip_model = tab_strip;
212       *tab_index = index;
213       return true;
214     }
215   }
216
217   return false;
218 }
219
220 bool ExtensionTabUtil::GetDefaultTab(Browser* browser,
221                                      WebContents** contents,
222                                      int* tab_id) {
223   DCHECK(browser);
224   DCHECK(contents);
225
226   *contents = browser->tab_strip_model()->GetActiveWebContents();
227   if (*contents) {
228     if (tab_id)
229       *tab_id = GetTabId(*contents);
230     return true;
231   }
232
233   return false;
234 }
235
236 bool ExtensionTabUtil::GetTabById(int tab_id,
237                                   Profile* profile,
238                                   bool include_incognito,
239                                   Browser** browser,
240                                   TabStripModel** tab_strip,
241                                   WebContents** contents,
242                                   int* tab_index) {
243   Profile* incognito_profile =
244       include_incognito && profile->HasOffTheRecordProfile() ?
245           profile->GetOffTheRecordProfile() : NULL;
246   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
247     Browser* target_browser = *it;
248     if (target_browser->profile() == profile ||
249         target_browser->profile() == incognito_profile) {
250       TabStripModel* target_tab_strip = target_browser->tab_strip_model();
251       for (int i = 0; i < target_tab_strip->count(); ++i) {
252         WebContents* target_contents = target_tab_strip->GetWebContentsAt(i);
253         if (SessionID::IdForTab(target_contents) == tab_id) {
254           if (browser)
255             *browser = target_browser;
256           if (tab_strip)
257             *tab_strip = target_tab_strip;
258           if (contents)
259             *contents = target_contents;
260           if (tab_index)
261             *tab_index = i;
262           return true;
263         }
264       }
265     }
266   }
267   return false;
268 }
269
270 GURL ExtensionTabUtil::ResolvePossiblyRelativeURL(const std::string& url_string,
271     const extensions::Extension* extension) {
272   GURL url = GURL(url_string);
273   if (!url.is_valid())
274     url = extension->GetResourceURL(url_string);
275
276   return url;
277 }
278
279 bool ExtensionTabUtil::IsCrashURL(const GURL& url) {
280   // Check a fixed-up URL, to normalize the scheme and parse hosts correctly.
281   GURL fixed_url =
282       URLFixerUpper::FixupURL(url.possibly_invalid_spec(), std::string());
283   return (fixed_url.SchemeIs(chrome::kChromeUIScheme) &&
284           (fixed_url.host() == content::kChromeUIBrowserCrashHost ||
285            fixed_url.host() == chrome::kChromeUICrashHost));
286 }
287
288 void ExtensionTabUtil::CreateTab(WebContents* web_contents,
289                                  const std::string& extension_id,
290                                  WindowOpenDisposition disposition,
291                                  const gfx::Rect& initial_pos,
292                                  bool user_gesture) {
293   Profile* profile =
294       Profile::FromBrowserContext(web_contents->GetBrowserContext());
295   chrome::HostDesktopType active_desktop = chrome::GetActiveDesktop();
296   Browser* browser = chrome::FindTabbedBrowser(profile, false, active_desktop);
297   const bool browser_created = !browser;
298   if (!browser)
299     browser = new Browser(Browser::CreateParams(profile, active_desktop));
300   chrome::NavigateParams params(browser, web_contents);
301
302   // The extension_app_id parameter ends up as app_name in the Browser
303   // which causes the Browser to return true for is_app().  This affects
304   // among other things, whether the location bar gets displayed.
305   // TODO(mpcomplete): This seems wrong. What if the extension content is hosted
306   // in a tab?
307   if (disposition == NEW_POPUP)
308     params.extension_app_id = extension_id;
309
310   params.disposition = disposition;
311   params.window_bounds = initial_pos;
312   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
313   params.user_gesture = user_gesture;
314   chrome::Navigate(&params);
315
316   // Close the browser if chrome::Navigate created a new one.
317   if (browser_created && (browser != params.browser))
318     browser->window()->Close();
319 }
320
321 // static
322 void ExtensionTabUtil::ForEachTab(
323     const base::Callback<void(WebContents*)>& callback) {
324   for (TabContentsIterator iterator; !iterator.done(); iterator.Next())
325     callback.Run(*iterator);
326 }
327
328 // static
329 extensions::WindowController* ExtensionTabUtil::GetWindowControllerOfTab(
330     const WebContents* web_contents) {
331   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
332   if (browser != NULL)
333     return browser->extension_window_controller();
334
335   return NULL;
336 }
337
338 void ExtensionTabUtil::OpenOptionsPage(const Extension* extension,
339                                        Browser* browser) {
340   DCHECK(!extensions::ManifestURL::GetOptionsPage(extension).is_empty());
341
342   // Force the options page to open in non-OTR window, because it won't be
343   // able to save settings from OTR.
344   scoped_ptr<chrome::ScopedTabbedBrowserDisplayer> displayer;
345   if (browser->profile()->IsOffTheRecord()) {
346     displayer.reset(new chrome::ScopedTabbedBrowserDisplayer(
347         browser->profile()->GetOriginalProfile(),
348         browser->host_desktop_type()));
349     browser = displayer->browser();
350   }
351
352   content::OpenURLParams params(
353       extensions::ManifestURL::GetOptionsPage(extension),
354       content::Referrer(), SINGLETON_TAB,
355       content::PAGE_TRANSITION_LINK, false);
356   browser->OpenURL(params);
357   browser->window()->Show();
358   WebContents* web_contents =
359       browser->tab_strip_model()->GetActiveWebContents();
360   web_contents->GetDelegate()->ActivateContents(web_contents);
361 }