Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / web_applications / web_app.cc
index 054f3f6..a588a94 100644 (file)
@@ -8,21 +8,59 @@
 #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/extensions/tab_helper.h"
+#include "chrome/browser/favicon/favicon_tab_helper.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_version_info.h"
+#include "chrome/common/extensions/api/file_handlers/file_handlers_parser.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.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 "extensions/common/manifest_handlers/icons_handler.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 {
 
+typedef base::Callback<void(const web_app::ShortcutInfo&,
+                            const extensions::FileHandlersInfo&)> InfoCallback;
+
+#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,
@@ -31,8 +69,23 @@ bool IconPrecedes(const WebApplicationInfo::IconInfo& left,
 }
 #endif
 
+bool CreateShortcutsWithInfoOnFileThread(
+    web_app::ShortcutCreationReason reason,
+    const web_app::ShortcutLocations& locations,
+    const web_app::ShortcutInfo& shortcut_info,
+    const extensions::FileHandlersInfo& file_handlers_info) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  base::FilePath shortcut_data_dir =
+      web_app::GetWebAppDataDirectory(shortcut_info.profile_path,
+                                      shortcut_info.extension_id,
+                                      shortcut_info.url);
+  return web_app::internals::CreatePlatformShortcuts(
+      shortcut_data_dir, shortcut_info, file_handlers_info, locations, reason);
+}
+
 void DeleteShortcutsOnFileThread(
-    const ShellIntegration::ShortcutInfo& shortcut_info) {
+    const web_app::ShortcutInfo& shortcut_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
   base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
@@ -43,13 +96,128 @@ void DeleteShortcutsOnFileThread(
 
 void UpdateShortcutsOnFileThread(
     const base::string16& old_app_title,
-    const ShellIntegration::ShortcutInfo& shortcut_info) {
+    const web_app::ShortcutInfo& shortcut_info,
+    const extensions::FileHandlersInfo& file_handlers_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
 
   base::FilePath shortcut_data_dir = web_app::GetWebAppDataDirectory(
       shortcut_info.profile_path, shortcut_info.extension_id, GURL());
   return web_app::internals::UpdatePlatformShortcuts(
-      shortcut_data_dir, old_app_title, shortcut_info);
+      shortcut_data_dir, old_app_title, shortcut_info, file_handlers_info);
+}
+
+void CreateShortcutsWithInfo(
+    web_app::ShortcutCreationReason reason,
+    const web_app::ShortcutLocations& locations,
+    const web_app::ShortcutInfo& shortcut_info,
+    const extensions::FileHandlersInfo& file_handlers_info) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+  BrowserThread::PostTask(
+      BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(
+          base::IgnoreResult(&CreateShortcutsWithInfoOnFileThread),
+          reason, locations, shortcut_info, file_handlers_info));
+}
+
+void UpdateAllShortcutsForShortcutInfo(
+    const base::string16& old_app_title,
+    const web_app::ShortcutInfo& shortcut_info,
+    const extensions::FileHandlersInfo& file_handlers_info) {
+  BrowserThread::PostTask(
+      BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(&UpdateShortcutsOnFileThread,
+                 old_app_title, shortcut_info, file_handlers_info));
+}
+
+void OnImageLoaded(web_app::ShortcutInfo shortcut_info,
+                   extensions::FileHandlersInfo file_handlers_info,
+                   InfoCallback 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, file_handlers_info);
+}
+
+void GetInfoForApp(const extensions::Extension* extension,
+                   Profile* profile,
+                   const InfoCallback& callback) {
+  web_app::ShortcutInfo shortcut_info =
+      web_app::ShortcutInfoForExtensionAndProfile(extension, profile);
+  extensions::FileHandlersInfo file_handlers_info;
+  const std::vector<extensions::FileHandlerInfo>* file_handlers =
+      extensions::FileHandlers::GetFileHandlers(extension);
+  if (file_handlers)
+    file_handlers_info.handlers = *file_handlers;
+
+  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, file_handlers_info, callback));
+}
+
+void IgnoreFileHandlersInfo(
+    const web_app::ShortcutInfoCallback& shortcut_info_callback,
+    const web_app::ShortcutInfo& shortcut_info,
+    const extensions::FileHandlersInfo& file_handlers_info) {
+  shortcut_info_callback.Run(shortcut_info);
 }
 
 }  // namespace
@@ -76,8 +244,86 @@ base::FilePath GetSanitizedFileName(const base::string16& name) {
   return base::FilePath(file_name);
 }
 
+bool CreateShortcutsOnFileThread(
+    ShortcutCreationReason reason,
+    const web_app::ShortcutLocations& locations,
+    const web_app::ShortcutInfo& shortcut_info) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  return CreateShortcutsWithInfoOnFileThread(
+      reason, locations, shortcut_info, extensions::FileHandlersInfo());
+}
+
 }  // namespace internals
 
