web_app.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/web_applications/web_app.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/file_util_icu.h"
11e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/prefs/pref_service.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
15e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/browser/extensions/image_loader.h"
16e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/browser/profiles/profile.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/chrome_version_info.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
20e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
21e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/common/pref_names.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h"
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
26e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "grit/theme_resources.h"
27e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "skia/ext/image_operations.h"
28e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
29e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "ui/base/resource/resource_bundle.h"
30e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "ui/gfx/image/image.h"
31e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "ui/gfx/image/image_family.h"
32e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "ui/gfx/image/image_skia.h"
33e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
34e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#if defined(OS_WIN)
35e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "ui/gfx/icon_util.h"
36e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#endif
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#if defined(OS_MACOSX)
43e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst int kDesiredSizes[] = {16, 32, 128, 256, 512};
44e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst size_t kNumDesiredSizes = arraysize(kDesiredSizes);
45e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#elif defined(OS_LINUX)
46e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Linux supports icons of any size. FreeDesktop Icon Theme Specification states
47e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// that "Minimally you should install a 48x48 icon in the hicolor theme."
48e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst int kDesiredSizes[] = {16, 32, 48, 128, 256, 512};
49e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst size_t kNumDesiredSizes = arraysize(kDesiredSizes);
50e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#elif defined(OS_WIN)
51e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst int* kDesiredSizes = IconUtil::kIconDimensions;
52e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst size_t kNumDesiredSizes = IconUtil::kNumIconDimensions;
53e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#else
54e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst int kDesiredSizes[] = {32};
55e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst size_t kNumDesiredSizes = arraysize(kDesiredSizes);
56e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#endif
57e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_VIEWS)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Predicator for sorting images from largest to smallest.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  const WebApplicationInfo::IconInfo& right) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return left.width < right.width;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeleteShortcutsOnFileThread(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ShellIntegration::ShortcutInfo& shortcut_info) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_info.profile_path, shortcut_info.extension_id, GURL());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return web_app::internals::DeletePlatformShortcuts(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_data_dir, shortcut_info);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutsOnFileThread(
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& old_app_title,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ShellIntegration::ShortcutInfo& shortcut_info) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_info.profile_path, shortcut_info.extension_id, GURL());
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return web_app::internals::UpdatePlatformShortcuts(
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      shortcut_data_dir, old_app_title, shortcut_info);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
87e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid OnImageLoaded(ShellIntegration::ShortcutInfo shortcut_info,
88e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   web_app::ShortcutInfoCallback callback,
89e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   const gfx::ImageFamily& image_family) {
90e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // If the image failed to load (e.g. if the resource being loaded was empty)
91e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // use the standard application icon.
92e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (image_family.empty()) {
93e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    gfx::Image default_icon =
94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON);
95e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    int size = kDesiredSizes[kNumDesiredSizes - 1];
96e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    SkBitmap bmp = skia::ImageOperations::Resize(
97e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
98e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          size, size);
99e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp);
100e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // We are on the UI thread, and this image is needed from the FILE thread,
101e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // for creating shortcut icon files.
102e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    image_skia.MakeThreadSafe();
103e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    shortcut_info.favicon.Add(gfx::Image(image_skia));
104e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  } else {
105e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    shortcut_info.favicon = image_family;
106e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
107e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
108e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  callback.Run(shortcut_info);
109e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace web_app {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following string is used to build the directory name for
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shortcuts to chrome applications (the kind which are installed
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from a CRX).  Application shortcuts to URLs use the {host}_{path}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for the name of this directory.  Hosts can't include an underscore.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// By starting this string with an underscore, we ensure that there
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are no naming conflicts.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char* kCrxAppPrefix = "_crx_";
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internals {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)base::FilePath GetSanitizedFileName(const base::string16& name) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 file_name = name;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string file_name = base::UTF16ToUTF8(name);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_util::ReplaceIllegalCharactersInPath(&file_name, '_');
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return base::FilePath(file_name);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internals
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
137e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochShellIntegration::ShortcutInfo ShortcutInfoForExtensionAndProfile(
138e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const extensions::Extension* app, Profile* profile) {
139e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ShellIntegration::ShortcutInfo shortcut_info;
140e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.extension_id = app->id();
141e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.is_platform_app = app->is_platform_app();
142e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.url = extensions::AppLaunchInfo::GetLaunchWebURL(app);
143e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.title = base::UTF8ToUTF16(app->name());
144e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.description = base::UTF8ToUTF16(app->description());
145e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.extension_path = app->path();
146e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.profile_path = profile->GetPath();
147e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  shortcut_info.profile_name =
148e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      profile->GetPrefs()->GetString(prefs::kProfileName);
149e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  return shortcut_info;
150e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
151e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
152e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid UpdateShortcutInfoAndIconForApp(
153e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const extensions::Extension* extension,
154e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    Profile* profile,
155e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    const web_app::ShortcutInfoCallback& callback) {
156e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ShellIntegration::ShortcutInfo shortcut_info =
157e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      ShortcutInfoForExtensionAndProfile(extension, profile);
158e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
159e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
160e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (size_t i = 0; i < kNumDesiredSizes; ++i) {
161e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    int size = kDesiredSizes[i];
162e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    extensions::ExtensionResource resource =
163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        extensions::IconsInfo::GetIconResource(
164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            extension, size, ExtensionIconSet::MATCH_EXACTLY);
165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!resource.empty()) {
166e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      info_list.push_back(extensions::ImageLoader::ImageRepresentation(
167e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          resource,
168e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
169e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          gfx::Size(size, size),
170e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          ui::SCALE_FACTOR_100P));
171e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
172e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
173e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
174e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (info_list.empty()) {
175e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    size_t i = kNumDesiredSizes - 1;
176e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    int size = kDesiredSizes[i];
177e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
178e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // If there is no icon at the desired sizes, we will resize what we can get.
179e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // Making a large icon smaller is preferred to making a small icon larger,
180e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // so look for a larger icon first:
181e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    extensions::ExtensionResource resource =
182e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        extensions::IconsInfo::GetIconResource(
183e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch            extension, size, ExtensionIconSet::MATCH_BIGGER);
184e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (resource.empty()) {
185e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      resource = extensions::IconsInfo::GetIconResource(
186e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          extension, size, ExtensionIconSet::MATCH_SMALLER);
187e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
188e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    info_list.push_back(extensions::ImageLoader::ImageRepresentation(
189e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        resource,
190e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
191e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        gfx::Size(size, size),
192e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        ui::SCALE_FACTOR_100P));
193e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
194e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
195e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // |info_list| may still be empty at this point, in which case
196e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty
197e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // image and exit immediately.
198e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync(
199e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      extension,
200e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      info_list,
201e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::Bind(&OnImageLoaded, shortcut_info, callback));
202e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
203e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& extension_id,
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const GURL& url) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!profile_path.empty());
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension_id.empty()) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return app_data_dir.AppendASCII(
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GenerateApplicationNameFromExtensionId(extension_id));
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string host(url.host());
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme(url.has_scheme() ? url.scheme() : "http");
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string port(url.has_port() ? url.port() : "80");
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string scheme_port(scheme + "_" + port);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath::StringType host_path(base::UTF8ToUTF16(host));
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath::StringType scheme_port_path(base::UTF8ToUTF16(scheme_port));
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType host_path(host);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath::StringType scheme_port_path(scheme_port);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return app_data_dir.Append(host_path).Append(scheme_port_path);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const extensions::Extension& extension) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetWebAppDataDirectory(
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      profile_path,
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension.id(),
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      GURL(extensions::AppLaunchInfo::GetLaunchWebURL(&extension)));
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GenerateApplicationNameFromInfo(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ShellIntegration::ShortcutInfo& shortcut_info) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!shortcut_info.extension_id.empty()) {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return web_app::GenerateApplicationNameFromExtensionId(
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shortcut_info.extension_id);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return web_app::GenerateApplicationNameFromURL(
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        shortcut_info.url);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GenerateApplicationNameFromURL(const GURL& url) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string t;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  t.append(url.host());
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  t.append("_");
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  t.append(url.path());
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return t;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GenerateApplicationNameFromExtensionId(const std::string& id) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string t(web_app::kCrxAppPrefix);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  t.append(id);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return t;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string prefix(kCrxAppPrefix);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (app_name.substr(0, prefix.length()) != prefix)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return std::string();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return app_name.substr(prefix.length());
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void CreateShortcuts(
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ShellIntegration::ShortcutInfo& shortcut_info,
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const ShellIntegration::ShortcutLocations& creation_locations,
274558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    ShortcutCreationReason creation_reason) {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(base::IgnoreResult(&CreateShortcutsOnFileThread),
281558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                 shortcut_info, creation_locations, creation_reason));
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&DeleteShortcutsOnFileThread, shortcut_info));
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void UpdateAllShortcuts(const base::string16& old_app_title,
29490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                        const ShellIntegration::ShortcutInfo& shortcut_info) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE,
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
30090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::Bind(&UpdateShortcutsOnFileThread, old_app_title, shortcut_info));
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateShortcutsOnFileThread(
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ShellIntegration::ShortcutInfo& shortcut_info,
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const ShellIntegration::ShortcutLocations& creation_locations,
306558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    ShortcutCreationReason creation_reason) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath shortcut_data_dir = GetWebAppDataDirectory(
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_info.profile_path, shortcut_info.extension_id,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_info.url);
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return internals::CreatePlatformShortcuts(shortcut_data_dir, shortcut_info,
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                            creation_locations,
314558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                                            creation_reason);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsValidUrl(const GURL& url) {
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const char* const kValidUrlSchemes[] = {
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::kFileScheme,
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      content::kFileSystemScheme,
321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      content::kFtpScheme,
322d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      content::kHttpScheme,
323424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      content::kHttpsScheme,
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::kExtensionScheme,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(kValidUrlSchemes); ++i) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (url.SchemeIs(kValidUrlSchemes[i]))
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(TOOLKIT_VIEWS)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetIconsInfo(const WebApplicationInfo& app_info,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  IconInfoList* icons) {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(icons);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icons->clear();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < app_info.icons.size(); ++i) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only take square shaped icons (i.e. width == height).
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (app_info.icons[i].width == app_info.icons[i].height) {
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      icons->push_back(app_info.icons[i]);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::sort(icons->begin(), icons->end(), &IconPrecedes);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
35258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#if defined(OS_LINUX)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string GetWMClassFromAppName(std::string app_name) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_util::ReplaceIllegalCharactersInPath(&app_name, '_');
355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::TrimString(app_name, "_", &app_name);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return app_name;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace web_app
361