blob: adc1dc55c14a64731be6ccdd60d59945b73a2ddf [file] [log] [blame]
[email protected]178f8512012-02-09 01:49:361// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ed5431872009-11-17 08:39:512// 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/web_applications/web_app.h"
6
[email protected]87212702011-12-08 21:17:197#include "base/bind.h"
[email protected]8806d3b2012-04-13 06:46:348#include "base/bind_helpers.h"
thestig18dfb7a52014-08-26 10:44:049#include "base/files/file_util.h"
[email protected]a0b60cfd2011-04-06 18:02:4110#include "base/i18n/file_util_icu.h"
[email protected]f18d37ef2014-04-01 11:17:4211#include "base/prefs/pref_service.h"
[email protected]9f0abdb2013-06-10 21:49:3412#include "base/strings/string_util.h"
[email protected]e309f312013-06-07 21:50:0813#include "base/strings/utf_string_conversions.h"
[email protected]7f070d42011-03-09 20:25:3214#include "base/threading/thread.h"
mitchelljones1c301022014-12-11 00:38:4715#include "chrome/browser/browser_process.h"
[email protected]090e1ee72014-06-03 13:08:4016#include "chrome/browser/extensions/extension_ui_util.h"
[email protected]f18d37ef2014-04-01 11:17:4217#include "chrome/browser/profiles/profile.h"
mitchelljones1c301022014-12-11 00:38:4718#include "chrome/browser/profiles/profile_manager.h"
[email protected]eabfdae92009-12-11 06:13:5119#include "chrome/common/chrome_constants.h"
[email protected]9922e922013-05-06 08:09:5520#include "chrome/common/chrome_version_info.h"
[email protected]6b414c232013-06-05 07:53:3421#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
[email protected]f18d37ef2014-04-01 11:17:4222#include "chrome/common/pref_names.h"
[email protected]c38831a12011-10-28 12:44:4923#include "content/public/browser/browser_thread.h"
[email protected]090e1ee72014-06-03 13:08:4024#include "extensions/browser/extension_registry.h"
[email protected]326e6f02014-06-20 04:53:3725#include "extensions/browser/image_loader.h"
[email protected]885c0e92012-11-13 20:27:4226#include "extensions/common/constants.h"
[email protected]e4452d32013-11-15 23:07:4127#include "extensions/common/extension.h"
[email protected]090e1ee72014-06-03 13:08:4028#include "extensions/common/extension_set.h"
[email protected]0db486f2014-04-09 19:32:2229#include "extensions/common/manifest_handlers/icons_handler.h"
mukai4245dfe82014-09-05 17:40:5130#include "extensions/grit/extensions_browser_resources.h"
[email protected]f18d37ef2014-04-01 11:17:4231#include "skia/ext/image_operations.h"
32#include "third_party/skia/include/core/SkBitmap.h"
33#include "ui/base/resource/resource_bundle.h"
34#include "ui/gfx/image/image.h"
35#include "ui/gfx/image/image_family.h"
36#include "ui/gfx/image/image_skia.h"
[email protected]cca6f392014-05-28 21:32:2637#include "url/url_constants.h"
[email protected]f18d37ef2014-04-01 11:17:4238
39#if defined(OS_WIN)
40#include "ui/gfx/icon_util.h"
41#endif
[email protected]ed5431872009-11-17 08:39:5142
[email protected]c7264f42014-06-22 21:23:0943#if defined(TOOLKIT_VIEWS)
44#include "chrome/browser/extensions/tab_helper.h"
45#include "chrome/browser/favicon/favicon_tab_helper.h"
46#endif
47
[email protected]631bb742011-11-02 11:29:3948using content::BrowserThread;
49
[email protected]ed5431872009-11-17 08:39:5150namespace {
51
[email protected]f18d37ef2014-04-01 11:17:4252#if defined(OS_MACOSX)
53const int kDesiredSizes[] = {16, 32, 128, 256, 512};
54const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
55#elif defined(OS_LINUX)
56// Linux supports icons of any size. FreeDesktop Icon Theme Specification states
57// that "Minimally you should install a 48x48 icon in the hicolor theme."
58const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512};
59const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
60#elif defined(OS_WIN)
61const int* kDesiredSizes = IconUtil::kIconDimensions;
62const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions;
63#else
64const int kDesiredSizes[] = {32};
65const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
66#endif
67
[email protected]16f765632010-09-21 21:31:2768#if defined(TOOLKIT_VIEWS)
[email protected]eabfdae92009-12-11 06:13:5169// Predicator for sorting images from largest to smallest.
[email protected]38789d82010-11-17 06:03:4470bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
71 const WebApplicationInfo::IconInfo& right) {
[email protected]eabfdae92009-12-11 06:13:5172 return left.width < right.width;
73}
[email protected]16f765632010-09-21 21:31:2774#endif
[email protected]eabfdae92009-12-11 06:13:5175
[email protected]238dd7b2014-05-23 07:07:2076base::FilePath GetShortcutDataDir(const web_app::ShortcutInfo& shortcut_info) {
77 return web_app::GetWebAppDataDirectory(shortcut_info.profile_path,
78 shortcut_info.extension_id,
79 shortcut_info.url);
[email protected]e66ba952012-10-09 09:59:4480}
81
[email protected]e6be3fe2014-04-11 13:17:5182void UpdateAllShortcutsForShortcutInfo(
83 const base::string16& old_app_title,
[email protected]2e0424a2014-04-15 13:02:1584 const web_app::ShortcutInfo& shortcut_info,
[email protected]e6be3fe2014-04-11 13:17:5185 const extensions::FileHandlersInfo& file_handlers_info) {
86 BrowserThread::PostTask(
87 BrowserThread::FILE,
88 FROM_HERE,
[email protected]238dd7b2014-05-23 07:07:2089 base::Bind(&web_app::internals::UpdatePlatformShortcuts,
90 GetShortcutDataDir(shortcut_info),
[email protected]e6be3fe2014-04-11 13:17:5191 old_app_title, shortcut_info, file_handlers_info));
[email protected]14885082014-04-08 04:41:2892}
93
[email protected]2e0424a2014-04-15 13:02:1594void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
[email protected]e6be3fe2014-04-11 13:17:5195 extensions::FileHandlersInfo file_handlers_info,
[email protected]5bbfbae2014-06-18 18:26:3896 web_app::InfoCallback callback,
[email protected]f18d37ef2014-04-01 11:17:4297 const gfx::ImageFamily& image_family) {
98 // If the image failed to load (e.g. if the resource being loaded was empty)
99 // use the standard application icon.
100 if (image_family.empty()) {
101 gfx::Image default_icon =
102 ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON);
103 int size = kDesiredSizes[kNumDesiredSizes - 1];
104 SkBitmap bmp = skia::ImageOperations::Resize(
105 *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
106 size, size);
107 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp);
108 // We are on the UI thread, and this image is needed from the FILE thread,
109 // for creating shortcut icon files.
110 image_skia.MakeThreadSafe();
111 shortcut_info.favicon.Add(gfx::Image(image_skia));
112 } else {
113 shortcut_info.favicon = image_family;
114 }
115
[email protected]e6be3fe2014-04-11 13:17:51116 callback.Run(shortcut_info, file_handlers_info);
117}
118
[email protected]5bbfbae2014-06-18 18:26:38119void IgnoreFileHandlersInfo(
120 const web_app::ShortcutInfoCallback& shortcut_info_callback,
121 const web_app::ShortcutInfo& shortcut_info,
122 const extensions::FileHandlersInfo& file_handlers_info) {
123 shortcut_info_callback.Run(shortcut_info);
124}
125
mitchelljones421df67c2014-12-18 03:06:50126void ScheduleCreatePlatformShortcut(
127 web_app::ShortcutCreationReason reason,
128 const web_app::ShortcutLocations& locations,
129 const web_app::ShortcutInfo& shortcut_info,
130 const extensions::FileHandlersInfo& file_handlers_info) {
131 BrowserThread::PostTask(
132 BrowserThread::FILE, FROM_HERE,
133 base::Bind(
134 base::IgnoreResult(&web_app::internals::CreatePlatformShortcuts),
135 GetShortcutDataDir(shortcut_info), shortcut_info, file_handlers_info,
136 locations, reason));
137}
138
[email protected]5bbfbae2014-06-18 18:26:38139} // namespace
140
141namespace web_app {
142
143// The following string is used to build the directory name for
144// shortcuts to chrome applications (the kind which are installed
145// from a CRX). Application shortcuts to URLs use the {host}_{path}
146// for the name of this directory. Hosts can't include an underscore.
147// By starting this string with an underscore, we ensure that there
148// are no naming conflicts.
149static const char kCrxAppPrefix[] = "_crx_";
150
151namespace internals {
152
[email protected]0085863a2013-12-06 21:19:03153base::FilePath GetSanitizedFileName(const base::string16& name) {
[email protected]b6b72222012-02-11 02:04:13154#if defined(OS_WIN)
[email protected]0085863a2013-12-06 21:19:03155 base::string16 file_name = name;
[email protected]b6b72222012-02-11 02:04:13156#else
[email protected]ab6df3b12013-12-24 23:32:26157 std::string file_name = base::UTF16ToUTF8(name);
[email protected]b6b72222012-02-11 02:04:13158#endif
[email protected]6bc03de2014-08-07 23:59:15159 base::i18n::ReplaceIllegalCharactersInPath(&file_name, '_');
[email protected]650b2d52013-02-10 03:41:45160 return base::FilePath(file_name);
[email protected]b6b72222012-02-11 02:04:13161}
162
[email protected]f847e6082011-03-24 00:08:26163} // namespace internals
164
[email protected]9b1b5fe2014-05-15 08:23:17165ShortcutInfo::ShortcutInfo()
[email protected]2e0424a2014-04-15 13:02:15166 : is_platform_app(false) {
167}
168
[email protected]9b1b5fe2014-05-15 08:23:17169ShortcutInfo::~ShortcutInfo() {}
[email protected]2e0424a2014-04-15 13:02:15170
[email protected]9b1b5fe2014-05-15 08:23:17171ShortcutLocations::ShortcutLocations()
[email protected]2e0424a2014-04-15 13:02:15172 : on_desktop(false),
173 applications_menu_location(APP_MENU_LOCATION_NONE),
[email protected]da0349e2014-06-11 07:38:28174 in_quick_launch_bar(false) {
[email protected]2e0424a2014-04-15 13:02:15175}
176
[email protected]c7264f42014-06-22 21:23:09177#if defined(TOOLKIT_VIEWS)
[email protected]2d1d16f2014-04-03 18:18:05178void GetShortcutInfoForTab(content::WebContents* web_contents,
[email protected]9b1b5fe2014-05-15 08:23:17179 ShortcutInfo* info) {
[email protected]2d1d16f2014-04-03 18:18:05180 DCHECK(info); // Must provide a valid info.
181
182 const FaviconTabHelper* favicon_tab_helper =
183 FaviconTabHelper::FromWebContents(web_contents);
184 const extensions::TabHelper* extensions_tab_helper =
185 extensions::TabHelper::FromWebContents(web_contents);
186 const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info();
187
188 info->url = app_info.app_url.is_empty() ? web_contents->GetURL() :
189 app_info.app_url;
190 info->title = app_info.title.empty() ?
191 (web_contents->GetTitle().empty() ? base::UTF8ToUTF16(info->url.spec()) :
192 web_contents->GetTitle()) :
193 app_info.title;
194 info->description = app_info.description;
195 info->favicon.Add(favicon_tab_helper->GetFavicon());
196
197 Profile* profile =
198 Profile::FromBrowserContext(web_contents->GetBrowserContext());
199 info->profile_path = profile->GetPath();
200}
[email protected]c7264f42014-06-22 21:23:09201#endif
[email protected]2d1d16f2014-04-03 18:18:05202
203#if !defined(OS_WIN)
204void UpdateShortcutForTabContents(content::WebContents* web_contents) {}
205#endif
206
[email protected]9b1b5fe2014-05-15 08:23:17207ShortcutInfo ShortcutInfoForExtensionAndProfile(
[email protected]f18d37ef2014-04-01 11:17:42208 const extensions::Extension* app, Profile* profile) {
[email protected]9b1b5fe2014-05-15 08:23:17209 ShortcutInfo shortcut_info;
[email protected]f18d37ef2014-04-01 11:17:42210 shortcut_info.extension_id = app->id();
211 shortcut_info.is_platform_app = app->is_platform_app();
212 shortcut_info.url = extensions::AppLaunchInfo::GetLaunchWebURL(app);
213 shortcut_info.title = base::UTF8ToUTF16(app->name());
214 shortcut_info.description = base::UTF8ToUTF16(app->description());
215 shortcut_info.extension_path = app->path();
216 shortcut_info.profile_path = profile->GetPath();
217 shortcut_info.profile_name =
218 profile->GetPrefs()->GetString(prefs::kProfileName);
219 return shortcut_info;
220}
221
[email protected]e886528e2014-07-01 10:18:41222void GetInfoForApp(const extensions::Extension* extension,
223 Profile* profile,
224 const InfoCallback& callback) {
225 web_app::ShortcutInfo shortcut_info =
226 web_app::ShortcutInfoForExtensionAndProfile(extension, profile);
227 const std::vector<extensions::FileHandlerInfo>* file_handlers =
228 extensions::FileHandlers::GetFileHandlers(extension);
229 extensions::FileHandlersInfo file_handlers_info =
230 file_handlers ? *file_handlers : extensions::FileHandlersInfo();
231
232 std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
233 for (size_t i = 0; i < kNumDesiredSizes; ++i) {
234 int size = kDesiredSizes[i];
235 extensions::ExtensionResource resource =
236 extensions::IconsInfo::GetIconResource(
237 extension, size, ExtensionIconSet::MATCH_EXACTLY);
238 if (!resource.empty()) {
239 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
240 resource,
241 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
242 gfx::Size(size, size),
243 ui::SCALE_FACTOR_100P));
244 }
245 }
246
247 if (info_list.empty()) {
248 size_t i = kNumDesiredSizes - 1;
249 int size = kDesiredSizes[i];
250
251 // If there is no icon at the desired sizes, we will resize what we can get.
252 // Making a large icon smaller is preferred to making a small icon larger,
253 // so look for a larger icon first:
254 extensions::ExtensionResource resource =
255 extensions::IconsInfo::GetIconResource(
256 extension, size, ExtensionIconSet::MATCH_BIGGER);
257 if (resource.empty()) {
258 resource = extensions::IconsInfo::GetIconResource(
259 extension, size, ExtensionIconSet::MATCH_SMALLER);
260 }
261 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
262 resource,
263 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
264 gfx::Size(size, size),
265 ui::SCALE_FACTOR_100P));
266 }
267
268 // |info_list| may still be empty at this point, in which case
269 // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty
270 // image and exit immediately.
271 extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync(
272 extension,
273 info_list,
274 base::Bind(&OnImageLoaded, shortcut_info, file_handlers_info, callback));
275}
276
277void GetShortcutInfoForApp(const extensions::Extension* extension,
278 Profile* profile,
279 const ShortcutInfoCallback& callback) {
280 GetInfoForApp(
[email protected]5bbfbae2014-06-18 18:26:38281 extension, profile, base::Bind(&IgnoreFileHandlersInfo, callback));
[email protected]f18d37ef2014-04-01 11:17:42282}
283
[email protected]090e1ee72014-06-03 13:08:40284bool ShouldCreateShortcutFor(Profile* profile,
285 const extensions::Extension* extension) {
mitchelljones1c301022014-12-11 00:38:47286 bool app_type_requires_shortcut = extension->is_platform_app();
287
288// An additional check here for OS X. We need app shims to be
289// able to show them in the dock.
290#if defined(OS_MACOSX)
291 app_type_requires_shortcut =
292 app_type_requires_shortcut || extension->is_hosted_app();
293#endif
294
295 return (app_type_requires_shortcut &&
296 extension->location() != extensions::Manifest::COMPONENT &&
297 extensions::ui_util::CanDisplayInAppLauncher(extension, profile));
[email protected]090e1ee72014-06-03 13:08:40298}
299
[email protected]650b2d52013-02-10 03:41:45300base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
301 const std::string& extension_id,
302 const GURL& url) {
[email protected]c002e752012-08-10 12:50:11303 DCHECK(!profile_path.empty());
[email protected]650b2d52013-02-10 03:41:45304 base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
[email protected]2b80909f2012-02-24 04:50:21305
306 if (!extension_id.empty()) {
307 return app_data_dir.AppendASCII(
308 GenerateApplicationNameFromExtensionId(extension_id));
309 }
310
311 std::string host(url.host());
312 std::string scheme(url.has_scheme() ? url.scheme() : "http");
313 std::string port(url.has_port() ? url.port() : "80");
314 std::string scheme_port(scheme + "_" + port);
315
316#if defined(OS_WIN)
[email protected]ab6df3b12013-12-24 23:32:26317 base::FilePath::StringType host_path(base::UTF8ToUTF16(host));
318 base::FilePath::StringType scheme_port_path(base::UTF8ToUTF16(scheme_port));
[email protected]2b80909f2012-02-24 04:50:21319#elif defined(OS_POSIX)
[email protected]650b2d52013-02-10 03:41:45320 base::FilePath::StringType host_path(host);
321 base::FilePath::StringType scheme_port_path(scheme_port);
[email protected]2b80909f2012-02-24 04:50:21322#endif
323
324 return app_data_dir.Append(host_path).Append(scheme_port_path);
325}
326
[email protected]650b2d52013-02-10 03:41:45327base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
328 const extensions::Extension& extension) {
[email protected]2b80909f2012-02-24 04:50:21329 return GetWebAppDataDirectory(
[email protected]6b414c232013-06-05 07:53:34330 profile_path,
331 extension.id(),
332 GURL(extensions::AppLaunchInfo::GetLaunchWebURL(&extension)));
[email protected]2b80909f2012-02-24 04:50:21333}
334
[email protected]9b1b5fe2014-05-15 08:23:17335std::string GenerateApplicationNameFromInfo(const ShortcutInfo& shortcut_info) {
[email protected]238dd7b2014-05-23 07:07:20336 if (!shortcut_info.extension_id.empty())
[email protected]9b1b5fe2014-05-15 08:23:17337 return GenerateApplicationNameFromExtensionId(shortcut_info.extension_id);
[email protected]238dd7b2014-05-23 07:07:20338 else
[email protected]9b1b5fe2014-05-15 08:23:17339 return GenerateApplicationNameFromURL(shortcut_info.url);
[email protected]a0b60cfd2011-04-06 18:02:41340}
341
[email protected]57ecc4b2010-08-11 03:02:51342std::string GenerateApplicationNameFromURL(const GURL& url) {
[email protected]86b54012009-11-19 09:18:50343 std::string t;
344 t.append(url.host());
345 t.append("_");
346 t.append(url.path());
[email protected]57ecc4b2010-08-11 03:02:51347 return t;
[email protected]86b54012009-11-19 09:18:50348}
349
[email protected]2f1c09d2011-01-14 14:58:14350std::string GenerateApplicationNameFromExtensionId(const std::string& id) {
[email protected]9b1b5fe2014-05-15 08:23:17351 std::string t(kCrxAppPrefix);
[email protected]2f1c09d2011-01-14 14:58:14352 t.append(id);
353 return t;
354}
355
[email protected]edee3faf2011-05-25 21:40:10356std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
357 std::string prefix(kCrxAppPrefix);
358 if (app_name.substr(0, prefix.length()) != prefix)
359 return std::string();
360 return app_name.substr(prefix.length());
361}
362
[email protected]371bd2e2014-07-01 07:10:02363void CreateShortcutsWithInfo(
364 ShortcutCreationReason reason,
365 const ShortcutLocations& locations,
366 const ShortcutInfo& shortcut_info,
367 const extensions::FileHandlersInfo& file_handlers_info) {
[email protected]0b7df36d2012-07-11 09:50:47368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
369
mitchelljones1c301022014-12-11 00:38:47370 // It's possible for the extension to be deleted before we get here.
371 // For example, creating a hosted app from a website. Double check that
372 // it still exists.
373 Profile* profile = g_browser_process->profile_manager()->GetProfileByPath(
374 shortcut_info.profile_path);
375 if (!profile)
376 return;
377
378 extensions::ExtensionRegistry* registry =
379 extensions::ExtensionRegistry::Get(profile);
380 const extensions::Extension* extension = registry->GetExtensionById(
381 shortcut_info.extension_id, extensions::ExtensionRegistry::ENABLED);
382 if (!extension)
383 return;
384
mitchelljones421df67c2014-12-18 03:06:50385 ScheduleCreatePlatformShortcut(reason, locations, shortcut_info,
386 file_handlers_info);
387}
388
389void CreateNonAppShortcut(const ShortcutLocations& locations,
390 const ShortcutInfo& shortcut_info) {
391 ScheduleCreatePlatformShortcut(SHORTCUT_CREATION_AUTOMATED, locations,
392 shortcut_info, extensions::FileHandlersInfo());
[email protected]f8a31292014-04-04 05:45:56393}
394
[email protected]9b1b5fe2014-05-15 08:23:17395void CreateShortcuts(ShortcutCreationReason reason,
396 const ShortcutLocations& locations,
397 Profile* profile,
398 const extensions::Extension* app) {
[email protected]14885082014-04-08 04:41:28399 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
400
[email protected]090e1ee72014-06-03 13:08:40401 if (!ShouldCreateShortcutFor(profile, app))
402 return;
403
[email protected]e886528e2014-07-01 10:18:41404 GetInfoForApp(
[email protected]5bbfbae2014-06-18 18:26:38405 app, profile, base::Bind(&CreateShortcutsWithInfo, reason, locations));
[email protected]14885082014-04-08 04:41:28406}
407
408void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app) {
[email protected]f8a31292014-04-04 05:45:56409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
410
[email protected]238dd7b2014-05-23 07:07:20411 ShortcutInfo shortcut_info =
412 ShortcutInfoForExtensionAndProfile(app, profile);
[email protected]f8a31292014-04-04 05:45:56413 BrowserThread::PostTask(
414 BrowserThread::FILE,
415 FROM_HERE,
[email protected]238dd7b2014-05-23 07:07:20416 base::Bind(&web_app::internals::DeletePlatformShortcuts,
417 GetShortcutDataDir(shortcut_info), shortcut_info));
[email protected]ed5431872009-11-17 08:39:51418}
419
[email protected]0085863a2013-12-06 21:19:03420void UpdateAllShortcuts(const base::string16& old_app_title,
[email protected]14885082014-04-08 04:41:28421 Profile* profile,
422 const extensions::Extension* app) {
[email protected]e66ba952012-10-09 09:59:44423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
424
[email protected]e886528e2014-07-01 10:18:41425 GetInfoForApp(app,
426 profile,
427 base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
[email protected]8806d3b2012-04-13 06:46:34428}
429
[email protected]12ea22a2009-11-19 07:17:23430bool IsValidUrl(const GURL& url) {
431 static const char* const kValidUrlSchemes[] = {
[email protected]cca6f392014-05-28 21:32:26432 url::kFileScheme,
433 url::kFileSystemScheme,
434 url::kFtpScheme,
[email protected]e8ca69c2014-05-07 15:31:19435 url::kHttpScheme,
436 url::kHttpsScheme,
[email protected]885c0e92012-11-13 20:27:42437 extensions::kExtensionScheme,
[email protected]12ea22a2009-11-19 07:17:23438 };
439
440 for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
441 if (url.SchemeIs(kValidUrlSchemes[i]))
442 return true;
443 }
444
445 return false;
446}
447
[email protected]be3df2b2010-06-25 21:39:07448#if defined(TOOLKIT_VIEWS)
[email protected]38789d82010-11-17 06:03:44449void GetIconsInfo(const WebApplicationInfo& app_info,
[email protected]eabfdae92009-12-11 06:13:51450 IconInfoList* icons) {
451 DCHECK(icons);
452
453 icons->clear();
454 for (size_t i = 0; i < app_info.icons.size(); ++i) {
455 // We only take square shaped icons (i.e. width == height).
456 if (app_info.icons[i].width == app_info.icons[i].height) {
457 icons->push_back(app_info.icons[i]);
458 }
459 }
460
461 std::sort(icons->begin(), icons->end(), &IconPrecedes);
462}
[email protected]be3df2b2010-06-25 21:39:07463#endif
[email protected]eabfdae92009-12-11 06:13:51464
[email protected]f93a77452013-09-02 05:26:35465#if defined(OS_LINUX)
[email protected]a0b60cfd2011-04-06 18:02:41466std::string GetWMClassFromAppName(std::string app_name) {
[email protected]6bc03de2014-08-07 23:59:15467 base::i18n::ReplaceIllegalCharactersInPath(&app_name, '_');
[email protected]466c9862013-12-03 22:05:28468 base::TrimString(app_name, "_", &app_name);
[email protected]a0b60cfd2011-04-06 18:02:41469 return app_name;
470}
471#endif
472
[email protected]f847e6082011-03-24 00:08:26473} // namespace web_app