+web_app::ShortcutInfo::ShortcutInfo()
+    : is_platform_app(false) {
+}
+
+web_app::ShortcutInfo::~ShortcutInfo() {}
+
+web_app::ShortcutLocations::ShortcutLocations()
+    : on_desktop(false),
+      applications_menu_location(APP_MENU_LOCATION_NONE),
+      in_quick_launch_bar(false)
+#if defined(OS_POSIX)
+      , hidden(false)
+#endif
+      {
+}
+
+void GetShortcutInfoForTab(content::WebContents* web_contents,
+                           web_app::ShortcutInfo* info) {
+  DCHECK(info);  // Must provide a valid info.
+
+  const FaviconTabHelper* favicon_tab_helper =
+      FaviconTabHelper::FromWebContents(web_contents);
+  const extensions::TabHelper* extensions_tab_helper =
+      extensions::TabHelper::FromWebContents(web_contents);
+  const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info();
+
+  info->url = app_info.app_url.is_empty() ? web_contents->GetURL() :
+                                            app_info.app_url;
+  info->title = app_info.title.empty() ?
+      (web_contents->GetTitle().empty() ? base::UTF8ToUTF16(info->url.spec()) :
+                                          web_contents->GetTitle()) :
+      app_info.title;
+  info->description = app_info.description;
+  info->favicon.Add(favicon_tab_helper->GetFavicon());
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  info->profile_path = profile->GetPath();
+}
+
+#if !defined(OS_WIN)
+void UpdateShortcutForTabContents(content::WebContents* web_contents) {}
+#endif
+
+web_app::ShortcutInfo ShortcutInfoForExtensionAndProfile(
+    const extensions::Extension* app, Profile* profile) {
+  web_app::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) {
+  GetInfoForApp(extension,
+                profile,
+                base::Bind(&IgnoreFileHandlersInfo, callback));
+}
+
 base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
                                       const std::string& extension_id,
                                       const GURL& url) {
@@ -114,7 +360,7 @@ base::FilePath GetWebAppDataDirectory(const base::FilePath& profile_path,
 }
 
 std::string GenerateApplicationNameFromInfo(
-    const ShellIntegration::ShortcutInfo& shortcut_info) {
+    const web_app::ShortcutInfo& shortcut_info) {
   if (!shortcut_info.extension_id.empty()) {
     return web_app::GenerateApplicationNameFromExtensionId(
         shortcut_info.extension_id);
@@ -145,50 +391,50 @@ std::string GetExtensionIdFromApplicationName(const std::string& app_name) {
   return app_name.substr(prefix.length());
 }
 
-void CreateShortcuts(
-    const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations,
-    ShortcutCreationReason creation_reason) {
+void CreateShortcutsForShortcutInfo(
+    web_app::ShortcutCreationReason reason,
+    const web_app::ShortcutLocations& locations,
+    const web_app::ShortcutInfo& shortcut_info) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   BrowserThread::PostTask(
       BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(base::IgnoreResult(&CreateShortcutsOnFileThread),
-                 shortcut_info, creation_locations, creation_reason));
+      base::Bind(
+          base::IgnoreResult(&web_app::internals::CreateShortcutsOnFileThread),
+          reason, locations, shortcut_info));
 }
 
-void DeleteAllShortcuts(const ShellIntegration::ShortcutInfo& shortcut_info) {
+void CreateShortcuts(
+    ShortcutCreationReason reason,
+    const web_app::ShortcutLocations& locations,
+    Profile* profile,
+    const extensions::Extension* app) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  BrowserThread::PostTask(
-      BrowserThread::FILE,
-      FROM_HERE,
-      base::Bind(&DeleteShortcutsOnFileThread, shortcut_info));
+  GetInfoForApp(app,
+                profile,
+                base::Bind(&CreateShortcutsWithInfo, reason, locations));
 }
 
-void UpdateAllShortcuts(const base::string16& old_app_title,
-                        const ShellIntegration::ShortcutInfo& shortcut_info) {
+void DeleteAllShortcuts(Profile* profile, const extensions::Extension* app) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   BrowserThread::PostTask(
       BrowserThread::FILE,
       FROM_HERE,
-      base::Bind(&UpdateShortcutsOnFileThread, old_app_title, shortcut_info));
+      base::Bind(&DeleteShortcutsOnFileThread,
+                 web_app::ShortcutInfoForExtensionAndProfile(app, profile)));
 }
 
-bool CreateShortcutsOnFileThread(
-    const ShellIntegration::ShortcutInfo& shortcut_info,
-    const ShellIntegration::ShortcutLocations& creation_locations,
-    ShortcutCreationReason creation_reason) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+void UpdateAllShortcuts(const base::string16& old_app_title,
+                        Profile* profile,
+                        const extensions::Extension* app) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  base::FilePath shortcut_data_dir = GetWebAppDataDirectory(
-      shortcut_info.profile_path, shortcut_info.extension_id,
-      shortcut_info.url);
-  return internals::CreatePlatformShortcuts(shortcut_data_dir, shortcut_info,
-                                            creation_locations,
-                                            creation_reason);
+  GetInfoForApp(app,
+                profile,
+                base::Bind(&UpdateAllShortcutsForShortcutInfo, old_app_title));
 }
 
 bool IsValidUrl(const GURL& url) {
@@ -196,8 +442,8 @@ bool IsValidUrl(const GURL& url) {
       content::kFileScheme,
       content::kFileSystemScheme,
       content::kFtpScheme,
-      content::kHttpScheme,
-      content::kHttpsScheme,
+      url::kHttpScheme,
+      url::kHttpsScheme,
       extensions::kExtensionScheme,
   };