| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/web_applications/web_app.h" | 5 #include "chrome/browser/web_applications/web_app.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
| 10 #include "base/i18n/file_util_icu.h" | 10 #include "base/i18n/file_util_icu.h" |
| 11 #include "base/prefs/pref_service.h" |
| 11 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/threading/thread.h" | 14 #include "base/threading/thread.h" |
| 15 #include "chrome/browser/extensions/image_loader.h" |
| 16 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/common/chrome_constants.h" | 17 #include "chrome/common/chrome_constants.h" |
| 15 #include "chrome/common/chrome_version_info.h" | 18 #include "chrome/common/chrome_version_info.h" |
| 16 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | 19 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" |
| 20 #include "chrome/common/extensions/manifest_handlers/icons_handler.h" |
| 21 #include "chrome/common/pref_names.h" |
| 17 #include "chrome/common/url_constants.h" | 22 #include "chrome/common/url_constants.h" |
| 18 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
| 19 #include "extensions/common/constants.h" | 24 #include "extensions/common/constants.h" |
| 20 #include "extensions/common/extension.h" | 25 #include "extensions/common/extension.h" |
| 26 #include "grit/theme_resources.h" |
| 27 #include "skia/ext/image_operations.h" |
| 28 #include "third_party/skia/include/core/SkBitmap.h" |
| 29 #include "ui/base/resource/resource_bundle.h" |
| 30 #include "ui/gfx/image/image.h" |
| 31 #include "ui/gfx/image/image_family.h" |
| 32 #include "ui/gfx/image/image_skia.h" |
| 21 | 33 |
| 22 using content::BrowserThread; | 34 using content::BrowserThread; |
| 23 | 35 |
| 24 namespace { | 36 namespace { |
| 25 | 37 |
| 38 #if defined(OS_MACOSX) |
| 39 const int kDesiredSizes[] = {16, 32, 128, 256, 512}; |
| 40 const size_t kNumDesiredSizes = arraysize(kDesiredSizes); |
| 41 #elif defined(OS_LINUX) |
| 42 // Linux supports icons of any size. FreeDesktop Icon Theme Specification states |
| 43 // that "Minimally you should install a 48x48 icon in the hicolor theme." |
| 44 const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512}; |
| 45 const size_t kNumDesiredSizes = arraysize(kDesiredSizes); |
| 46 #elif defined(OS_WIN) |
| 47 const int* kDesiredSizes = IconUtil::kIconDimensions; |
| 48 const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions; |
| 49 #else |
| 50 const int kDesiredSizes[] = {32}; |
| 51 const size_t kNumDesiredSizes = arraysize(kDesiredSizes); |
| 52 #endif |
| 53 |
| 26 #if defined(TOOLKIT_VIEWS) | 54 #if defined(TOOLKIT_VIEWS) |
| 27 // Predicator for sorting images from largest to smallest. | 55 // Predicator for sorting images from largest to smallest. |
| 28 bool IconPrecedes(const WebApplicationInfo::IconInfo& left, | 56 bool IconPrecedes(const WebApplicationInfo::IconInfo& left, |
| 29 const WebApplicationInfo::IconInfo& right) { | 57 const WebApplicationInfo::IconInfo& right) { |
| 30 return left.width < right.width; | 58 return left.width < right.width; |
| 31 } | 59 } |
| 32 #endif | 60 #endif |
| 33 | 61 |
| 34 void DeleteShortcutsOnFileThread( | 62 void DeleteShortcutsOnFileThread( |
| 35 const ShellIntegration::ShortcutInfo& shortcut_info) { | 63 const ShellIntegration::ShortcutInfo& shortcut_info) { |
| 36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 37 | 65 |
| 38 base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory( | 66 base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory( |
| 39 shortcut_info.profile_path, shortcut_info.extension_id, GURL()); | 67 shortcut_info.profile_path, shortcut_info.extension_id, GURL()); |
| 40 return web_app::internals::DeletePlatformShortcuts( | 68 return web_app::internals::DeletePlatformShortcuts( |
| 41 shortcut_data_dir, shortcut_info); | 69 shortcut_data_dir, shortcut_info); |
| 42 } | 70 } |
| 43 | 71 |
| 44 void UpdateShortcutsOnFileThread( | 72 void UpdateShortcutsOnFileThread( |
| 45 const base::string16& old_app_title, | 73 const base::string16& old_app_title, |
| 46 const ShellIntegration::ShortcutInfo& shortcut_info) { | 74 const ShellIntegration::ShortcutInfo& shortcut_info) { |
| 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
| 48 | 76 |
| 49 base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory( | 77 base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory( |
| 50 shortcut_info.profile_path, shortcut_info.extension_id, GURL()); | 78 shortcut_info.profile_path, shortcut_info.extension_id, GURL()); |
| 51 return web_app::internals::UpdatePlatformShortcuts( | 79 return web_app::internals::UpdatePlatformShortcuts( |
| 52 shortcut_data_dir, old_app_title, shortcut_info); | 80 shortcut_data_dir, old_app_title, shortcut_info); |
| 53 } | 81 } |
| 54 | 82 |
| 83 void OnImageLoaded(ShellIntegration::ShortcutInfo shortcut_info, |
| 84 web_app::ShortcutInfoCallback callback, |
| 85 const gfx::ImageFamily& image_family) { |
| 86 // If the image failed to load (e.g. if the resource being loaded was empty) |
| 87 // use the standard application icon. |
| 88 if (image_family.empty()) { |
| 89 gfx::Image default_icon = |
| 90 ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON); |
| 91 int size = kDesiredSizes[kNumDesiredSizes - 1]; |
| 92 SkBitmap bmp = skia::ImageOperations::Resize( |
| 93 *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST, |
| 94 size, size); |
| 95 gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp); |
| 96 // We are on the UI thread, and this image is needed from the FILE thread, |
| 97 // for creating shortcut icon files. |
| 98 image_skia.MakeThreadSafe(); |
| 99 shortcut_info.favicon.Add(gfx::Image(image_skia)); |
| 100 } else { |
| 101 shortcut_info.favicon = image_family; |
| 102 } |
| 103 |
| 104 callback.Run(shortcut_info); |
| 105 } |
| 106 |
| 55 } // namespace | 107 } // namespace |
| 56 | 108 |
| 57 namespace web_app { | 109 namespace web_app { |
| 58 | 110 |
| 59 // The following string is used to build the directory name for | 111 // The following string is used to build the directory name for |
| 60 // shortcuts to chrome applications (the kind which are installed | 112 // shortcuts to chrome applications (the kind which are installed |
| 61 // from a CRX). Application shortcuts to URLs use the {host}_{path} | 113 // from a CRX). Application shortcuts to URLs use the {host}_{path} |
| 62 // for the name of this directory. Hosts can't include an underscore. | 114 // for the name of this directory. Hosts can't include an underscore. |
| 63 // By starting this string with an underscore, we ensure that there | 115 // By starting this string with an underscore, we ensure that there |
| 64 // are no naming conflicts. | 116 // are no naming conflicts. |
| 65 static const char* kCrxAppPrefix = "_crx_"; | 117 static const char* kCrxAppPrefix = "_crx_"; |
| 66 | 118 |
| 67 namespace internals { | 119 namespace internals { |
| 68 | 120 |
| 69 base::FilePath GetSanitizedFileName(const base::string16& name) { | 121 base::FilePath GetSanitizedFileName(const base::string16& name) { |
| 70 #if defined(OS_WIN) | 122 #if defined(OS_WIN) |
| 71 base::string16 file_name = name; | 123 base::string16 file_name = name; |
| 72 #else | 124 #else |
| 73 std::string file_name = base::UTF16ToUTF8(name); | 125 std::string file_name = base::UTF16ToUTF8(name); |
| 74 #endif | 126 #endif |
| 75 file_util::ReplaceIllegalCharactersInPath(&file_name, '_'); | 127 file_util::ReplaceIllegalCharactersInPath(&file_name, '_'); |
| 76 return base::FilePath(file_name); | 128 return base::FilePath(file_name); |
| 77 } | 129 } |
| 78 | 130 |
| 79 } // namespace internals | 131 } // namespace internals |
| 80 | 132 |
| 133 ShellIntegration::ShortcutInfo ShortcutInfoForExtensionAndProfile( |
| 134 const extensions::Extension* app, Profile* profile) { |
| 135 ShellIntegration::ShortcutInfo shortcut_info; |
| 136 shortcut_info.extension_id = app->id(); |
| 137 shortcut_info.is_platform_app = app->is_platform_app(); |
| 138 shortcut_info.url = extensions::AppLaunchInfo::GetLaunchWebURL(app); |
| 139 shortcut_info.title = base::UTF8ToUTF16(app->name()); |
| 140 shortcut_info.description = base::UTF8ToUTF16(app->description()); |
| 141 shortcut_info.extension_path = app->path(); |
| 142 shortcut_info.profile_path = profile->GetPath(); |
| 143 shortcut_info.profile_name = |
| 144 profile->GetPrefs()->GetString(prefs::kProfileName); |
| 145 return shortcut_info; |
| 146 } |
| 147 |
| 148 void UpdateShortcutInfoAndIconForApp( |
| 149 const extensions::Extension* extension, |
| 150 Profile* profile, |
| 151 const web_app::ShortcutInfoCallback& callback) { |
| 152 ShellIntegration::ShortcutInfo shortcut_info = |
| 153 ShortcutInfoForExtensionAndProfile(extension, profile); |
| 154 |
| 155 std::vector<extensions::ImageLoader::ImageRepresentation> info_list; |
| 156 for (size_t i = 0; i < kNumDesiredSizes; ++i) { |
| 157 int size = kDesiredSizes[i]; |
| 158 extensions::ExtensionResource resource = |
| 159 extensions::IconsInfo::GetIconResource( |
| 160 extension, size, ExtensionIconSet::MATCH_EXACTLY); |
| 161 if (!resource.empty()) { |
| 162 info_list.push_back(extensions::ImageLoader::ImageRepresentation( |
| 163 resource, |
| 164 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, |
| 165 gfx::Size(size, size), |
| 166 ui::SCALE_FACTOR_100P)); |
| 167 } |
| 168 } |
| 169 |
| 170 if (info_list.empty()) { |
| 171 size_t i = kNumDesiredSizes - 1; |
| 172 int size = kDesiredSizes[i]; |
| 173 |
| 174 // If there is no icon at the desired sizes, we will resize what we can get. |
| 175 // Making a large icon smaller is preferred to making a small icon larger, |
| 176 // so look for a larger icon first: |
| 177 extensions::ExtensionResource resource = |
| 178 extensions::IconsInfo::GetIconResource( |
| 179 extension, size, ExtensionIconSet::MATCH_BIGGER); |
| 180 if (resource.empty()) { |
| 181 resource = extensions::IconsInfo::GetIconResource( |
| 182 extension, size, ExtensionIconSet::MATCH_SMALLER); |
| 183 } |
| 184 info_list.push_back(extensions::ImageLoader::ImageRepresentation( |
| 185 resource, |
| 186 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, |
| 187 gfx::Size(size, size), |
| 188 ui::SCALE_FACTOR_100P)); |
| 189 } |
| 190 |
| 191 // |info_list| may still be empty at this point, in which case |
| 192 // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty |
| 193 // image and exit immediately. |
| 194 extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync( |
| 195 extension, |
| 196 info_list, |
| 197 base::Bind(&OnImageLoaded, shortcut_info, callback)); |
| 198 } |
| 199 |
| 81 base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path, | 200 base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path, |
| 82 const std::string& extension_id, | 201 const std::string& extension_id, |
| 83 const GURL& url) { | 202 const GURL& url) { |
| 84 DCHECK(!profile_path.empty()); | 203 DCHECK(!profile_path.empty()); |
| 85 base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname)); | 204 base::FilePath app_data_dir(profile_path.Append(chrome::kWebAppDirname)); |
| 86 | 205 |
| 87 if (!extension_id.empty()) { | 206 if (!extension_id.empty()) { |
| 88 return app_data_dir.AppendASCII( | 207 return app_data_dir.AppendASCII( |
| 89 GenerateApplicationNameFromExtensionId(extension_id)); | 208 GenerateApplicationNameFromExtensionId(extension_id)); |
| 90 } | 209 } |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 | 347 |
| 229 #if defined(OS_LINUX) | 348 #if defined(OS_LINUX) |
| 230 std::string GetWMClassFromAppName(std::string app_name) { | 349 std::string GetWMClassFromAppName(std::string app_name) { |
| 231 file_util::ReplaceIllegalCharactersInPath(&app_name, '_'); | 350 file_util::ReplaceIllegalCharactersInPath(&app_name, '_'); |
| 232 base::TrimString(app_name, "_", &app_name); | 351 base::TrimString(app_name, "_", &app_name); |
| 233 return app_name; | 352 return app_name; |
| 234 } | 353 } |
| 235 #endif | 354 #endif |
| 236 | 355 |
| 237 } // namespace web_app | 356 } // namespace web_app |
| OLD | NEW |