Index: chrome/browser/web_applications/web_app.cc |
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc |
index 054f3f62958de23501558681496ff9c52fedee3b..5149be787b16580945f238ce0b98bce8f501f825 100644 |
--- a/chrome/browser/web_applications/web_app.cc |
+++ b/chrome/browser/web_applications/web_app.cc |
@@ -8,21 +8,53 @@ |
#include "base/bind_helpers.h" |
#include "base/file_util.h" |
#include "base/i18n/file_util_icu.h" |
+#include "base/prefs/pref_service.h" |
#include "base/strings/string_util.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/threading/thread.h" |
+#include "chrome/browser/extensions/image_loader.h" |
+#include "chrome/browser/profiles/profile.h" |
#include "chrome/common/chrome_constants.h" |
#include "chrome/common/chrome_version_info.h" |
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" |
+#include "chrome/common/extensions/manifest_handlers/icons_handler.h" |
+#include "chrome/common/pref_names.h" |
#include "chrome/common/url_constants.h" |
#include "content/public/browser/browser_thread.h" |
#include "extensions/common/constants.h" |
#include "extensions/common/extension.h" |
+#include "grit/theme_resources.h" |
+#include "skia/ext/image_operations.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/gfx/image/image.h" |
+#include "ui/gfx/image/image_family.h" |
+#include "ui/gfx/image/image_skia.h" |
+ |
+#if defined(OS_WIN) |
+#include "ui/gfx/icon_util.h" |
+#endif |
using content::BrowserThread; |
namespace { |
+#if defined(OS_MACOSX) |
+const int kDesiredSizes[] = {16, 32, 128, 256, 512}; |
+const size_t kNumDesiredSizes = arraysize(kDesiredSizes); |
+#elif defined(OS_LINUX) |
+// Linux supports icons of any size. FreeDesktop Icon Theme Specification states |
+// that "Minimally you should install a 48x48 icon in the hicolor theme." |
+const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512}; |
+const size_t kNumDesiredSizes = arraysize(kDesiredSizes); |
+#elif defined(OS_WIN) |
+const int* kDesiredSizes = IconUtil::kIconDimensions; |
+const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions; |
+#else |
+const int kDesiredSizes[] = {32}; |
+const size_t kNumDesiredSizes = arraysize(kDesiredSizes); |
+#endif |
+ |
#if defined(TOOLKIT_VIEWS) |
// Predicator for sorting images from largest to smallest. |
bool IconPrecedes(const WebApplicationInfo::IconInfo& left, |
@@ -52,6 +84,30 @@ void UpdateShortcutsOnFileThread( |
shortcut_data_dir, old_app_title, shortcut_info); |
} |
+void OnImageLoaded(ShellIntegration::ShortcutInfo shortcut_info, |
+ web_app::ShortcutInfoCallback callback, |
+ const gfx::ImageFamily& image_family) { |
+ // If the image failed to load (e.g. if the resource being loaded was empty) |
+ // use the standard application icon. |
+ if (image_family.empty()) { |
+ gfx::Image default_icon = |
+ ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON); |
+ int size = kDesiredSizes[kNumDesiredSizes - 1]; |
+ SkBitmap bmp = skia::ImageOperations::Resize( |
+ *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST, |
+ size, size); |
+ gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp); |
+ // We are on the UI thread, and this image is needed from the FILE thread, |
+ // for creating shortcut icon files. |
+ image_skia.MakeThreadSafe(); |
+ shortcut_info.favicon.Add(gfx::Image(image_skia)); |
+ } else { |
+ shortcut_info.favicon = image_family; |
+ } |
+ |
+ callback.Run(shortcut_info); |
+} |
+ |
} // namespace |
namespace web_app { |
@@ -78,6 +134,73 @@ base::FilePath GetSanitizedFileName(const base::string16& name) { |
} // namespace internals |
+ShellIntegration::ShortcutInfo ShortcutInfoForExtensionAndProfile( |
+ const extensions::Extension* app, Profile* profile) { |
+ ShellIntegration::ShortcutInfo shortcut_info; |
+ shortcut_info.extension_id = app->id(); |
+ shortcut_info.is_platform_app = app->is_platform_app(); |
+ shortcut_info.url = extensions::AppLaunchInfo::GetLaunchWebURL(app); |
+ shortcut_info.title = base::UTF8ToUTF16(app->name()); |
+ shortcut_info.description = base::UTF8ToUTF16(app->description()); |
+ shortcut_info.extension_path = app->path(); |
+ shortcut_info.profile_path = profile->GetPath(); |
+ shortcut_info.profile_name = |
+ profile->GetPrefs()->GetString(prefs::kProfileName); |
+ return shortcut_info; |
+} |
+ |
+void UpdateShortcutInfoAndIconForApp( |
+ const extensions::Extension* extension, |
+ Profile* profile, |
+ const web_app::ShortcutInfoCallback& callback) { |
+ ShellIntegration::ShortcutInfo shortcut_info = |
+ ShortcutInfoForExtensionAndProfile(extension, profile); |
+ |
+ std::vector<extensions::ImageLoader::ImageRepresentation> info_list; |
+ for (size_t i = 0; i < kNumDesiredSizes; ++i) { |
+ int size = kDesiredSizes[i]; |
+ extensions::ExtensionResource resource = |
+ extensions::IconsInfo::GetIconResource( |
+ extension, size, ExtensionIconSet::MATCH_EXACTLY); |
+ if (!resource.empty()) { |
+ info_list.push_back(extensions::ImageLoader::ImageRepresentation( |
+ resource, |
+ extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, |
+ gfx::Size(size, size), |
+ ui::SCALE_FACTOR_100P)); |
+ } |
+ } |
+ |
+ if (info_list.empty()) { |
+ size_t i = kNumDesiredSizes - 1; |
+ int size = kDesiredSizes[i]; |
+ |
+ // If there is no icon at the desired sizes, we will resize what we can get. |
+ // Making a large icon smaller is preferred to making a small icon larger, |
+ // so look for a larger icon first: |
+ extensions::ExtensionResource resource = |
+ extensions::IconsInfo::GetIconResource( |
+ extension, size, ExtensionIconSet::MATCH_BIGGER); |
+ if (resource.empty()) { |
+ resource = extensions::IconsInfo::GetIconResource( |
+ extension, size, ExtensionIconSet::MATCH_SMALLER); |
+ } |
+ info_list.push_back(extensions::ImageLoader::ImageRepresentation( |
+ resource, |
+ extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, |
+ gfx::Size(size, size), |
+ ui::SCALE_FACTOR_100P)); |
+ } |
+ |
+ // |info_list| may still be empty at this point, in which case |
+ // LoadImageFamilyAsync will call the OnImageLoaded callback with an empty |
+ // image and exit immediately. |
+ extensions::ImageLoader::Get(profile)->LoadImageFamilyAsync( |
+ extension, |
+ info_list, |
+ base::Bind(&OnImageLoaded, shortcut_info, callback)); |
+} |
+ |
base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path, |
const std::string& extension_id, |
const GURL& url) { |